diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-14 16:29:51 +1100 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2009-01-14 16:29:51 +1100 |
commit | cb7a97d01521797cad9f63e8478403c3e51fea49 (patch) | |
tree | 84cddf20369f82f10c1c3712e6cce20dd1b9d863 /drivers | |
parent | 0335cb76aa3fa913a2164bc9b669e5aef9d56fa3 (diff) | |
parent | a6525042bfdfcab128bd91fad264de10fd24a55e (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'drivers')
701 files changed, 33994 insertions, 18997 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig index 2f557f570ad..00cf9553f74 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -107,4 +107,6 @@ source "drivers/uio/Kconfig" source "drivers/xen/Kconfig" source "drivers/staging/Kconfig" + +source "drivers/platform/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index e121b66ef08..c1bf4173793 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_ARM_AMBA) += amba/ obj-$(CONFIG_XEN) += xen/ +# regulators early, since some subsystems rely on them to initialize +obj-$(CONFIG_REGULATOR) += regulator/ + # char/ comes before serial/ etc so that the VT console is the boot-time # default. obj-y += char/ @@ -101,5 +104,5 @@ obj-$(CONFIG_PPC_PS3) += ps3/ obj-$(CONFIG_OF) += of/ obj-$(CONFIG_SSB) += ssb/ obj-$(CONFIG_VIRTIO) += virtio/ -obj-$(CONFIG_REGULATOR) += regulator/ obj-$(CONFIG_STAGING) += staging/ +obj-y += platform/ diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b0243fd55ac..d7f9839ba26 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -196,90 +196,6 @@ config ACPI_NUMA depends on (X86 || IA64) default y if IA64_GENERIC || IA64_SGI_SN2 -config ACPI_WMI - tristate "WMI (EXPERIMENTAL)" - depends on X86 - depends on EXPERIMENTAL - help - This driver adds support for the ACPI-WMI (Windows Management - Instrumentation) mapper device (PNP0C14) found on some systems. - - ACPI-WMI is a proprietary extension to ACPI to expose parts of the - ACPI firmware to userspace - this is done through various vendor - defined methods and data blocks in a PNP0C14 device, which are then - made available for userspace to call. - - The implementation of this in Linux currently only exposes this to - other kernel space drivers. - - This driver is a required dependency to build the firmware specific - drivers needed on many machines, including Acer and HP laptops. - - It is safe to enable this driver even if your DSDT doesn't define - any ACPI-WMI devices. - -config ACPI_ASUS - tristate "ASUS/Medion Laptop Extras" - depends on X86 - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver provides support for extra features of ACPI-compatible - ASUS laptops. As some of Medion laptops are made by ASUS, it may also - support some Medion laptops (such as 9675 for example). It makes all - the extra buttons generate standard ACPI events that go through - /proc/acpi/events, and (on some models) adds support for changing the - display brightness and output, switching the LCD backlight on and off, - and most importantly, allows you to blink those fancy LEDs intended - for reporting mail and wireless status. - - Note: display switching code is currently considered EXPERIMENTAL, - toying with these values may even lock your machine. - - All settings are changed via /proc/acpi/asus directory entries. Owner - and group for these entries can be set with asus_uid and asus_gid - parameters. - - More information and a userspace daemon for handling the extra buttons - at <http://sourceforge.net/projects/acpi4asus/>. - - If you have an ACPI-compatible ASUS laptop, say Y or M here. This - driver is still under development, so if your laptop is unsupported or - something works not quite as expected, please use the mailing list - available on the above page (acpi4asus-user@lists.sourceforge.net). - - NOTE: This driver is deprecated and will probably be removed soon, - use asus-laptop instead. - -config ACPI_TOSHIBA - tristate "Toshiba Laptop Extras" - depends on X86 && INPUT - select INPUT_POLLDEV - select NET - select RFKILL - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver adds support for access to certain system settings - on "legacy free" Toshiba laptops. These laptops can be recognized by - their lack of a BIOS setup menu and APM support. - - On these machines, all system configuration is handled through the - ACPI. This driver is required for access to controls not covered - by the general ACPI drivers, such as LCD brightness, video output, - etc. - - This driver differs from the non-ACPI Toshiba laptop driver (located - under "Processor type and features") in several aspects. - Configuration is accessed by reading and writing text files in the - /proc tree instead of by program interface to /dev. Furthermore, no - power management functions are exposed, as those are handled by the - general ACPI drivers. - - More information about this driver is available at - <http://memebeam.org/toys/ToshibaAcpiDriver>. - - If you have a legacy free Toshiba laptop (such as the Libretto L1 - series), say Y. - config ACPI_CUSTOM_DSDT_FILE string "Custom DSDT Table file to include" default "" diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 3c0c93300f1..d80f4cc2e0d 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -2,15 +2,8 @@ # Makefile for the Linux ACPI interpreter # -export ACPI_CFLAGS - -ACPI_CFLAGS := -Os - -ifdef CONFIG_ACPI_DEBUG - ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT -endif - -EXTRA_CFLAGS += $(ACPI_CFLAGS) +ccflags-y := -Os +ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # # ACPI Boot-Time Table Parsing @@ -22,9 +15,13 @@ obj-$(CONFIG_X86) += blacklist.o # ACPI Core Subsystem (Interpreter) # obj-y += osl.o utils.o reboot.o\ - dispatcher/ events/ executer/ hardware/ \ - namespace/ parser/ resources/ tables/ \ - utilities/ + acpica/ + +# sleep related files +obj-y += wakeup.o +obj-y += main.o +obj-$(CONFIG_ACPI_SLEEP) += proc.o + # # ACPI Bus and Device Drivers @@ -35,7 +32,6 @@ ifdef CONFIG_CPU_FREQ processor-objs += processor_perflib.o endif -obj-y += sleep/ obj-y += bus.o glue.o obj-y += scan.o # Keep EC driver first. Initialization of others depend on it. @@ -59,9 +55,6 @@ obj-y += power.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_NUMA) += numa.o -obj-$(CONFIG_ACPI_WMI) += wmi.o -obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o -obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o obj-$(CONFIG_ACPI_SBS) += sbshc.o diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile new file mode 100644 index 00000000000..3f23298ee3f --- /dev/null +++ b/drivers/acpi/acpica/Makefile @@ -0,0 +1,44 @@ +# +# Makefile for ACPICA Core interpreter +# + +ccflags-y := -Os +ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT + +obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ + dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ + dsinit.o + +obj-y += evevent.o evregion.o evsci.o evxfevnt.o \ + evmisc.o evrgnini.o evxface.o evxfregn.o \ + evgpe.o evgpeblk.o + +obj-y += exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ + exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ + excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ + exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o + +obj-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o + +obj-$(ACPI_FUTURE_USAGE) += hwtimer.o + +obj-y += nsaccess.o nsload.o nssearch.o nsxfeval.o \ + nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ + nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ + nsparse.o nspredef.o + +obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o + +obj-y += psargs.o psparse.o psloop.o pstree.o pswalk.o \ + psopcode.o psscope.o psutils.o psxface.o + +obj-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ + rscalc.o rsirq.o rsmemory.o rsutils.o + +obj-$(ACPI_FUTURE_USAGE) += rsdump.o + +obj-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o + +obj-y += utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ + utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ + utstate.o utmutex.o utobject.o utresrc.o diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h new file mode 100644 index 00000000000..3b20786cbb0 --- /dev/null +++ b/drivers/acpi/acpica/accommon.h @@ -0,0 +1,63 @@ +/****************************************************************************** + * + * Name: accommon.h - Common include files for generation of ACPICA source + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACCOMMON_H__ +#define __ACCOMMON_H__ + +/* + * Common set of includes for all ACPICA source files. + * We put them here because we don't want to duplicate them + * in the the source code again and again. + * + * Note: The order of these include files is important. + */ +#include "acconfig.h" /* Global configuration constants */ +#include "acmacros.h" /* C macros */ +#include "aclocal.h" /* Internal data types */ +#include "acobject.h" /* ACPI internal object */ +#include "acstruct.h" /* Common structures */ +#include "acglobal.h" /* All global variables */ +#include "achware.h" /* Hardware defines and interfaces */ +#include "acutils.h" /* Utility interfaces */ + +#endif /* __ACCOMMON_H__ */ diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h new file mode 100644 index 00000000000..e6777fb883d --- /dev/null +++ b/drivers/acpi/acpica/acconfig.h @@ -0,0 +1,217 @@ +/****************************************************************************** + * + * Name: acconfig.h - Global configuration constants + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef _ACCONFIG_H +#define _ACCONFIG_H + +/****************************************************************************** + * + * Configuration options + * + *****************************************************************************/ + +/* + * ACPI_DEBUG_OUTPUT - This switch enables all the debug facilities of the + * ACPI subsystem. This includes the DEBUG_PRINT output + * statements. When disabled, all DEBUG_PRINT + * statements are compiled out. + * + * ACPI_APPLICATION - Use this switch if the subsystem is going to be run + * at the application level. + * + */ + +/* + * OS name, used for the _OS object. The _OS object is essentially obsolete, + * but there is a large base of ASL/AML code in existing machines that check + * for the string below. The use of this string usually guarantees that + * the ASL will execute down the most tested code path. Also, there is some + * code that will not execute the _OSI method unless _OS matches the string + * below. Therefore, change this string at your own risk. + */ +#define ACPI_OS_NAME "Microsoft Windows NT" + +/* Maximum objects in the various object caches */ + +#define ACPI_MAX_STATE_CACHE_DEPTH 96 /* State objects */ +#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ +#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ +#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ + +/* + * Should the subsystem abort the loading of an ACPI table if the + * table checksum is incorrect? + */ +#define ACPI_CHECKSUM_ABORT FALSE + +/****************************************************************************** + * + * Subsystem Constants + * + *****************************************************************************/ + +/* Version of ACPI supported */ + +#define ACPI_CA_SUPPORT_LEVEL 3 + +/* Maximum count for a semaphore object */ + +#define ACPI_MAX_SEMAPHORE_COUNT 256 + +/* Maximum object reference count (detects object deletion issues) */ + +#define ACPI_MAX_REFERENCE_COUNT 0x1000 + +/* Size of cached memory mapping for system memory operation region */ + +#define ACPI_SYSMEM_REGION_WINDOW_SIZE 4096 + +/* owner_id tracking. 8 entries allows for 255 owner_ids */ + +#define ACPI_NUM_OWNERID_MASKS 8 + +/* Size of the root table array is increased by this increment */ + +#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 + +/* Maximum number of While() loop iterations before forced abort */ + +#define ACPI_MAX_LOOP_ITERATIONS 0xFFFF + +/****************************************************************************** + * + * ACPI Specification constants (Do not change unless the specification changes) + * + *****************************************************************************/ + +/* Number of distinct GPE register blocks and register width */ + +#define ACPI_MAX_GPE_BLOCKS 2 +#define ACPI_GPE_REGISTER_WIDTH 8 + +/* Method info (in WALK_STATE), containing local variables and argumetns */ + +#define ACPI_METHOD_NUM_LOCALS 8 +#define ACPI_METHOD_MAX_LOCAL 7 + +#define ACPI_METHOD_NUM_ARGS 7 +#define ACPI_METHOD_MAX_ARG 6 + +/* Length of _HID, _UID, _CID, and UUID values */ + +#define ACPI_DEVICE_ID_LENGTH 0x09 +#define ACPI_MAX_CID_LENGTH 48 +#define ACPI_UUID_LENGTH 16 + +/* + * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG + */ +#define ACPI_OBJ_NUM_OPERANDS 8 +#define ACPI_OBJ_MAX_OPERAND 7 + +/* Number of elements in the Result Stack frame, can be an arbitrary value */ + +#define ACPI_RESULTS_FRAME_OBJ_NUM 8 + +/* + * Maximal number of elements the Result Stack can contain, + * it may be an arbitray value not exceeding the types of + * result_size and result_count (now u8). + */ +#define ACPI_RESULTS_OBJ_NUM_MAX 255 + +/* Names within the namespace are 4 bytes long */ + +#define ACPI_NAME_SIZE 4 +#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ +#define ACPI_PATH_SEPARATOR '.' + +/* Sizes for ACPI table headers */ + +#define ACPI_OEM_ID_SIZE 6 +#define ACPI_OEM_TABLE_ID_SIZE 8 + +/* Constants used in searching for the RSDP in low memory */ + +#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ +#define ACPI_EBDA_PTR_LENGTH 2 +#define ACPI_EBDA_WINDOW_SIZE 1024 +#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ +#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 +#define ACPI_RSDP_SCAN_STEP 16 + +/* Operation regions */ + +#define ACPI_NUM_PREDEFINED_REGIONS 8 +#define ACPI_USER_REGION_BEGIN 0x80 + +/* Maximum space_ids for Operation Regions */ + +#define ACPI_MAX_ADDRESS_SPACE 255 + +/* Array sizes. Used for range checking also */ + +#define ACPI_MAX_MATCH_OPCODE 5 + +/* RSDP checksums */ + +#define ACPI_RSDP_CHECKSUM_LENGTH 20 +#define ACPI_RSDP_XCHECKSUM_LENGTH 36 + +/* SMBus bidirectional buffer size */ + +#define ACPI_SMBUS_BUFFER_SIZE 34 + +/****************************************************************************** + * + * ACPI AML Debugger + * + *****************************************************************************/ + +#define ACPI_DEBUGGER_MAX_ARGS 8 /* Must be max method args + 1 */ + +#define ACPI_DEBUGGER_COMMAND_PROMPT '-' +#define ACPI_DEBUGGER_EXECUTE_PROMPT '%' + +#endif /* _ACCONFIG_H */ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h new file mode 100644 index 00000000000..62c59df3b86 --- /dev/null +++ b/drivers/acpi/acpica/acdebug.h @@ -0,0 +1,231 @@ +/****************************************************************************** + * + * Name: acdebug.h - ACPI/AML debugger + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACDEBUG_H__ +#define __ACDEBUG_H__ + +#define ACPI_DEBUG_BUFFER_SIZE 4196 + +struct command_info { + char *name; /* Command Name */ + u8 min_args; /* Minimum arguments required */ +}; + +struct argument_info { + char *name; /* Argument Name */ +}; + +#define PARAM_LIST(pl) pl +#define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose) +#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ + acpi_os_printf PARAM_LIST(fp);} + +#define EX_NO_SINGLE_STEP 1 +#define EX_SINGLE_STEP 2 + +/* + * dbxface - external debugger interfaces + */ +acpi_status acpi_db_initialize(void); + +void acpi_db_terminate(void); + +acpi_status +acpi_db_single_step(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, u32 op_type); + +/* + * dbcmds - debug commands and output routines + */ +acpi_status acpi_db_disassemble_method(char *name); + +void acpi_db_display_table_info(char *table_arg); + +void acpi_db_unload_acpi_table(char *table_arg, char *instance_arg); + +void +acpi_db_set_method_breakpoint(char *location, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +void acpi_db_set_method_call_breakpoint(union acpi_parse_object *op); + +void acpi_db_get_bus_info(void); + +void acpi_db_disassemble_aml(char *statements, union acpi_parse_object *op); + +void acpi_db_dump_namespace(char *start_arg, char *depth_arg); + +void acpi_db_dump_namespace_by_owner(char *owner_arg, char *depth_arg); + +void acpi_db_send_notify(char *name, u32 value); + +void acpi_db_set_method_data(char *type_arg, char *index_arg, char *value_arg); + +acpi_status +acpi_db_display_objects(char *obj_type_arg, char *display_count_arg); + +acpi_status acpi_db_find_name_in_namespace(char *name_arg); + +void acpi_db_set_scope(char *name); + +acpi_status acpi_db_sleep(char *object_arg); + +void acpi_db_find_references(char *object_arg); + +void acpi_db_display_locks(void); + +void acpi_db_display_resources(char *object_arg); + +void acpi_db_display_gpes(void); + +void acpi_db_check_integrity(void); + +void acpi_db_generate_gpe(char *gpe_arg, char *block_arg); + +void acpi_db_check_predefined_names(void); + +void acpi_db_batch_execute(void); + +/* + * dbdisply - debug display commands + */ +void acpi_db_display_method_info(union acpi_parse_object *op); + +void acpi_db_decode_and_display_object(char *target, char *output_type); + +void +acpi_db_display_result_object(union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +acpi_status acpi_db_display_all_methods(char *display_count_arg); + +void acpi_db_display_arguments(void); + +void acpi_db_display_locals(void); + +void acpi_db_display_results(void); + +void acpi_db_display_calling_tree(void); + +void acpi_db_display_object_type(char *object_arg); + +void +acpi_db_display_argument_object(union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void acpi_db_check_predefined_names(void); + +void acpi_db_batch_execute(void); + +/* + * dbexec - debugger control method execution + */ +void acpi_db_execute(char *name, char **args, u32 flags); + +void +acpi_db_create_execution_threads(char *num_threads_arg, + char *num_loops_arg, char *method_name_arg); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +u32 acpi_db_get_cache_info(struct acpi_memory_list *cache); +#endif + +/* + * dbfileio - Debugger file I/O commands + */ +acpi_object_type +acpi_db_match_argument(char *user_argument, struct argument_info *arguments); + +void acpi_db_close_debug_file(void); + +void acpi_db_open_debug_file(char *name); + +acpi_status acpi_db_load_acpi_table(char *filename); + +acpi_status +acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table); + +acpi_status +acpi_db_read_table_from_file(char *filename, struct acpi_table_header **table); + +/* + * dbhistry - debugger HISTORY command + */ +void acpi_db_add_to_history(char *command_line); + +void acpi_db_display_history(void); + +char *acpi_db_get_from_history(char *command_num_arg); + +/* + * dbinput - user front-end to the AML debugger + */ +acpi_status +acpi_db_command_dispatch(char *input_buffer, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +void ACPI_SYSTEM_XFACE acpi_db_execute_thread(void *context); + +/* + * dbstats - Generation and display of ACPI table statistics + */ +void acpi_db_generate_statistics(union acpi_parse_object *root, u8 is_method); + +acpi_status acpi_db_display_statistics(char *type_arg); + +/* + * dbutils - AML debugger utilities + */ +void acpi_db_set_output_destination(u32 where); + +void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level); + +void acpi_db_prep_namestring(char *name); + +struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name); + +void acpi_db_uint32_to_hex_string(u32 value, char *buffer); + +#endif /* __ACDEBUG_H__ */ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h new file mode 100644 index 00000000000..6291904be01 --- /dev/null +++ b/drivers/acpi/acpica/acdispat.h @@ -0,0 +1,345 @@ +/****************************************************************************** + * + * Name: acdispat.h - dispatcher (parser to interpreter interface) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef _ACDISPAT_H_ +#define _ACDISPAT_H_ + +#define NAMEOF_LOCAL_NTE "__L0" +#define NAMEOF_ARG_NTE "__A0" + +/* + * dsopcode - support for late evaluation + */ +acpi_status +acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc); + +acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *rgn_desc); + +acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc); + +acpi_status acpi_ds_get_package_arguments(union acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_eval_buffer_field_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_eval_region_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + union acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status acpi_ds_initialize_region(acpi_handle obj_handle); + +/* + * dsctrl - Parser/Interpreter interface, control stack routines + */ +acpi_status +acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +/* + * dsexec - Parser/Interpreter interface, method execution callbacks + */ +acpi_status +acpi_ds_get_predicate_value(struct acpi_walk_state *walk_state, + union acpi_operand_object *result_obj); + +acpi_status +acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op); + +acpi_status acpi_ds_exec_end_op(struct acpi_walk_state *state); + +/* + * dsfield - Parser/Interpreter interface for AML fields + */ +acpi_status +acpi_ds_create_field(union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_create_bank_field(union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_create_index_field(union acpi_parse_object *op, + struct acpi_namespace_node *region_node, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_create_buffer_field(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_init_field_objects(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + +/* + * dsload - Parser/Interpreter interface, namespace load callbacks + */ +acpi_status +acpi_ds_load1_begin_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op); + +acpi_status acpi_ds_load1_end_op(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, + union acpi_parse_object **out_op); + +acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_init_callbacks(struct acpi_walk_state *walk_state, u32 pass_number); + +/* + * dsmthdat - method data (locals/args) + */ +acpi_status +acpi_ds_store_object_to_local(u8 type, + u32 index, + union acpi_operand_object *src_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_method_data_get_entry(u16 opcode, + u32 index, + struct acpi_walk_state *walk_state, + union acpi_operand_object ***node); + +void acpi_ds_method_data_delete_all(struct acpi_walk_state *walk_state); + +u8 acpi_ds_is_method_value(union acpi_operand_object *obj_desc); + +acpi_status +acpi_ds_method_data_get_value(u8 type, + u32 index, + struct acpi_walk_state *walk_state, + union acpi_operand_object **dest_desc); + +acpi_status +acpi_ds_method_data_init_args(union acpi_operand_object **params, + u32 max_param_count, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_method_data_get_node(u8 type, + u32 index, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node **node); + +void acpi_ds_method_data_init(struct acpi_walk_state *walk_state); + +/* + * dsmethod - Parser/Interpreter interface - control method parsing + */ +acpi_status acpi_ds_parse_method(struct acpi_namespace_node *node); + +acpi_status +acpi_ds_call_control_method(struct acpi_thread_state *thread, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ds_restart_control_method(struct acpi_walk_state *walk_state, + union acpi_operand_object *return_desc); + +void +acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state); + +/* + * dsinit + */ +acpi_status +acpi_ds_initialize_objects(u32 table_index, + struct acpi_namespace_node *start_node); + +/* + * dsobject - Parser/Interpreter interface - object initialization and conversion + */ +acpi_status +acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u32 buffer_length, + union acpi_operand_object **obj_desc_ptr); + +acpi_status +acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u32 package_length, + union acpi_operand_object **obj_desc); + +acpi_status +acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + u16 opcode, union acpi_operand_object **obj_desc); + +acpi_status +acpi_ds_create_node(struct acpi_walk_state *walk_state, + struct acpi_namespace_node *node, + union acpi_parse_object *op); + +/* + * dsutils - Parser/Interpreter interface utility routines + */ +void acpi_ds_clear_implicit_return(struct acpi_walk_state *walk_state); + +u8 +acpi_ds_do_implicit_return(union acpi_operand_object *return_desc, + struct acpi_walk_state *walk_state, + u8 add_reference); + +u8 +acpi_ds_is_result_used(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + +void +acpi_ds_delete_result_if_not_used(union acpi_parse_object *op, + union acpi_operand_object *result_obj, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_create_operand(struct acpi_walk_state *walk_state, + union acpi_parse_object *arg, u32 args_remaining); + +acpi_status +acpi_ds_create_operands(struct acpi_walk_state *walk_state, + union acpi_parse_object *first_arg); + +acpi_status acpi_ds_resolve_operands(struct acpi_walk_state *walk_state); + +void acpi_ds_clear_operands(struct acpi_walk_state *walk_state); + +acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state); + +/* + * dswscope - Scope Stack manipulation + */ +acpi_status +acpi_ds_scope_stack_push(struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_walk_state *walk_state); + +acpi_status acpi_ds_scope_stack_pop(struct acpi_walk_state *walk_state); + +void acpi_ds_scope_stack_clear(struct acpi_walk_state *walk_state); + +/* + * dswstate - parser WALK_STATE management routines + */ +acpi_status +acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state); + +struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, union acpi_parse_object + *origin, union acpi_operand_object + *mth_desc, struct acpi_thread_state + *thread); + +acpi_status +acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + struct acpi_namespace_node *method_node, + u8 * aml_start, + u32 aml_length, + struct acpi_evaluate_info *info, u8 pass_number); + +void +acpi_ds_obj_stack_pop_and_delete(u32 pop_count, + struct acpi_walk_state *walk_state); + +void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state); + +struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state + *thread); + +void +acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, + struct acpi_thread_state *thread); + +acpi_status acpi_ds_result_stack_clear(struct acpi_walk_state *walk_state); + +struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state + *thread); + +acpi_status +acpi_ds_result_pop(union acpi_operand_object **object, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ds_result_push(union acpi_operand_object *object, + struct acpi_walk_state *walk_state); + +#endif /* _ACDISPAT_H_ */ diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h new file mode 100644 index 00000000000..07e20135f01 --- /dev/null +++ b/drivers/acpi/acpica/acevents.h @@ -0,0 +1,218 @@ +/****************************************************************************** + * + * Name: acevents.h - Event subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACEVENTS_H__ +#define __ACEVENTS_H__ + +/* + * evevent + */ +acpi_status acpi_ev_initialize_events(void); + +acpi_status acpi_ev_install_xrupt_handlers(void); + +acpi_status acpi_ev_install_fadt_gpes(void); + +u32 acpi_ev_fixed_event_detect(void); + +/* + * evmisc + */ +u8 acpi_ev_is_notify_object(struct acpi_namespace_node *node); + +acpi_status acpi_ev_acquire_global_lock(u16 timeout); + +acpi_status acpi_ev_release_global_lock(void); + +acpi_status acpi_ev_init_global_lock_handler(void); + +u32 acpi_ev_get_gpe_number_index(u32 gpe_number); + +acpi_status +acpi_ev_queue_notify_request(struct acpi_namespace_node *node, + u32 notify_value); + +/* + * evgpe - GPE handling and dispatch + */ +acpi_status +acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, + u8 type); + +acpi_status +acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, + u8 write_to_hardware); + +acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info); + +struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, + u32 gpe_number); + +/* + * evgpeblk + */ +u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info); + +acpi_status +acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context); + +acpi_status +acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, + void *context); + +acpi_status +acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, + struct acpi_generic_address *gpe_block_address, + u32 register_count, + u8 gpe_block_base_number, + u32 interrupt_number, + struct acpi_gpe_block_info **return_gpe_block); + +acpi_status +acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, + struct acpi_gpe_block_info *gpe_block); + +acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block); + +u32 +acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, + u32 gpe_number); + +u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list); + +acpi_status +acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type); + +acpi_status +acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info); + +acpi_status acpi_ev_gpe_initialize(void); + +/* + * evregion - Address Space handling + */ +acpi_status acpi_ev_install_region_handlers(void); + +acpi_status acpi_ev_initialize_op_regions(void); + +acpi_status +acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + u32 function, + acpi_physical_address address, + u32 bit_width, acpi_integer * value); + +acpi_status +acpi_ev_attach_region(union acpi_operand_object *handler_obj, + union acpi_operand_object *region_obj, + u8 acpi_ns_is_locked); + +void +acpi_ev_detach_region(union acpi_operand_object *region_obj, + u8 acpi_ns_is_locked); + +acpi_status +acpi_ev_install_space_handler(struct acpi_namespace_node *node, + acpi_adr_space_type space_id, + acpi_adr_space_handler handler, + acpi_adr_space_setup setup, void *context); + +acpi_status +acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, + acpi_adr_space_type space_id); + +acpi_status +acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function); + +/* + * evregini - Region initialization and setup + */ +acpi_status +acpi_ev_system_memory_region_setup(acpi_handle handle, + u32 function, + void *handler_context, + void **region_context); + +acpi_status +acpi_ev_io_space_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status +acpi_ev_pci_config_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status +acpi_ev_cmos_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status +acpi_ev_pci_bar_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status +acpi_ev_default_region_setup(acpi_handle handle, + u32 function, + void *handler_context, void **region_context); + +acpi_status +acpi_ev_initialize_region(union acpi_operand_object *region_obj, + u8 acpi_ns_locked); + +/* + * evsci - SCI (System Control Interrupt) handling/dispatch + */ +u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context); + +u32 acpi_ev_install_sci_handler(void); + +acpi_status acpi_ev_remove_sci_handler(void); + +u32 acpi_ev_initialize_sCI(u32 program_sCI); + +void acpi_ev_terminate(void); + +#endif /* __ACEVENTS_H__ */ diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h new file mode 100644 index 00000000000..ddb40f5c68f --- /dev/null +++ b/drivers/acpi/acpica/acglobal.h @@ -0,0 +1,394 @@ +/****************************************************************************** + * + * Name: acglobal.h - Declarations for global variables + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACGLOBAL_H__ +#define __ACGLOBAL_H__ + +/* + * Ensure that the globals are actually defined and initialized only once. + * + * The use of these macros allows a single list of globals (here) in order + * to simplify maintenance of the code. + */ +#ifdef DEFINE_ACPI_GLOBALS +#define ACPI_EXTERN +#define ACPI_INIT_GLOBAL(a,b) a=b +#else +#define ACPI_EXTERN extern +#define ACPI_INIT_GLOBAL(a,b) a +#endif + +/***************************************************************************** + * + * Runtime configuration (static defaults that can be overriden at runtime) + * + ****************************************************************************/ + +/* + * Enable "slack" in the AML interpreter? Default is FALSE, and the + * interpreter strictly follows the ACPI specification. Setting to TRUE + * allows the interpreter to ignore certain errors and/or bad AML constructs. + * + * Currently, these features are enabled by this flag: + * + * 1) Allow "implicit return" of last value in a control method + * 2) Allow access beyond the end of an operation region + * 3) Allow access to uninitialized locals/args (auto-init to integer 0) + * 4) Allow ANY object type to be a source operand for the Store() operator + * 5) Allow unresolved references (invalid target name) in package objects + * 6) Enable warning messages for behavior that is not ACPI spec compliant + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_interpreter_slack, FALSE); + +/* + * Automatically serialize ALL control methods? Default is FALSE, meaning + * to use the Serialized/not_serialized method flags on a per method basis. + * Only change this if the ASL code is poorly written and cannot handle + * reentrancy even though methods are marked "NotSerialized". + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_all_methods_serialized, FALSE); + +/* + * Create the predefined _OSI method in the namespace? Default is TRUE + * because ACPI CA is fully compatible with other ACPI implementations. + * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE); + +/* + * Disable wakeup GPEs during runtime? Default is TRUE because WAKE and + * RUNTIME GPEs should never be shared, and WAKE GPEs should typically only + * be enabled just before going to sleep. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE); + +/* + * Optionally use default values for the ACPI register widths. Set this to + * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. + */ +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE); + +/***************************************************************************** + * + * Debug support + * + ****************************************************************************/ + +/* Runtime configuration of debug print levels */ + +extern u32 acpi_dbg_level; +extern u32 acpi_dbg_layer; + +/* Procedure nesting level for debug output */ + +extern u32 acpi_gbl_nesting_level; + +/* Support for dynamic control method tracing mechanism */ + +ACPI_EXTERN u32 acpi_gbl_original_dbg_level; +ACPI_EXTERN u32 acpi_gbl_original_dbg_layer; +ACPI_EXTERN acpi_name acpi_gbl_trace_method_name; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_level; +ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer; +ACPI_EXTERN u32 acpi_gbl_trace_flags; + +/***************************************************************************** + * + * ACPI Table globals + * + ****************************************************************************/ + +/* + * acpi_gbl_root_table_list is the master list of ACPI tables found in the + * RSDT/XSDT. + * + * acpi_gbl_FADT is a local copy of the FADT, converted to a common format. + */ +ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list; +ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT; +ACPI_EXTERN struct acpi_table_facs *acpi_gbl_FACS; + +/* These addresses are calculated from FADT address values */ + +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable; +ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable; + +/* + * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is + * determined by the revision of the DSDT: If the DSDT revision is less than + * 2, use only the lower 32 bits of the internal 64-bit Integer. + */ +ACPI_EXTERN u8 acpi_gbl_integer_bit_width; +ACPI_EXTERN u8 acpi_gbl_integer_byte_width; +ACPI_EXTERN u8 acpi_gbl_integer_nybble_width; + +/***************************************************************************** + * + * Mutual exlusion within ACPICA subsystem + * + ****************************************************************************/ + +/* + * Predefined mutex objects. This array contains the + * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs. + * (The table maps local handles to the real OS handles) + */ +ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX]; + +/* + * Global lock mutex is an actual AML mutex object + * Global lock semaphore works in conjunction with the HW global lock + */ +ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex; +ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore; +ACPI_EXTERN u16 acpi_gbl_global_lock_handle; +ACPI_EXTERN u8 acpi_gbl_global_lock_acquired; +ACPI_EXTERN u8 acpi_gbl_global_lock_present; + +/* + * Spinlocks are used for interfaces that can be possibly called at + * interrupt level + */ +ACPI_EXTERN spinlock_t _acpi_gbl_gpe_lock; /* For GPE data structs and registers */ +ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock; /* For ACPI H/W except GPE registers */ +#define acpi_gbl_gpe_lock &_acpi_gbl_gpe_lock +#define acpi_gbl_hardware_lock &_acpi_gbl_hardware_lock + +/***************************************************************************** + * + * Miscellaneous globals + * + ****************************************************************************/ + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS + +/* Lists for tracking memory allocations */ + +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list; +ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list; +ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats; +#endif + +/* Object caches */ + +ACPI_EXTERN acpi_cache_t *acpi_gbl_namespace_cache; +ACPI_EXTERN acpi_cache_t *acpi_gbl_state_cache; +ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_cache; +ACPI_EXTERN acpi_cache_t *acpi_gbl_ps_node_ext_cache; +ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache; + +/* Global handlers */ + +ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify; +ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify; +ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler; +ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler; +ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler; +ACPI_EXTERN void *acpi_gbl_table_handler_context; +ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk; + +/* Owner ID support */ + +ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS]; +ACPI_EXTERN u8 acpi_gbl_last_owner_id_index; +ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset; + +/* Misc */ + +ACPI_EXTERN u32 acpi_gbl_original_mode; +ACPI_EXTERN u32 acpi_gbl_rsdp_original_location; +ACPI_EXTERN u32 acpi_gbl_ns_lookup_count; +ACPI_EXTERN u32 acpi_gbl_ps_find_count; +ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save; +ACPI_EXTERN u8 acpi_gbl_debugger_configuration; +ACPI_EXTERN u8 acpi_gbl_step_to_next_call; +ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; +ACPI_EXTERN u8 acpi_gbl_events_initialized; +ACPI_EXTERN u8 acpi_gbl_system_awake_and_running; + +#ifndef DEFINE_ACPI_GLOBALS + +/* Other miscellaneous */ + +extern u8 acpi_gbl_shutdown; +extern u32 acpi_gbl_startup_flags; +extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT]; +extern const char *acpi_gbl_highest_dstate_names[4]; +extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES]; +extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS]; + +#endif + +/* Exception codes */ + +extern char const *acpi_gbl_exception_names_env[]; +extern char const *acpi_gbl_exception_names_pgm[]; +extern char const *acpi_gbl_exception_names_tbl[]; +extern char const *acpi_gbl_exception_names_aml[]; +extern char const *acpi_gbl_exception_names_ctrl[]; + +/***************************************************************************** + * + * Namespace globals + * + ****************************************************************************/ + +#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY) +#define NUM_PREDEFINED_NAMES 10 +#else +#define NUM_PREDEFINED_NAMES 9 +#endif + +ACPI_EXTERN struct acpi_namespace_node acpi_gbl_root_node_struct; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device; + +extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES]; +extern const struct acpi_predefined_names + acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES]; + +#ifdef ACPI_DEBUG_OUTPUT +ACPI_EXTERN u32 acpi_gbl_current_node_count; +ACPI_EXTERN u32 acpi_gbl_current_node_size; +ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count; +ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer; +ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer; +ACPI_EXTERN u32 acpi_gbl_deepest_nesting; +#endif + +/***************************************************************************** + * + * Interpreter globals + * + ****************************************************************************/ + +ACPI_EXTERN struct acpi_thread_state *acpi_gbl_current_walk_list; + +/* Control method single step flag */ + +ACPI_EXTERN u8 acpi_gbl_cm_single_step; + +/***************************************************************************** + * + * Hardware globals + * + ****************************************************************************/ + +extern struct acpi_bit_register_info + acpi_gbl_bit_register_info[ACPI_NUM_BITREG]; +ACPI_EXTERN u8 acpi_gbl_sleep_type_a; +ACPI_EXTERN u8 acpi_gbl_sleep_type_b; + +/***************************************************************************** + * + * Event and GPE globals + * + ****************************************************************************/ + +extern struct acpi_fixed_event_info + acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS]; +ACPI_EXTERN struct acpi_fixed_event_handler + acpi_gbl_fixed_event_handlers[ACPI_NUM_FIXED_EVENTS]; +ACPI_EXTERN struct acpi_gpe_xrupt_info *acpi_gbl_gpe_xrupt_list_head; +ACPI_EXTERN struct acpi_gpe_block_info +*acpi_gbl_gpe_fadt_blocks[ACPI_MAX_GPE_BLOCKS]; +ACPI_EXTERN u32 acpi_current_gpe_count; + +/***************************************************************************** + * + * Debugger globals + * + ****************************************************************************/ + +ACPI_EXTERN u8 acpi_gbl_db_output_flags; + +#ifdef ACPI_DISASSEMBLER + +ACPI_EXTERN u8 acpi_gbl_db_opt_disasm; +ACPI_EXTERN u8 acpi_gbl_db_opt_verbose; +#endif + +#ifdef ACPI_DEBUGGER + +extern u8 acpi_gbl_method_executing; +extern u8 acpi_gbl_abort_method; +extern u8 acpi_gbl_db_terminate_threads; + +ACPI_EXTERN int optind; +ACPI_EXTERN char *optarg; + +ACPI_EXTERN u8 acpi_gbl_db_opt_tables; +ACPI_EXTERN u8 acpi_gbl_db_opt_stats; +ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; + +ACPI_EXTERN char *acpi_gbl_db_args[ACPI_DEBUGGER_MAX_ARGS]; +ACPI_EXTERN char acpi_gbl_db_line_buf[80]; +ACPI_EXTERN char acpi_gbl_db_parsed_buf[80]; +ACPI_EXTERN char acpi_gbl_db_scope_buf[40]; +ACPI_EXTERN char acpi_gbl_db_debug_filename[40]; +ACPI_EXTERN u8 acpi_gbl_db_output_to_file; +ACPI_EXTERN char *acpi_gbl_db_buffer; +ACPI_EXTERN char *acpi_gbl_db_filename; +ACPI_EXTERN u32 acpi_gbl_db_debug_level; +ACPI_EXTERN u32 acpi_gbl_db_console_debug_level; +ACPI_EXTERN struct acpi_table_header *acpi_gbl_db_table_ptr; +ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_db_scope_node; + +/* + * Statistic globals + */ +ACPI_EXTERN u16 acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1]; +ACPI_EXTERN u16 acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1]; +ACPI_EXTERN u16 acpi_gbl_obj_type_count_misc; +ACPI_EXTERN u16 acpi_gbl_node_type_count_misc; +ACPI_EXTERN u32 acpi_gbl_num_nodes; +ACPI_EXTERN u32 acpi_gbl_num_objects; + +ACPI_EXTERN u32 acpi_gbl_size_of_parse_tree; +ACPI_EXTERN u32 acpi_gbl_size_of_method_trees; +ACPI_EXTERN u32 acpi_gbl_size_of_node_entries; +ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects; + +#endif /* ACPI_DEBUGGER */ + +#endif /* __ACGLOBAL_H__ */ diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h new file mode 100644 index 00000000000..58c69dc49ab --- /dev/null +++ b/drivers/acpi/acpica/achware.h @@ -0,0 +1,119 @@ +/****************************************************************************** + * + * Name: achware.h -- hardware specific interfaces + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACHWARE_H__ +#define __ACHWARE_H__ + +/* Values for the _SST predefined method */ + +#define ACPI_SST_INDICATOR_OFF 0 +#define ACPI_SST_WORKING 1 +#define ACPI_SST_WAKING 2 +#define ACPI_SST_SLEEPING 3 +#define ACPI_SST_SLEEP_CONTEXT 4 + +/* + * hwacpi - high level functions + */ +acpi_status acpi_hw_set_mode(u32 mode); + +u32 acpi_hw_get_mode(void); + +/* + * hwregs - ACPI Register I/O + */ +struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id); + +acpi_status +acpi_hw_register_read(u32 register_id, u32 * return_value); + +acpi_status acpi_hw_register_write(u32 register_id, u32 value); + +acpi_status acpi_hw_clear_acpi_status(void); + +/* + * hwgpe - GPE support + */ +acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info); + +acpi_status +acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info); + +acpi_status +acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + +acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info *gpe_event_info); + +acpi_status +acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + +acpi_status +acpi_hw_get_gpe_status(struct acpi_gpe_event_info *gpe_event_info, + acpi_event_status * event_status); + +acpi_status acpi_hw_disable_all_gpes(void); + +acpi_status acpi_hw_enable_all_runtime_gpes(void); + +acpi_status acpi_hw_enable_all_wakeup_gpes(void); + +acpi_status +acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, + void *context); + +#ifdef ACPI_FUTURE_USAGE +/* + * hwtimer - ACPI Timer prototypes + */ +acpi_status acpi_get_timer_resolution(u32 * resolution); + +acpi_status acpi_get_timer(u32 * ticks); + +acpi_status +acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed); +#endif /* ACPI_FUTURE_USAGE */ + +#endif /* __ACHWARE_H__ */ diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h new file mode 100644 index 00000000000..e8db7a3143a --- /dev/null +++ b/drivers/acpi/acpica/acinterp.h @@ -0,0 +1,529 @@ +/****************************************************************************** + * + * Name: acinterp.h - Interpreter subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACINTERP_H__ +#define __ACINTERP_H__ + +#define ACPI_WALK_OPERANDS (&(walk_state->operands [walk_state->num_operands -1])) + +/* Macros for tables used for debug output */ + +#define ACPI_EXD_OFFSET(f) (u8) ACPI_OFFSET (union acpi_operand_object,f) +#define ACPI_EXD_NSOFFSET(f) (u8) ACPI_OFFSET (struct acpi_namespace_node,f) +#define ACPI_EXD_TABLE_SIZE(name) (sizeof(name) / sizeof (struct acpi_exdump_info)) + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +typedef const struct acpi_exdump_info { + u8 opcode; + u8 offset; + char *name; + +} acpi_exdump_info; + +/* Values for the Opcode field above */ + +#define ACPI_EXD_INIT 0 +#define ACPI_EXD_TYPE 1 +#define ACPI_EXD_UINT8 2 +#define ACPI_EXD_UINT16 3 +#define ACPI_EXD_UINT32 4 +#define ACPI_EXD_UINT64 5 +#define ACPI_EXD_LITERAL 6 +#define ACPI_EXD_POINTER 7 +#define ACPI_EXD_ADDRESS 8 +#define ACPI_EXD_STRING 9 +#define ACPI_EXD_BUFFER 10 +#define ACPI_EXD_PACKAGE 11 +#define ACPI_EXD_FIELD 12 +#define ACPI_EXD_REFERENCE 13 + +/* restore default alignment */ + +#pragma pack() + +/* + * exconvrt - object conversion + */ +acpi_status +acpi_ex_convert_to_integer(union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc, u32 flags); + +acpi_status +acpi_ex_convert_to_buffer(union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc); + +acpi_status +acpi_ex_convert_to_string(union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc, u32 type); + +/* Types for ->String conversion */ + +#define ACPI_EXPLICIT_BYTE_COPY 0x00000000 +#define ACPI_EXPLICIT_CONVERT_HEX 0x00000001 +#define ACPI_IMPLICIT_CONVERT_HEX 0x00000002 +#define ACPI_EXPLICIT_CONVERT_DECIMAL 0x00000003 + +acpi_status +acpi_ex_convert_to_target_type(acpi_object_type destination_type, + union acpi_operand_object *source_desc, + union acpi_operand_object **result_desc, + struct acpi_walk_state *walk_state); + +/* + * exfield - ACPI AML (p-code) execution - field manipulation + */ +acpi_status +acpi_ex_common_buffer_setup(union acpi_operand_object *obj_desc, + u32 buffer_length, u32 * datum_count); + +acpi_status +acpi_ex_write_with_update_rule(union acpi_operand_object *obj_desc, + acpi_integer mask, + acpi_integer field_value, + u32 field_datum_byte_offset); + +void +acpi_ex_get_buffer_datum(acpi_integer * datum, + void *buffer, + u32 buffer_length, + u32 byte_granularity, u32 buffer_offset); + +void +acpi_ex_set_buffer_datum(acpi_integer merged_datum, + void *buffer, + u32 buffer_length, + u32 byte_granularity, u32 buffer_offset); + +acpi_status +acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, + union acpi_operand_object *obj_desc, + union acpi_operand_object **ret_buffer_desc); + +acpi_status +acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, + union acpi_operand_object *obj_desc, + union acpi_operand_object **result_desc); + +/* + * exfldio - low level field I/O + */ +acpi_status +acpi_ex_extract_from_field(union acpi_operand_object *obj_desc, + void *buffer, u32 buffer_length); + +acpi_status +acpi_ex_insert_into_field(union acpi_operand_object *obj_desc, + void *buffer, u32 buffer_length); + +acpi_status +acpi_ex_access_region(union acpi_operand_object *obj_desc, + u32 field_datum_byte_offset, + acpi_integer * value, u32 read_write); + +/* + * exmisc - misc support routines + */ +acpi_status +acpi_ex_get_object_reference(union acpi_operand_object *obj_desc, + union acpi_operand_object **return_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_concat_template(union acpi_operand_object *obj_desc, + union acpi_operand_object *obj_desc2, + union acpi_operand_object **actual_return_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_do_concatenate(union acpi_operand_object *obj_desc, + union acpi_operand_object *obj_desc2, + union acpi_operand_object **actual_return_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_do_logical_numeric_op(u16 opcode, + acpi_integer integer0, + acpi_integer integer1, u8 * logical_result); + +acpi_status +acpi_ex_do_logical_op(u16 opcode, + union acpi_operand_object *operand0, + union acpi_operand_object *operand1, u8 * logical_result); + +acpi_integer +acpi_ex_do_math_op(u16 opcode, acpi_integer operand0, acpi_integer operand1); + +acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_create_processor(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_create_power_resource(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_create_region(u8 * aml_start, + u32 aml_length, + u8 region_space, struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_create_method(u8 * aml_start, + u32 aml_length, struct acpi_walk_state *walk_state); + +/* + * exconfig - dynamic table load/unload + */ +acpi_status +acpi_ex_load_op(union acpi_operand_object *obj_desc, + union acpi_operand_object *target, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_load_table_op(struct acpi_walk_state *walk_state, + union acpi_operand_object **return_desc); + +acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle); + +/* + * exmutex - mutex support + */ +acpi_status +acpi_ex_acquire_mutex(union acpi_operand_object *time_desc, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_acquire_mutex_object(u16 timeout, + union acpi_operand_object *obj_desc, + acpi_thread_id thread_id); + +acpi_status +acpi_ex_release_mutex(union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc); + +void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread); + +void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc); + +/* + * exprep - ACPI AML execution - prep utilities + */ +acpi_status +acpi_ex_prep_common_field_object(union acpi_operand_object *obj_desc, + u8 field_flags, + u8 field_attribute, + u32 field_bit_position, u32 field_bit_length); + +acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info); + +/* + * exsystem - Interface to OS services + */ +acpi_status +acpi_ex_system_do_notify_op(union acpi_operand_object *value, + union acpi_operand_object *obj_desc); + +acpi_status acpi_ex_system_do_suspend(acpi_integer time); + +acpi_status acpi_ex_system_do_stall(u32 time); + +acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc); + +acpi_status +acpi_ex_system_wait_event(union acpi_operand_object *time, + union acpi_operand_object *obj_desc); + +acpi_status acpi_ex_system_reset_event(union acpi_operand_object *obj_desc); + +acpi_status +acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout); + +acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout); + +/* + * exoparg1 - ACPI AML execution, 1 operand + */ +acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state); + +/* + * exoparg2 - ACPI AML execution, 2 operands + */ +acpi_status acpi_ex_opcode_2A_0T_0R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_2A_0T_1R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_2A_1T_1R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_2A_2T_1R(struct acpi_walk_state *walk_state); + +/* + * exoparg3 - ACPI AML execution, 3 operands + */ +acpi_status acpi_ex_opcode_3A_0T_0R(struct acpi_walk_state *walk_state); + +acpi_status acpi_ex_opcode_3A_1T_1R(struct acpi_walk_state *walk_state); + +/* + * exoparg6 - ACPI AML execution, 6 operands + */ +acpi_status acpi_ex_opcode_6A_0T_1R(struct acpi_walk_state *walk_state); + +/* + * exresolv - Object resolution and get value functions + */ +acpi_status +acpi_ex_resolve_to_value(union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, + union acpi_operand_object *operand, + acpi_object_type * return_type, + union acpi_operand_object **return_desc); + +/* + * exresnte - resolve namespace node + */ +acpi_status +acpi_ex_resolve_node_to_value(struct acpi_namespace_node **stack_ptr, + struct acpi_walk_state *walk_state); + +/* + * exresop - resolve operand to value + */ +acpi_status +acpi_ex_resolve_operands(u16 opcode, + union acpi_operand_object **stack_ptr, + struct acpi_walk_state *walk_state); + +/* + * exdump - Interpreter debug output routines + */ +void acpi_ex_dump_operand(union acpi_operand_object *obj_desc, u32 depth); + +void +acpi_ex_dump_operands(union acpi_operand_object **operands, + const char *opcode_name, u32 num_opcodes); + +#ifdef ACPI_FUTURE_USAGE +void +acpi_ex_dump_object_descriptor(union acpi_operand_object *object, u32 flags); + +void acpi_ex_dump_namespace_node(struct acpi_namespace_node *node, u32 flags); +#endif /* ACPI_FUTURE_USAGE */ + +/* + * exnames - AML namestring support + */ +acpi_status +acpi_ex_get_name_string(acpi_object_type data_type, + u8 * in_aml_address, + char **out_name_string, u32 * out_name_length); + +/* + * exstore - Object store support + */ +acpi_status +acpi_ex_store(union acpi_operand_object *val_desc, + union acpi_operand_object *dest_desc, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_store_object_to_node(union acpi_operand_object *source_desc, + struct acpi_namespace_node *node, + struct acpi_walk_state *walk_state, + u8 implicit_conversion); + +#define ACPI_IMPLICIT_CONVERSION TRUE +#define ACPI_NO_IMPLICIT_CONVERSION FALSE + +/* + * exstoren - resolve/store object + */ +acpi_status +acpi_ex_resolve_object(union acpi_operand_object **source_desc_ptr, + acpi_object_type target_type, + struct acpi_walk_state *walk_state); + +acpi_status +acpi_ex_store_object_to_object(union acpi_operand_object *source_desc, + union acpi_operand_object *dest_desc, + union acpi_operand_object **new_desc, + struct acpi_walk_state *walk_state); + +/* + * exstorob - store object - buffer/string + */ +acpi_status +acpi_ex_store_buffer_to_buffer(union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc); + +acpi_status +acpi_ex_store_string_to_string(union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc); + +/* + * excopy - object copy + */ +acpi_status +acpi_ex_copy_integer_to_index_field(union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc); + +acpi_status +acpi_ex_copy_integer_to_bank_field(union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc); + +acpi_status +acpi_ex_copy_data_to_named_field(union acpi_operand_object *source_desc, + struct acpi_namespace_node *node); + +acpi_status +acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc, + union acpi_operand_object *target_desc); + +/* + * exutils - interpreter/scanner utilities + */ +void acpi_ex_enter_interpreter(void); + +void acpi_ex_exit_interpreter(void); + +void acpi_ex_reacquire_interpreter(void); + +void acpi_ex_relinquish_interpreter(void); + +void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc); + +void acpi_ex_acquire_global_lock(u32 rule); + +void acpi_ex_release_global_lock(u32 rule); + +void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string); + +void acpi_ex_unsigned_integer_to_string(acpi_integer value, char *out_string); + +/* + * exregion - default op_region handlers + */ +acpi_status +acpi_ex_system_memory_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, + void *region_context); + +acpi_status +acpi_ex_system_io_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +acpi_status +acpi_ex_pci_config_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +acpi_status +acpi_ex_cmos_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +acpi_status +acpi_ex_pci_bar_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +acpi_status +acpi_ex_embedded_controller_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, + void *region_context); + +acpi_status +acpi_ex_sm_bus_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +acpi_status +acpi_ex_data_table_space_handler(u32 function, + acpi_physical_address address, + u32 bit_width, + acpi_integer * value, + void *handler_context, void *region_context); + +#endif /* __INTERP_H__ */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h new file mode 100644 index 00000000000..492d02761bb --- /dev/null +++ b/drivers/acpi/acpica/aclocal.h @@ -0,0 +1,990 @@ +/****************************************************************************** + * + * Name: aclocal.h - Internal data types used across the ACPI subsystem + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACLOCAL_H__ +#define __ACLOCAL_H__ + +/* acpisrc:struct_defs -- for acpisrc conversion */ + +#define ACPI_SERIALIZED 0xFF + +typedef u32 acpi_mutex_handle; +#define ACPI_GLOBAL_LOCK (acpi_semaphore) (-1) + +/* Total number of aml opcodes defined */ + +#define AML_NUM_OPCODES 0x7F + +/* Forward declarations */ + +struct acpi_walk_state; +struct acpi_obj_mutex; +union acpi_parse_object; + +/***************************************************************************** + * + * Mutex typedefs and structs + * + ****************************************************************************/ + +/* + * Predefined handles for the mutex objects used within the subsystem + * All mutex objects are automatically created by acpi_ut_mutex_initialize. + * + * The acquire/release ordering protocol is implied via this list. Mutexes + * with a lower value must be acquired before mutexes with a higher value. + * + * NOTE: any changes here must be reflected in the acpi_gbl_mutex_names + * table below also! + */ +#define ACPI_MTX_INTERPRETER 0 /* AML Interpreter, main lock */ +#define ACPI_MTX_NAMESPACE 1 /* ACPI Namespace */ +#define ACPI_MTX_TABLES 2 /* Data for ACPI tables */ +#define ACPI_MTX_EVENTS 3 /* Data for ACPI events */ +#define ACPI_MTX_CACHES 4 /* Internal caches, general purposes */ +#define ACPI_MTX_MEMORY 5 /* Debug memory tracking lists */ +#define ACPI_MTX_DEBUG_CMD_COMPLETE 6 /* AML debugger */ +#define ACPI_MTX_DEBUG_CMD_READY 7 /* AML debugger */ + +#define ACPI_MAX_MUTEX 7 +#define ACPI_NUM_MUTEX ACPI_MAX_MUTEX+1 + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +#ifdef DEFINE_ACPI_GLOBALS + +/* Debug names for the mutexes above */ + +static char *acpi_gbl_mutex_names[ACPI_NUM_MUTEX] = { + "ACPI_MTX_Interpreter", + "ACPI_MTX_Namespace", + "ACPI_MTX_Tables", + "ACPI_MTX_Events", + "ACPI_MTX_Caches", + "ACPI_MTX_Memory", + "ACPI_MTX_CommandComplete", + "ACPI_MTX_CommandReady" +}; + +#endif +#endif + +/* + * Predefined handles for spinlocks used within the subsystem. + * These spinlocks are created by acpi_ut_mutex_initialize + */ +#define ACPI_LOCK_GPES 0 +#define ACPI_LOCK_HARDWARE 1 + +#define ACPI_MAX_LOCK 1 +#define ACPI_NUM_LOCK ACPI_MAX_LOCK+1 + +/* This Thread ID means that the mutex is not in use (unlocked) */ + +#define ACPI_MUTEX_NOT_ACQUIRED (acpi_thread_id) 0 + +/* Table for the global mutexes */ + +struct acpi_mutex_info { + acpi_mutex mutex; + u32 use_count; + acpi_thread_id thread_id; +}; + +/* Lock flag parameter for various interfaces */ + +#define ACPI_MTX_DO_NOT_LOCK 0 +#define ACPI_MTX_LOCK 1 + +/* Field access granularities */ + +#define ACPI_FIELD_BYTE_GRANULARITY 1 +#define ACPI_FIELD_WORD_GRANULARITY 2 +#define ACPI_FIELD_DWORD_GRANULARITY 4 +#define ACPI_FIELD_QWORD_GRANULARITY 8 + +#define ACPI_ENTRY_NOT_FOUND NULL + +/***************************************************************************** + * + * Namespace typedefs and structs + * + ****************************************************************************/ + +/* Operational modes of the AML interpreter/scanner */ + +typedef enum { + ACPI_IMODE_LOAD_PASS1 = 0x01, + ACPI_IMODE_LOAD_PASS2 = 0x02, + ACPI_IMODE_EXECUTE = 0x03 +} acpi_interpreter_mode; + +/* + * The Namespace Node describes a named object that appears in the AML. + * descriptor_type is used to differentiate between internal descriptors. + * + * The node is optimized for both 32-bit and 64-bit platforms: + * 20 bytes for the 32-bit case, 32 bytes for the 64-bit case. + * + * Note: The descriptor_type and Type fields must appear in the identical + * position in both the struct acpi_namespace_node and union acpi_operand_object + * structures. + */ +struct acpi_namespace_node { + union acpi_operand_object *object; /* Interpreter object */ + u8 descriptor_type; /* Differentiate object descriptor types */ + u8 type; /* ACPI Type associated with this name */ + u8 flags; /* Miscellaneous flags */ + acpi_owner_id owner_id; /* Node creator */ + union acpi_name_union name; /* ACPI Name, always 4 chars per ACPI spec */ + struct acpi_namespace_node *child; /* First child */ + struct acpi_namespace_node *peer; /* Peer. Parent if ANOBJ_END_OF_PEER_LIST set */ + + /* + * The following fields are used by the ASL compiler and disassembler only + */ +#ifdef ACPI_LARGE_NAMESPACE_NODE + union acpi_parse_object *op; + u32 value; + u32 length; +#endif +}; + +/* Namespace Node flags */ + +#define ANOBJ_END_OF_PEER_LIST 0x01 /* End-of-list, Peer field points to parent */ +#define ANOBJ_TEMPORARY 0x02 /* Node is create by a method and is temporary */ +#define ANOBJ_METHOD_ARG 0x04 /* Node is a method argument */ +#define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ +#define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ +#define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ + +#define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ +#define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ +#define ANOBJ_METHOD_SOME_NO_RETVAL 0x20 /* i_aSL only: Method has at least one return value */ +#define ANOBJ_IS_BIT_OFFSET 0x40 /* i_aSL only: Reference is a bit offset */ +#define ANOBJ_IS_REFERENCED 0x80 /* i_aSL only: Object was referenced */ + +/* One internal RSDT for table management */ + +struct acpi_internal_rsdt { + struct acpi_table_desc *tables; + u32 count; + u32 size; + u8 flags; +}; + +/* Flags for above */ + +#define ACPI_ROOT_ORIGIN_UNKNOWN (0) /* ~ORIGIN_ALLOCATED */ +#define ACPI_ROOT_ORIGIN_ALLOCATED (1) +#define ACPI_ROOT_ALLOW_RESIZE (2) + +/* Predefined (fixed) table indexes */ + +#define ACPI_TABLE_INDEX_DSDT (0) +#define ACPI_TABLE_INDEX_FACS (1) + +struct acpi_find_context { + char *search_for; + acpi_handle *list; + u32 *count; +}; + +struct acpi_ns_search_data { + struct acpi_namespace_node *node; +}; + +/* Object types used during package copies */ + +#define ACPI_COPY_TYPE_SIMPLE 0 +#define ACPI_COPY_TYPE_PACKAGE 1 + +/* Info structure used to convert external<->internal namestrings */ + +struct acpi_namestring_info { + const char *external_name; + const char *next_external_char; + char *internal_name; + u32 length; + u32 num_segments; + u32 num_carats; + u8 fully_qualified; +}; + +/* Field creation info */ + +struct acpi_create_field_info { + struct acpi_namespace_node *region_node; + struct acpi_namespace_node *field_node; + struct acpi_namespace_node *register_node; + struct acpi_namespace_node *data_register_node; + u32 bank_value; + u32 field_bit_position; + u32 field_bit_length; + u8 field_flags; + u8 attribute; + u8 field_type; +}; + +typedef +acpi_status(*ACPI_INTERNAL_METHOD) (struct acpi_walk_state * walk_state); + +/* + * Bitmapped ACPI types. Used internally only + */ +#define ACPI_BTYPE_ANY 0x00000000 +#define ACPI_BTYPE_INTEGER 0x00000001 +#define ACPI_BTYPE_STRING 0x00000002 +#define ACPI_BTYPE_BUFFER 0x00000004 +#define ACPI_BTYPE_PACKAGE 0x00000008 +#define ACPI_BTYPE_FIELD_UNIT 0x00000010 +#define ACPI_BTYPE_DEVICE 0x00000020 +#define ACPI_BTYPE_EVENT 0x00000040 +#define ACPI_BTYPE_METHOD 0x00000080 +#define ACPI_BTYPE_MUTEX 0x00000100 +#define ACPI_BTYPE_REGION 0x00000200 +#define ACPI_BTYPE_POWER 0x00000400 +#define ACPI_BTYPE_PROCESSOR 0x00000800 +#define ACPI_BTYPE_THERMAL 0x00001000 +#define ACPI_BTYPE_BUFFER_FIELD 0x00002000 +#define ACPI_BTYPE_DDB_HANDLE 0x00004000 +#define ACPI_BTYPE_DEBUG_OBJECT 0x00008000 +#define ACPI_BTYPE_REFERENCE 0x00010000 +#define ACPI_BTYPE_RESOURCE 0x00020000 + +#define ACPI_BTYPE_COMPUTE_DATA (ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_BUFFER) + +#define ACPI_BTYPE_DATA (ACPI_BTYPE_COMPUTE_DATA | ACPI_BTYPE_PACKAGE) +#define ACPI_BTYPE_DATA_REFERENCE (ACPI_BTYPE_DATA | ACPI_BTYPE_REFERENCE | ACPI_BTYPE_DDB_HANDLE) +#define ACPI_BTYPE_DEVICE_OBJECTS (ACPI_BTYPE_DEVICE | ACPI_BTYPE_THERMAL | ACPI_BTYPE_PROCESSOR) +#define ACPI_BTYPE_OBJECTS_AND_REFS 0x0001FFFF /* ARG or LOCAL */ +#define ACPI_BTYPE_ALL_OBJECTS 0x0000FFFF + +/* + * Information structure for ACPI predefined names. + * Each entry in the table contains the following items: + * + * Name - The ACPI reserved name + * param_count - Number of arguments to the method + * expected_return_btypes - Allowed type(s) for the return value + */ +struct acpi_name_info { + char name[ACPI_NAME_SIZE]; + u8 param_count; + u8 expected_btypes; +}; + +/* + * Secondary information structures for ACPI predefined objects that return + * package objects. This structure appears as the next entry in the table + * after the NAME_INFO structure above. + * + * The reason for this is to minimize the size of the predefined name table. + */ + +/* + * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, + * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT + */ +struct acpi_package_info { + u8 type; + u8 object_type1; + u8 count1; + u8 object_type2; + u8 count2; + u8 reserved; +}; + +/* Used for ACPI_PTYPE2_FIXED */ + +struct acpi_package_info2 { + u8 type; + u8 count; + u8 object_type[4]; +}; + +/* Used for ACPI_PTYPE1_OPTION */ + +struct acpi_package_info3 { + u8 type; + u8 count; + u8 object_type[2]; + u8 tail_object_type; + u8 reserved; +}; + +union acpi_predefined_info { + struct acpi_name_info info; + struct acpi_package_info ret_info; + struct acpi_package_info2 ret_info2; + struct acpi_package_info3 ret_info3; +}; + +/* + * Bitmapped return value types + * Note: the actual data types must be contiguous, a loop in nspredef.c + * depends on this. + */ +#define ACPI_RTYPE_ANY 0x00 +#define ACPI_RTYPE_NONE 0x01 +#define ACPI_RTYPE_INTEGER 0x02 +#define ACPI_RTYPE_STRING 0x04 +#define ACPI_RTYPE_BUFFER 0x08 +#define ACPI_RTYPE_PACKAGE 0x10 +#define ACPI_RTYPE_REFERENCE 0x20 +#define ACPI_RTYPE_ALL 0x3F + +#define ACPI_NUM_RTYPES 5 /* Number of actual object types */ + +/***************************************************************************** + * + * Event typedefs and structs + * + ****************************************************************************/ + +/* Dispatch info for each GPE -- either a method or handler, cannot be both */ + +struct acpi_handler_info { + acpi_event_handler address; /* Address of handler, if any */ + void *context; /* Context to be passed to handler */ + struct acpi_namespace_node *method_node; /* Method node for this GPE level (saved) */ +}; + +union acpi_gpe_dispatch_info { + struct acpi_namespace_node *method_node; /* Method node for this GPE level */ + struct acpi_handler_info *handler; +}; + +/* + * Information about a GPE, one per each GPE in an array. + * NOTE: Important to keep this struct as small as possible. + */ +struct acpi_gpe_event_info { + union acpi_gpe_dispatch_info dispatch; /* Either Method or Handler */ + struct acpi_gpe_register_info *register_info; /* Backpointer to register info */ + u8 flags; /* Misc info about this GPE */ + u8 gpe_number; /* This GPE */ +}; + +/* Information about a GPE register pair, one per each status/enable pair in an array */ + +struct acpi_gpe_register_info { + struct acpi_generic_address status_address; /* Address of status reg */ + struct acpi_generic_address enable_address; /* Address of enable reg */ + u8 enable_for_wake; /* GPEs to keep enabled when sleeping */ + u8 enable_for_run; /* GPEs to keep enabled when running */ + u8 base_gpe_number; /* Base GPE number for this register */ +}; + +/* + * Information about a GPE register block, one per each installed block -- + * GPE0, GPE1, and one per each installed GPE Block Device. + */ +struct acpi_gpe_block_info { + struct acpi_namespace_node *node; + struct acpi_gpe_block_info *previous; + struct acpi_gpe_block_info *next; + struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */ + struct acpi_gpe_register_info *register_info; /* One per GPE register pair */ + struct acpi_gpe_event_info *event_info; /* One for each GPE */ + struct acpi_generic_address block_address; /* Base address of the block */ + u32 register_count; /* Number of register pairs in block */ + u8 block_base_number; /* Base GPE number for this block */ +}; + +/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */ + +struct acpi_gpe_xrupt_info { + struct acpi_gpe_xrupt_info *previous; + struct acpi_gpe_xrupt_info *next; + struct acpi_gpe_block_info *gpe_block_list_head; /* List of GPE blocks for this xrupt */ + u32 interrupt_number; /* System interrupt number */ +}; + +struct acpi_gpe_walk_info { + struct acpi_namespace_node *gpe_device; + struct acpi_gpe_block_info *gpe_block; +}; + +struct acpi_gpe_device_info { + u32 index; + u32 next_block_base_index; + acpi_status status; + struct acpi_namespace_node *gpe_device; +}; + +typedef acpi_status(*acpi_gpe_callback) (struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + +/* Information about each particular fixed event */ + +struct acpi_fixed_event_handler { + acpi_event_handler handler; /* Address of handler. */ + void *context; /* Context to be passed to handler */ +}; + +struct acpi_fixed_event_info { + u8 status_register_id; + u8 enable_register_id; + u16 status_bit_mask; + u16 enable_bit_mask; +}; + +/* Information used during field processing */ + +struct acpi_field_info { + u8 skip_field; + u8 field_flag; + u32 pkg_length; +}; + +/***************************************************************************** + * + * Generic "state" object for stacks + * + ****************************************************************************/ + +#define ACPI_CONTROL_NORMAL 0xC0 +#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1 +#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2 +#define ACPI_CONTROL_PREDICATE_FALSE 0xC3 +#define ACPI_CONTROL_PREDICATE_TRUE 0xC4 + +#define ACPI_STATE_COMMON \ + void *next; \ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 flags; \ + u16 value; \ + u16 state; + + /* There are 2 bytes available here until the next natural alignment boundary */ + +struct acpi_common_state { +ACPI_STATE_COMMON}; + +/* + * Update state - used to traverse complex objects such as packages + */ +struct acpi_update_state { + ACPI_STATE_COMMON union acpi_operand_object *object; +}; + +/* + * Pkg state - used to traverse nested package structures + */ +struct acpi_pkg_state { + ACPI_STATE_COMMON u16 index; + union acpi_operand_object *source_object; + union acpi_operand_object *dest_object; + struct acpi_walk_state *walk_state; + void *this_target_obj; + u32 num_packages; +}; + +/* + * Control state - one per if/else and while constructs. + * Allows nesting of these constructs + */ +struct acpi_control_state { + ACPI_STATE_COMMON u16 opcode; + union acpi_parse_object *predicate_op; + u8 *aml_predicate_start; /* Start of if/while predicate */ + u8 *package_end; /* End of if/while block */ + u32 loop_count; /* While() loop counter */ +}; + +/* + * Scope state - current scope during namespace lookups + */ +struct acpi_scope_state { + ACPI_STATE_COMMON struct acpi_namespace_node *node; +}; + +struct acpi_pscope_state { + ACPI_STATE_COMMON u32 arg_count; /* Number of fixed arguments */ + union acpi_parse_object *op; /* Current op being parsed */ + u8 *arg_end; /* Current argument end */ + u8 *pkg_end; /* Current package end */ + u32 arg_list; /* Next argument to parse */ +}; + +/* + * Thread state - one per thread across multiple walk states. Multiple walk + * states are created when there are nested control methods executing. + */ +struct acpi_thread_state { + ACPI_STATE_COMMON u8 current_sync_level; /* Mutex Sync (nested acquire) level */ + struct acpi_walk_state *walk_state_list; /* Head of list of walk_states for this thread */ + union acpi_operand_object *acquired_mutex_list; /* List of all currently acquired mutexes */ + acpi_thread_id thread_id; /* Running thread ID */ +}; + +/* + * Result values - used to accumulate the results of nested + * AML arguments + */ +struct acpi_result_values { + ACPI_STATE_COMMON + union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM]; +}; + +typedef +acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state, + union acpi_parse_object ** out_op); + +typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state); + +/* + * Notify info - used to pass info to the deferred notify + * handler/dispatcher. + */ +struct acpi_notify_info { + ACPI_STATE_COMMON struct acpi_namespace_node *node; + union acpi_operand_object *handler_obj; +}; + +/* Generic state is union of structs above */ + +union acpi_generic_state { + struct acpi_common_state common; + struct acpi_control_state control; + struct acpi_update_state update; + struct acpi_scope_state scope; + struct acpi_pscope_state parse_scope; + struct acpi_pkg_state pkg; + struct acpi_thread_state thread; + struct acpi_result_values results; + struct acpi_notify_info notify; +}; + +/***************************************************************************** + * + * Interpreter typedefs and structs + * + ****************************************************************************/ + +typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); + +/***************************************************************************** + * + * Parser typedefs and structs + * + ****************************************************************************/ + +/* + * AML opcode, name, and argument layout + */ +struct acpi_opcode_info { +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) + char *name; /* Opcode name (disassembler/debug only) */ +#endif + u32 parse_args; /* Grammar/Parse time arguments */ + u32 runtime_args; /* Interpret time arguments */ + u16 flags; /* Misc flags */ + u8 object_type; /* Corresponding internal object type */ + u8 class; /* Opcode class */ + u8 type; /* Opcode type */ +}; + +union acpi_parse_value { + acpi_integer integer; /* Integer constant (Up to 64 bits) */ + struct uint64_struct integer64; /* Structure overlay for 2 32-bit Dwords */ + u32 size; /* bytelist or field size */ + char *string; /* NULL terminated string */ + u8 *buffer; /* buffer or string */ + char *name; /* NULL terminated string */ + union acpi_parse_object *arg; /* arguments and contained ops */ +}; + +#ifdef ACPI_DISASSEMBLER +#define ACPI_DISASM_ONLY_MEMBERS(a) a; +#else +#define ACPI_DISASM_ONLY_MEMBERS(a) +#endif + +#define ACPI_PARSE_COMMON \ + union acpi_parse_object *parent; /* Parent op */\ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 flags; /* Type of Op */\ + u16 aml_opcode; /* AML opcode */\ + u32 aml_offset; /* Offset of declaration in AML */\ + union acpi_parse_object *next; /* Next op */\ + struct acpi_namespace_node *node; /* For use by interpreter */\ + union acpi_parse_value value; /* Value or args associated with the opcode */\ + u8 arg_list_length; /* Number of elements in the arg list */\ + ACPI_DISASM_ONLY_MEMBERS (\ + u8 disasm_flags; /* Used during AML disassembly */\ + u8 disasm_opcode; /* Subtype used for disassembly */\ + char aml_op_name[16]) /* Op name (debug only) */ + +#define ACPI_DASM_BUFFER 0x00 +#define ACPI_DASM_RESOURCE 0x01 +#define ACPI_DASM_STRING 0x02 +#define ACPI_DASM_UNICODE 0x03 +#define ACPI_DASM_EISAID 0x04 +#define ACPI_DASM_MATCHOP 0x05 +#define ACPI_DASM_LNOT_PREFIX 0x06 +#define ACPI_DASM_LNOT_SUFFIX 0x07 +#define ACPI_DASM_IGNORE 0x08 + +/* + * Generic operation (for example: If, While, Store) + */ +struct acpi_parse_obj_common { +ACPI_PARSE_COMMON}; + +/* + * Extended Op for named ops (Scope, Method, etc.), deferred ops (Methods and op_regions), + * and bytelists. + */ +struct acpi_parse_obj_named { + ACPI_PARSE_COMMON u8 *path; + u8 *data; /* AML body or bytelist data */ + u32 length; /* AML length */ + u32 name; /* 4-byte name or zero if no name */ +}; + +/* This version is used by the i_aSL compiler only */ + +#define ACPI_MAX_PARSEOP_NAME 20 + +struct acpi_parse_obj_asl { + ACPI_PARSE_COMMON union acpi_parse_object *child; + union acpi_parse_object *parent_method; + char *filename; + char *external_name; + char *namepath; + char name_seg[4]; + u32 extra_value; + u32 column; + u32 line_number; + u32 logical_line_number; + u32 logical_byte_offset; + u32 end_line; + u32 end_logical_line; + u32 acpi_btype; + u32 aml_length; + u32 aml_subtree_length; + u32 final_aml_length; + u32 final_aml_offset; + u32 compile_flags; + u16 parse_opcode; + u8 aml_opcode_length; + u8 aml_pkg_len_bytes; + u8 extra; + char parse_op_name[ACPI_MAX_PARSEOP_NAME]; +}; + +union acpi_parse_object { + struct acpi_parse_obj_common common; + struct acpi_parse_obj_named named; + struct acpi_parse_obj_asl asl; +}; + +/* + * Parse state - one state per parser invocation and each control + * method. + */ +struct acpi_parse_state { + u8 *aml_start; /* First AML byte */ + u8 *aml; /* Next AML byte */ + u8 *aml_end; /* (last + 1) AML byte */ + u8 *pkg_start; /* Current package begin */ + u8 *pkg_end; /* Current package end */ + union acpi_parse_object *start_op; /* Root of parse tree */ + struct acpi_namespace_node *start_node; + union acpi_generic_state *scope; /* Current scope */ + union acpi_parse_object *start_scope; + u32 aml_size; +}; + +/* Parse object flags */ + +#define ACPI_PARSEOP_GENERIC 0x01 +#define ACPI_PARSEOP_NAMED 0x02 +#define ACPI_PARSEOP_DEFERRED 0x04 +#define ACPI_PARSEOP_BYTELIST 0x08 +#define ACPI_PARSEOP_IN_STACK 0x10 +#define ACPI_PARSEOP_TARGET 0x20 +#define ACPI_PARSEOP_IN_CACHE 0x80 + +/* Parse object disasm_flags */ + +#define ACPI_PARSEOP_IGNORE 0x01 +#define ACPI_PARSEOP_PARAMLIST 0x02 +#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04 +#define ACPI_PARSEOP_SPECIAL 0x10 + +/***************************************************************************** + * + * Hardware (ACPI registers) and PNP + * + ****************************************************************************/ + +struct acpi_bit_register_info { + u8 parent_register; + u8 bit_position; + u16 access_bit_mask; +}; + +/* + * Some ACPI registers have bits that must be ignored -- meaning that they + * must be preserved. + */ +#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */ +#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */ + +/* + * Register IDs + * These are the full ACPI registers + */ +#define ACPI_REGISTER_PM1_STATUS 0x01 +#define ACPI_REGISTER_PM1_ENABLE 0x02 +#define ACPI_REGISTER_PM1_CONTROL 0x03 +#define ACPI_REGISTER_PM1A_CONTROL 0x04 +#define ACPI_REGISTER_PM1B_CONTROL 0x05 +#define ACPI_REGISTER_PM2_CONTROL 0x06 +#define ACPI_REGISTER_PM_TIMER 0x07 +#define ACPI_REGISTER_PROCESSOR_BLOCK 0x08 +#define ACPI_REGISTER_SMI_COMMAND_BLOCK 0x09 + +/* Masks used to access the bit_registers */ + +#define ACPI_BITMASK_TIMER_STATUS 0x0001 +#define ACPI_BITMASK_BUS_MASTER_STATUS 0x0010 +#define ACPI_BITMASK_GLOBAL_LOCK_STATUS 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_STATUS 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_STATUS 0x0200 +#define ACPI_BITMASK_RT_CLOCK_STATUS 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_STATUS 0x4000 /* ACPI 3.0 */ +#define ACPI_BITMASK_WAKE_STATUS 0x8000 + +#define ACPI_BITMASK_ALL_FIXED_STATUS (\ + ACPI_BITMASK_TIMER_STATUS | \ + ACPI_BITMASK_BUS_MASTER_STATUS | \ + ACPI_BITMASK_GLOBAL_LOCK_STATUS | \ + ACPI_BITMASK_POWER_BUTTON_STATUS | \ + ACPI_BITMASK_SLEEP_BUTTON_STATUS | \ + ACPI_BITMASK_RT_CLOCK_STATUS | \ + ACPI_BITMASK_WAKE_STATUS) + +#define ACPI_BITMASK_TIMER_ENABLE 0x0001 +#define ACPI_BITMASK_GLOBAL_LOCK_ENABLE 0x0020 +#define ACPI_BITMASK_POWER_BUTTON_ENABLE 0x0100 +#define ACPI_BITMASK_SLEEP_BUTTON_ENABLE 0x0200 +#define ACPI_BITMASK_RT_CLOCK_ENABLE 0x0400 +#define ACPI_BITMASK_PCIEXP_WAKE_DISABLE 0x4000 /* ACPI 3.0 */ + +#define ACPI_BITMASK_SCI_ENABLE 0x0001 +#define ACPI_BITMASK_BUS_MASTER_RLD 0x0002 +#define ACPI_BITMASK_GLOBAL_LOCK_RELEASE 0x0004 +#define ACPI_BITMASK_SLEEP_TYPE_X 0x1C00 +#define ACPI_BITMASK_SLEEP_ENABLE 0x2000 + +#define ACPI_BITMASK_ARB_DISABLE 0x0001 + +/* Raw bit position of each bit_register */ + +#define ACPI_BITPOSITION_TIMER_STATUS 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_STATUS 0x04 +#define ACPI_BITPOSITION_GLOBAL_LOCK_STATUS 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_STATUS 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_STATUS 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_STATUS 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_STATUS 0x0E /* ACPI 3.0 */ +#define ACPI_BITPOSITION_WAKE_STATUS 0x0F + +#define ACPI_BITPOSITION_TIMER_ENABLE 0x00 +#define ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE 0x05 +#define ACPI_BITPOSITION_POWER_BUTTON_ENABLE 0x08 +#define ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE 0x09 +#define ACPI_BITPOSITION_RT_CLOCK_ENABLE 0x0A +#define ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE 0x0E /* ACPI 3.0 */ + +#define ACPI_BITPOSITION_SCI_ENABLE 0x00 +#define ACPI_BITPOSITION_BUS_MASTER_RLD 0x01 +#define ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE 0x02 +#define ACPI_BITPOSITION_SLEEP_TYPE_X 0x0A +#define ACPI_BITPOSITION_SLEEP_ENABLE 0x0D + +#define ACPI_BITPOSITION_ARB_DISABLE 0x00 + +/***************************************************************************** + * + * Resource descriptors + * + ****************************************************************************/ + +/* resource_type values */ + +#define ACPI_ADDRESS_TYPE_MEMORY_RANGE 0 +#define ACPI_ADDRESS_TYPE_IO_RANGE 1 +#define ACPI_ADDRESS_TYPE_BUS_NUMBER_RANGE 2 + +/* Resource descriptor types and masks */ + +#define ACPI_RESOURCE_NAME_LARGE 0x80 +#define ACPI_RESOURCE_NAME_SMALL 0x00 + +#define ACPI_RESOURCE_NAME_SMALL_MASK 0x78 /* Bits 6:3 contain the type */ +#define ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK 0x07 /* Bits 2:0 contain the length */ +#define ACPI_RESOURCE_NAME_LARGE_MASK 0x7F /* Bits 6:0 contain the type */ + +/* + * Small resource descriptor "names" as defined by the ACPI specification. + * Note: Bits 2:0 are used for the descriptor length + */ +#define ACPI_RESOURCE_NAME_IRQ 0x20 +#define ACPI_RESOURCE_NAME_DMA 0x28 +#define ACPI_RESOURCE_NAME_START_DEPENDENT 0x30 +#define ACPI_RESOURCE_NAME_END_DEPENDENT 0x38 +#define ACPI_RESOURCE_NAME_IO 0x40 +#define ACPI_RESOURCE_NAME_FIXED_IO 0x48 +#define ACPI_RESOURCE_NAME_RESERVED_S1 0x50 +#define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 +#define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 +#define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 +#define ACPI_RESOURCE_NAME_VENDOR_SMALL 0x70 +#define ACPI_RESOURCE_NAME_END_TAG 0x78 + +/* + * Large resource descriptor "names" as defined by the ACPI specification. + * Note: includes the Large Descriptor bit in bit[7] + */ +#define ACPI_RESOURCE_NAME_MEMORY24 0x81 +#define ACPI_RESOURCE_NAME_GENERIC_REGISTER 0x82 +#define ACPI_RESOURCE_NAME_RESERVED_L1 0x83 +#define ACPI_RESOURCE_NAME_VENDOR_LARGE 0x84 +#define ACPI_RESOURCE_NAME_MEMORY32 0x85 +#define ACPI_RESOURCE_NAME_FIXED_MEMORY32 0x86 +#define ACPI_RESOURCE_NAME_ADDRESS32 0x87 +#define ACPI_RESOURCE_NAME_ADDRESS16 0x88 +#define ACPI_RESOURCE_NAME_EXTENDED_IRQ 0x89 +#define ACPI_RESOURCE_NAME_ADDRESS64 0x8A +#define ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 0x8B +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8B + +/***************************************************************************** + * + * Miscellaneous + * + ****************************************************************************/ + +#define ACPI_ASCII_ZERO 0x30 + +/***************************************************************************** + * + * Debugger + * + ****************************************************************************/ + +struct acpi_db_method_info { + acpi_handle main_thread_gate; + acpi_handle thread_complete_gate; + u32 *threads; + u32 num_threads; + u32 num_created; + u32 num_completed; + + char *name; + u32 flags; + u32 num_loops; + char pathname[128]; + char **args; + + /* + * Arguments to be passed to method for the command + * Threads - + * the Number of threads, ID of current thread and + * Index of current thread inside all them created. + */ + char init_args; + char *arguments[4]; + char num_threads_str[11]; + char id_of_thread_str[11]; + char index_of_thread_str[11]; +}; + +struct acpi_integrity_info { + u32 nodes; + u32 objects; +}; + +#define ACPI_DB_REDIRECTABLE_OUTPUT 0x01 +#define ACPI_DB_CONSOLE_OUTPUT 0x02 +#define ACPI_DB_DUPLICATE_OUTPUT 0x03 + +/***************************************************************************** + * + * Debug + * + ****************************************************************************/ + +/* Entry for a memory allocation (debug only) */ + +#define ACPI_MEM_MALLOC 0 +#define ACPI_MEM_CALLOC 1 +#define ACPI_MAX_MODULE_NAME 16 + +#define ACPI_COMMON_DEBUG_MEM_HEADER \ + struct acpi_debug_mem_block *previous; \ + struct acpi_debug_mem_block *next; \ + u32 size; \ + u32 component; \ + u32 line; \ + char module[ACPI_MAX_MODULE_NAME]; \ + u8 alloc_type; + +struct acpi_debug_mem_header { +ACPI_COMMON_DEBUG_MEM_HEADER}; + +struct acpi_debug_mem_block { + ACPI_COMMON_DEBUG_MEM_HEADER u64 user_space; +}; + +#define ACPI_MEM_LIST_GLOBAL 0 +#define ACPI_MEM_LIST_NSNODE 1 +#define ACPI_MEM_LIST_MAX 1 +#define ACPI_NUM_MEM_LISTS 2 + +#endif /* __ACLOCAL_H__ */ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h new file mode 100644 index 00000000000..9c127e8e2d6 --- /dev/null +++ b/drivers/acpi/acpica/acmacros.h @@ -0,0 +1,577 @@ +/****************************************************************************** + * + * Name: acmacros.h - C macros for the entire subsystem. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACMACROS_H__ +#define __ACMACROS_H__ + +/* + * Extract data using a pointer. Any more than a byte and we + * get into potential aligment issues -- see the STORE macros below. + * Use with care. + */ +#define ACPI_GET8(ptr) *ACPI_CAST_PTR (u8, ptr) +#define ACPI_GET16(ptr) *ACPI_CAST_PTR (u16, ptr) +#define ACPI_GET32(ptr) *ACPI_CAST_PTR (u32, ptr) +#define ACPI_GET64(ptr) *ACPI_CAST_PTR (u64, ptr) +#define ACPI_SET8(ptr) *ACPI_CAST_PTR (u8, ptr) +#define ACPI_SET16(ptr) *ACPI_CAST_PTR (u16, ptr) +#define ACPI_SET32(ptr) *ACPI_CAST_PTR (u32, ptr) +#define ACPI_SET64(ptr) *ACPI_CAST_PTR (u64, ptr) + +/* + * printf() format helpers + */ + +/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */ + +#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i), ACPI_LODWORD(i) + +#if ACPI_MACHINE_WIDTH == 64 +#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i) +#else +#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i) +#endif + +/* + * Macros for moving data around to/from buffers that are possibly unaligned. + * If the hardware supports the transfer of unaligned data, just do the store. + * Otherwise, we have to move one byte at a time. + */ +#ifdef ACPI_BIG_ENDIAN +/* + * Macros for big-endian machines + */ + +/* These macros reverse the bytes during the move, converting little-endian to big endian */ + + /* Big Endian <== Little Endian */ + /* Hi...Lo Lo...Hi */ +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d))=0;\ + ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + +#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ + ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d))=0;\ + ((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ + ((u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\ + ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ + +#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[7];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[6];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[5];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[4];\ + (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\ + (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];} +#else +/* + * Macros for little-endian machines + */ + +#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED + +/* The hardware supports unaligned transfers, just do the little-endian move */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) *(u16 *)(void *)(d) = *(u16 *)(void *)(s) +#define ACPI_MOVE_16_TO_32(d, s) *(u32 *)(void *)(d) = *(u16 *)(void *)(s) +#define ACPI_MOVE_16_TO_64(d, s) *(u64 *)(void *)(d) = *(u16 *)(void *)(s) + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_32_TO_32(d, s) *(u32 *)(void *)(d) = *(u32 *)(void *)(s) +#define ACPI_MOVE_32_TO_64(d, s) *(u64 *)(void *)(d) = *(u32 *)(void *)(s) + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) *(u64 *)(void *)(d) = *(u64 *)(void *)(s) + +#else +/* + * The hardware does not support unaligned transfers. We must move the + * data one byte at a time. These macros work whether the source or + * the destination (or both) is/are unaligned. (Little-endian move) + */ + +/* 16-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_16_TO_16(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];} + +#define ACPI_MOVE_16_TO_32(d, s) {(*(u32 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} +#define ACPI_MOVE_16_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_16_TO_16(d, s);} + +/* 32-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_32_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ + +#define ACPI_MOVE_32_TO_32(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];} + +#define ACPI_MOVE_32_TO_64(d, s) {(*(u64 *)(void *)(d)) = 0; ACPI_MOVE_32_TO_32(d, s);} + +/* 64-bit source, 16/32/64 destination */ + +#define ACPI_MOVE_64_TO_16(d, s) ACPI_MOVE_16_TO_16(d, s) /* Truncate to 16 */ +#define ACPI_MOVE_64_TO_32(d, s) ACPI_MOVE_32_TO_32(d, s) /* Truncate to 32 */ +#define ACPI_MOVE_64_TO_64(d, s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[0];\ + (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[1];\ + (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[2];\ + (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[3];\ + (( u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[4];\ + (( u8 *)(void *)(d))[5] = ((u8 *)(void *)(s))[5];\ + (( u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[6];\ + (( u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[7];} +#endif +#endif + +/* Macros based on machine integer width */ + +#if ACPI_MACHINE_WIDTH == 32 +#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_32_TO_16(d, s) + +#elif ACPI_MACHINE_WIDTH == 64 +#define ACPI_MOVE_SIZE_TO_16(d, s) ACPI_MOVE_64_TO_16(d, s) + +#else +#error unknown ACPI_MACHINE_WIDTH +#endif + +/* + * Fast power-of-two math macros for non-optimized compilers + */ +#define _ACPI_DIV(value, power_of2) ((u32) ((value) >> (power_of2))) +#define _ACPI_MUL(value, power_of2) ((u32) ((value) << (power_of2))) +#define _ACPI_MOD(value, divisor) ((u32) ((value) & ((divisor) -1))) + +#define ACPI_DIV_2(a) _ACPI_DIV(a, 1) +#define ACPI_MUL_2(a) _ACPI_MUL(a, 1) +#define ACPI_MOD_2(a) _ACPI_MOD(a, 2) + +#define ACPI_DIV_4(a) _ACPI_DIV(a, 2) +#define ACPI_MUL_4(a) _ACPI_MUL(a, 2) +#define ACPI_MOD_4(a) _ACPI_MOD(a, 4) + +#define ACPI_DIV_8(a) _ACPI_DIV(a, 3) +#define ACPI_MUL_8(a) _ACPI_MUL(a, 3) +#define ACPI_MOD_8(a) _ACPI_MOD(a, 8) + +#define ACPI_DIV_16(a) _ACPI_DIV(a, 4) +#define ACPI_MUL_16(a) _ACPI_MUL(a, 4) +#define ACPI_MOD_16(a) _ACPI_MOD(a, 16) + +#define ACPI_DIV_32(a) _ACPI_DIV(a, 5) +#define ACPI_MUL_32(a) _ACPI_MUL(a, 5) +#define ACPI_MOD_32(a) _ACPI_MOD(a, 32) + +/* + * Rounding macros (Power of two boundaries only) + */ +#define ACPI_ROUND_DOWN(value, boundary) (((acpi_size)(value)) & \ + (~(((acpi_size) boundary)-1))) + +#define ACPI_ROUND_UP(value, boundary) ((((acpi_size)(value)) + \ + (((acpi_size) boundary)-1)) & \ + (~(((acpi_size) boundary)-1))) + +/* Note: sizeof(acpi_size) evaluates to either 4 or 8 (32- vs 64-bit mode) */ + +#define ACPI_ROUND_DOWN_TO_32BIT(a) ACPI_ROUND_DOWN(a, 4) +#define ACPI_ROUND_DOWN_TO_64BIT(a) ACPI_ROUND_DOWN(a, 8) +#define ACPI_ROUND_DOWN_TO_NATIVE_WORD(a) ACPI_ROUND_DOWN(a, sizeof(acpi_size)) + +#define ACPI_ROUND_UP_TO_32BIT(a) ACPI_ROUND_UP(a, 4) +#define ACPI_ROUND_UP_TO_64BIT(a) ACPI_ROUND_UP(a, 8) +#define ACPI_ROUND_UP_TO_NATIVE_WORD(a) ACPI_ROUND_UP(a, sizeof(acpi_size)) + +#define ACPI_ROUND_BITS_UP_TO_BYTES(a) ACPI_DIV_8((a) + 7) +#define ACPI_ROUND_BITS_DOWN_TO_BYTES(a) ACPI_DIV_8((a)) + +#define ACPI_ROUND_UP_TO_1K(a) (((a) + 1023) >> 10) + +/* Generic (non-power-of-two) rounding */ + +#define ACPI_ROUND_UP_TO(value, boundary) (((value) + ((boundary)-1)) / (boundary)) + +#define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) + +/* + * Bitmask creation + * Bit positions start at zero. + * MASK_BITS_ABOVE creates a mask starting AT the position and above + * MASK_BITS_BELOW creates a mask starting one bit BELOW the position + */ +#define ACPI_MASK_BITS_ABOVE(position) (~((ACPI_INTEGER_MAX) << ((u32) (position)))) +#define ACPI_MASK_BITS_BELOW(position) ((ACPI_INTEGER_MAX) << ((u32) (position))) + +/* Bitfields within ACPI registers */ + +#define ACPI_REGISTER_PREPARE_BITS(val, pos, mask) ((val << pos) & mask) +#define ACPI_REGISTER_INSERT_VALUE(reg, pos, mask, val) reg = (reg & (~(mask))) | ACPI_REGISTER_PREPARE_BITS(val, pos, mask) + +#define ACPI_INSERT_BITS(target, mask, source) target = ((target & (~(mask))) | (source & mask)) + +/* + * A struct acpi_namespace_node can appear in some contexts + * where a pointer to a union acpi_operand_object can also + * appear. This macro is used to distinguish them. + * + * The "Descriptor" field is the first field in both structures. + */ +#define ACPI_GET_DESCRIPTOR_TYPE(d) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type) +#define ACPI_SET_DESCRIPTOR_TYPE(d, t) (((union acpi_descriptor *)(void *)(d))->common.descriptor_type = t) + +/* Macro to test the object type */ + +#define ACPI_GET_OBJECT_TYPE(d) (((union acpi_operand_object *)(void *)(d))->common.type) + +/* + * Macros for the master AML opcode table + */ +#if defined (ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT) +#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \ + {name, (u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type} +#else +#define ACPI_OP(name, Pargs, Iargs, obj_type, class, type, flags) \ + {(u32)(Pargs), (u32)(Iargs), (u32)(flags), obj_type, class, type} +#endif + +#define ARG_TYPE_WIDTH 5 +#define ARG_1(x) ((u32)(x)) +#define ARG_2(x) ((u32)(x) << (1 * ARG_TYPE_WIDTH)) +#define ARG_3(x) ((u32)(x) << (2 * ARG_TYPE_WIDTH)) +#define ARG_4(x) ((u32)(x) << (3 * ARG_TYPE_WIDTH)) +#define ARG_5(x) ((u32)(x) << (4 * ARG_TYPE_WIDTH)) +#define ARG_6(x) ((u32)(x) << (5 * ARG_TYPE_WIDTH)) + +#define ARGI_LIST1(a) (ARG_1(a)) +#define ARGI_LIST2(a, b) (ARG_1(b)|ARG_2(a)) +#define ARGI_LIST3(a, b, c) (ARG_1(c)|ARG_2(b)|ARG_3(a)) +#define ARGI_LIST4(a, b, c, d) (ARG_1(d)|ARG_2(c)|ARG_3(b)|ARG_4(a)) +#define ARGI_LIST5(a, b, c, d, e) (ARG_1(e)|ARG_2(d)|ARG_3(c)|ARG_4(b)|ARG_5(a)) +#define ARGI_LIST6(a, b, c, d, e, f) (ARG_1(f)|ARG_2(e)|ARG_3(d)|ARG_4(c)|ARG_5(b)|ARG_6(a)) + +#define ARGP_LIST1(a) (ARG_1(a)) +#define ARGP_LIST2(a, b) (ARG_1(a)|ARG_2(b)) +#define ARGP_LIST3(a, b, c) (ARG_1(a)|ARG_2(b)|ARG_3(c)) +#define ARGP_LIST4(a, b, c, d) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)) +#define ARGP_LIST5(a, b, c, d, e) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)) +#define ARGP_LIST6(a, b, c, d, e, f) (ARG_1(a)|ARG_2(b)|ARG_3(c)|ARG_4(d)|ARG_5(e)|ARG_6(f)) + +#define GET_CURRENT_ARG_TYPE(list) (list & ((u32) 0x1F)) +#define INCREMENT_ARG_LIST(list) (list >>= ((u32) ARG_TYPE_WIDTH)) + +/* + * Ascii error messages can be configured out + */ +#ifndef ACPI_NO_ERROR_MESSAGES + +/* + * Error reporting. Callers module and line number are inserted by AE_INFO, + * the plist contains a set of parens to allow variable-length lists. + * These macros are used for both the debug and non-debug versions of the code. + */ +#define ACPI_ERROR_NAMESPACE(s, e) acpi_ns_report_error (AE_INFO, s, e); +#define ACPI_ERROR_METHOD(s, n, p, e) acpi_ns_report_method_error (AE_INFO, s, n, p, e); + +#else + +/* No error messages */ + +#define ACPI_ERROR_NAMESPACE(s, e) +#define ACPI_ERROR_METHOD(s, n, p, e) +#endif /* ACPI_NO_ERROR_MESSAGES */ + +/* + * Debug macros that are conditionally compiled + */ +#ifdef ACPI_DEBUG_OUTPUT + +/* + * Function entry tracing + */ +#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE + +#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ + acpi_ut_trace(ACPI_DEBUG_PARAMETERS) +#define ACPI_FUNCTION_TRACE_PTR(a, b) ACPI_FUNCTION_NAME(a) \ + acpi_ut_trace_ptr(ACPI_DEBUG_PARAMETERS, (void *)b) +#define ACPI_FUNCTION_TRACE_U32(a, b) ACPI_FUNCTION_NAME(a) \ + acpi_ut_trace_u32(ACPI_DEBUG_PARAMETERS, (u32)b) +#define ACPI_FUNCTION_TRACE_STR(a, b) ACPI_FUNCTION_NAME(a) \ + acpi_ut_trace_str(ACPI_DEBUG_PARAMETERS, (char *)b) + +#define ACPI_FUNCTION_ENTRY() acpi_ut_track_stack_ptr() + +/* + * Function exit tracing. + * WARNING: These macros include a return statement. This is usually considered + * bad form, but having a separate exit macro is very ugly and difficult to maintain. + * One of the FUNCTION_TRACE macros above must be used in conjunction with these macros + * so that "_AcpiFunctionName" is defined. + * + * Note: the DO_WHILE0 macro is used to prevent some compilers from complaining + * about these constructs. + */ +#ifdef ACPI_USE_DO_WHILE_0 +#define ACPI_DO_WHILE0(a) do a while(0) +#else +#define ACPI_DO_WHILE0(a) a +#endif + +#define return_VOID ACPI_DO_WHILE0 ({ \ + acpi_ut_exit (ACPI_DEBUG_PARAMETERS); \ + return;}) +/* + * There are two versions of most of the return macros. The default version is + * safer, since it avoids side-effects by guaranteeing that the argument will + * not be evaluated twice. + * + * A less-safe version of the macros is provided for optional use if the + * compiler uses excessive CPU stack (for example, this may happen in the + * debug case if code optimzation is disabled.) + */ +#ifndef ACPI_SIMPLE_RETURN_MACROS + +#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \ + register acpi_status _s = (s); \ + acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, _s); \ + return (_s); }) +#define return_PTR(s) ACPI_DO_WHILE0 ({ \ + register void *_s = (void *) (s); \ + acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) _s); \ + return (_s); }) +#define return_VALUE(s) ACPI_DO_WHILE0 ({ \ + register acpi_integer _s = (s); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, _s); \ + return (_s); }) +#define return_UINT8(s) ACPI_DO_WHILE0 ({ \ + register u8 _s = (u8) (s); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \ + return (_s); }) +#define return_UINT32(s) ACPI_DO_WHILE0 ({ \ + register u32 _s = (u32) (s); \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) _s); \ + return (_s); }) +#else /* Use original less-safe macros */ + +#define return_ACPI_STATUS(s) ACPI_DO_WHILE0 ({ \ + acpi_ut_status_exit (ACPI_DEBUG_PARAMETERS, (s)); \ + return((s)); }) +#define return_PTR(s) ACPI_DO_WHILE0 ({ \ + acpi_ut_ptr_exit (ACPI_DEBUG_PARAMETERS, (u8 *) (s)); \ + return((s)); }) +#define return_VALUE(s) ACPI_DO_WHILE0 ({ \ + acpi_ut_value_exit (ACPI_DEBUG_PARAMETERS, (acpi_integer) (s)); \ + return((s)); }) +#define return_UINT8(s) return_VALUE(s) +#define return_UINT32(s) return_VALUE(s) + +#endif /* ACPI_SIMPLE_RETURN_MACROS */ + +#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */ + +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_TRACE_PTR(a,b) +#define ACPI_FUNCTION_TRACE_U32(a,b) +#define ACPI_FUNCTION_TRACE_STR(a,b) +#define ACPI_FUNCTION_EXIT +#define ACPI_FUNCTION_STATUS_EXIT(s) +#define ACPI_FUNCTION_VALUE_EXIT(s) +#define ACPI_FUNCTION_TRACE(a) +#define ACPI_FUNCTION_ENTRY() + +#define return_VOID return +#define return_ACPI_STATUS(s) return(s) +#define return_VALUE(s) return(s) +#define return_UINT8(s) return(s) +#define return_UINT32(s) return(s) +#define return_PTR(s) return(s) + +#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */ + +/* Conditional execution */ + +#define ACPI_DEBUG_EXEC(a) a +#define ACPI_NORMAL_EXEC(a) + +#define ACPI_DEBUG_DEFINE(a) a; +#define ACPI_DEBUG_ONLY_MEMBERS(a) a; +#define _VERBOSE_STRUCTURES + +/* Stack and buffer dumping */ + +#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0) +#define ACPI_DUMP_OPERANDS(a, b, c) acpi_ex_dump_operands(a, b, c) + +#define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b) +#define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) +#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a) +#define ACPI_DUMP_BUFFER(a, b) acpi_ut_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) + +#else +/* + * This is the non-debug case -- make everything go away, + * leaving no executable debug code! + */ +#define ACPI_DEBUG_EXEC(a) +#define ACPI_NORMAL_EXEC(a) a; + +#define ACPI_DEBUG_DEFINE(a) do { } while(0) +#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0) +#define ACPI_FUNCTION_TRACE(a) do { } while(0) +#define ACPI_FUNCTION_TRACE_PTR(a, b) do { } while(0) +#define ACPI_FUNCTION_TRACE_U32(a, b) do { } while(0) +#define ACPI_FUNCTION_TRACE_STR(a, b) do { } while(0) +#define ACPI_FUNCTION_EXIT do { } while(0) +#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0) +#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0) +#define ACPI_FUNCTION_ENTRY() do { } while(0) +#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0) +#define ACPI_DUMP_OPERANDS(a, b, c) do { } while(0) +#define ACPI_DUMP_ENTRY(a, b) do { } while(0) +#define ACPI_DUMP_TABLES(a, b) do { } while(0) +#define ACPI_DUMP_PATHNAME(a, b, c, d) do { } while(0) +#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0) +#define ACPI_DUMP_BUFFER(a, b) do { } while(0) + +#define return_VOID return +#define return_ACPI_STATUS(s) return(s) +#define return_VALUE(s) return(s) +#define return_UINT8(s) return(s) +#define return_UINT32(s) return(s) +#define return_PTR(s) return(s) + +#endif /* ACPI_DEBUG_OUTPUT */ + +/* + * Some code only gets executed when the debugger is built in. + * Note that this is entirely independent of whether the + * DEBUG_PRINT stuff (set by ACPI_DEBUG_OUTPUT) is on, or not. + */ +#ifdef ACPI_DEBUGGER +#define ACPI_DEBUGGER_EXEC(a) a +#else +#define ACPI_DEBUGGER_EXEC(a) +#endif + +#ifdef ACPI_DEBUG_OUTPUT +/* + * 1) Set name to blanks + * 2) Copy the object name + */ +#define ACPI_ADD_OBJECT_NAME(a,b) ACPI_MEMSET (a->common.name, ' ', sizeof (a->common.name));\ + ACPI_STRNCPY (a->common.name, acpi_gbl_ns_type_names[b], sizeof (a->common.name)) +#else + +#define ACPI_ADD_OBJECT_NAME(a,b) +#endif + +/* + * Memory allocation tracking (DEBUG ONLY) + */ +#define ACPI_MEM_PARAMETERS _COMPONENT, _acpi_module_name, __LINE__ + +#ifndef ACPI_DBG_TRACK_ALLOCATIONS + +/* Memory allocation */ + +#ifndef ACPI_ALLOCATE +#define ACPI_ALLOCATE(a) acpi_ut_allocate((acpi_size)(a), ACPI_MEM_PARAMETERS) +#endif +#ifndef ACPI_ALLOCATE_ZEROED +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed((acpi_size)(a), ACPI_MEM_PARAMETERS) +#endif +#ifndef ACPI_FREE +#define ACPI_FREE(a) acpio_os_free(a) +#endif +#define ACPI_MEM_TRACKING(a) + +#else + +/* Memory allocation */ + +#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track((acpi_size)(a), ACPI_MEM_PARAMETERS) +#define ACPI_FREE(a) acpi_ut_free_and_track(a, ACPI_MEM_PARAMETERS) +#define ACPI_MEM_TRACKING(a) a + +#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ + +/* Preemption point */ +#ifndef ACPI_PREEMPTION_POINT +#define ACPI_PREEMPTION_POINT() /* no preemption */ +#endif + +#endif /* ACMACROS_H */ diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h new file mode 100644 index 00000000000..46cb5b46d28 --- /dev/null +++ b/drivers/acpi/acpica/acnamesp.h @@ -0,0 +1,324 @@ +/****************************************************************************** + * + * Name: acnamesp.h - Namespace subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACNAMESP_H__ +#define __ACNAMESP_H__ + +/* To search the entire name space, pass this as search_base */ + +#define ACPI_NS_ALL ((acpi_handle)0) + +/* + * Elements of acpi_ns_properties are bit significant + * and should be one-to-one with values of acpi_object_type + */ +#define ACPI_NS_NORMAL 0 +#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */ +#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */ + +/* Flags for acpi_ns_lookup, acpi_ns_search_and_enter */ + +#define ACPI_NS_NO_UPSEARCH 0 +#define ACPI_NS_SEARCH_PARENT 0x01 +#define ACPI_NS_DONT_OPEN_SCOPE 0x02 +#define ACPI_NS_NO_PEER_SEARCH 0x04 +#define ACPI_NS_ERROR_IF_FOUND 0x08 +#define ACPI_NS_PREFIX_IS_SCOPE 0x10 +#define ACPI_NS_EXTERNAL 0x20 +#define ACPI_NS_TEMPORARY 0x40 + +/* Flags for acpi_ns_walk_namespace */ + +#define ACPI_NS_WALK_NO_UNLOCK 0 +#define ACPI_NS_WALK_UNLOCK 0x01 +#define ACPI_NS_WALK_TEMP_NODES 0x02 + +/* + * nsinit - Namespace initialization + */ +acpi_status acpi_ns_initialize_objects(void); + +acpi_status acpi_ns_initialize_devices(void); + +/* + * nsload - Namespace loading + */ +acpi_status acpi_ns_load_namespace(void); + +acpi_status +acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node); + +/* + * nswalk - walk the namespace + */ +acpi_status +acpi_ns_walk_namespace(acpi_object_type type, + acpi_handle start_object, + u32 max_depth, + u32 flags, + acpi_walk_callback user_function, + void *context, void **return_value); + +struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node + *parent, struct acpi_namespace_node + *child); + +/* + * nsparse - table parsing + */ +acpi_status +acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node); + +acpi_status +acpi_ns_one_complete_parse(u32 pass_number, + u32 table_index, + struct acpi_namespace_node *start_node); + +/* + * nsaccess - Top-level namespace access + */ +acpi_status acpi_ns_root_initialize(void); + +acpi_status +acpi_ns_lookup(union acpi_generic_state *scope_info, + char *name, + acpi_object_type type, + acpi_interpreter_mode interpreter_mode, + u32 flags, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node **ret_node); + +/* + * nsalloc - Named object allocation/deallocation + */ +struct acpi_namespace_node *acpi_ns_create_node(u32 name); + +void acpi_ns_delete_node(struct acpi_namespace_node *node); + +void +acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_handle); + +void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id); + +void acpi_ns_detach_object(struct acpi_namespace_node *node); + +void acpi_ns_delete_children(struct acpi_namespace_node *parent); + +int acpi_ns_compare_names(char *name1, char *name2); + +/* + * nsdump - Namespace dump/print utilities + */ +#ifdef ACPI_FUTURE_USAGE +void acpi_ns_dump_tables(acpi_handle search_base, u32 max_depth); +#endif /* ACPI_FUTURE_USAGE */ + +void acpi_ns_dump_entry(acpi_handle handle, u32 debug_level); + +void +acpi_ns_dump_pathname(acpi_handle handle, char *msg, u32 level, u32 component); + +void acpi_ns_print_pathname(u32 num_segments, char *pathname); + +acpi_status +acpi_ns_dump_one_object(acpi_handle obj_handle, + u32 level, void *context, void **return_value); + +#ifdef ACPI_FUTURE_USAGE +void +acpi_ns_dump_objects(acpi_object_type type, + u8 display_type, + u32 max_depth, + acpi_owner_id owner_id, acpi_handle start_handle); +#endif /* ACPI_FUTURE_USAGE */ + +/* + * nseval - Namespace evaluation functions + */ +acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info); + +/* + * nspredef - Support for predefined/reserved names + */ +acpi_status +acpi_ns_check_predefined_names(struct acpi_namespace_node *node, + u32 user_param_count, + acpi_status return_status, + union acpi_operand_object **return_object); + +const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct + acpi_namespace_node + *node); + +void +acpi_ns_check_parameter_count(char *pathname, + struct acpi_namespace_node *node, + u32 user_param_count, + const union acpi_predefined_info *info); + +/* + * nsnames - Name and Scope manipulation + */ +u32 acpi_ns_opens_scope(acpi_object_type type); + +acpi_status +acpi_ns_build_external_path(struct acpi_namespace_node *node, + acpi_size size, char *name_buffer); + +char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node); + +char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ns_handle_to_pathname(acpi_handle target_handle, + struct acpi_buffer *buffer); + +u8 +acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for); + +acpi_status +acpi_ns_get_node(struct acpi_namespace_node *prefix_node, + const char *external_pathname, + u32 flags, struct acpi_namespace_node **out_node); + +acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node); + +/* + * nsobject - Object management for namespace nodes + */ +acpi_status +acpi_ns_attach_object(struct acpi_namespace_node *node, + union acpi_operand_object *object, acpi_object_type type); + +union acpi_operand_object *acpi_ns_get_attached_object(struct + acpi_namespace_node + *node); + +union acpi_operand_object *acpi_ns_get_secondary_object(union + acpi_operand_object + *obj_desc); + +acpi_status +acpi_ns_attach_data(struct acpi_namespace_node *node, + acpi_object_handler handler, void *data); + +acpi_status +acpi_ns_detach_data(struct acpi_namespace_node *node, + acpi_object_handler handler); + +acpi_status +acpi_ns_get_attached_data(struct acpi_namespace_node *node, + acpi_object_handler handler, void **data); + +/* + * nssearch - Namespace searching and entry + */ +acpi_status +acpi_ns_search_and_enter(u32 entry_name, + struct acpi_walk_state *walk_state, + struct acpi_namespace_node *node, + acpi_interpreter_mode interpreter_mode, + acpi_object_type type, + u32 flags, struct acpi_namespace_node **ret_node); + +acpi_status +acpi_ns_search_one_scope(u32 entry_name, + struct acpi_namespace_node *node, + acpi_object_type type, + struct acpi_namespace_node **ret_node); + +void +acpi_ns_install_node(struct acpi_walk_state *walk_state, + struct acpi_namespace_node *parent_node, + struct acpi_namespace_node *node, acpi_object_type type); + +/* + * nsutils - Utility functions + */ +u8 acpi_ns_valid_root_prefix(char prefix); + +acpi_object_type acpi_ns_get_type(struct acpi_namespace_node *node); + +u32 acpi_ns_local(acpi_object_type type); + +void +acpi_ns_report_error(const char *module_name, + u32 line_number, + const char *internal_name, acpi_status lookup_status); + +void +acpi_ns_report_method_error(const char *module_name, + u32 line_number, + const char *message, + struct acpi_namespace_node *node, + const char *path, acpi_status lookup_status); + +void +acpi_ns_print_node_pathname(struct acpi_namespace_node *node, const char *msg); + +acpi_status acpi_ns_build_internal_name(struct acpi_namestring_info *info); + +void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info); + +acpi_status +acpi_ns_internalize_name(const char *dotted_name, char **converted_name); + +acpi_status +acpi_ns_externalize_name(u32 internal_name_length, + const char *internal_name, + u32 * converted_name_length, char **converted_name); + +struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle); + +acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node); + +void acpi_ns_terminate(void); + +struct acpi_namespace_node *acpi_ns_get_parent_node(struct acpi_namespace_node + *node); + +struct acpi_namespace_node *acpi_ns_get_next_valid_node(struct + acpi_namespace_node + *node); + +#endif /* __ACNAMESP_H__ */ diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h new file mode 100644 index 00000000000..eb6f038b03d --- /dev/null +++ b/drivers/acpi/acpica/acobject.h @@ -0,0 +1,446 @@ + +/****************************************************************************** + * + * Name: acobject.h - Definition of union acpi_operand_object (Internal object only) + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef _ACOBJECT_H +#define _ACOBJECT_H + +/* acpisrc:struct_defs -- for acpisrc conversion */ + +/* + * The union acpi_operand_object is used to pass AML operands from the dispatcher + * to the interpreter, and to keep track of the various handlers such as + * address space handlers and notify handlers. The object is a constant + * size in order to allow it to be cached and reused. + * + * Note: The object is optimized to be aligned and will not work if it is + * byte-packed. + */ +#if ACPI_MACHINE_WIDTH == 64 +#pragma pack(8) +#else +#pragma pack(4) +#endif + +/******************************************************************************* + * + * Common Descriptors + * + ******************************************************************************/ + +/* + * Common area for all objects. + * + * descriptor_type is used to differentiate between internal descriptors, and + * must be in the same place across all descriptors + * + * Note: The descriptor_type and Type fields must appear in the identical + * position in both the struct acpi_namespace_node and union acpi_operand_object + * structures. + */ +#define ACPI_OBJECT_COMMON_HEADER \ + union acpi_operand_object *next_object; /* Objects linked to parent NS node */\ + u8 descriptor_type; /* To differentiate various internal objs */\ + u8 type; /* acpi_object_type */\ + u16 reference_count; /* For object deletion management */\ + u8 flags; + /* + * Note: There are 3 bytes available here before the + * next natural alignment boundary (for both 32/64 cases) + */ + +/* Values for Flag byte above */ + +#define AOPOBJ_AML_CONSTANT 0x01 +#define AOPOBJ_STATIC_POINTER 0x02 +#define AOPOBJ_DATA_VALID 0x04 +#define AOPOBJ_OBJECT_INITIALIZED 0x08 +#define AOPOBJ_SETUP_COMPLETE 0x10 +#define AOPOBJ_SINGLE_DATUM 0x20 +#define AOPOBJ_INVALID 0x40 /* Used if host OS won't allow an op_region address */ + +/****************************************************************************** + * + * Basic data types + * + *****************************************************************************/ + +struct acpi_object_common { +ACPI_OBJECT_COMMON_HEADER}; + +struct acpi_object_integer { + ACPI_OBJECT_COMMON_HEADER u8 fill[3]; /* Prevent warning on some compilers */ + acpi_integer value; +}; + +/* + * Note: The String and Buffer object must be identical through the Pointer + * and length elements. There is code that depends on this. + * + * Fields common to both Strings and Buffers + */ +#define ACPI_COMMON_BUFFER_INFO(_type) \ + _type *pointer; \ + u32 length; + +struct acpi_object_string { /* Null terminated, ASCII characters only */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(char) /* String in AML stream or allocated string */ +}; + +struct acpi_object_buffer { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_BUFFER_INFO(u8) /* Buffer in AML stream or allocated buffer */ + u32 aml_length; + u8 *aml_start; + struct acpi_namespace_node *node; /* Link back to parent node */ +}; + +struct acpi_object_package { + ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Link back to parent node */ + union acpi_operand_object **elements; /* Array of pointers to acpi_objects */ + u8 *aml_start; + u32 aml_length; + u32 count; /* # of elements in package */ +}; + +/****************************************************************************** + * + * Complex data types + * + *****************************************************************************/ + +struct acpi_object_event { + ACPI_OBJECT_COMMON_HEADER acpi_semaphore os_semaphore; /* Actual OS synchronization object */ +}; + +struct acpi_object_mutex { + ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */ + u16 acquisition_depth; /* Allow multiple Acquires, same thread */ + acpi_mutex os_mutex; /* Actual OS synchronization object */ + acpi_thread_id thread_id; /* Current owner of the mutex */ + struct acpi_thread_state *owner_thread; /* Current owner of the mutex */ + union acpi_operand_object *prev; /* Link for list of acquired mutexes */ + union acpi_operand_object *next; /* Link for list of acquired mutexes */ + struct acpi_namespace_node *node; /* Containing namespace node */ + u8 original_sync_level; /* Owner's original sync level (0-15) */ +}; + +struct acpi_object_region { + ACPI_OBJECT_COMMON_HEADER u8 space_id; + struct acpi_namespace_node *node; /* Containing namespace node */ + union acpi_operand_object *handler; /* Handler for region access */ + union acpi_operand_object *next; + acpi_physical_address address; + u32 length; +}; + +struct acpi_object_method { + ACPI_OBJECT_COMMON_HEADER u8 method_flags; + u8 param_count; + u8 sync_level; + union acpi_operand_object *mutex; + u8 *aml_start; + ACPI_INTERNAL_METHOD implementation; + u32 aml_length; + u8 thread_count; + acpi_owner_id owner_id; +}; + +/****************************************************************************** + * + * Objects that can be notified. All share a common notify_info area. + * + *****************************************************************************/ + +/* + * Common fields for objects that support ASL notifications + */ +#define ACPI_COMMON_NOTIFY_INFO \ + union acpi_operand_object *system_notify; /* Handler for system notifies */\ + union acpi_operand_object *device_notify; /* Handler for driver notifies */\ + union acpi_operand_object *handler; /* Handler for Address space */ + +struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ +ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; + +struct acpi_object_device { + ACPI_OBJECT_COMMON_HEADER + ACPI_COMMON_NOTIFY_INFO struct acpi_gpe_block_info *gpe_block; +}; + +struct acpi_object_power_resource { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO u32 system_level; + u32 resource_order; +}; + +struct acpi_object_processor { + ACPI_OBJECT_COMMON_HEADER + /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */ + u8 proc_id; + u8 length; + ACPI_COMMON_NOTIFY_INFO acpi_io_address address; +}; + +struct acpi_object_thermal_zone { +ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; + +/****************************************************************************** + * + * Fields. All share a common header/info field. + * + *****************************************************************************/ + +/* + * Common bitfield for the field objects + * "Field Datum" -- a datum from the actual field object + * "Buffer Datum" -- a datum from a user buffer, read from or to be written to the field + */ +#define ACPI_COMMON_FIELD_INFO \ + u8 field_flags; /* Access, update, and lock bits */\ + u8 attribute; /* From access_as keyword */\ + u8 access_byte_width; /* Read/Write size in bytes */\ + struct acpi_namespace_node *node; /* Link back to parent node */\ + u32 bit_length; /* Length of field in bits */\ + u32 base_byte_offset; /* Byte offset within containing object */\ + u32 value; /* Value to store into the Bank or Index register */\ + u8 start_field_bit_offset;/* Bit offset within first field datum (0-63) */\ + u8 access_bit_width; /* Read/Write size in bits (8-64) */ + +struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Parent Operation Region object (REGION/BANK fields only) */ +}; + +struct acpi_object_region_field { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */ +}; + +struct acpi_object_bank_field { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */ + union acpi_operand_object *bank_obj; /* bank_select Register object */ +}; + +struct acpi_object_index_field { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO + /* + * No "RegionObj" pointer needed since the Index and Data registers + * are each field definitions unto themselves. + */ + union acpi_operand_object *index_obj; /* Index register */ + union acpi_operand_object *data_obj; /* Data register */ +}; + +/* The buffer_field is different in that it is part of a Buffer, not an op_region */ + +struct acpi_object_buffer_field { + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *buffer_obj; /* Containing Buffer object */ +}; + +/****************************************************************************** + * + * Objects for handlers + * + *****************************************************************************/ + +struct acpi_object_notify_handler { + ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */ + acpi_notify_handler handler; + void *context; +}; + +struct acpi_object_addr_handler { + ACPI_OBJECT_COMMON_HEADER u8 space_id; + u8 handler_flags; + acpi_adr_space_handler handler; + struct acpi_namespace_node *node; /* Parent device */ + void *context; + acpi_adr_space_setup setup; + union acpi_operand_object *region_list; /* regions using this handler */ + union acpi_operand_object *next; +}; + +/* Flags for address handler (handler_flags) */ + +#define ACPI_ADDR_HANDLER_DEFAULT_INSTALLED 0x01 + +/****************************************************************************** + * + * Special internal objects + * + *****************************************************************************/ + +/* + * The Reference object is used for these opcodes: + * Arg[0-6], Local[0-7], index_op, name_op, ref_of_op, load_op, load_table_op, debug_op + * The Reference.Class differentiates these types. + */ +struct acpi_object_reference { + ACPI_OBJECT_COMMON_HEADER u8 class; /* Reference Class */ + u8 target_type; /* Used for Index Op */ + u8 reserved; + void *object; /* name_op=>HANDLE to obj, index_op=>union acpi_operand_object */ + struct acpi_namespace_node *node; /* ref_of or Namepath */ + union acpi_operand_object **where; /* Target of Index */ + u32 value; /* Used for Local/Arg/Index/ddb_handle */ +}; + +/* Values for Reference.Class above */ + +typedef enum { + ACPI_REFCLASS_LOCAL = 0, /* Method local */ + ACPI_REFCLASS_ARG = 1, /* Method argument */ + ACPI_REFCLASS_REFOF = 2, /* Result of ref_of() TBD: Split to Ref/Node and Ref/operand_obj? */ + ACPI_REFCLASS_INDEX = 3, /* Result of Index() */ + ACPI_REFCLASS_TABLE = 4, /* ddb_handle - Load(), load_table() */ + ACPI_REFCLASS_NAME = 5, /* Reference to a named object */ + ACPI_REFCLASS_DEBUG = 6, /* Debug object */ + + ACPI_REFCLASS_MAX = 6 +} ACPI_REFERENCE_CLASSES; + +/* + * Extra object is used as additional storage for types that + * have AML code in their declarations (term_args) that must be + * evaluated at run time. + * + * Currently: Region and field_unit types + */ +struct acpi_object_extra { + ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ + void *region_context; /* Region-specific data */ + u8 *aml_start; + u32 aml_length; +}; + +/* Additional data that can be attached to namespace nodes */ + +struct acpi_object_data { + ACPI_OBJECT_COMMON_HEADER acpi_object_handler handler; + void *pointer; +}; + +/* Structure used when objects are cached for reuse */ + +struct acpi_object_cache_list { + ACPI_OBJECT_COMMON_HEADER union acpi_operand_object *next; /* Link for object cache and internal lists */ +}; + +/****************************************************************************** + * + * union acpi_operand_object Descriptor - a giant union of all of the above + * + *****************************************************************************/ + +union acpi_operand_object { + struct acpi_object_common common; + struct acpi_object_integer integer; + struct acpi_object_string string; + struct acpi_object_buffer buffer; + struct acpi_object_package package; + struct acpi_object_event event; + struct acpi_object_method method; + struct acpi_object_mutex mutex; + struct acpi_object_region region; + struct acpi_object_notify_common common_notify; + struct acpi_object_device device; + struct acpi_object_power_resource power_resource; + struct acpi_object_processor processor; + struct acpi_object_thermal_zone thermal_zone; + struct acpi_object_field_common common_field; + struct acpi_object_region_field field; + struct acpi_object_buffer_field buffer_field; + struct acpi_object_bank_field bank_field; + struct acpi_object_index_field index_field; + struct acpi_object_notify_handler notify; + struct acpi_object_addr_handler address_space; + struct acpi_object_reference reference; + struct acpi_object_extra extra; + struct acpi_object_data data; + struct acpi_object_cache_list cache; + + /* + * Add namespace node to union in order to simplify code that accepts both + * ACPI_OPERAND_OBJECTs and ACPI_NAMESPACE_NODEs. The structures share + * a common descriptor_type field in order to differentiate them. + */ + struct acpi_namespace_node node; +}; + +/****************************************************************************** + * + * union acpi_descriptor - objects that share a common descriptor identifier + * + *****************************************************************************/ + +/* Object descriptor types */ + +#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */ +#define ACPI_DESC_TYPE_STATE 0x02 +#define ACPI_DESC_TYPE_STATE_UPDATE 0x03 +#define ACPI_DESC_TYPE_STATE_PACKAGE 0x04 +#define ACPI_DESC_TYPE_STATE_CONTROL 0x05 +#define ACPI_DESC_TYPE_STATE_RPSCOPE 0x06 +#define ACPI_DESC_TYPE_STATE_PSCOPE 0x07 +#define ACPI_DESC_TYPE_STATE_WSCOPE 0x08 +#define ACPI_DESC_TYPE_STATE_RESULT 0x09 +#define ACPI_DESC_TYPE_STATE_NOTIFY 0x0A +#define ACPI_DESC_TYPE_STATE_THREAD 0x0B +#define ACPI_DESC_TYPE_WALK 0x0C +#define ACPI_DESC_TYPE_PARSER 0x0D +#define ACPI_DESC_TYPE_OPERAND 0x0E +#define ACPI_DESC_TYPE_NAMED 0x0F +#define ACPI_DESC_TYPE_MAX 0x0F + +struct acpi_common_descriptor { + void *common_pointer; + u8 descriptor_type; /* To differentiate various internal objs */ +}; + +union acpi_descriptor { + struct acpi_common_descriptor common; + union acpi_operand_object object; + struct acpi_namespace_node node; + union acpi_parse_object op; +}; + +#pragma pack() + +#endif /* _ACOBJECT_H */ diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h new file mode 100644 index 00000000000..dfdf6332788 --- /dev/null +++ b/drivers/acpi/acpica/acopcode.h @@ -0,0 +1,323 @@ +/****************************************************************************** + * + * Name: acopcode.h - AML opcode information for the AML parser and interpreter + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACOPCODE_H__ +#define __ACOPCODE_H__ + +#define MAX_EXTENDED_OPCODE 0x88 +#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1) +#define MAX_INTERNAL_OPCODE +#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1) + +/* Used for non-assigned opcodes */ + +#define _UNK 0x6B + +/* + * Reserved ASCII characters. Do not use any of these for + * internal opcodes, since they are used to differentiate + * name strings from AML opcodes + */ +#define _ASC 0x6C +#define _NAM 0x6C +#define _PFX 0x6D + +/* + * All AML opcodes and the parse-time arguments for each. Used by the AML + * parser Each list is compressed into a 32-bit number and stored in the + * master opcode table (in psopcode.c). + */ +#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA) +#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME) +#define ARGP_ARG0 ARG_NONE +#define ARGP_ARG1 ARG_NONE +#define ARGP_ARG2 ARG_NONE +#define ARGP_ARG3 ARG_NONE +#define ARGP_ARG4 ARG_NONE +#define ARGP_ARG5 ARG_NONE +#define ARGP_ARG6 ARG_NONE +#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_BREAK_OP ARG_NONE +#define ARGP_BREAK_POINT_OP ARG_NONE +#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST) +#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA) +#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME) +#define ARGP_CONTINUE_OP ARG_NONE +#define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) +#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME) +#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_DEBUG_OP ARG_NONE +#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) +#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) +#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST) +#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME) +#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG) +#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST) +#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME) +#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_LOCAL0 ARG_NONE +#define ARGP_LOCAL1 ARG_NONE +#define ARGP_LOCAL2 ARG_NONE +#define ARGP_LOCAL3 ARG_NONE +#define ARGP_LOCAL4 ARG_NONE +#define ARGP_LOCAL5 ARG_NONE +#define ARGP_LOCAL6 ARG_NONE +#define ARGP_LOCAL7 ARG_NONE +#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST) +#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA) +#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ) +#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_NOOP_OP ARG_NONE +#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_ONE_OP ARG_NONE +#define ARGP_ONES_OP ARG_NONE +#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) +#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) +#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) +#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) +#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_REVISION_OP ARG_NONE +#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST) +#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING) +#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME) +#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST) +#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) +#define ARGP_TIMER_OP ARG_NONE +#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) +#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME) +#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST) +#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) +#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST) +#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA) +#define ARGP_ZERO_OP ARG_NONE + +/* + * All AML opcodes and the runtime arguments for each. Used by the AML + * interpreter Each list is compressed into a 32-bit number and stored + * in the master opcode table (in psopcode.c). + * + * (Used by prep_operands procedure and the ASL Compiler) + */ +#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER) +#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE +#define ARGI_ARG0 ARG_NONE +#define ARGI_ARG1 ARG_NONE +#define ARGI_ARG2 ARG_NONE +#define ARGI_ARG3 ARG_NONE +#define ARGI_ARG4 ARG_NONE +#define ARGI_ARG5 ARG_NONE +#define ARGI_ARG6 ARG_NONE +#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_BREAK_OP ARG_NONE +#define ARGI_BREAK_POINT_OP ARG_NONE +#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_BYTE_OP ARGI_INVALID_OPCODE +#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE +#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF) +#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF) +#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF) +#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE +#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET) +#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE) +#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING) +#define ARGI_DEBUG_OP ARG_NONE +#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING) +#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE +#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF) +#define ARGI_DWORD_OP ARGI_INVALID_OPCODE +#define ARGI_ELSE_OP ARGI_INVALID_OPCODE +#define ARGI_EVENT_OP ARGI_INVALID_OPCODE +#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_IF_OP ARGI_INVALID_OPCODE +#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) +#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE +#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA) +#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE +#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF) +#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE) +#define ARGI_LOCAL0 ARG_NONE +#define ARGI_LOCAL1 ARG_NONE +#define ARGI_LOCAL2 ARG_NONE +#define ARGI_LOCAL3 ARG_NONE +#define ARGI_LOCAL4 ARG_NONE +#define ARGI_LOCAL5 ARG_NONE +#define ARGI_LOCAL6 ARG_NONE +#define ARGI_LOCAL7 ARG_NONE +#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER) +#define ARGI_METHOD_OP ARGI_INVALID_OPCODE +#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE +#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE +#define ARGI_NAME_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE +#define ARGI_NOOP_OP ARG_NONE +#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER) +#define ARGI_ONE_OP ARG_NONE +#define ARGI_ONES_OP ARG_NONE +#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE +#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE +#define ARGI_QWORD_OP ARGI_INVALID_OPCODE +#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF) +#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER) +#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX) +#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE +#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_RETURN_OP ARGI_INVALID_OPCODE +#define ARGI_REVISION_OP ARG_NONE +#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE +#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT) +#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT) +#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE +#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF) +#define ARGI_STRING_OP ARGI_INVALID_OPCODE +#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE +#define ARGI_TIMER_OP ARG_NONE +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE) +#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) +#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) +#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) +#define ARGI_WHILE_OP ARGI_INVALID_OPCODE +#define ARGI_WORD_OP ARGI_INVALID_OPCODE +#define ARGI_ZERO_OP ARG_NONE + +#endif /* __ACOPCODE_H__ */ diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h new file mode 100644 index 00000000000..23ee0fbf561 --- /dev/null +++ b/drivers/acpi/acpica/acparser.h @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Module Name: acparser.h - AML Parser subcomponent prototypes and defines + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACPARSER_H__ +#define __ACPARSER_H__ + +#define OP_HAS_RETURN_VALUE 1 + +/* Variable number of arguments. This field must be 32 bits */ + +#define ACPI_VAR_ARGS ACPI_UINT32_MAX + +#define ACPI_PARSE_DELETE_TREE 0x0001 +#define ACPI_PARSE_NO_TREE_DELETE 0x0000 +#define ACPI_PARSE_TREE_MASK 0x0001 + +#define ACPI_PARSE_LOAD_PASS1 0x0010 +#define ACPI_PARSE_LOAD_PASS2 0x0020 +#define ACPI_PARSE_EXECUTE 0x0030 +#define ACPI_PARSE_MODE_MASK 0x0030 + +#define ACPI_PARSE_DEFERRED_OP 0x0100 +#define ACPI_PARSE_DISASSEMBLE 0x0200 + +/****************************************************************************** + * + * Parser interfaces + * + *****************************************************************************/ + +/* + * psxface - Parser external interfaces + */ +acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info); + +/* + * psargs - Parse AML opcode arguments + */ +u8 *acpi_ps_get_next_package_end(struct acpi_parse_state *parser_state); + +char *acpi_ps_get_next_namestring(struct acpi_parse_state *parser_state); + +void +acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, + u32 arg_type, union acpi_parse_object *arg); + +acpi_status +acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, + struct acpi_parse_state *parser_state, + union acpi_parse_object *arg, u8 method_call); + +acpi_status +acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, + struct acpi_parse_state *parser_state, + u32 arg_type, union acpi_parse_object **return_arg); + +/* + * psfind + */ +union acpi_parse_object *acpi_ps_find_name(union acpi_parse_object *scope, + u32 name, u32 opcode); + +union acpi_parse_object *acpi_ps_get_parent(union acpi_parse_object *op); + +/* + * psopcode - AML Opcode information + */ +const struct acpi_opcode_info *acpi_ps_get_opcode_info(u16 opcode); + +char *acpi_ps_get_opcode_name(u16 opcode); + +u8 acpi_ps_get_argument_count(u32 op_type); + +/* + * psparse - top level parsing routines + */ +acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state); + +u32 acpi_ps_get_opcode_size(u32 opcode); + +u16 acpi_ps_peek_opcode(struct acpi_parse_state *state); + +acpi_status +acpi_ps_complete_this_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + +acpi_status +acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + acpi_status callback_status); + +/* + * psloop - main parse loop + */ +acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state); + +/* + * psscope - Scope stack management routines + */ +acpi_status +acpi_ps_init_scope(struct acpi_parse_state *parser_state, + union acpi_parse_object *root); + +union acpi_parse_object *acpi_ps_get_parent_scope(struct acpi_parse_state + *state); + +u8 acpi_ps_has_completed_scope(struct acpi_parse_state *parser_state); + +void +acpi_ps_pop_scope(struct acpi_parse_state *parser_state, + union acpi_parse_object **op, + u32 * arg_list, u32 * arg_count); + +acpi_status +acpi_ps_push_scope(struct acpi_parse_state *parser_state, + union acpi_parse_object *op, + u32 remaining_args, u32 arg_count); + +void acpi_ps_cleanup_scope(struct acpi_parse_state *state); + +/* + * pstree - parse tree manipulation routines + */ +void +acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg); + +union acpi_parse_object *acpi_ps_find(union acpi_parse_object *scope, + char *path, u16 opcode, u32 create); + +union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn); + +#ifdef ACPI_FUTURE_USAGE +union acpi_parse_object *acpi_ps_get_depth_next(union acpi_parse_object *origin, + union acpi_parse_object *op); +#endif /* ACPI_FUTURE_USAGE */ + +/* + * pswalk - parse tree walk routines + */ +acpi_status +acpi_ps_walk_parsed_aml(union acpi_parse_object *start_op, + union acpi_parse_object *end_op, + union acpi_operand_object *mth_desc, + struct acpi_namespace_node *start_node, + union acpi_operand_object **params, + union acpi_operand_object **caller_return_desc, + acpi_owner_id owner_id, + acpi_parse_downwards descending_callback, + acpi_parse_upwards ascending_callback); + +acpi_status +acpi_ps_get_next_walk_op(struct acpi_walk_state *walk_state, + union acpi_parse_object *op, + acpi_parse_upwards ascending_callback); + +acpi_status acpi_ps_delete_completed_op(struct acpi_walk_state *walk_state); + +void acpi_ps_delete_parse_tree(union acpi_parse_object *root); + +/* + * psutils - parser utilities + */ +union acpi_parse_object *acpi_ps_create_scope_op(void); + +void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode); + +union acpi_parse_object *acpi_ps_alloc_op(u16 opcode); + +void acpi_ps_free_op(union acpi_parse_object *op); + +u8 acpi_ps_is_leading_char(u32 c); + +u8 acpi_ps_is_prefix_char(u32 c); + +#ifdef ACPI_FUTURE_USAGE +u32 acpi_ps_get_name(union acpi_parse_object *op); +#endif /* ACPI_FUTURE_USAGE */ + +void acpi_ps_set_name(union acpi_parse_object *op, u32 name); + +/* + * psdump - display parser tree + */ +u32 +acpi_ps_sprint_path(char *buffer_start, + u32 buffer_size, union acpi_parse_object *op); + +u32 +acpi_ps_sprint_op(char *buffer_start, + u32 buffer_size, union acpi_parse_object *op); + +void acpi_ps_show(union acpi_parse_object *op); + +#endif /* __ACPARSER_H__ */ diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h new file mode 100644 index 00000000000..16a9ca9a66e --- /dev/null +++ b/drivers/acpi/acpica/acpredef.h @@ -0,0 +1,371 @@ +/****************************************************************************** + * + * Name: acpredef - Information table for ACPI predefined methods and objects + * $Revision: 1.1 $ + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACPREDEF_H__ +#define __ACPREDEF_H__ + +/****************************************************************************** + * + * Return Package types + * + * 1) PTYPE1 packages do not contain sub-packages. + * + * ACPI_PTYPE1_FIXED: Fixed length, 1 or 2 object types: + * object type + * count + * object type + * count + * + * ACPI_PTYPE1_VAR: Variable length: + * object type (Int/Buf/Ref) + * + * ACPI_PTYPE1_OPTION: Package has some required and some optional elements: + * Used for _PRW + * + * + * 2) PTYPE2 packages contain a variable number of sub-packages. Each of the + * different types describe the contents of each of the sub-packages. + * + * ACPI_PTYPE2: Each subpackage contains 1 or 2 object types: + * object type + * count + * object type + * count + * + * ACPI_PTYPE2_COUNT: Each subpackage has a count as first element: + * object type + * + * ACPI_PTYPE2_PKG_COUNT: Count of subpackages at start, 1 or 2 object types: + * object type + * count + * object type + * count + * + * ACPI_PTYPE2_FIXED: Each subpackage is of fixed length: + * Used for _PRT + * + * ACPI_PTYPE2_MIN: Each subpackage has a variable but minimum length + * Used for _HPX + * + *****************************************************************************/ + +enum acpi_return_package_types { + ACPI_PTYPE1_FIXED = 1, + ACPI_PTYPE1_VAR = 2, + ACPI_PTYPE1_OPTION = 3, + ACPI_PTYPE2 = 4, + ACPI_PTYPE2_COUNT = 5, + ACPI_PTYPE2_PKG_COUNT = 6, + ACPI_PTYPE2_FIXED = 7, + ACPI_PTYPE2_MIN = 8 +}; + +/* + * Predefined method/object information table. + * + * These are the names that can actually be evaluated via acpi_evaluate_object. + * Not present in this table are the following: + * + * 1) Predefined/Reserved names that are never evaluated via acpi_evaluate_object: + * _Lxx and _Exx GPE methods + * _Qxx EC methods + * _T_x compiler temporary variables + * + * 2) Predefined names that never actually exist within the AML code: + * Predefined resource descriptor field names + * + * 3) Predefined names that are implemented within ACPICA: + * _OSI + * + * 4) Some predefined names that are not documented within the ACPI spec. + * _WDG, _WED + * + * The main entries in the table each contain the following items: + * + * Name - The ACPI reserved name + * param_count - Number of arguments to the method + * expected_btypes - Allowed type(s) for the return value. + * 0 means that no return value is expected. + * + * For methods that return packages, the next entry in the table contains + * information about the expected structure of the package. This information + * is saved here (rather than in a separate table) in order to minimize the + * overall size of the stored data. + */ +static const union acpi_predefined_info predefined_names[] = { + {.info = {"_AC0", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC1", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC2", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC3", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC4", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC5", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC6", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC7", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC8", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AC9", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_ADR", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_AL0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL3", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL4", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL5", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL6", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL7", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL8", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_AL9", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_ALC", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_ALI", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_ALP", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_ALR", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* variable (Pkgs) each 2 (Ints) */ + {.info = {"_ALT", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_BBN", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_BCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ + {.info = {"_BCM", 1, 0}}, + {.info = {"_BDN", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_BFS", 1, 0}}, + {.info = {"_BIF", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, + 9, + ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER, 4, 0}}, /* fixed (9 Int),(4 Str) */ + {.info = {"_BLT", 3, 0}}, + {.info = {"_BMC", 1, 0}}, + {.info = {"_BMD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* fixed (5 Int) */ + {.info = {"_BQC", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_BST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ + {.info = {"_BTM", 1, ACPI_RTYPE_INTEGER}}, + {.info = {"_BTP", 1, 0}}, + {.info = {"_CBA", 0, ACPI_RTYPE_INTEGER}}, /* see PCI firmware spec 3.0 */ + {.info = {"_CID", 0, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, + {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0, 0, 0, 0}}, /* variable (Ints/Strs) */ + {.info = {"_CRS", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_CRT", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_CSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (1 Int(n), n-1 Int) */ + {.info = {"_CST", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_PKG_COUNT, + ACPI_RTYPE_BUFFER, 1, + ACPI_RTYPE_INTEGER, 3, 0}}, /* variable (1 Int(n), n Pkg (1 Buf/3 Int) */ + {.info = {"_DCK", 1, ACPI_RTYPE_INTEGER}}, + {.info = {"_DCS", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}}, + {.info = {"_DDN", 0, ACPI_RTYPE_STRING}}, + {.info = {"_DGS", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_DIS", 0, 0}}, + {.info = {"_DMA", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_DOD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ + {.info = {"_DOS", 1, 0}}, + {.info = {"_DSM", 4, ACPI_RTYPE_ALL}}, /* Must return a type, but it can be of any type */ + {.info = {"_DSS", 1, 0}}, + {.info = {"_DSW", 3, 0}}, + {.info = {"_EC_", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_EDL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_EJ0", 1, 0}}, + {.info = {"_EJ1", 1, 0}}, + {.info = {"_EJ2", 1, 0}}, + {.info = {"_EJ3", 1, 0}}, + {.info = {"_EJ4", 1, 0}}, + {.info = {"_EJD", 0, ACPI_RTYPE_STRING}}, + {.info = {"_FDE", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_FDI", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16, 0, 0, 0}}, /* fixed (16 Int) */ + {.info = {"_FDM", 1, 0}}, + {.info = {"_FIX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Ints) */ + {.info = {"_GLK", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_GPD", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ + {.info = {"_GSB", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_GTF", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_GTM", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_GTS", 1, 0}}, + {.info = {"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, + {.info = {"_HOT", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_HPP", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ + + /* + * For _HPX, a single package is returned, containing a variable number of sub-packages. + * Each sub-package contains a PCI record setting. There are several different type of + * record settings, of different lengths, but all elements of all settings are Integers. + */ + {.info = {"_HPX", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each (var Ints) */ + {.info = {"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */ + {.info = {"_INI", 0, 0}}, + {.info = {"_IRC", 0, 0}}, + {.info = {"_LCK", 1, 0}}, + {.info = {"_LID", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_MAT", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_MLS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_STRING, 2, 0, 0, 0}}, /* variable (Pkgs) each (2 Str) */ + {.info = {"_MSG", 1, 0}}, + {.info = {"_OFF", 0, 0}}, + {.info = {"_ON_", 0, 0}}, + {.info = {"_OS_", 0, ACPI_RTYPE_STRING}}, + {.info = {"_OSC", 4, ACPI_RTYPE_BUFFER}}, + {.info = {"_OST", 3, 0}}, + {.info = {"_PCL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_PCT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */ + {.info = {"_PDC", 1, 0}}, + {.info = {"_PIC", 1, 0}}, + {.info = {"_PLD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_BUFFER, 0, 0, 0, 0}}, /* variable (Bufs) */ + {.info = {"_PPC", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_PPE", 0, ACPI_RTYPE_INTEGER}}, /* see dig64 spec */ + {.info = {"_PR0", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_PR1", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_PR2", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_PRS", 0, ACPI_RTYPE_BUFFER}}, + + /* + * For _PRT, many BIOSs reverse the 2nd and 3rd Package elements. This bug is so prevalent that there + * is code in the ACPICA Resource Manager to detect this and switch them back. For now, do not allow + * and issue a warning. To allow this and eliminate the warning, add the ACPI_RTYPE_REFERENCE + * type to the 2nd element (index 1) in the statement below. + */ + {.info = {"_PRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_FIXED, 4, + ACPI_RTYPE_INTEGER, + ACPI_RTYPE_INTEGER, + ACPI_RTYPE_INTEGER | ACPI_RTYPE_REFERENCE, ACPI_RTYPE_INTEGER}}, /* variable (Pkgs) each (4): Int,Int,Int/Ref,Int */ + + {.info = {"_PRW", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_OPTION, 2, + ACPI_RTYPE_INTEGER | + ACPI_RTYPE_PACKAGE, + ACPI_RTYPE_INTEGER, ACPI_RTYPE_REFERENCE, 0}}, /* variable (Pkgs) each: Pkg/Int,Int,[variable Refs] (Pkg is Ref/Int) */ + + {.info = {"_PS0", 0, 0}}, + {.info = {"_PS1", 0, 0}}, + {.info = {"_PS2", 0, 0}}, + {.info = {"_PS3", 0, 0}}, + {.info = {"_PSC", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_PSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 0, 0, 0, 0}}, /* variable (Pkgs) each (5 Int) with count */ + {.info = {"_PSL", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_PSR", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_PSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 6, 0, 0, 0}}, /* variable (Pkgs) each (6 Int) */ + {.info = {"_PSV", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_PSW", 1, 0}}, + {.info = {"_PTC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_BUFFER, 2, 0, 0, 0}}, /* fixed (2 Buf) */ + {.info = {"_PTS", 1, 0}}, + {.info = {"_PXM", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_REG", 2, 0}}, + {.info = {"_REV", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_RMV", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_ROM", 2, ACPI_RTYPE_BUFFER}}, + {.info = {"_RTV", 0, ACPI_RTYPE_INTEGER}}, + + /* + * For _S0_ through _S5_, the ACPI spec defines a return Package containing 1 Integer, + * but most DSDTs have it wrong - 2,3, or 4 integers. Allow this by making the objects "variable length", + * but all elements must be Integers. + */ + {.info = {"_S0_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + {.info = {"_S1_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + {.info = {"_S2_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + {.info = {"_S3_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + {.info = {"_S4_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + {.info = {"_S5_", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 1, 0, 0, 0}}, /* fixed (1 Int) */ + + {.info = {"_S1D", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S2D", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S3D", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S4D", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S0W", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S1W", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S2W", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S3W", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_S4W", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_SBS", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_SCP", 0x13, 0}}, /* Acpi 1.0 allowed 1 arg. Acpi 3.0 expanded to 3 args. Allow both. */ + /* Note: the 3-arg definition may be removed for ACPI 4.0 */ + {.info = {"_SDD", 1, 0}}, + {.info = {"_SEG", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_SLI", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_SPD", 1, ACPI_RTYPE_INTEGER}}, + {.info = {"_SRS", 1, 0}}, + {.info = {"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* see IPMI spec */ + {.info = {"_SST", 1, 0}}, + {.info = {"_STA", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_STM", 3, 0}}, + {.info = {"_STR", 0, ACPI_RTYPE_BUFFER}}, + {.info = {"_SUN", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_SWS", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TC1", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TC2", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TMP", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TPC", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TPT", 1, 0}}, + {.info = {"_TRT", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_REFERENCE, 2, + ACPI_RTYPE_INTEGER, 6, 0}}, /* variable (Pkgs) each 2_ref/6_int */ + {.info = {"_TSD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int with count */ + {.info = {"_TSP", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TSS", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE2, ACPI_RTYPE_INTEGER, 5, 0, 0, 0}}, /* variable (Pkgs) each 5_int */ + {.info = {"_TST", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_TTS", 1, 0}}, + {.info = {"_TZD", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0}}, /* variable (Refs) */ + {.info = {"_TZM", 0, ACPI_RTYPE_REFERENCE}}, + {.info = {"_TZP", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_UID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, + {.info = {"_UPC", 0, ACPI_RTYPE_PACKAGE}}, {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0}}, /* fixed (4 Int) */ + {.info = {"_UPD", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_UPP", 0, ACPI_RTYPE_INTEGER}}, + {.info = {"_VPO", 0, ACPI_RTYPE_INTEGER}}, + + /* Acpi 1.0 defined _WAK with no return value. Later, it was changed to return a package */ + + {.info = {"_WAK", 1, ACPI_RTYPE_NONE | ACPI_RTYPE_INTEGER | ACPI_RTYPE_PACKAGE}}, + {.ret_info = {ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0}}, /* fixed (2 Int), but is optional */ + {.ret_info = {0, 0, 0, 0, 0, 0}} /* Table terminator */ +}; + +#if 0 + /* Not implemented */ + +{ +"_WDG", 0, ACPI_RTYPE_BUFFER}, /* MS Extension */ + +{ +"_WED", 1, ACPI_RTYPE_PACKAGE}, /* MS Extension */ + + /* This is an internally implemented control method, no need to check */ +{ +"_OSI", 1, ACPI_RTYPE_INTEGER}, + + /* TBD: */ + _PRT - currently ignore reversed entries.attempt to fix here ? + think about code that attempts to fix package elements like _BIF, etc. +#endif +#endif diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h new file mode 100644 index 00000000000..eef5bd7a59f --- /dev/null +++ b/drivers/acpi/acpica/acresrc.h @@ -0,0 +1,336 @@ +/****************************************************************************** + * + * Name: acresrc.h - Resource Manager function prototypes + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACRESRC_H__ +#define __ACRESRC_H__ + +/* Need the AML resource descriptor structs */ + +#include "amlresrc.h" + +/* + * If possible, pack the following structures to byte alignment, since we + * don't care about performance for debug output. Two cases where we cannot + * pack the structures: + * + * 1) Hardware does not support misaligned memory transfers + * 2) Compiler does not support pointers within packed structures + */ +#if (!defined(ACPI_MISALIGNMENT_NOT_SUPPORTED) && !defined(ACPI_PACKED_POINTERS_NOT_SUPPORTED)) +#pragma pack(1) +#endif + +/* + * Individual entry for the resource conversion tables + */ +typedef const struct acpi_rsconvert_info { + u8 opcode; + u8 resource_offset; + u8 aml_offset; + u8 value; + +} acpi_rsconvert_info; + +/* Resource conversion opcodes */ + +#define ACPI_RSC_INITGET 0 +#define ACPI_RSC_INITSET 1 +#define ACPI_RSC_FLAGINIT 2 +#define ACPI_RSC_1BITFLAG 3 +#define ACPI_RSC_2BITFLAG 4 +#define ACPI_RSC_COUNT 5 +#define ACPI_RSC_COUNT16 6 +#define ACPI_RSC_LENGTH 7 +#define ACPI_RSC_MOVE8 8 +#define ACPI_RSC_MOVE16 9 +#define ACPI_RSC_MOVE32 10 +#define ACPI_RSC_MOVE64 11 +#define ACPI_RSC_SET8 12 +#define ACPI_RSC_DATA8 13 +#define ACPI_RSC_ADDRESS 14 +#define ACPI_RSC_SOURCE 15 +#define ACPI_RSC_SOURCEX 16 +#define ACPI_RSC_BITMASK 17 +#define ACPI_RSC_BITMASK16 18 +#define ACPI_RSC_EXIT_NE 19 +#define ACPI_RSC_EXIT_LE 20 +#define ACPI_RSC_EXIT_EQ 21 + +/* Resource Conversion sub-opcodes */ + +#define ACPI_RSC_COMPARE_AML_LENGTH 0 +#define ACPI_RSC_COMPARE_VALUE 1 + +#define ACPI_RSC_TABLE_SIZE(d) (sizeof (d) / sizeof (struct acpi_rsconvert_info)) + +#define ACPI_RS_OFFSET(f) (u8) ACPI_OFFSET (struct acpi_resource,f) +#define AML_OFFSET(f) (u8) ACPI_OFFSET (union aml_resource,f) + +typedef const struct acpi_rsdump_info { + u8 opcode; + u8 offset; + char *name; + const char **pointer; + +} acpi_rsdump_info; + +/* Values for the Opcode field above */ + +#define ACPI_RSD_TITLE 0 +#define ACPI_RSD_LITERAL 1 +#define ACPI_RSD_STRING 2 +#define ACPI_RSD_UINT8 3 +#define ACPI_RSD_UINT16 4 +#define ACPI_RSD_UINT32 5 +#define ACPI_RSD_UINT64 6 +#define ACPI_RSD_1BITFLAG 7 +#define ACPI_RSD_2BITFLAG 8 +#define ACPI_RSD_SHORTLIST 9 +#define ACPI_RSD_LONGLIST 10 +#define ACPI_RSD_DWORDLIST 11 +#define ACPI_RSD_ADDRESS 12 +#define ACPI_RSD_SOURCE 13 + +/* restore default alignment */ + +#pragma pack() + +/* Resource tables indexed by internal resource type */ + +extern const u8 acpi_gbl_aml_resource_sizes[]; +extern struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[]; + +/* Resource tables indexed by raw AML resource descriptor type */ + +extern const u8 acpi_gbl_resource_struct_sizes[]; +extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[]; + +struct acpi_vendor_walk_info { + struct acpi_vendor_uuid *uuid; + struct acpi_buffer *buffer; + acpi_status status; +}; + +/* + * rscreate + */ +acpi_status +acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, + struct acpi_buffer *output_buffer); + +acpi_status +acpi_rs_create_aml_resources(struct acpi_resource *linked_list_buffer, + struct acpi_buffer *output_buffer); + +acpi_status +acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, + struct acpi_buffer *output_buffer); + +/* + * rsutils + */ + +acpi_status +acpi_rs_get_prt_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + +acpi_status +acpi_rs_get_crs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + +acpi_status +acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + +acpi_status +acpi_rs_get_method_data(acpi_handle handle, + char *path, struct acpi_buffer *ret_buffer); + +acpi_status +acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + +/* + * rscalc + */ +acpi_status +acpi_rs_get_list_length(u8 * aml_buffer, + u32 aml_buffer_length, acpi_size * size_needed); + +acpi_status +acpi_rs_get_aml_length(struct acpi_resource *linked_list_buffer, + acpi_size * size_needed); + +acpi_status +acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, + acpi_size * buffer_size_needed); + +acpi_status +acpi_rs_convert_aml_to_resources(u8 * aml, + u32 length, + u32 offset, u8 resource_index, void **context); + +acpi_status +acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, + acpi_size aml_size_needed, u8 * output_buffer); + +/* + * rsaddr + */ +void +acpi_rs_set_address_common(union aml_resource *aml, + struct acpi_resource *resource); + +u8 +acpi_rs_get_address_common(struct acpi_resource *resource, + union aml_resource *aml); + +/* + * rsmisc + */ +acpi_status +acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, + union aml_resource *aml, + struct acpi_rsconvert_info *info); + +acpi_status +acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, + union aml_resource *aml, + struct acpi_rsconvert_info *info); + +/* + * rsutils + */ +void +acpi_rs_move_data(void *destination, + void *source, u16 item_count, u8 move_type); + +u8 acpi_rs_decode_bitmask(u16 mask, u8 * list); + +u16 acpi_rs_encode_bitmask(u8 * list, u8 count); + +acpi_rs_length +acpi_rs_get_resource_source(acpi_rs_length resource_length, + acpi_rs_length minimum_length, + struct acpi_resource_source *resource_source, + union aml_resource *aml, char *string_ptr); + +acpi_rsdesc_size +acpi_rs_set_resource_source(union aml_resource *aml, + acpi_rs_length minimum_length, + struct acpi_resource_source *resource_source); + +void +acpi_rs_set_resource_header(u8 descriptor_type, + acpi_rsdesc_size total_length, + union aml_resource *aml); + +void +acpi_rs_set_resource_length(acpi_rsdesc_size total_length, + union aml_resource *aml); + +/* + * rsdump + */ +void acpi_rs_dump_resource_list(struct acpi_resource *resource); + +void acpi_rs_dump_irq_list(u8 * route_table); + +/* + * Resource conversion tables + */ +extern struct acpi_rsconvert_info acpi_rs_convert_dma[]; +extern struct acpi_rsconvert_info acpi_rs_convert_end_dpf[]; +extern struct acpi_rsconvert_info acpi_rs_convert_io[]; +extern struct acpi_rsconvert_info acpi_rs_convert_fixed_io[]; +extern struct acpi_rsconvert_info acpi_rs_convert_end_tag[]; +extern struct acpi_rsconvert_info acpi_rs_convert_memory24[]; +extern struct acpi_rsconvert_info acpi_rs_convert_generic_reg[]; +extern struct acpi_rsconvert_info acpi_rs_convert_memory32[]; +extern struct acpi_rsconvert_info acpi_rs_convert_fixed_memory32[]; +extern struct acpi_rsconvert_info acpi_rs_convert_address32[]; +extern struct acpi_rsconvert_info acpi_rs_convert_address16[]; +extern struct acpi_rsconvert_info acpi_rs_convert_ext_irq[]; +extern struct acpi_rsconvert_info acpi_rs_convert_address64[]; +extern struct acpi_rsconvert_info acpi_rs_convert_ext_address64[]; + +/* These resources require separate get/set tables */ + +extern struct acpi_rsconvert_info acpi_rs_get_irq[]; +extern struct acpi_rsconvert_info acpi_rs_get_start_dpf[]; +extern struct acpi_rsconvert_info acpi_rs_get_vendor_small[]; +extern struct acpi_rsconvert_info acpi_rs_get_vendor_large[]; + +extern struct acpi_rsconvert_info acpi_rs_set_irq[]; +extern struct acpi_rsconvert_info acpi_rs_set_start_dpf[]; +extern struct acpi_rsconvert_info acpi_rs_set_vendor[]; + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* + * rsinfo + */ +extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[]; + +/* + * rsdump + */ +extern struct acpi_rsdump_info acpi_rs_dump_irq[]; +extern struct acpi_rsdump_info acpi_rs_dump_dma[]; +extern struct acpi_rsdump_info acpi_rs_dump_start_dpf[]; +extern struct acpi_rsdump_info acpi_rs_dump_end_dpf[]; +extern struct acpi_rsdump_info acpi_rs_dump_io[]; +extern struct acpi_rsdump_info acpi_rs_dump_fixed_io[]; +extern struct acpi_rsdump_info acpi_rs_dump_vendor[]; +extern struct acpi_rsdump_info acpi_rs_dump_end_tag[]; +extern struct acpi_rsdump_info acpi_rs_dump_memory24[]; +extern struct acpi_rsdump_info acpi_rs_dump_memory32[]; +extern struct acpi_rsdump_info acpi_rs_dump_fixed_memory32[]; +extern struct acpi_rsdump_info acpi_rs_dump_address16[]; +extern struct acpi_rsdump_info acpi_rs_dump_address32[]; +extern struct acpi_rsdump_info acpi_rs_dump_address64[]; +extern struct acpi_rsdump_info acpi_rs_dump_ext_address64[]; +extern struct acpi_rsdump_info acpi_rs_dump_ext_irq[]; +extern struct acpi_rsdump_info acpi_rs_dump_generic_reg[]; +#endif + +#endif /* __ACRESRC_H__ */ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h new file mode 100644 index 00000000000..7980a26bad3 --- /dev/null +++ b/drivers/acpi/acpica/acstruct.h @@ -0,0 +1,228 @@ +/****************************************************************************** + * + * Name: acstruct.h - Internal structs + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACSTRUCT_H__ +#define __ACSTRUCT_H__ + +/* acpisrc:struct_defs -- for acpisrc conversion */ + +/***************************************************************************** + * + * Tree walking typedefs and structs + * + ****************************************************************************/ + +/* + * Walk state - current state of a parse tree walk. Used for both a leisurely + * stroll through the tree (for whatever reason), and for control method + * execution. + */ +#define ACPI_NEXT_OP_DOWNWARD 1 +#define ACPI_NEXT_OP_UPWARD 2 + +/* + * Groups of definitions for walk_type used for different implementations of + * walkers (never simultaneously) - flags for interpreter: + */ +#define ACPI_WALK_NON_METHOD 0 +#define ACPI_WALK_METHOD 0x01 +#define ACPI_WALK_METHOD_RESTART 0x02 + +/* Flags for i_aSL compiler only */ + +#define ACPI_WALK_CONST_REQUIRED 0x10 +#define ACPI_WALK_CONST_OPTIONAL 0x20 + +struct acpi_walk_state { + struct acpi_walk_state *next; /* Next walk_state in list */ + u8 descriptor_type; /* To differentiate various internal objs */ + u8 walk_type; + u16 opcode; /* Current AML opcode */ + u8 next_op_info; /* Info about next_op */ + u8 num_operands; /* Stack pointer for Operands[] array */ + u8 operand_index; /* Index into operand stack, to be used by acpi_ds_obj_stack_push */ + acpi_owner_id owner_id; /* Owner of objects created during the walk */ + u8 last_predicate; /* Result of last predicate */ + u8 current_result; + u8 return_used; + u8 scope_depth; + u8 pass_number; /* Parse pass during table load */ + u8 result_size; /* Total elements for the result stack */ + u8 result_count; /* Current number of occupied elements of result stack */ + u32 aml_offset; + u32 arg_types; + u32 method_breakpoint; /* For single stepping */ + u32 user_breakpoint; /* User AML breakpoint */ + u32 parse_flags; + + struct acpi_parse_state parser_state; /* Current state of parser */ + u32 prev_arg_types; + u32 arg_count; /* push for fixed or var args */ + + struct acpi_namespace_node arguments[ACPI_METHOD_NUM_ARGS]; /* Control method arguments */ + struct acpi_namespace_node local_variables[ACPI_METHOD_NUM_LOCALS]; /* Control method locals */ + union acpi_operand_object *operands[ACPI_OBJ_NUM_OPERANDS + 1]; /* Operands passed to the interpreter (+1 for NULL terminator) */ + union acpi_operand_object **params; + + u8 *aml_last_while; + union acpi_operand_object **caller_return_desc; + union acpi_generic_state *control_state; /* List of control states (nested IFs) */ + struct acpi_namespace_node *deferred_node; /* Used when executing deferred opcodes */ + union acpi_operand_object *implicit_return_obj; + struct acpi_namespace_node *method_call_node; /* Called method Node */ + union acpi_parse_object *method_call_op; /* method_call Op if running a method */ + union acpi_operand_object *method_desc; /* Method descriptor if running a method */ + struct acpi_namespace_node *method_node; /* Method node if running a method. */ + union acpi_parse_object *op; /* Current parser op */ + const struct acpi_opcode_info *op_info; /* Info on current opcode */ + union acpi_parse_object *origin; /* Start of walk [Obsolete] */ + union acpi_operand_object *result_obj; + union acpi_generic_state *results; /* Stack of accumulated results */ + union acpi_operand_object *return_desc; /* Return object, if any */ + union acpi_generic_state *scope_info; /* Stack of nested scopes */ + union acpi_parse_object *prev_op; /* Last op that was processed */ + union acpi_parse_object *next_op; /* next op to be processed */ + struct acpi_thread_state *thread; + acpi_parse_downwards descending_callback; + acpi_parse_upwards ascending_callback; +}; + +/* Info used by acpi_ps_init_objects */ + +struct acpi_init_walk_info { + u16 method_count; + u16 device_count; + u16 op_region_count; + u16 field_count; + u16 buffer_count; + u16 package_count; + u16 op_region_init; + u16 field_init; + u16 buffer_init; + u16 package_init; + u16 object_count; + acpi_owner_id owner_id; + u32 table_index; +}; + +struct acpi_get_devices_info { + acpi_walk_callback user_function; + void *context; + const char *hid; +}; + +union acpi_aml_operands { + union acpi_operand_object *operands[7]; + + struct { + struct acpi_object_integer *type; + struct acpi_object_integer *code; + struct acpi_object_integer *argument; + + } fatal; + + struct { + union acpi_operand_object *source; + struct acpi_object_integer *index; + union acpi_operand_object *target; + + } index; + + struct { + union acpi_operand_object *source; + struct acpi_object_integer *index; + struct acpi_object_integer *length; + union acpi_operand_object *target; + + } mid; +}; + +/* + * Structure used to pass object evaluation parameters. + * Purpose is to reduce CPU stack use. + */ +struct acpi_evaluate_info { + struct acpi_namespace_node *prefix_node; + char *pathname; + union acpi_operand_object *obj_desc; + union acpi_operand_object **parameters; + struct acpi_namespace_node *resolved_node; + union acpi_operand_object *return_object; + u8 param_count; + u8 pass_number; + u8 return_object_type; + u8 flags; +}; + +/* Values for Flags above */ + +#define ACPI_IGNORE_RETURN_VALUE 1 + +/* Info used by acpi_ns_initialize_devices */ + +struct acpi_device_walk_info { + u16 device_count; + u16 num_STA; + u16 num_INI; + struct acpi_table_desc *table_desc; + struct acpi_evaluate_info *evaluate_info; +}; + +/* TBD: [Restructure] Merge with struct above */ + +struct acpi_walk_info { + u32 debug_level; + u32 count; + acpi_owner_id owner_id; + u8 display_type; +}; + +/* Display Types */ + +#define ACPI_DISPLAY_SUMMARY (u8) 0 +#define ACPI_DISPLAY_OBJECTS (u8) 1 +#define ACPI_DISPLAY_MASK (u8) 1 + +#define ACPI_DISPLAY_SHORT (u8) 2 + +#endif diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h new file mode 100644 index 00000000000..7ce6e33c7f7 --- /dev/null +++ b/drivers/acpi/acpica/actables.h @@ -0,0 +1,117 @@ +/****************************************************************************** + * + * Name: actables.h - ACPI table management + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __ACTABLES_H__ +#define __ACTABLES_H__ + +acpi_status acpi_allocate_root_table(u32 initial_table_count); + +/* + * tbfadt - FADT parse/convert/validate + */ +void acpi_tb_parse_fadt(u32 table_index, u8 flags); + +void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length); + +/* + * tbfind - find ACPI table + */ +acpi_status +acpi_tb_find_table(char *signature, + char *oem_id, char *oem_table_id, u32 *table_index); + +/* + * tbinstal - Table removal and deletion + */ +acpi_status acpi_tb_resize_root_table_list(void); + +acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc); + +acpi_status +acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index); + +acpi_status +acpi_tb_store_table(acpi_physical_address address, + struct acpi_table_header *table, + u32 length, u8 flags, u32 *table_index); + +void acpi_tb_delete_table(struct acpi_table_desc *table_desc); + +void acpi_tb_terminate(void); + +void acpi_tb_delete_namespace_by_owner(u32 table_index); + +acpi_status acpi_tb_allocate_owner_id(u32 table_index); + +acpi_status acpi_tb_release_owner_id(u32 table_index); + +acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id); + +u8 acpi_tb_is_table_loaded(u32 table_index); + +void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded); + +/* + * tbutils - table manager utilities + */ +acpi_status acpi_tb_initialize_facs(void); + +u8 acpi_tb_tables_loaded(void); + +void +acpi_tb_print_table_header(acpi_physical_address address, + struct acpi_table_header *header); + +u8 acpi_tb_checksum(u8 *buffer, u32 length); + +acpi_status +acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length); + +void +acpi_tb_install_table(acpi_physical_address address, + u8 flags, char *signature, u32 table_index); + +acpi_status +acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags); + +#endif /* __ACTABLES_H__ */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h new file mode 100644 index 00000000000..80d8813484f --- /dev/null +++ b/drivers/acpi/acpica/acutils.h @@ -0,0 +1,549 @@ +/****************************************************************************** + * + * Name: acutils.h -- prototypes for the common (subsystem-wide) procedures + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef _ACUTILS_H +#define _ACUTILS_H + +extern const u8 acpi_gbl_resource_aml_sizes[]; + +/* Strings used by the disassembler and debugger resource dump routines */ + +#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUGGER) + +extern const char *acpi_gbl_bm_decode[]; +extern const char *acpi_gbl_config_decode[]; +extern const char *acpi_gbl_consume_decode[]; +extern const char *acpi_gbl_dec_decode[]; +extern const char *acpi_gbl_he_decode[]; +extern const char *acpi_gbl_io_decode[]; +extern const char *acpi_gbl_ll_decode[]; +extern const char *acpi_gbl_max_decode[]; +extern const char *acpi_gbl_mem_decode[]; +extern const char *acpi_gbl_min_decode[]; +extern const char *acpi_gbl_mtp_decode[]; +extern const char *acpi_gbl_rng_decode[]; +extern const char *acpi_gbl_rw_decode[]; +extern const char *acpi_gbl_shr_decode[]; +extern const char *acpi_gbl_siz_decode[]; +extern const char *acpi_gbl_trs_decode[]; +extern const char *acpi_gbl_ttp_decode[]; +extern const char *acpi_gbl_typ_decode[]; +#endif + +/* Types for Resource descriptor entries */ + +#define ACPI_INVALID_RESOURCE 0 +#define ACPI_FIXED_LENGTH 1 +#define ACPI_VARIABLE_LENGTH 2 +#define ACPI_SMALL_VARIABLE_LENGTH 3 + +typedef +acpi_status(*acpi_walk_aml_callback) (u8 * aml, + u32 length, + u32 offset, + u8 resource_index, void **context); + +typedef +acpi_status(*acpi_pkg_callback) (u8 object_type, + union acpi_operand_object * source_object, + union acpi_generic_state * state, + void *context); + +struct acpi_pkg_info { + u8 *free_space; + acpi_size length; + u32 object_space; + u32 num_packages; +}; + +#define REF_INCREMENT (u16) 0 +#define REF_DECREMENT (u16) 1 +#define REF_FORCE_DELETE (u16) 2 + +/* acpi_ut_dump_buffer */ + +#define DB_BYTE_DISPLAY 1 +#define DB_WORD_DISPLAY 2 +#define DB_DWORD_DISPLAY 4 +#define DB_QWORD_DISPLAY 8 + +/* + * utglobal - Global data structures and procedures + */ +acpi_status acpi_ut_init_globals(void); + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) + +char *acpi_ut_get_mutex_name(u32 mutex_id); + +const char *acpi_ut_get_notify_name(u32 notify_value); + +#endif + +char *acpi_ut_get_type_name(acpi_object_type type); + +char *acpi_ut_get_node_name(void *object); + +char *acpi_ut_get_descriptor_name(void *object); + +const char *acpi_ut_get_reference_name(union acpi_operand_object *object); + +char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc); + +char *acpi_ut_get_region_name(u8 space_id); + +char *acpi_ut_get_event_name(u32 event_id); + +char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position); + +u8 acpi_ut_valid_object_type(acpi_object_type type); + +/* + * utinit - miscellaneous initialization and shutdown + */ +acpi_status acpi_ut_hardware_initialize(void); + +void acpi_ut_subsystem_shutdown(void); + +/* + * utclib - Local implementations of C library functions + */ +#ifndef ACPI_USE_SYSTEM_CLIBRARY + +acpi_size acpi_ut_strlen(const char *string); + +char *acpi_ut_strcpy(char *dst_string, const char *src_string); + +char *acpi_ut_strncpy(char *dst_string, + const char *src_string, acpi_size count); + +int acpi_ut_memcmp(const char *buffer1, const char *buffer2, acpi_size count); + +int acpi_ut_strncmp(const char *string1, const char *string2, acpi_size count); + +int acpi_ut_strcmp(const char *string1, const char *string2); + +char *acpi_ut_strcat(char *dst_string, const char *src_string); + +char *acpi_ut_strncat(char *dst_string, + const char *src_string, acpi_size count); + +u32 acpi_ut_strtoul(const char *string, char **terminator, u32 base); + +char *acpi_ut_strstr(char *string1, char *string2); + +void *acpi_ut_memcpy(void *dest, const void *src, acpi_size count); + +void *acpi_ut_memset(void *dest, u8 value, acpi_size count); + +int acpi_ut_to_upper(int c); + +int acpi_ut_to_lower(int c); + +extern const u8 _acpi_ctype[]; + +#define _ACPI_XA 0x00 /* extra alphabetic - not supported */ +#define _ACPI_XS 0x40 /* extra space */ +#define _ACPI_BB 0x00 /* BEL, BS, etc. - not supported */ +#define _ACPI_CN 0x20 /* CR, FF, HT, NL, VT */ +#define _ACPI_DI 0x04 /* '0'-'9' */ +#define _ACPI_LO 0x02 /* 'a'-'z' */ +#define _ACPI_PU 0x10 /* punctuation */ +#define _ACPI_SP 0x08 /* space */ +#define _ACPI_UP 0x01 /* 'A'-'Z' */ +#define _ACPI_XD 0x80 /* '0'-'9', 'A'-'F', 'a'-'f' */ + +#define ACPI_IS_DIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_DI)) +#define ACPI_IS_SPACE(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_SP)) +#define ACPI_IS_XDIGIT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_XD)) +#define ACPI_IS_UPPER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_UP)) +#define ACPI_IS_LOWER(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO)) +#define ACPI_IS_PRINT(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP | _ACPI_DI | _ACPI_SP | _ACPI_PU)) +#define ACPI_IS_ALPHA(c) (_acpi_ctype[(unsigned char)(c)] & (_ACPI_LO | _ACPI_UP)) + +#endif /* ACPI_USE_SYSTEM_CLIBRARY */ + +/* + * utcopy - Object construction and conversion interfaces + */ +acpi_status +acpi_ut_build_simple_object(union acpi_operand_object *obj, + union acpi_object *user_obj, + u8 * data_space, u32 * buffer_space_used); + +acpi_status +acpi_ut_build_package_object(union acpi_operand_object *obj, + u8 * buffer, u32 * space_used); + +acpi_status +acpi_ut_copy_iobject_to_eobject(union acpi_operand_object *obj, + struct acpi_buffer *ret_buffer); + +acpi_status +acpi_ut_copy_eobject_to_iobject(union acpi_object *obj, + union acpi_operand_object **internal_obj); + +acpi_status +acpi_ut_copy_isimple_to_isimple(union acpi_operand_object *source_obj, + union acpi_operand_object *dest_obj); + +acpi_status +acpi_ut_copy_iobject_to_iobject(union acpi_operand_object *source_desc, + union acpi_operand_object **dest_desc, + struct acpi_walk_state *walk_state); + +/* + * utcreate - Object creation + */ +acpi_status +acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action); + +/* + * utdebug - Debug interfaces + */ +void acpi_ut_init_stack_ptr_trace(void); + +void acpi_ut_track_stack_ptr(void); + +void +acpi_ut_trace(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id); + +void +acpi_ut_trace_ptr(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id, void *pointer); + +void +acpi_ut_trace_u32(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id, u32 integer); + +void +acpi_ut_trace_str(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id, char *string); + +void +acpi_ut_exit(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id); + +void +acpi_ut_status_exit(u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, acpi_status status); + +void +acpi_ut_value_exit(u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, acpi_integer value); + +void +acpi_ut_ptr_exit(u32 line_number, + const char *function_name, + const char *module_name, u32 component_id, u8 *ptr); + +void acpi_ut_dump_buffer(u8 * buffer, u32 count, u32 display, u32 component_id); + +void acpi_ut_dump_buffer2(u8 * buffer, u32 count, u32 display); + +void acpi_ut_report_error(char *module_name, u32 line_number); + +void acpi_ut_report_info(char *module_name, u32 line_number); + +void acpi_ut_report_warning(char *module_name, u32 line_number); + +/* + * utdelete - Object deletion and reference counts + */ +void acpi_ut_add_reference(union acpi_operand_object *object); + +void acpi_ut_remove_reference(union acpi_operand_object *object); + +void acpi_ut_delete_internal_package_object(union acpi_operand_object *object); + +void acpi_ut_delete_internal_simple_object(union acpi_operand_object *object); + +void acpi_ut_delete_internal_object_list(union acpi_operand_object **obj_list); + +/* + * uteval - object evaluation + */ +acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state); + +acpi_status +acpi_ut_evaluate_object(struct acpi_namespace_node *prefix_node, + char *path, + u32 expected_return_btypes, + union acpi_operand_object **return_desc); + +acpi_status +acpi_ut_evaluate_numeric_object(char *object_name, + struct acpi_namespace_node *device_node, + acpi_integer * address); + +acpi_status +acpi_ut_execute_HID(struct acpi_namespace_node *device_node, + struct acpica_device_id *hid); + +acpi_status +acpi_ut_execute_CID(struct acpi_namespace_node *device_node, + struct acpi_compatible_id_list **return_cid_list); + +acpi_status +acpi_ut_execute_STA(struct acpi_namespace_node *device_node, + u32 * status_flags); + +acpi_status +acpi_ut_execute_UID(struct acpi_namespace_node *device_node, + struct acpica_device_id *uid); + +acpi_status +acpi_ut_execute_sxds(struct acpi_namespace_node *device_node, u8 * highest); + +/* + * utobject - internal object create/delete/cache routines + */ +union acpi_operand_object *acpi_ut_create_internal_object_dbg(const char + *module_name, + u32 line_number, + u32 component_id, + acpi_object_type + type); + +void *acpi_ut_allocate_object_desc_dbg(const char *module_name, + u32 line_number, u32 component_id); + +#define acpi_ut_create_internal_object(t) acpi_ut_create_internal_object_dbg (_acpi_module_name,__LINE__,_COMPONENT,t) +#define acpi_ut_allocate_object_desc() acpi_ut_allocate_object_desc_dbg (_acpi_module_name,__LINE__,_COMPONENT) + +void acpi_ut_delete_object_desc(union acpi_operand_object *object); + +u8 acpi_ut_valid_internal_object(void *object); + +union acpi_operand_object *acpi_ut_create_package_object(u32 count); + +union acpi_operand_object *acpi_ut_create_buffer_object(acpi_size buffer_size); + +union acpi_operand_object *acpi_ut_create_string_object(acpi_size string_size); + +acpi_status +acpi_ut_get_object_size(union acpi_operand_object *obj, acpi_size * obj_length); + +/* + * utstate - Generic state creation/cache routines + */ +void +acpi_ut_push_generic_state(union acpi_generic_state **list_head, + union acpi_generic_state *state); + +union acpi_generic_state *acpi_ut_pop_generic_state(union acpi_generic_state + **list_head); + +union acpi_generic_state *acpi_ut_create_generic_state(void); + +struct acpi_thread_state *acpi_ut_create_thread_state(void); + +union acpi_generic_state *acpi_ut_create_update_state(union acpi_operand_object + *object, u16 action); + +union acpi_generic_state *acpi_ut_create_pkg_state(void *internal_object, + void *external_object, + u16 index); + +acpi_status +acpi_ut_create_update_state_and_push(union acpi_operand_object *object, + u16 action, + union acpi_generic_state **state_list); + +#ifdef ACPI_FUTURE_USAGE +acpi_status +acpi_ut_create_pkg_state_and_push(void *internal_object, + void *external_object, + u16 index, + union acpi_generic_state **state_list); +#endif /* ACPI_FUTURE_USAGE */ + +union acpi_generic_state *acpi_ut_create_control_state(void); + +void acpi_ut_delete_generic_state(union acpi_generic_state *state); + +/* + * utmath + */ +acpi_status +acpi_ut_divide(acpi_integer in_dividend, + acpi_integer in_divisor, + acpi_integer * out_quotient, acpi_integer * out_remainder); + +acpi_status +acpi_ut_short_divide(acpi_integer in_dividend, + u32 divisor, + acpi_integer * out_quotient, u32 * out_remainder); + +/* + * utmisc + */ +const char *acpi_ut_validate_exception(acpi_status status); + +u8 acpi_ut_is_aml_table(struct acpi_table_header *table); + +acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id); + +void acpi_ut_release_owner_id(acpi_owner_id * owner_id); + +acpi_status +acpi_ut_walk_package_tree(union acpi_operand_object *source_object, + void *target_object, + acpi_pkg_callback walk_callback, void *context); + +void acpi_ut_strupr(char *src_string); + +void acpi_ut_print_string(char *string, u8 max_length); + +u8 acpi_ut_valid_acpi_name(u32 name); + +acpi_name acpi_ut_repair_name(char *name); + +u8 acpi_ut_valid_acpi_char(char character, u32 position); + +acpi_status +acpi_ut_strtoul64(char *string, u32 base, acpi_integer * ret_integer); + +/* Values for Base above (16=Hex, 10=Decimal) */ + +#define ACPI_ANY_BASE 0 + +u32 acpi_ut_dword_byte_swap(u32 value); + +void acpi_ut_set_integer_width(u8 revision); + +#ifdef ACPI_DEBUG_OUTPUT +void +acpi_ut_display_init_pathname(u8 type, + struct acpi_namespace_node *obj_handle, + char *path); +#endif + +/* + * utresrc + */ +acpi_status +acpi_ut_walk_aml_resources(u8 * aml, + acpi_size aml_length, + acpi_walk_aml_callback user_function, + void **context); + +acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index); + +u32 acpi_ut_get_descriptor_length(void *aml); + +u16 acpi_ut_get_resource_length(void *aml); + +u8 acpi_ut_get_resource_header_length(void *aml); + +u8 acpi_ut_get_resource_type(void *aml); + +acpi_status +acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, + u8 ** end_tag); + +/* + * utmutex - mutex support + */ +acpi_status acpi_ut_mutex_initialize(void); + +void acpi_ut_mutex_terminate(void); + +acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id); + +acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id); + +/* + * utalloc - memory allocation and object caching + */ +acpi_status acpi_ut_create_caches(void); + +acpi_status acpi_ut_delete_caches(void); + +acpi_status acpi_ut_validate_buffer(struct acpi_buffer *buffer); + +acpi_status +acpi_ut_initialize_buffer(struct acpi_buffer *buffer, + acpi_size required_length); + +void *acpi_ut_allocate(acpi_size size, + u32 component, const char *module, u32 line); + +void *acpi_ut_allocate_zeroed(acpi_size size, + u32 component, const char *module, u32 line); + +#ifdef ACPI_DBG_TRACK_ALLOCATIONS +void *acpi_ut_allocate_and_track(acpi_size size, + u32 component, const char *module, u32 line); + +void *acpi_ut_allocate_zeroed_and_track(acpi_size size, + u32 component, + const char *module, u32 line); + +void +acpi_ut_free_and_track(void *address, + u32 component, const char *module, u32 line); + +#ifdef ACPI_FUTURE_USAGE +void acpi_ut_dump_allocation_info(void); +#endif /* ACPI_FUTURE_USAGE */ + +void acpi_ut_dump_allocations(u32 component, const char *module); + +acpi_status +acpi_ut_create_list(char *list_name, + u16 object_size, struct acpi_memory_list **return_cache); + +#endif + +#endif /* _ACUTILS_H */ diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h new file mode 100644 index 00000000000..ff851c5df69 --- /dev/null +++ b/drivers/acpi/acpica/amlcode.h @@ -0,0 +1,494 @@ +/****************************************************************************** + * + * Name: amlcode.h - Definitions for AML, as included in "definition blocks" + * Declarations and definitions contained herein are derived + * directly from the ACPI specification. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#ifndef __AMLCODE_H__ +#define __AMLCODE_H__ + +/* primary opcodes */ + +#define AML_NULL_CHAR (u16) 0x00 + +#define AML_ZERO_OP (u16) 0x00 +#define AML_ONE_OP (u16) 0x01 +#define AML_UNASSIGNED (u16) 0x02 +#define AML_ALIAS_OP (u16) 0x06 +#define AML_NAME_OP (u16) 0x08 +#define AML_BYTE_OP (u16) 0x0a +#define AML_WORD_OP (u16) 0x0b +#define AML_DWORD_OP (u16) 0x0c +#define AML_STRING_OP (u16) 0x0d +#define AML_QWORD_OP (u16) 0x0e /* ACPI 2.0 */ +#define AML_SCOPE_OP (u16) 0x10 +#define AML_BUFFER_OP (u16) 0x11 +#define AML_PACKAGE_OP (u16) 0x12 +#define AML_VAR_PACKAGE_OP (u16) 0x13 /* ACPI 2.0 */ +#define AML_METHOD_OP (u16) 0x14 +#define AML_DUAL_NAME_PREFIX (u16) 0x2e +#define AML_MULTI_NAME_PREFIX_OP (u16) 0x2f +#define AML_NAME_CHAR_SUBSEQ (u16) 0x30 +#define AML_NAME_CHAR_FIRST (u16) 0x41 +#define AML_EXTENDED_OP_PREFIX (u16) 0x5b +#define AML_ROOT_PREFIX (u16) 0x5c +#define AML_PARENT_PREFIX (u16) 0x5e +#define AML_LOCAL_OP (u16) 0x60 +#define AML_LOCAL0 (u16) 0x60 +#define AML_LOCAL1 (u16) 0x61 +#define AML_LOCAL2 (u16) 0x62 +#define AML_LOCAL3 (u16) 0x63 +#define AML_LOCAL4 (u16) 0x64 +#define AML_LOCAL5 (u16) 0x65 +#define AML_LOCAL6 (u16) 0x66 +#define AML_LOCAL7 (u16) 0x67 +#define AML_ARG_OP (u16) 0x68 +#define AML_ARG0 (u16) 0x68 +#define AML_ARG1 (u16) 0x69 +#define AML_ARG2 (u16) 0x6a +#define AML_ARG3 (u16) 0x6b +#define AML_ARG4 (u16) 0x6c +#define AML_ARG5 (u16) 0x6d +#define AML_ARG6 (u16) 0x6e +#define AML_STORE_OP (u16) 0x70 +#define AML_REF_OF_OP (u16) 0x71 +#define AML_ADD_OP (u16) 0x72 +#define AML_CONCAT_OP (u16) 0x73 +#define AML_SUBTRACT_OP (u16) 0x74 +#define AML_INCREMENT_OP (u16) 0x75 +#define AML_DECREMENT_OP (u16) 0x76 +#define AML_MULTIPLY_OP (u16) 0x77 +#define AML_DIVIDE_OP (u16) 0x78 +#define AML_SHIFT_LEFT_OP (u16) 0x79 +#define AML_SHIFT_RIGHT_OP (u16) 0x7a +#define AML_BIT_AND_OP (u16) 0x7b +#define AML_BIT_NAND_OP (u16) 0x7c +#define AML_BIT_OR_OP (u16) 0x7d +#define AML_BIT_NOR_OP (u16) 0x7e +#define AML_BIT_XOR_OP (u16) 0x7f +#define AML_BIT_NOT_OP (u16) 0x80 +#define AML_FIND_SET_LEFT_BIT_OP (u16) 0x81 +#define AML_FIND_SET_RIGHT_BIT_OP (u16) 0x82 +#define AML_DEREF_OF_OP (u16) 0x83 +#define AML_CONCAT_RES_OP (u16) 0x84 /* ACPI 2.0 */ +#define AML_MOD_OP (u16) 0x85 /* ACPI 2.0 */ +#define AML_NOTIFY_OP (u16) 0x86 +#define AML_SIZE_OF_OP (u16) 0x87 +#define AML_INDEX_OP (u16) 0x88 +#define AML_MATCH_OP (u16) 0x89 +#define AML_CREATE_DWORD_FIELD_OP (u16) 0x8a +#define AML_CREATE_WORD_FIELD_OP (u16) 0x8b +#define AML_CREATE_BYTE_FIELD_OP (u16) 0x8c +#define AML_CREATE_BIT_FIELD_OP (u16) 0x8d +#define AML_TYPE_OP (u16) 0x8e +#define AML_CREATE_QWORD_FIELD_OP (u16) 0x8f /* ACPI 2.0 */ +#define AML_LAND_OP (u16) 0x90 +#define AML_LOR_OP (u16) 0x91 +#define AML_LNOT_OP (u16) 0x92 +#define AML_LEQUAL_OP (u16) 0x93 +#define AML_LGREATER_OP (u16) 0x94 +#define AML_LLESS_OP (u16) 0x95 +#define AML_TO_BUFFER_OP (u16) 0x96 /* ACPI 2.0 */ +#define AML_TO_DECSTRING_OP (u16) 0x97 /* ACPI 2.0 */ +#define AML_TO_HEXSTRING_OP (u16) 0x98 /* ACPI 2.0 */ +#define AML_TO_INTEGER_OP (u16) 0x99 /* ACPI 2.0 */ +#define AML_TO_STRING_OP (u16) 0x9c /* ACPI 2.0 */ +#define AML_COPY_OP (u16) 0x9d /* ACPI 2.0 */ +#define AML_MID_OP (u16) 0x9e /* ACPI 2.0 */ +#define AML_CONTINUE_OP (u16) 0x9f /* ACPI 2.0 */ +#define AML_IF_OP (u16) 0xa0 +#define AML_ELSE_OP (u16) 0xa1 +#define AML_WHILE_OP (u16) 0xa2 +#define AML_NOOP_OP (u16) 0xa3 +#define AML_RETURN_OP (u16) 0xa4 +#define AML_BREAK_OP (u16) 0xa5 +#define AML_BREAK_POINT_OP (u16) 0xcc +#define AML_ONES_OP (u16) 0xff + +/* prefixed opcodes */ + +#define AML_EXTENDED_OPCODE (u16) 0x5b00 /* prefix for 2-byte opcodes */ + +#define AML_MUTEX_OP (u16) 0x5b01 +#define AML_EVENT_OP (u16) 0x5b02 +#define AML_SHIFT_RIGHT_BIT_OP (u16) 0x5b10 +#define AML_SHIFT_LEFT_BIT_OP (u16) 0x5b11 +#define AML_COND_REF_OF_OP (u16) 0x5b12 +#define AML_CREATE_FIELD_OP (u16) 0x5b13 +#define AML_LOAD_TABLE_OP (u16) 0x5b1f /* ACPI 2.0 */ +#define AML_LOAD_OP (u16) 0x5b20 +#define AML_STALL_OP (u16) 0x5b21 +#define AML_SLEEP_OP (u16) 0x5b22 +#define AML_ACQUIRE_OP (u16) 0x5b23 +#define AML_SIGNAL_OP (u16) 0x5b24 +#define AML_WAIT_OP (u16) 0x5b25 +#define AML_RESET_OP (u16) 0x5b26 +#define AML_RELEASE_OP (u16) 0x5b27 +#define AML_FROM_BCD_OP (u16) 0x5b28 +#define AML_TO_BCD_OP (u16) 0x5b29 +#define AML_UNLOAD_OP (u16) 0x5b2a +#define AML_REVISION_OP (u16) 0x5b30 +#define AML_DEBUG_OP (u16) 0x5b31 +#define AML_FATAL_OP (u16) 0x5b32 +#define AML_TIMER_OP (u16) 0x5b33 /* ACPI 3.0 */ +#define AML_REGION_OP (u16) 0x5b80 +#define AML_FIELD_OP (u16) 0x5b81 +#define AML_DEVICE_OP (u16) 0x5b82 +#define AML_PROCESSOR_OP (u16) 0x5b83 +#define AML_POWER_RES_OP (u16) 0x5b84 +#define AML_THERMAL_ZONE_OP (u16) 0x5b85 +#define AML_INDEX_FIELD_OP (u16) 0x5b86 +#define AML_BANK_FIELD_OP (u16) 0x5b87 +#define AML_DATA_REGION_OP (u16) 0x5b88 /* ACPI 2.0 */ + +/* + * Combination opcodes (actually two one-byte opcodes) + * Used by the disassembler and i_aSL compiler + */ +#define AML_LGREATEREQUAL_OP (u16) 0x9295 +#define AML_LLESSEQUAL_OP (u16) 0x9294 +#define AML_LNOTEQUAL_OP (u16) 0x9293 + +/* + * Internal opcodes + * Use only "Unknown" AML opcodes, don't attempt to use + * any valid ACPI ASCII values (A-Z, 0-9, '-') + */ +#define AML_INT_NAMEPATH_OP (u16) 0x002d +#define AML_INT_NAMEDFIELD_OP (u16) 0x0030 +#define AML_INT_RESERVEDFIELD_OP (u16) 0x0031 +#define AML_INT_ACCESSFIELD_OP (u16) 0x0032 +#define AML_INT_BYTELIST_OP (u16) 0x0033 +#define AML_INT_STATICSTRING_OP (u16) 0x0034 +#define AML_INT_METHODCALL_OP (u16) 0x0035 +#define AML_INT_RETURN_VALUE_OP (u16) 0x0036 +#define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037 + +#define ARG_NONE 0x0 + +/* + * Argument types for the AML Parser + * Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types + * Zero is reserved as end-of-list indicator + */ +#define ARGP_BYTEDATA 0x01 +#define ARGP_BYTELIST 0x02 +#define ARGP_CHARLIST 0x03 +#define ARGP_DATAOBJ 0x04 +#define ARGP_DATAOBJLIST 0x05 +#define ARGP_DWORDDATA 0x06 +#define ARGP_FIELDLIST 0x07 +#define ARGP_NAME 0x08 +#define ARGP_NAMESTRING 0x09 +#define ARGP_OBJLIST 0x0A +#define ARGP_PKGLENGTH 0x0B +#define ARGP_SUPERNAME 0x0C +#define ARGP_TARGET 0x0D +#define ARGP_TERMARG 0x0E +#define ARGP_TERMLIST 0x0F +#define ARGP_WORDDATA 0x10 +#define ARGP_QWORDDATA 0x11 +#define ARGP_SIMPLENAME 0x12 + +/* + * Resolved argument types for the AML Interpreter + * Each field in the arg_types u32 is 5 bits, allowing for a maximum of 6 arguments. + * There can be up to 31 unique argument types (0 is end-of-arg-list indicator) + * + * Note1: These values are completely independent from the ACPI_TYPEs + * i.e., ARGI_INTEGER != ACPI_TYPE_INTEGER + * + * Note2: If and when 5 bits becomes insufficient, it would probably be best + * to convert to a 6-byte array of argument types, allowing 8 bits per argument. + */ + +/* Single, simple types */ + +#define ARGI_ANYTYPE 0x01 /* Don't care */ +#define ARGI_PACKAGE 0x02 +#define ARGI_EVENT 0x03 +#define ARGI_MUTEX 0x04 +#define ARGI_DDBHANDLE 0x05 + +/* Interchangeable types (via implicit conversion) */ + +#define ARGI_INTEGER 0x06 +#define ARGI_STRING 0x07 +#define ARGI_BUFFER 0x08 +#define ARGI_BUFFER_OR_STRING 0x09 /* Used by MID op only */ +#define ARGI_COMPUTEDATA 0x0A /* Buffer, String, or Integer */ + +/* Reference objects */ + +#define ARGI_INTEGER_REF 0x0B +#define ARGI_OBJECT_REF 0x0C +#define ARGI_DEVICE_REF 0x0D +#define ARGI_REFERENCE 0x0E +#define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ +#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ +#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ + +/* Multiple/complex types */ + +#define ARGI_DATAOBJECT 0x12 /* Buffer, String, package or reference to a Node - Used only by size_of operator */ +#define ARGI_COMPLEXOBJ 0x13 /* Buffer, String, or package (Used by INDEX op only) */ +#define ARGI_REF_OR_STRING 0x14 /* Reference or String (Used by DEREFOF op only) */ +#define ARGI_REGION_OR_BUFFER 0x15 /* Used by LOAD op only */ +#define ARGI_DATAREFOBJ 0x16 + +/* Note: types above can expand to 0x1F maximum */ + +#define ARGI_INVALID_OPCODE 0xFFFFFFFF + +/* + * hash offsets + */ +#define AML_EXTOP_HASH_OFFSET 22 +#define AML_LNOT_HASH_OFFSET 19 + +/* + * opcode groups and types + */ +#define OPGRP_NAMED 0x01 +#define OPGRP_FIELD 0x02 +#define OPGRP_BYTELIST 0x04 + +/* + * Opcode information + */ + +/* Opcode flags */ + +#define AML_LOGICAL 0x0001 +#define AML_LOGICAL_NUMERIC 0x0002 +#define AML_MATH 0x0004 +#define AML_CREATE 0x0008 +#define AML_FIELD 0x0010 +#define AML_DEFER 0x0020 +#define AML_NAMED 0x0040 +#define AML_NSNODE 0x0080 +#define AML_NSOPCODE 0x0100 +#define AML_NSOBJECT 0x0200 +#define AML_HAS_RETVAL 0x0400 +#define AML_HAS_TARGET 0x0800 +#define AML_HAS_ARGS 0x1000 +#define AML_CONSTANT 0x2000 +#define AML_NO_OPERAND_RESOLVE 0x4000 + +/* Convenient flag groupings */ + +#define AML_FLAGS_EXEC_0A_0T_1R AML_HAS_RETVAL +#define AML_FLAGS_EXEC_1A_0T_0R AML_HAS_ARGS /* Monadic1 */ +#define AML_FLAGS_EXEC_1A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Monadic2 */ +#define AML_FLAGS_EXEC_1A_1T_0R AML_HAS_ARGS | AML_HAS_TARGET +#define AML_FLAGS_EXEC_1A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* monadic2_r */ +#define AML_FLAGS_EXEC_2A_0T_0R AML_HAS_ARGS /* Dyadic1 */ +#define AML_FLAGS_EXEC_2A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL /* Dyadic2 */ +#define AML_FLAGS_EXEC_2A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL /* dyadic2_r */ +#define AML_FLAGS_EXEC_2A_2T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_3A_0T_0R AML_HAS_ARGS +#define AML_FLAGS_EXEC_3A_1T_1R AML_HAS_ARGS | AML_HAS_TARGET | AML_HAS_RETVAL +#define AML_FLAGS_EXEC_6A_0T_1R AML_HAS_ARGS | AML_HAS_RETVAL + +/* + * The opcode Type is used in a dispatch table, do not change + * without updating the table. + */ +#define AML_TYPE_EXEC_0A_0T_1R 0x00 +#define AML_TYPE_EXEC_1A_0T_0R 0x01 /* Monadic1 */ +#define AML_TYPE_EXEC_1A_0T_1R 0x02 /* Monadic2 */ +#define AML_TYPE_EXEC_1A_1T_0R 0x03 +#define AML_TYPE_EXEC_1A_1T_1R 0x04 /* monadic2_r */ +#define AML_TYPE_EXEC_2A_0T_0R 0x05 /* Dyadic1 */ +#define AML_TYPE_EXEC_2A_0T_1R 0x06 /* Dyadic2 */ +#define AML_TYPE_EXEC_2A_1T_1R 0x07 /* dyadic2_r */ +#define AML_TYPE_EXEC_2A_2T_1R 0x08 +#define AML_TYPE_EXEC_3A_0T_0R 0x09 +#define AML_TYPE_EXEC_3A_1T_1R 0x0A +#define AML_TYPE_EXEC_6A_0T_1R 0x0B +/* End of types used in dispatch table */ + +#define AML_TYPE_LITERAL 0x0B +#define AML_TYPE_CONSTANT 0x0C +#define AML_TYPE_METHOD_ARGUMENT 0x0D +#define AML_TYPE_LOCAL_VARIABLE 0x0E +#define AML_TYPE_DATA_TERM 0x0F + +/* Generic for an op that returns a value */ + +#define AML_TYPE_METHOD_CALL 0x10 + +/* Misc */ + +#define AML_TYPE_CREATE_FIELD 0x11 +#define AML_TYPE_CREATE_OBJECT 0x12 +#define AML_TYPE_CONTROL 0x13 +#define AML_TYPE_NAMED_NO_OBJ 0x14 +#define AML_TYPE_NAMED_FIELD 0x15 +#define AML_TYPE_NAMED_SIMPLE 0x16 +#define AML_TYPE_NAMED_COMPLEX 0x17 +#define AML_TYPE_RETURN 0x18 + +#define AML_TYPE_UNDEFINED 0x19 +#define AML_TYPE_BOGUS 0x1A + +/* AML Package Length encodings */ + +#define ACPI_AML_PACKAGE_TYPE1 0x40 +#define ACPI_AML_PACKAGE_TYPE2 0x4000 +#define ACPI_AML_PACKAGE_TYPE3 0x400000 +#define ACPI_AML_PACKAGE_TYPE4 0x40000000 + +/* + * Opcode classes + */ +#define AML_CLASS_EXECUTE 0x00 +#define AML_CLASS_CREATE 0x01 +#define AML_CLASS_ARGUMENT 0x02 +#define AML_CLASS_NAMED_OBJECT 0x03 +#define AML_CLASS_CONTROL 0x04 +#define AML_CLASS_ASCII 0x05 +#define AML_CLASS_PREFIX 0x06 +#define AML_CLASS_INTERNAL 0x07 +#define AML_CLASS_RETURN_VALUE 0x08 +#define AML_CLASS_METHOD_CALL 0x09 +#define AML_CLASS_UNKNOWN 0x0A + +/* Predefined Operation Region space_iDs */ + +typedef enum { + REGION_MEMORY = 0, + REGION_IO, + REGION_PCI_CONFIG, + REGION_EC, + REGION_SMBUS, + REGION_CMOS, + REGION_PCI_BAR, + REGION_DATA_TABLE, /* Internal use only */ + REGION_FIXED_HW = 0x7F +} AML_REGION_TYPES; + +/* Comparison operation codes for match_op operator */ + +typedef enum { + MATCH_MTR = 0, + MATCH_MEQ = 1, + MATCH_MLE = 2, + MATCH_MLT = 3, + MATCH_MGE = 4, + MATCH_MGT = 5 +} AML_MATCH_OPERATOR; + +#define MAX_MATCH_OPERATOR 5 + +/* + * field_flags + * + * This byte is extracted from the AML and includes three separate + * pieces of information about the field: + * 1) The field access type + * 2) The field update rule + * 3) The lock rule for the field + * + * Bits 00 - 03 : access_type (any_acc, byte_acc, etc.) + * 04 : lock_rule (1 == Lock) + * 05 - 06 : update_rule + */ +#define AML_FIELD_ACCESS_TYPE_MASK 0x0F +#define AML_FIELD_LOCK_RULE_MASK 0x10 +#define AML_FIELD_UPDATE_RULE_MASK 0x60 + +/* 1) Field Access Types */ + +typedef enum { + AML_FIELD_ACCESS_ANY = 0x00, + AML_FIELD_ACCESS_BYTE = 0x01, + AML_FIELD_ACCESS_WORD = 0x02, + AML_FIELD_ACCESS_DWORD = 0x03, + AML_FIELD_ACCESS_QWORD = 0x04, /* ACPI 2.0 */ + AML_FIELD_ACCESS_BUFFER = 0x05 /* ACPI 2.0 */ +} AML_ACCESS_TYPE; + +/* 2) Field Lock Rules */ + +typedef enum { + AML_FIELD_LOCK_NEVER = 0x00, + AML_FIELD_LOCK_ALWAYS = 0x10 +} AML_LOCK_RULE; + +/* 3) Field Update Rules */ + +typedef enum { + AML_FIELD_UPDATE_PRESERVE = 0x00, + AML_FIELD_UPDATE_WRITE_AS_ONES = 0x20, + AML_FIELD_UPDATE_WRITE_AS_ZEROS = 0x40 +} AML_UPDATE_RULE; + +/* + * Field Access Attributes. + * This byte is extracted from the AML via the + * access_as keyword + */ +typedef enum { + AML_FIELD_ATTRIB_SMB_QUICK = 0x02, + AML_FIELD_ATTRIB_SMB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_SMB_BYTE = 0x06, + AML_FIELD_ATTRIB_SMB_WORD = 0x08, + AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_SMB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D +} AML_ACCESS_ATTRIBUTE; + +/* Bit fields in method_flags byte */ + +#define AML_METHOD_ARG_COUNT 0x07 +#define AML_METHOD_SERIALIZED 0x08 +#define AML_METHOD_SYNCH_LEVEL 0xF0 + +/* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ + +#define AML_METHOD_INTERNAL_ONLY 0x01 +#define AML_METHOD_RESERVED1 0x02 +#define AML_METHOD_RESERVED2 0x04 + +#endif /* __AMLCODE_H__ */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h new file mode 100644 index 00000000000..7b070e42b7c --- /dev/null +++ b/drivers/acpi/acpica/amlresrc.h @@ -0,0 +1,311 @@ + +/****************************************************************************** + * + * Module Name: amlresrc.h - AML resource descriptors + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +/* acpisrc:struct_defs -- for acpisrc conversion */ + +#ifndef __AMLRESRC_H +#define __AMLRESRC_H + +/* + * Resource descriptor tags, as defined in the ACPI specification. + * Used to symbolically reference fields within a descriptor. + */ +#define ACPI_RESTAG_ADDRESS "_ADR" +#define ACPI_RESTAG_ALIGNMENT "_ALN" +#define ACPI_RESTAG_ADDRESSSPACE "_ASI" +#define ACPI_RESTAG_ACCESSSIZE "_ASZ" +#define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" +#define ACPI_RESTAG_BASEADDRESS "_BAS" +#define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DMA "_DMA" +#define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_GRANULARITY "_GRA" +#define ACPI_RESTAG_INTERRUPT "_INT" +#define ACPI_RESTAG_INTERRUPTLEVEL "_LL_" /* active_lo(1), active_hi(0) */ +#define ACPI_RESTAG_INTERRUPTSHARE "_SHR" /* Shareable(1), no_share(0) */ +#define ACPI_RESTAG_INTERRUPTTYPE "_HE_" /* Edge(1), Level(0) */ +#define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_MEMATTRIBUTES "_MTP" /* Memory(0), Reserved(1), ACPI(2), NVS(3) */ +#define ACPI_RESTAG_MEMTYPE "_MEM" /* non_cache(0), Cacheable(1) Cache+combine(2), Cache+prefetch(3) */ +#define ACPI_RESTAG_MAXADDR "_MAX" +#define ACPI_RESTAG_MINADDR "_MIN" +#define ACPI_RESTAG_MAXTYPE "_MAF" +#define ACPI_RESTAG_MINTYPE "_MIF" +#define ACPI_RESTAG_REGISTERBITOFFSET "_RBO" +#define ACPI_RESTAG_REGISTERBITWIDTH "_RBW" +#define ACPI_RESTAG_RANGETYPE "_RNG" +#define ACPI_RESTAG_READWRITETYPE "_RW_" /* read_only(0), Writeable (1) */ +#define ACPI_RESTAG_TRANSLATION "_TRA" +#define ACPI_RESTAG_TRANSTYPE "_TRS" /* Sparse(1), Dense(0) */ +#define ACPI_RESTAG_TYPE "_TTP" /* Translation(1), Static (0) */ +#define ACPI_RESTAG_XFERTYPE "_SIZ" /* 8(0), 8_and16(1), 16(2) */ + +/* Default sizes for "small" resource descriptors */ + +#define ASL_RDESC_IRQ_SIZE 0x02 +#define ASL_RDESC_DMA_SIZE 0x02 +#define ASL_RDESC_ST_DEPEND_SIZE 0x00 +#define ASL_RDESC_END_DEPEND_SIZE 0x00 +#define ASL_RDESC_IO_SIZE 0x07 +#define ASL_RDESC_FIXED_IO_SIZE 0x03 +#define ASL_RDESC_END_TAG_SIZE 0x01 + +struct asl_resource_node { + u32 buffer_length; + void *buffer; + struct asl_resource_node *next; +}; + +/* Macros used to generate AML resource length fields */ + +#define ACPI_AML_SIZE_LARGE(r) (sizeof (r) - sizeof (struct aml_resource_large_header)) +#define ACPI_AML_SIZE_SMALL(r) (sizeof (r) - sizeof (struct aml_resource_small_header)) + +/* + * Resource descriptors defined in the ACPI specification. + * + * Packing/alignment must be BYTE because these descriptors + * are used to overlay the raw AML byte stream. + */ +#pragma pack(1) + +/* + * SMALL descriptors + */ +#define AML_RESOURCE_SMALL_HEADER_COMMON \ + u8 descriptor_type; + +struct aml_resource_small_header { +AML_RESOURCE_SMALL_HEADER_COMMON}; + +struct aml_resource_irq { + AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask; + u8 flags; +}; + +struct aml_resource_irq_noflags { + AML_RESOURCE_SMALL_HEADER_COMMON u16 irq_mask; +}; + +struct aml_resource_dma { + AML_RESOURCE_SMALL_HEADER_COMMON u8 dma_channel_mask; + u8 flags; +}; + +struct aml_resource_start_dependent { + AML_RESOURCE_SMALL_HEADER_COMMON u8 flags; +}; + +struct aml_resource_start_dependent_noprio { +AML_RESOURCE_SMALL_HEADER_COMMON}; + +struct aml_resource_end_dependent { +AML_RESOURCE_SMALL_HEADER_COMMON}; + +struct aml_resource_io { + AML_RESOURCE_SMALL_HEADER_COMMON u8 flags; + u16 minimum; + u16 maximum; + u8 alignment; + u8 address_length; +}; + +struct aml_resource_fixed_io { + AML_RESOURCE_SMALL_HEADER_COMMON u16 address; + u8 address_length; +}; + +struct aml_resource_vendor_small { +AML_RESOURCE_SMALL_HEADER_COMMON}; + +struct aml_resource_end_tag { + AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum; +}; + +/* + * LARGE descriptors + */ +#define AML_RESOURCE_LARGE_HEADER_COMMON \ + u8 descriptor_type;\ + u16 resource_length; + +struct aml_resource_large_header { +AML_RESOURCE_LARGE_HEADER_COMMON}; + +struct aml_resource_memory24 { + AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; + u16 minimum; + u16 maximum; + u16 alignment; + u16 address_length; +}; + +struct aml_resource_vendor_large { +AML_RESOURCE_LARGE_HEADER_COMMON}; + +struct aml_resource_memory32 { + AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; + u32 minimum; + u32 maximum; + u32 alignment; + u32 address_length; +}; + +struct aml_resource_fixed_memory32 { + AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; + u32 address; + u32 address_length; +}; + +#define AML_RESOURCE_ADDRESS_COMMON \ + u8 resource_type; \ + u8 flags; \ + u8 specific_flags; + +struct aml_resource_address { +AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_ADDRESS_COMMON}; + +struct aml_resource_extended_address64 { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON u8 revision_iD; + u8 reserved; + u64 granularity; + u64 minimum; + u64 maximum; + u64 translation_offset; + u64 address_length; + u64 type_specific; +}; + +#define AML_RESOURCE_EXTENDED_ADDRESS_REVISION 1 /* ACPI 3.0 */ + +struct aml_resource_address64 { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON u64 granularity; + u64 minimum; + u64 maximum; + u64 translation_offset; + u64 address_length; +}; + +struct aml_resource_address32 { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON u32 granularity; + u32 minimum; + u32 maximum; + u32 translation_offset; + u32 address_length; +}; + +struct aml_resource_address16 { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_ADDRESS_COMMON u16 granularity; + u16 minimum; + u16 maximum; + u16 translation_offset; + u16 address_length; +}; + +struct aml_resource_extended_irq { + AML_RESOURCE_LARGE_HEADER_COMMON u8 flags; + u8 interrupt_count; + u32 interrupts[1]; + /* res_source_index, res_source optional fields follow */ +}; + +struct aml_resource_generic_register { + AML_RESOURCE_LARGE_HEADER_COMMON u8 address_space_id; + u8 bit_width; + u8 bit_offset; + u8 access_size; /* ACPI 3.0, was previously Reserved */ + u64 address; +}; + +/* restore default alignment */ + +#pragma pack() + +/* Union of all resource descriptors, so we can allocate the worst case */ + +union aml_resource { + /* Descriptor headers */ + + u8 descriptor_type; + struct aml_resource_small_header small_header; + struct aml_resource_large_header large_header; + + /* Small resource descriptors */ + + struct aml_resource_irq irq; + struct aml_resource_dma dma; + struct aml_resource_start_dependent start_dpf; + struct aml_resource_end_dependent end_dpf; + struct aml_resource_io io; + struct aml_resource_fixed_io fixed_io; + struct aml_resource_vendor_small vendor_small; + struct aml_resource_end_tag end_tag; + + /* Large resource descriptors */ + + struct aml_resource_memory24 memory24; + struct aml_resource_generic_register generic_reg; + struct aml_resource_vendor_large vendor_large; + struct aml_resource_memory32 memory32; + struct aml_resource_fixed_memory32 fixed_memory32; + struct aml_resource_address16 address16; + struct aml_resource_address32 address32; + struct aml_resource_address64 address64; + struct aml_resource_extended_address64 ext_address64; + struct aml_resource_extended_irq extended_irq; + + /* Utility overlays */ + + struct aml_resource_address address; + u32 dword_item; + u16 word_item; + u8 byte_item; +}; + +#endif diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/acpica/dsfield.c index f988a5e7d2b..53e27bc5a73 100644 --- a/drivers/acpi/dispatcher/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -42,11 +42,12 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acparser.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsfield") diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/acpica/dsinit.c index 949f7c75029..eb144b13d8f 100644 --- a/drivers/acpi/dispatcher/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsinit") diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 279a5a60a0d..14b8b8ed802 100644 --- a/drivers/acpi/dispatcher/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -42,11 +42,14 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#ifdef ACPI_DISASSEMBLER #include <acpi/acdisasm.h> +#endif #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmethod") @@ -412,6 +415,9 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { status = obj_desc->method.implementation(next_walk_state); + if (status == AE_OK) { + status = AE_CTRL_TERMINATE; + } } return_ACPI_STATUS(status); diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index d03f81bd1bc..da0f5468184 100644 --- a/drivers/acpi/dispatcher/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmthdat") diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/acpica/dsobject.c index 4f08e599d07..15c628e6aa0 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -42,11 +42,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsobject") diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index 69fae5905bb..0c3b4dd60e8 100644 --- a/drivers/acpi/dispatcher/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -43,13 +43,14 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsopcode") @@ -1140,10 +1141,29 @@ acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state, op->common.aml_opcode, walk_state)); switch (op->common.aml_opcode) { - case AML_IF_OP: case AML_WHILE_OP: /* + * If this is an additional iteration of a while loop, continue. + * There is no need to allocate a new control state. + */ + if (walk_state->control_state) { + if (walk_state->control_state->control.aml_predicate_start + == (walk_state->parser_state.aml - 1)) { + + /* Reset the state to start-of-loop */ + + walk_state->control_state->common.state = + ACPI_CONTROL_CONDITIONAL_EXECUTING; + break; + } + } + + /*lint -fallthrough */ + + case AML_IF_OP: + + /* * IF/WHILE: Create a new control state to manage these * constructs. We need to manage these as a stack, in order * to handle nesting. @@ -1243,13 +1263,36 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op)); - if (walk_state->control_state->common.value) { + control_state = walk_state->control_state; + if (control_state->common.value) { - /* Predicate was true, go back and evaluate it again! */ + /* Predicate was true, the body of the loop was just executed */ + /* + * This loop counter mechanism allows the interpreter to escape + * possibly infinite loops. This can occur in poorly written AML + * when the hardware does not respond within a while loop and the + * loop does not implement a timeout. + */ + control_state->control.loop_count++; + if (control_state->control.loop_count > + ACPI_MAX_LOOP_ITERATIONS) { + status = AE_AML_INFINITE_LOOP; + break; + } + + /* + * Go back and evaluate the predicate and maybe execute the loop + * another time + */ status = AE_CTRL_PENDING; + walk_state->aml_last_while = + control_state->control.aml_predicate_start; + break; } + /* Predicate was false, terminate this while loop */ + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op)); @@ -1257,9 +1300,6 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, control_state = acpi_ut_pop_generic_state(&walk_state->control_state); - - walk_state->aml_last_while = - control_state->control.aml_predicate_start; acpi_ut_delete_generic_state(control_state); break; diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/acpica/dsutils.c index b398982f0d8..dabc23a4617 100644 --- a/drivers/acpi/dispatcher/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -42,12 +42,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsutils") diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/acpica/dswexec.c index 396fe12078c..350e6656bc8 100644 --- a/drivers/acpi/dispatcher/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -43,12 +43,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswexec") diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/acpica/dswload.c index dff7a3e445a..3023ceaa8d5 100644 --- a/drivers/acpi/dispatcher/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -42,12 +42,13 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" #ifdef ACPI_ASL_COMPILER #include <acpi/acdisasm.h> diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/acpica/dswscope.c index 9e607326587..908645e72f0 100644 --- a/drivers/acpi/dispatcher/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acdispat.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswscope") diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/acpica/dswstate.c index b00d4af791a..40f92bf7dce 100644 --- a/drivers/acpi/dispatcher/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acnamesp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dswstate") diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/acpica/evevent.c index c56c5c6ea77..803edd9e3f6 100644 --- a/drivers/acpi/events/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evevent") @@ -72,8 +73,8 @@ acpi_status acpi_ev_initialize_events(void) /* * Initialize the Fixed and General Purpose Events. This is done prior to - * enabling SCIs to prevent interrupts from occurring before the handlers are - * installed. + * enabling SCIs to prevent interrupts from occurring before the handlers + * are installed. */ status = acpi_ev_fixed_event_initialize(); if (ACPI_FAILURE(status)) { @@ -192,8 +193,8 @@ static acpi_status acpi_ev_fixed_event_initialize(void) acpi_status status; /* - * Initialize the structure that keeps track of fixed event handlers - * and enable the fixed events. + * Initialize the structure that keeps track of fixed event handlers and + * enable the fixed events. */ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) { acpi_gbl_fixed_event_handlers[i].handler = NULL; @@ -237,7 +238,7 @@ u32 acpi_ev_fixed_event_detect(void) /* * Read the fixed feature status and enable registers, as all the cases - * depend on their values. Ignore errors here. + * depend on their values. Ignore errors here. */ (void)acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, &fixed_status); (void)acpi_hw_register_read(ACPI_REGISTER_PM1_ENABLE, &fixed_enable); @@ -291,8 +292,8 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event) status_register_id, 1); /* - * Make sure we've got a handler. If not, report an error. - * The event is disabled to prevent further interrupts. + * Make sure we've got a handler. If not, report an error. The event is + * disabled to prevent further interrupts. */ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) { (void)acpi_set_register(acpi_gbl_fixed_event_info[event]. diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/acpica/evgpe.c index f45c74fe745..f345ced3647 100644 --- a/drivers/acpi/events/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evgpe") @@ -125,7 +126,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, (1 << (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number)); - /* 1) Disable case. Simply clear all enable bits */ + /* 1) Disable case. Simply clear all enable bits */ if (type == ACPI_GPE_DISABLE) { ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, @@ -134,7 +135,7 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, return_ACPI_STATUS(AE_OK); } - /* 2) Enable case. Set/Clear the appropriate enable bits */ + /* 2) Enable case. Set/Clear the appropriate enable bits */ switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { case ACPI_GPE_TYPE_WAKE: @@ -295,7 +296,7 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) * * FUNCTION: acpi_ev_get_gpe_event_info * - * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 + * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1 * gpe_number - Raw GPE number * * RETURN: A GPE event_info struct. NULL if not a valid GPE @@ -372,7 +373,7 @@ struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, * * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED * - * DESCRIPTION: Detect if any GP events have occurred. This function is + * DESCRIPTION: Detect if any GP events have occurred. This function is * executed at interrupt level. * ******************************************************************************/ @@ -400,8 +401,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* * We need to obtain the GPE lock for both the data structs and registers - * Note: Not necessary to obtain the hardware lock, since the GPE registers - * are owned by the gpe_lock. + * Note: Not necessary to obtain the hardware lock, since the GPE + * registers are owned by the gpe_lock. */ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); @@ -410,9 +411,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) gpe_block = gpe_xrupt_list->gpe_block_list_head; while (gpe_block) { /* - * Read all of the 8-bit GPE status and enable registers - * in this GPE block, saving all of them. - * Find all currently active GP events. + * Read all of the 8-bit GPE status and enable registers in this GPE + * block, saving all of them. Find all currently active GP events. */ for (i = 0; i < gpe_block->register_count; i++) { @@ -423,10 +423,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Status Register */ status = - acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, - &status_reg, - &gpe_register_info-> - status_address); + acpi_read(&status_reg, + &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -434,10 +432,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) /* Read the Enable Register */ status = - acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, - &enable_reg, - &gpe_register_info-> - enable_address); + acpi_read(&enable_reg, + &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -527,8 +523,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); /* - * Take a snapshot of the GPE info for this level - we copy the - * info to prevent a race condition with remove_handler/remove_block. + * Take a snapshot of the GPE info for this level - we copy the info to + * prevent a race condition with remove_handler/remove_block. */ ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info, sizeof(struct acpi_gpe_event_info)); @@ -539,8 +535,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) } /* - * Must check for control method type dispatch one more - * time to avoid race with ev_gpe_install_handler + * Must check for control method type dispatch one more time to avoid a + * race with ev_gpe_install_handler */ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { @@ -584,8 +580,8 @@ static void acpi_ev_asynch_enable_gpe(void *context) if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* - * GPE is level-triggered, we clear the GPE status bit after - * handling the event. + * GPE is level-triggered, we clear the GPE status bit after handling + * the event. */ status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { @@ -624,7 +620,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) acpi_os_gpe_count(gpe_number); /* - * If edge-triggered, clear the GPE status bit now. Note that + * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == @@ -650,7 +646,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) /* * Invoke the installed handler (at interrupt level) - * Ignore return status for now. TBD: leave GPE disabled on error? + * Ignore return status for now. + * TBD: leave GPE disabled on error? */ (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> dispatch. @@ -708,7 +705,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) gpe_number)); /* - * Disable the GPE. The GPE will remain disabled until the ACPI + * Disable the GPE. The GPE will remain disabled until the ACPICA * Core Subsystem is restarted, or a handler is installed. */ status = acpi_ev_disable_gpe(gpe_event_info); diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index 73c058e2f5c..484cc0565d5 100644 --- a/drivers/acpi/events/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evgpeblk") @@ -124,6 +125,7 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) * FUNCTION: acpi_ev_walk_gpe_list * * PARAMETERS: gpe_walk_callback - Routine called for each GPE block + * Context - Value passed to callback * * RETURN: Status * @@ -131,7 +133,8 @@ u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) * ******************************************************************************/ -acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) +acpi_status +acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context) { struct acpi_gpe_block_info *gpe_block; struct acpi_gpe_xrupt_info *gpe_xrupt_info; @@ -154,8 +157,13 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) /* One callback per GPE block */ - status = gpe_walk_callback(gpe_xrupt_info, gpe_block); + status = + gpe_walk_callback(gpe_xrupt_info, gpe_block, + context); if (ACPI_FAILURE(status)) { + if (status == AE_CTRL_END) { /* Callback abort */ + status = AE_OK; + } goto unlock_and_exit; } @@ -186,7 +194,8 @@ acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) acpi_status acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) + struct acpi_gpe_block_info *gpe_block, + void *context) { struct acpi_gpe_event_info *gpe_event_info; u32 i; @@ -309,17 +318,17 @@ acpi_ev_save_method_info(acpi_handle obj_handle, (gpe_block->block_base_number + (gpe_block->register_count * 8)))) { /* - * Not valid for this GPE block, just ignore it - * However, it may be valid for a different GPE block, since GPE0 and GPE1 - * methods both appear under \_GPE. + * Not valid for this GPE block, just ignore it. However, it may be + * valid for a different GPE block, since GPE0 and GPE1 methods both + * appear under \_GPE. */ return_ACPI_STATUS(AE_OK); } /* - * Now we can add this information to the gpe_event_info block - * for use during dispatch of this GPE. Default type is RUNTIME, although - * this may change when the _PRW methods are executed later. + * Now we can add this information to the gpe_event_info block for use + * during dispatch of this GPE. Default type is RUNTIME, although this may + * change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; @@ -394,8 +403,8 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, gpe_block = gpe_info->gpe_block; /* - * The _PRW object must return a package, we are only interested - * in the first element + * The _PRW object must return a package, we are only interested in the + * first element */ obj_desc = pkg_desc->package.elements[0]; @@ -434,7 +443,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, /* * Is this GPE within this block? * - * TRUE iff these conditions are true: + * TRUE if and only if these conditions are true: * 1) The GPE devices match. * 2) The GPE index(number) is within the range of the Gpe Block * associated with the GPE device. @@ -457,6 +466,7 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, if (ACPI_FAILURE(status)) { goto cleanup; } + status = acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE); @@ -476,9 +486,9 @@ acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, * RETURN: A GPE interrupt block * * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt - * block per unique interrupt level used for GPEs. - * Should be called only when the GPE lists are semaphore locked - * and not subject to change. + * block per unique interrupt level used for GPEs. Should be + * called only when the GPE lists are semaphore locked and not + * subject to change. * ******************************************************************************/ @@ -608,8 +618,9 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) * * FUNCTION: acpi_ev_install_gpe_block * - * PARAMETERS: gpe_block - New GPE block - * interrupt_number - Xrupt to be associated with this GPE block + * PARAMETERS: gpe_block - New GPE block + * interrupt_number - Xrupt to be associated with this + * GPE block * * RETURN: Status * @@ -666,7 +677,7 @@ acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, * * FUNCTION: acpi_ev_delete_gpe_block * - * PARAMETERS: gpe_block - Existing GPE block + * PARAMETERS: gpe_block - Existing GPE block * * RETURN: Status * @@ -688,7 +699,8 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs in this block */ - status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block); + status = + acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block, NULL); if (!gpe_block->previous && !gpe_block->next) { @@ -715,6 +727,9 @@ acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) acpi_os_release_lock(acpi_gbl_gpe_lock, flags); } + acpi_current_gpe_count -= + gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH; + /* Free the gpe_block */ ACPI_FREE(gpe_block->register_info); @@ -786,9 +801,9 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* * Initialize the GPE Register and Event structures. A goal of these - * tables is to hide the fact that there are two separate GPE register sets - * in a given GPE hardware block, the status registers occupy the first half, - * and the enable registers occupy the second half. + * tables is to hide the fact that there are two separate GPE register + * sets in a given GPE hardware block, the status registers occupy the + * first half, and the enable registers occupy the second half. */ this_register = gpe_register_info; this_event = gpe_event_info; @@ -816,10 +831,8 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) ACPI_GPE_REGISTER_WIDTH; this_register->enable_address.bit_width = ACPI_GPE_REGISTER_WIDTH; - this_register->status_address.bit_offset = - ACPI_GPE_REGISTER_WIDTH; - this_register->enable_address.bit_offset = - ACPI_GPE_REGISTER_WIDTH; + this_register->status_address.bit_offset = 0; + this_register->enable_address.bit_offset = 0; /* Init the event_info for each GPE within this register */ @@ -832,18 +845,14 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) /* Disable all GPEs within this register */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0x00, - &this_register-> - enable_address); + status = acpi_write(0x00, &this_register->enable_address); if (ACPI_FAILURE(status)) { goto error_exit; } /* Clear any pending GPE events within this register */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0xFF, - &this_register-> - status_address); + status = acpi_write(0xFF, &this_register->status_address); if (ACPI_FAILURE(status)) { goto error_exit; } @@ -956,6 +965,9 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, gpe_device->name.ascii, gpe_block->register_count, interrupt_number)); + /* Update global count of currently available GPEs */ + + acpi_current_gpe_count += register_count * ACPI_GPE_REGISTER_WIDTH; return_ACPI_STATUS(AE_OK); } @@ -1055,7 +1067,7 @@ acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, /* Enable all valid runtime GPEs found above */ - status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block); + status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block, NULL); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p", gpe_block)); diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/acpica/evmisc.c index 1d5670be729..5f893057bcc 100644 --- a/drivers/acpi/events/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -42,18 +42,15 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evmisc") -/* Pointer to FACS needed for the Global Lock */ -static struct acpi_table_facs *facs = NULL; - /* Local prototypes */ - static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context); static u32 acpi_ev_global_lock_handler(void *context); @@ -152,7 +149,9 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, break; default: + /* All other types are not supported */ + return (AE_TYPE); } } @@ -193,9 +192,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, acpi_ut_delete_generic_state(notify_info); } } else { - /* - * There is no notify handler (per-device or system) for this device. - */ + /* There is no notify handler (per-device or system) for this device */ + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No notify handler for Notify (%4.4s, %X) node %p\n", acpi_ut_get_node_name(node), notify_value, @@ -229,9 +227,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) ACPI_FUNCTION_ENTRY(); /* - * We will invoke a global notify handler if installed. - * This is done _before_ we invoke the per-device handler attached - * to the device. + * We will invoke a global notify handler if installed. This is done + * _before_ we invoke the per-device handler attached to the device. */ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) { @@ -299,7 +296,7 @@ static u32 acpi_ev_global_lock_handler(void *context) * If we don't get it now, it will be marked pending and we will * take another interrupt when it becomes free. */ - ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); if (acquired) { /* Got the lock, now wake all threads waiting for it */ @@ -336,34 +333,27 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } + /* Attempt installation of the global lock handler */ - acpi_gbl_global_lock_present = TRUE; status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, acpi_ev_global_lock_handler, NULL); /* - * If the global lock does not exist on this platform, the attempt - * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick) - * Map to AE_OK, but mark global lock as not present. - * Any attempt to actually use the global lock will be flagged - * with an error. + * If the global lock does not exist on this platform, the attempt to + * enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick). + * Map to AE_OK, but mark global lock as not present. Any attempt to + * actually use the global lock will be flagged with an error. */ if (status == AE_NO_HARDWARE_RESPONSE) { ACPI_ERROR((AE_INFO, "No response from Global Lock hardware, disabling lock")); acpi_gbl_global_lock_present = FALSE; - status = AE_OK; + return_ACPI_STATUS(AE_OK); } + acpi_gbl_global_lock_present = TRUE; return_ACPI_STATUS(status); } @@ -462,8 +452,8 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) } /* - * Make sure that a global lock actually exists. If not, just treat - * the lock as a standard mutex. + * Make sure that a global lock actually exists. If not, just treat the + * lock as a standard mutex. */ if (!acpi_gbl_global_lock_present) { acpi_gbl_global_lock_acquired = TRUE; @@ -472,7 +462,7 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout) /* Attempt to acquire the actual hardware lock */ - ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired); + ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_FACS, acquired); if (acquired) { /* We got the lock */ @@ -536,7 +526,7 @@ acpi_status acpi_ev_release_global_lock(void) /* Allow any thread to release the lock */ - ACPI_RELEASE_GLOBAL_LOCK(facs, pending); + ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_FACS, pending); /* * If the pending bit was set, we must write GBL_RLS to the control @@ -582,8 +572,8 @@ void acpi_ev_terminate(void) if (acpi_gbl_events_initialized) { /* - * Disable all event-related functionality. - * In all cases, on error, print a message but obviously we don't abort. + * Disable all event-related functionality. In all cases, on error, + * print a message but obviously we don't abort. */ /* Disable all fixed events */ @@ -599,7 +589,7 @@ void acpi_ev_terminate(void) /* Disable all GPEs in all GPE blocks */ - status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); /* Remove SCI handler */ @@ -617,7 +607,7 @@ void acpi_ev_terminate(void) /* Deallocate all handler objects installed within GPE info structs */ - status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers); + status = acpi_ev_walk_gpe_list(acpi_ev_delete_gpe_handlers, NULL); /* Return to original mode if necessary */ diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/acpica/evregion.c index 236fbd1ca43..665c0887ab4 100644 --- a/drivers/acpi/events/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -42,22 +42,15 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evregion") -#define ACPI_NUM_DEFAULT_SPACES 4 -static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { - ACPI_ADR_SPACE_SYSTEM_MEMORY, - ACPI_ADR_SPACE_SYSTEM_IO, - ACPI_ADR_SPACE_PCI_CONFIG, - ACPI_ADR_SPACE_DATA_TABLE -}; /* Local prototypes */ - static acpi_status acpi_ev_reg_run(acpi_handle obj_handle, u32 level, void *context, void **return_value); @@ -66,6 +59,17 @@ static acpi_status acpi_ev_install_handler(acpi_handle obj_handle, u32 level, void *context, void **return_value); +/* These are the address spaces that will get default handlers */ + +#define ACPI_NUM_DEFAULT_SPACES 4 + +static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = { + ACPI_ADR_SPACE_SYSTEM_MEMORY, + ACPI_ADR_SPACE_SYSTEM_IO, + ACPI_ADR_SPACE_PCI_CONFIG, + ACPI_ADR_SPACE_DATA_TABLE +}; + /******************************************************************************* * * FUNCTION: acpi_ev_install_region_handlers @@ -91,18 +95,19 @@ acpi_status acpi_ev_install_region_handlers(void) } /* - * All address spaces (PCI Config, EC, SMBus) are scope dependent - * and registration must occur for a specific device. + * All address spaces (PCI Config, EC, SMBus) are scope dependent and + * registration must occur for a specific device. * - * In the case of the system memory and IO address spaces there is currently - * no device associated with the address space. For these we use the root. + * In the case of the system memory and IO address spaces there is + * currently no device associated with the address space. For these we + * use the root. * - * We install the default PCI config space handler at the root so - * that this space is immediately available even though the we have - * not enumerated all the PCI Root Buses yet. This is to conform - * to the ACPI specification which states that the PCI config - * space must be always available -- even though we are nowhere - * near ready to find the PCI root buses at this point. + * We install the default PCI config space handler at the root so that + * this space is immediately available even though the we have not + * enumerated all the PCI Root Buses yet. This is to conform to the ACPI + * specification which states that the PCI config space must be always + * available -- even though we are nowhere near ready to find the PCI root + * buses at this point. * * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler * has already been installed (via acpi_install_address_space_handler). @@ -160,12 +165,11 @@ acpi_status acpi_ev_initialize_op_regions(void) return_ACPI_STATUS(status); } - /* - * Run the _REG methods for op_regions in each default address space - */ - for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* Run the _REG methods for op_regions in each default address space */ - /* TBD: Make sure handler is the DEFAULT handler, otherwise + for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) { + /* + * TBD: Make sure handler is the DEFAULT handler, otherwise * _REG will have already been run. */ status = acpi_ev_execute_reg_methods(acpi_gbl_root_node, @@ -318,13 +322,13 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, } /* - * It may be the case that the region has never been initialized + * It may be the case that the region has never been initialized. * Some types of regions require special init code */ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { - /* - * This region has not been initialized yet, do it - */ + + /* This region has not been initialized yet, do it */ + region_setup = handler_desc->address_space.setup; if (!region_setup) { @@ -339,9 +343,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, } /* - * We must exit the interpreter because the region - * setup will potentially execute control methods - * (e.g., _REG method for this region) + * We must exit the interpreter because the region setup will + * potentially execute control methods (for example, the _REG method + * for this region) */ acpi_ex_exit_interpreter(); @@ -364,9 +368,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, return_ACPI_STATUS(status); } - /* - * Region initialization may have been completed by region_setup - */ + /* Region initialization may have been completed by region_setup */ + if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) { region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE; @@ -521,8 +524,8 @@ acpi_ev_detach_region(union acpi_operand_object *region_obj, } /* - * If the region has been activated, call the setup handler - * with the deactivate notification + * If the region has been activated, call the setup handler with + * the deactivate notification */ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) { region_setup = handler_obj->address_space.setup; @@ -668,8 +671,8 @@ acpi_ev_install_handler(acpi_handle obj_handle, } /* - * We only care about regions.and objects - * that are allowed to have address space handlers + * We only care about regions and objects that are allowed to have + * address space handlers */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { @@ -710,9 +713,9 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* * Since the object we found it on was a device, then it * means that someone has already installed a handler for - * the branch of the namespace from this device on. Just + * the branch of the namespace from this device on. Just * bail out telling the walk routine to not traverse this - * branch. This preserves the scoping rule for handlers. + * branch. This preserves the scoping rule for handlers. */ return (AE_CTRL_DEPTH); } @@ -723,9 +726,8 @@ acpi_ev_install_handler(acpi_handle obj_handle, } /* - * As long as the device didn't have a handler for this - * space we don't care about it. We just ignore it and - * proceed. + * As long as the device didn't have a handler for this space we + * don't care about it. We just ignore it and proceed. */ return (AE_OK); } @@ -733,16 +735,14 @@ acpi_ev_install_handler(acpi_handle obj_handle, /* Object is a Region */ if (obj_desc->region.space_id != handler_obj->address_space.space_id) { - /* - * This region is for a different address space - * -- just ignore it - */ + + /* This region is for a different address space, just ignore it */ + return (AE_OK); } /* - * Now we have a region and it is for the handler's address - * space type. + * Now we have a region and it is for the handler's address space type. * * First disconnect region for any previous handler (if any) */ @@ -786,9 +786,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, ACPI_FUNCTION_TRACE(ev_install_space_handler); /* - * This registration is valid for only the types below - * and the root. This is where the default handlers - * get placed. + * This registration is valid for only the types below and the root. This + * is where the default handlers get placed. */ if ((node->type != ACPI_TYPE_DEVICE) && (node->type != ACPI_TYPE_PROCESSOR) && @@ -848,8 +847,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, obj_desc = acpi_ns_get_attached_object(node); if (obj_desc) { /* - * The attached device object already exists. - * Make sure the handler is not already installed. + * The attached device object already exists. Make sure the handler + * is not already installed. */ handler_obj = obj_desc->device.handler; @@ -864,8 +863,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, handler) { /* * It is (relatively) OK to attempt to install the SAME - * handler twice. This can easily happen - * with PCI_Config space. + * handler twice. This can easily happen with the + * PCI_Config space. */ status = AE_SAME_HANDLER; goto unlock_and_exit; @@ -925,9 +924,8 @@ acpi_ev_install_space_handler(struct acpi_namespace_node * node, /* * Install the handler * - * At this point there is no existing handler. - * Just allocate the object for the handler and link it - * into the list. + * At this point there is no existing handler. Just allocate the object + * for the handler and link it into the list. */ handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_ADDRESS_HANDLER); @@ -1000,11 +998,10 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, ACPI_FUNCTION_TRACE(ev_execute_reg_methods); /* - * Run all _REG methods for all Operation Regions for this - * space ID. This is a separate walk in order to handle any - * interdependencies between regions and _REG methods. (i.e. handlers - * must be installed for all regions of this Space ID before we - * can run any _REG methods) + * Run all _REG methods for all Operation Regions for this space ID. This + * is a separate walk in order to handle any interdependencies between + * regions and _REG methods. (i.e. handlers must be installed for all + * regions of this Space ID before we can run any _REG methods) */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, @@ -1042,8 +1039,8 @@ acpi_ev_reg_run(acpi_handle obj_handle, } /* - * We only care about regions.and objects - * that are allowed to have address space handlers + * We only care about regions.and objects that are allowed to have address + * space handlers */ if ((node->type != ACPI_TYPE_REGION) && (node != acpi_gbl_root_node)) { return (AE_OK); @@ -1062,10 +1059,9 @@ acpi_ev_reg_run(acpi_handle obj_handle, /* Object is a Region */ if (obj_desc->region.space_id != space_id) { - /* - * This region is for a different address space - * -- just ignore it - */ + + /* This region is for a different address space, just ignore it */ + return (AE_OK); } diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 6b94b38df07..f3f1fb45c3d 100644 --- a/drivers/acpi/events/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evrgnini") @@ -233,9 +234,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, if (ACPI_FAILURE(status)) { if (status == AE_SAME_HANDLER) { /* - * It is OK if the handler is already installed on the root - * bridge. Still need to return a context object for the - * new PCI_Config operation region, however. + * It is OK if the handler is already installed on the + * root bridge. Still need to return a context object + * for the new PCI_Config operation region, however. */ status = AE_OK; } else { @@ -272,8 +273,8 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } /* - * For PCI_Config space access, we need the segment, bus, - * device and function numbers. Acquire them here. + * For PCI_Config space access, we need the segment, bus, device and + * function numbers. Acquire them here. * * Find the parent device object. (This allows the operation region to be * within a subscope under the device, such as a control method.) @@ -289,16 +290,16 @@ acpi_ev_pci_config_region_setup(acpi_handle handle, } /* - * Get the PCI device and function numbers from the _ADR object - * contained in the parent's scope. + * Get the PCI device and function numbers from the _ADR object contained + * in the parent's scope. */ status = acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node, &pci_value); /* - * The default is zero, and since the allocation above zeroed - * the data, just do nothing on failure. + * The default is zero, and since the allocation above zeroed the data, + * just do nothing on failure. */ if (ACPI_SUCCESS(status)) { pci_id->device = ACPI_HIWORD(ACPI_LODWORD(pci_value)); @@ -382,9 +383,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) struct acpi_compatible_id_list *cid; u32 i; - /* - * Get the _HID and check for a PCI Root Bridge - */ + /* Get the _HID and check for a PCI Root Bridge */ + status = acpi_ut_execute_HID(node, &hid); if (ACPI_FAILURE(status)) { return (FALSE); @@ -394,10 +394,8 @@ static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node) return (TRUE); } - /* - * The _HID did not match. - * Get the _CID and check for a PCI Root Bridge - */ + /* The _HID did not match. Get the _CID and check for a PCI Root Bridge */ + status = acpi_ut_execute_CID(node, &cid); if (ACPI_FAILURE(status)) { return (FALSE); @@ -516,9 +514,9 @@ acpi_ev_default_region_setup(acpi_handle handle, * Get the appropriate address space handler for a newly * created region. * - * This also performs address space specific initialization. For + * This also performs address space specific initialization. For * example, PCI regions must have an _ADR object that contains - * a PCI address in the scope of the definition. This address is + * a PCI address in the scope of the definition. This address is * required to perform an access to PCI config space. * * MUTEX: Interpreter should be unlocked, because we may run the _REG @@ -572,7 +570,7 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, if (ACPI_SUCCESS(status)) { /* * The _REG method is optional and there can be only one per region - * definition. This will be executed when the handler is attached + * definition. This will be executed when the handler is attached * or removed */ region_obj2->extra.method_REG = method_node; @@ -670,10 +668,8 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, } } - /* - * This node does not have the handler we need; - * Pop up one level - */ + /* This node does not have the handler we need; Pop up one level */ + node = acpi_ns_get_parent_node(node); } diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/acpica/evsci.c index 2a8b7787761..567b356c85a 100644 --- a/drivers/acpi/events/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evsci") @@ -115,10 +116,8 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context) * if this interrupt handler is installed, ACPI is enabled. */ - /* - * GPEs: - * Check for and dispatch any GPEs that have occurred - */ + /* GPEs: Check for and dispatch any GPEs that have occurred */ + interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list); return_UINT32(interrupt_handled); @@ -158,11 +157,11 @@ u32 acpi_ev_install_sci_handler(void) * RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not * installed to begin with * - * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be + * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be * taken. * * Note: It doesn't seem important to disable all events or set the event - * enable registers to their original values. The OS should disable + * enable registers to their original values. The OS should disable * the SCI interrupt level when the handler is removed, so no more * events will come in. * diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/acpica/evxface.c index 94a6efe020b..3aca9010a11 100644 --- a/drivers/acpi/events/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "acinterp.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxface") @@ -267,7 +268,7 @@ acpi_install_notify_handler(acpi_handle device, /* * Root Object: * Registering a notify handler on the root object indicates that the - * caller wishes to receive notifications for all objects. Note that + * caller wishes to receive notifications for all objects. Note that * only one <external> global handler can be regsitered (per notify type). */ if (device == ACPI_ROOT_OBJECT) { diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 41554f736b6..35485e4b60a 100644 --- a/drivers/acpi/events/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -42,13 +42,19 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfevnt") +/* Local prototypes */ +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context); + /******************************************************************************* * * FUNCTION: acpi_enable @@ -60,6 +66,7 @@ ACPI_MODULE_NAME("evxfevnt") * DESCRIPTION: Transfers the system into ACPI mode. * ******************************************************************************/ + acpi_status acpi_enable(void) { acpi_status status = AE_OK; @@ -161,8 +168,8 @@ acpi_status acpi_enable_event(u32 event, u32 flags) } /* - * Enable the requested fixed event (by writing a one to the - * enable register bit) + * Enable the requested fixed event (by writing a one to the enable + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -343,8 +350,8 @@ acpi_status acpi_disable_event(u32 event, u32 flags) } /* - * Disable the requested fixed event (by writing a zero to the - * enable register bit) + * Disable the requested fixed event (by writing a zero to the enable + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -396,8 +403,8 @@ acpi_status acpi_clear_event(u32 event) } /* - * Clear the requested fixed event (By writing a one to the - * status register bit) + * Clear the requested fixed event (By writing a one to the status + * register bit) */ status = acpi_set_register(acpi_gbl_fixed_event_info[event]. @@ -717,3 +724,148 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) } ACPI_EXPORT_SYMBOL(acpi_remove_gpe_block) + +/******************************************************************************* + * + * FUNCTION: acpi_get_gpe_device + * + * PARAMETERS: Index - System GPE index (0-current_gpe_count) + * gpe_device - Where the parent GPE Device is returned + * + * RETURN: Status + * + * DESCRIPTION: Obtain the GPE device associated with the input index. A NULL + * gpe device indicates that the gpe number is contained in one of + * the FADT-defined gpe blocks. Otherwise, the GPE block device. + * + ******************************************************************************/ +acpi_status +acpi_get_gpe_device(u32 index, acpi_handle *gpe_device) +{ + struct acpi_gpe_device_info info; + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_get_gpe_device); + + if (!gpe_device) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (index >= acpi_current_gpe_count) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + + /* Setup and walk the GPE list */ + + info.index = index; + info.status = AE_NOT_EXIST; + info.gpe_device = NULL; + info.next_block_base_index = 0; + + status = acpi_ev_walk_gpe_list(acpi_ev_get_gpe_device, &info); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + *gpe_device = info.gpe_device; + return_ACPI_STATUS(info.status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) + +/******************************************************************************* + * + * FUNCTION: acpi_ev_get_gpe_device + * + * PARAMETERS: GPE_WALK_CALLBACK + * + * RETURN: Status + * + * DESCRIPTION: Matches the input GPE index (0-current_gpe_count) with a GPE + * block device. NULL if the GPE is one of the FADT-defined GPEs. + * + ******************************************************************************/ +acpi_status +acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) +{ + struct acpi_gpe_device_info *info = context; + + /* Increment Index by the number of GPEs in this block */ + + info->next_block_base_index += + (gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH); + + if (info->index < info->next_block_base_index) { + /* + * The GPE index is within this block, get the node. Leave the node + * NULL for the FADT-defined GPEs + */ + if ((gpe_block->node)->type == ACPI_TYPE_DEVICE) { + info->gpe_device = gpe_block->node; + } + + info->status = AE_OK; + return (AE_CTRL_END); + } + + return (AE_OK); +} + +/****************************************************************************** + * + * FUNCTION: acpi_disable_all_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Disable and clear all GPEs in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_disable_all_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_disable_all_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_disable_all_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_enable_all_runtime_gpes + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks + * + ******************************************************************************/ + +acpi_status acpi_enable_all_runtime_gpes(void) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_enable_all_runtime_gpes); + + status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_hw_enable_all_runtime_gpes(); + (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); + + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index e8750807e57..479e7a3721b 100644 --- a/drivers/acpi/events/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT ACPI_EVENTS ACPI_MODULE_NAME("evxfregn") diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/acpica/exconfig.c index 74da6fa52ef..932bbc26aa0 100644 --- a/drivers/acpi/executer/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "actables.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconfig") diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 1d1f35adddd..0be10188316 100644 --- a/drivers/acpi/executer/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exconvrt") diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/acpica/excreate.c index ad09696d506..a57ad2564ab 100644 --- a/drivers/acpi/executer/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("excreate") diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/acpica/exdump.c index d087a7d28aa..aa313574b0d 100644 --- a/drivers/acpi/executer/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exdump") diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/acpica/exfield.c index 3e440d84226..a352d023385 100644 --- a/drivers/acpi/executer/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exfield") diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/acpica/exfldio.c index 9ff9d1f4615..ef58ac4e687 100644 --- a/drivers/acpi/executer/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acevents.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acevents.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exfldio") @@ -498,14 +499,13 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, return_ACPI_STATUS(status); } - ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, - "I/O to Data Register: ValuePtr %p\n", - value)); - if (read_write == ACPI_READ) { /* Read the datum from the data_register */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "Read from Data Register\n")); + status = acpi_ex_extract_from_field(obj_desc->index_field. data_obj, value, @@ -513,6 +513,10 @@ acpi_ex_field_datum_io(union acpi_operand_object *obj_desc, } else { /* Write the datum to the data_register */ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "Write to Data Register: Value %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(*value))); + status = acpi_ex_insert_into_field(obj_desc->index_field. data_obj, value, diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/acpica/exmisc.c index efb19134005..6b0747ac683 100644 --- a/drivers/acpi/executer/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/amlresrc.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "amlresrc.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmisc") diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/acpica/exmutex.c index a8bf3d713e2..d301c1f363e 100644 --- a/drivers/acpi/executer/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acinterp.h" +#include "acevents.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exmutex") diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/acpica/exnames.c index 817e67be369..ffdae122d94 100644 --- a/drivers/acpi/executer/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exnames") diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index f622f9eac8a..b530480cc7d 100644 --- a/drivers/acpi/executer/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -43,11 +43,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg1") diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 368def5dffc..0b4f513ca88 100644 --- a/drivers/acpi/executer/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acevents.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acevents.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg2") diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 9cb4197681a..c6520bbf882 100644 --- a/drivers/acpi/executer/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg3") diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index 67d48737af5..ae43f7670a6 100644 --- a/drivers/acpi/executer/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exoparg6") diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/acpica/exprep.c index a7dc87ecee3..a226f74d4a5 100644 --- a/drivers/acpi/executer/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exprep") diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/acpica/exregion.c index 7a41c409ae4..76ec8ff903b 100644 --- a/drivers/acpi/executer/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exregion") diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/acpica/exresnte.c index 423ad3635f3..a063a74006f 100644 --- a/drivers/acpi/executer/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresnte") diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/acpica/exresolv.c index 60e8c47128e..f6105a6d612 100644 --- a/drivers/acpi/executer/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acdispat.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresolv") diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/acpica/exresop.c index 0bb82593da7..3c3802764bf 100644 --- a/drivers/acpi/executer/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exresop") diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/acpica/exstore.c index 1c118ba78ad..e35e9b4f6a4 100644 --- a/drivers/acpi/executer/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -43,10 +43,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstore") diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/acpica/exstoren.c index eef61a00803..145d15305f7 100644 --- a/drivers/acpi/executer/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -44,8 +44,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstoren") diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/acpica/exstorob.c index 9a75ff09fb0..67340cc7014 100644 --- a/drivers/acpi/executer/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exstorob") diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/acpica/exsystem.c index 68990f1df37..3d00b935723 100644 --- a/drivers/acpi/executer/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exsystem") diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/acpica/exutils.c index 86c03880b52..32b85d68e75 100644 --- a/drivers/acpi/executer/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -59,8 +59,9 @@ #define DEFINE_AML_GLOBALS #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exutils") diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 816894ea839..a9d4fea4167 100644 --- a/drivers/acpi/hardware/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -43,6 +43,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwacpi") diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 0b80db9d919..2013b66745d 100644 --- a/drivers/acpi/hardware/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acevents.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwgpe") @@ -51,7 +52,8 @@ ACPI_MODULE_NAME("hwgpe") /* Local prototypes */ static acpi_status acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block); + struct acpi_gpe_block_info *gpe_block, + void *context); /****************************************************************************** * @@ -80,8 +82,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Get current value of the enable register that contains this GPE */ - status = acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, &enable_mask, - &gpe_register_info->enable_address); + status = acpi_read(&enable_mask, &gpe_register_info->enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -95,9 +96,7 @@ acpi_status acpi_hw_low_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) /* Write the updated enable mask */ - status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, enable_mask, - &gpe_register_info->enable_address); - + status = acpi_write(enable_mask, &gpe_register_info->enable_address); return (status); } @@ -132,8 +131,8 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info * gpe_event_info) /* Write the entire GPE (runtime) enable register */ - status = acpi_hw_low_level_write(8, gpe_register_info->enable_for_run, - &gpe_register_info->enable_address); + status = acpi_write(gpe_register_info->enable_for_run, + &gpe_register_info->enable_address); return (status); } @@ -166,9 +165,8 @@ acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info) * Write a one to the appropriate bit in the status register to * clear this GPE. */ - status = acpi_hw_low_level_write(8, register_bit, - &gpe_event_info->register_info-> - status_address); + status = acpi_write(register_bit, + &gpe_event_info->register_info->status_address); return (status); } @@ -227,9 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, /* GPE currently active (status bit == 1)? */ - status = - acpi_hw_low_level_read(8, &in_byte, - &gpe_register_info->status_address); + status = acpi_read(&in_byte, &gpe_register_info->status_address); if (ACPI_FAILURE(status)) { goto unlock_and_exit; } @@ -260,8 +256,8 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info, ******************************************************************************/ acpi_status -acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -272,9 +268,9 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Disable all GPEs in this register */ - status = acpi_hw_low_level_write(8, 0x00, - &gpe_block->register_info[i]. - enable_address); + status = + acpi_write(0x00, + &gpe_block->register_info[i].enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -297,8 +293,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, ******************************************************************************/ acpi_status -acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -309,9 +305,9 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Clear status on all GPEs in this register */ - status = acpi_hw_low_level_write(8, 0xFF, - &gpe_block->register_info[i]. - status_address); + status = + acpi_write(0xFF, + &gpe_block->register_info[i].status_address); if (ACPI_FAILURE(status)) { return (status); } @@ -335,8 +331,8 @@ acpi_hw_clear_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, ******************************************************************************/ acpi_status -acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, - struct acpi_gpe_block_info * gpe_block) +acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, + struct acpi_gpe_block_info *gpe_block, void *context) { u32 i; acpi_status status; @@ -352,12 +348,9 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, /* Enable all "runtime" GPEs in this register */ - status = - acpi_hw_low_level_write(8, - gpe_block->register_info[i]. - enable_for_run, - &gpe_block->register_info[i]. - enable_address); + status = acpi_write(gpe_block->register_info[i].enable_for_run, + &gpe_block->register_info[i]. + enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -382,7 +375,8 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info * gpe_xrupt_info, static acpi_status acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, - struct acpi_gpe_block_info *gpe_block) + struct acpi_gpe_block_info *gpe_block, + void *context) { u32 i; acpi_status status; @@ -396,11 +390,9 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info, /* Enable all "wake" GPEs in this register */ - status = acpi_hw_low_level_write(8, - gpe_block->register_info[i]. - enable_for_wake, - &gpe_block->register_info[i]. - enable_address); + status = acpi_write(gpe_block->register_info[i].enable_for_wake, + &gpe_block->register_info[i]. + enable_address); if (ACPI_FAILURE(status)) { return (status); } @@ -427,8 +419,8 @@ acpi_status acpi_hw_disable_all_gpes(void) ACPI_FUNCTION_TRACE(hw_disable_all_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block); - status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_disable_gpe_block, NULL); + status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); return_ACPI_STATUS(status); } @@ -450,7 +442,7 @@ acpi_status acpi_hw_enable_all_runtime_gpes(void) ACPI_FUNCTION_TRACE(hw_enable_all_runtime_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_enable_runtime_gpe_block, NULL); return_ACPI_STATUS(status); } @@ -472,6 +464,6 @@ acpi_status acpi_hw_enable_all_wakeup_gpes(void) ACPI_FUNCTION_TRACE(hw_enable_all_wakeup_gpes); - status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block); + status = acpi_ev_walk_gpe_list(acpi_hw_enable_wakeup_gpe_block, NULL); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c new file mode 100644 index 00000000000..4dc43b01851 --- /dev/null +++ b/drivers/acpi/acpica/hwregs.c @@ -0,0 +1,353 @@ + +/******************************************************************************* + * + * Module Name: hwregs - Read/write access functions for the various ACPI + * control and status registers. + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2008, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. + */ + +#include <acpi/acpi.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" + +#define _COMPONENT ACPI_HARDWARE +ACPI_MODULE_NAME("hwregs") + +/******************************************************************************* + * + * FUNCTION: acpi_hw_clear_acpi_status + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Clears all fixed and general purpose status bits + * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * + ******************************************************************************/ +acpi_status acpi_hw_clear_acpi_status(void) +{ + acpi_status status; + acpi_cpu_flags lock_flags = 0; + + ACPI_FUNCTION_TRACE(hw_clear_acpi_status); + + ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", + ACPI_BITMASK_ALL_FIXED_STATUS, + (u16) acpi_gbl_FADT.xpm1a_event_block.address)); + + lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + + status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, + ACPI_BITMASK_ALL_FIXED_STATUS); + if (ACPI_FAILURE(status)) { + goto unlock_and_exit; + } + + /* Clear the fixed events */ + + if (acpi_gbl_FADT.xpm1b_event_block.address) { + status = acpi_write(ACPI_BITMASK_ALL_FIXED_STATUS, + &acpi_gbl_FADT.xpm1b_event_block); + if (ACPI_FAILURE(status)) { + goto unlock_and_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); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_hw_get_register_bit_mask + * + * PARAMETERS: register_id - Index of ACPI Register to access + * + * RETURN: The bitmask to be used when accessing the register + * + * DESCRIPTION: Map register_id into a register bitmask. + * + ******************************************************************************/ + +struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) +{ + ACPI_FUNCTION_ENTRY(); + + if (register_id > ACPI_BITREG_MAX) { + ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", + register_id)); + return (NULL); + } + + return (&acpi_gbl_bit_register_info[register_id]); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_register_read + * + * PARAMETERS: register_id - ACPI Register ID + * return_value - Where the register value is returned + * + * RETURN: Status and the value read. + * + * DESCRIPTION: Read from the specified ACPI register + * + ******************************************************************************/ +acpi_status +acpi_hw_register_read(u32 register_id, u32 * return_value) +{ + u32 value1 = 0; + u32 value2 = 0; + acpi_status status; + + ACPI_FUNCTION_TRACE(hw_register_read); + + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_event_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_event_block); + value1 |= value2; + break; + + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_xpm1a_enable); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_read(&value2, &acpi_gbl_xpm1b_enable); + value1 |= value2; + break; + + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm1a_control_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + status = acpi_read(&value2, &acpi_gbl_FADT.xpm1b_control_block); + value1 |= value2; + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm2_control_block); + break; + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + status = acpi_read(&value1, &acpi_gbl_FADT.xpm_timer_block); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + status = + acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); + break; + + default: + ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); + status = AE_BAD_PARAMETER; + break; + } + + exit: + + if (ACPI_SUCCESS(status)) { + *return_value = value1; + } + + return_ACPI_STATUS(status); +} + +/****************************************************************************** + * + * FUNCTION: acpi_hw_register_write + * + * PARAMETERS: register_id - ACPI Register ID + * Value - The value to write + * + * RETURN: Status + * + * DESCRIPTION: Write to the specified ACPI register + * + * NOTE: In accordance with the ACPI specification, this function automatically + * preserves the value of the following bits, meaning that these bits cannot be + * changed via this interface: + * + * PM1_CONTROL[0] = SCI_EN + * PM1_CONTROL[9] + * PM1_STATUS[11] + * + * ACPI References: + * 1) Hardware Ignored Bits: When software writes to a register with ignored + * bit fields, it preserves the ignored bit fields + * 2) SCI_EN: OSPM always preserves this bit position + * + ******************************************************************************/ + +acpi_status acpi_hw_register_write(u32 register_id, u32 value) +{ + acpi_status status; + u32 read_value; + + ACPI_FUNCTION_TRACE(hw_register_write); + + switch (register_id) { + case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ + + /* Perform a read first to preserve certain bits (per ACPI spec) */ + + status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, + &read_value); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS, + read_value); + + /* Now we can write the data */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_event_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_event_block); + break; + + case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_xpm1a_enable); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* PM1B is optional */ + + status = acpi_write(value, &acpi_gbl_xpm1b_enable); + break; + + case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ + + /* + * Perform a read first to preserve certain bits (per ACPI spec) + */ + status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, + &read_value); + if (ACPI_FAILURE(status)) { + goto exit; + } + + /* Insert the bits to be preserved */ + + ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, + read_value); + + /* Now we can write the data */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block); + if (ACPI_FAILURE(status)) { + goto exit; + } + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block); + break; + + case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1a_control_block); + break; + + case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm1b_control_block); + break; + + case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm2_control_block); + break; + + case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ + + status = acpi_write(value, &acpi_gbl_FADT.xpm_timer_block); + break; + + case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + + /* SMI_CMD is currently always in IO space */ + + status = + acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); + break; + + default: + status = AE_BAD_PARAMETER; + break; + } + + exit: + return_ACPI_STATUS(status); +} diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index 25dccdf179b..a2af2a4f2f2 100644 --- a/drivers/acpi/hardware/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwsleep") @@ -52,31 +53,19 @@ ACPI_MODULE_NAME("hwsleep") * * FUNCTION: acpi_set_firmware_waking_vector * - * PARAMETERS: physical_address - Physical address of ACPI real mode + * PARAMETERS: physical_address - 32-bit physical address of ACPI real mode * entry point. * * RETURN: Status * - * DESCRIPTION: Access function for the firmware_waking_vector field in FACS + * DESCRIPTION: Sets the 32-bit firmware_waking_vector field of the FACS * ******************************************************************************/ acpi_status -acpi_set_firmware_waking_vector(acpi_physical_address physical_address) +acpi_set_firmware_waking_vector(u32 physical_address) { - struct acpi_table_facs *facs; - acpi_status status; - ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector); - /* Get the FACS */ - - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); - } /* * According to the ACPI specification 2.0c and later, the 64-bit @@ -85,10 +74,16 @@ acpi_set_firmware_waking_vector(acpi_physical_address physical_address) * Protected Mode. Some systems (for example HP dv5-1004nr) are known * to fail to resume if the 64-bit vector is used. */ - if (facs->version >= 1) - facs->xfirmware_waking_vector = 0; - facs->firmware_waking_vector = (u32)physical_address; + /* Set the 32-bit vector */ + + acpi_gbl_FACS->firmware_waking_vector = physical_address; + + /* Clear the 64-bit vector if it exists */ + + if ((acpi_gbl_FACS->length > 32) && (acpi_gbl_FACS->version >= 1)) { + acpi_gbl_FACS->xfirmware_waking_vector = 0; + } return_ACPI_STATUS(AE_OK); } @@ -97,48 +92,39 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector) /******************************************************************************* * - * FUNCTION: acpi_get_firmware_waking_vector + * FUNCTION: acpi_set_firmware_waking_vector64 * - * PARAMETERS: *physical_address - Where the contents of - * the firmware_waking_vector field of - * the FACS will be returned. + * PARAMETERS: physical_address - 64-bit physical address of ACPI protected + * mode entry point. * - * RETURN: Status, vector + * RETURN: Status * - * DESCRIPTION: Access function for the firmware_waking_vector field in FACS + * DESCRIPTION: Sets the 64-bit X_firmware_waking_vector field of the FACS, if + * it exists in the table. * ******************************************************************************/ -#ifdef ACPI_FUTURE_USAGE acpi_status -acpi_get_firmware_waking_vector(acpi_physical_address * physical_address) +acpi_set_firmware_waking_vector64(u64 physical_address) { - struct acpi_table_facs *facs; - acpi_status status; + ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector64); - ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector); - - if (!physical_address) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - /* Get the FACS */ + /* Determine if the 64-bit vector actually exists */ - status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &facs)); - if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + if ((acpi_gbl_FACS->length <= 32) || (acpi_gbl_FACS->version < 1)) { + return_ACPI_STATUS(AE_NOT_EXIST); } - /* Get the vector */ - *physical_address = (acpi_physical_address)facs->firmware_waking_vector; + /* Clear 32-bit vector, set the 64-bit X_ vector */ + + acpi_gbl_FACS->firmware_waking_vector = 0; + acpi_gbl_FACS->xfirmware_waking_vector = physical_address; return_ACPI_STATUS(AE_OK); } -ACPI_EXPORT_SYMBOL(acpi_get_firmware_waking_vector) -#endif +ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector64) + /******************************************************************************* * * FUNCTION: acpi_enter_sleep_state_prep diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index b53d575491b..b7f522c8f02 100644 --- a/drivers/acpi/hardware/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -43,6 +43,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_HARDWARE ACPI_MODULE_NAME("hwtimer") diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/acpica/hwxface.c index ddf792adcf9..ae597c0ab53 100644 --- a/drivers/acpi/hardware/hwregs.c +++ b/drivers/acpi/acpica/hwxface.c @@ -1,10 +1,9 @@ -/******************************************************************************* +/****************************************************************************** * - * Module Name: hwregs - Read/write access functions for the various ACPI - * control and status registers. + * Module Name: hwxface - Public ACPICA hardware interfaces * - ******************************************************************************/ + *****************************************************************************/ /* * Copyright (C) 2000 - 2008, Intel Corp. @@ -44,209 +43,208 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_HARDWARE -ACPI_MODULE_NAME("hwregs") +ACPI_MODULE_NAME("hwxface") -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_hw_clear_acpi_status + * FUNCTION: acpi_reset * * PARAMETERS: None * - * RETURN: None + * RETURN: Status * - * DESCRIPTION: Clears all fixed and general purpose status bits - * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED + * DESCRIPTION: Set reset register in memory or IO space. Note: Does not + * support reset register in PCI config space, this must be + * handled separately. * ******************************************************************************/ -acpi_status acpi_hw_clear_acpi_status(void) +acpi_status acpi_reset(void) { + struct acpi_generic_address *reset_reg; acpi_status status; - acpi_cpu_flags lock_flags = 0; - ACPI_FUNCTION_TRACE(hw_clear_acpi_status); + ACPI_FUNCTION_TRACE(acpi_reset); - ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n", - ACPI_BITMASK_ALL_FIXED_STATUS, - (u16) acpi_gbl_FADT.xpm1a_event_block.address)); + reset_reg = &acpi_gbl_FADT.reset_register; - lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); + /* Check if the reset register is supported */ - status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, - ACPI_BITMASK_ALL_FIXED_STATUS); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + if (!(acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) || + !reset_reg->address) { + return_ACPI_STATUS(AE_NOT_EXIST); } - /* Clear the fixed events */ - - if (acpi_gbl_FADT.xpm1b_event_block.address) { - status = - acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS, - &acpi_gbl_FADT.xpm1b_event_block); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } - } - - /* Clear the GPE Bits in all GPE registers in all GPE blocks */ - - status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block); + /* Write the reset value to the reset register */ - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg); return_ACPI_STATUS(status); } -/******************************************************************************* +ACPI_EXPORT_SYMBOL(acpi_reset) + +/****************************************************************************** * - * FUNCTION: acpi_get_sleep_type_data + * FUNCTION: acpi_read * - * PARAMETERS: sleep_state - Numeric sleep state - * *sleep_type_a - Where SLP_TYPa is returned - * *sleep_type_b - Where SLP_TYPb is returned + * PARAMETERS: Value - Where the value is returned + * Reg - GAS register structure * - * RETURN: Status - ACPI status + * RETURN: Status * - * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep - * state. + * DESCRIPTION: Read from either memory or IO space. * ******************************************************************************/ - -acpi_status -acpi_get_sleep_type_data(u8 sleep_state, u8 * sleep_type_a, u8 * sleep_type_b) +acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg) { - acpi_status status = AE_OK; - struct acpi_evaluate_info *info; - - ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); - - /* Validate parameters */ - - if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { - return_ACPI_STATUS(AE_BAD_PARAMETER); - } + u32 width; + u64 address; + acpi_status status; - /* Allocate the evaluation information block */ + ACPI_FUNCTION_NAME(acpi_read); - info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); - if (!info) { - return_ACPI_STATUS(AE_NO_MEMORY); + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if (!reg) { + return (AE_OK); } - info->pathname = - ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); - - /* Evaluate the namespace object containing the values for this state */ - - status = acpi_ns_evaluate(info); - if (ACPI_FAILURE(status)) { - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "%s while evaluating SleepState [%s]\n", - acpi_format_exception(status), - info->pathname)); + /* Get a local copy of the address. Handles possible alignment issues */ - goto cleanup; + ACPI_MOVE_64_TO_64(&address, ®->address); + if (!address) { + return (AE_OK); } - /* Must have a return object */ + /* Supported widths are 8/16/32 */ - if (!info->return_object) { - ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", - info->pathname)); - status = AE_NOT_EXIST; + width = reg->bit_width; + if ((width != 8) && (width != 16) && (width != 32)) { + return (AE_SUPPORT); } - /* It must be of type Package */ + /* Initialize entire 32-bit return value to zero */ - else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) { - ACPI_ERROR((AE_INFO, - "Sleep State return object is not a Package")); - status = AE_AML_OPERAND_TYPE; - } + *value = 0; /* - * The package must have at least two elements. NOTE (March 2005): This - * goes against the current ACPI spec which defines this object as a - * package with one encoded DWORD element. However, existing practice - * by BIOS vendors seems to be to have 2 or more elements, at least - * one per sleep type (A/B). + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient */ - else if (info->return_object->package.count < 2) { - ACPI_ERROR((AE_INFO, - "Sleep State return package does not have at least two elements")); - status = AE_AML_NO_OPERAND; - } + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* The first two elements must both be of type Integer */ + status = acpi_os_read_memory((acpi_physical_address) address, + value, width); + break; - else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0]) - != ACPI_TYPE_INTEGER) || - (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1]) - != ACPI_TYPE_INTEGER)) { - ACPI_ERROR((AE_INFO, - "Sleep State return package elements are not both Integers (%s, %s)", - acpi_ut_get_object_type_name(info->return_object-> - package.elements[0]), - acpi_ut_get_object_type_name(info->return_object-> - package.elements[1]))); - status = AE_AML_OPERAND_TYPE; - } else { - /* Valid _Sx_ package size, type, and value */ + case ACPI_ADR_SPACE_SYSTEM_IO: - *sleep_type_a = (u8) - (info->return_object->package.elements[0])->integer.value; - *sleep_type_b = (u8) - (info->return_object->package.elements[1])->integer.value; - } + status = + acpi_os_read_port((acpi_io_address) address, value, width); + break; - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "While evaluating SleepState [%s], bad Sleep object %p type %s", - info->pathname, info->return_object, - acpi_ut_get_object_type_name(info-> - return_object))); + default: + ACPI_ERROR((AE_INFO, + "Unsupported address space: %X", reg->space_id)); + return (AE_BAD_PARAMETER); } - acpi_ut_remove_reference(info->return_object); + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", + *value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); - cleanup: - ACPI_FREE(info); - return_ACPI_STATUS(status); + return (status); } -ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) +ACPI_EXPORT_SYMBOL(acpi_read) -/******************************************************************************* +/****************************************************************************** * - * FUNCTION: acpi_hw_get_register_bit_mask + * FUNCTION: acpi_write * - * PARAMETERS: register_id - Index of ACPI Register to access + * PARAMETERS: Value - To be written + * Reg - GAS register structure * - * RETURN: The bitmask to be used when accessing the register + * RETURN: Status * - * DESCRIPTION: Map register_id into a register bitmask. + * DESCRIPTION: Write to either memory or IO space. * ******************************************************************************/ -struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) +acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) { - ACPI_FUNCTION_ENTRY(); + u32 width; + u64 address; + acpi_status status; - if (register_id > ACPI_BITREG_MAX) { - ACPI_ERROR((AE_INFO, "Invalid BitRegister ID: %X", - register_id)); - return (NULL); + ACPI_FUNCTION_NAME(acpi_write); + + /* + * Must have a valid pointer to a GAS structure, and + * a non-zero address within. However, don't return an error + * because the PM1A/B code must not fail if B isn't present. + */ + if (!reg) { + return (AE_OK); } - return (&acpi_gbl_bit_register_info[register_id]); + /* Get a local copy of the address. Handles possible alignment issues */ + + ACPI_MOVE_64_TO_64(&address, ®->address); + if (!address) { + return (AE_OK); + } + + /* Supported widths are 8/16/32 */ + + width = reg->bit_width; + if ((width != 8) && (width != 16) && (width != 32)) { + return (AE_SUPPORT); + } + + /* + * Two address spaces supported: Memory or IO. + * PCI_Config is not supported here because the GAS struct is insufficient + */ + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + + status = acpi_os_write_memory((acpi_physical_address) address, + value, width); + break; + + case ACPI_ADR_SPACE_SYSTEM_IO: + + status = acpi_os_write_port((acpi_io_address) address, value, + width); + break; + + default: + ACPI_ERROR((AE_INFO, + "Unsupported address space: %X", reg->space_id)); + return (AE_BAD_PARAMETER); + } + + ACPI_DEBUG_PRINT((ACPI_DB_IO, + "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", + value, width, ACPI_FORMAT_UINT64(address), + acpi_ut_get_region_name(reg->space_id))); + + return (status); } +ACPI_EXPORT_SYMBOL(acpi_write) + /******************************************************************************* * - * FUNCTION: acpi_get_register + * FUNCTION: acpi_get_register_unlocked * * PARAMETERS: register_id - ID of ACPI bit_register to access * return_value - Value that was read from the register @@ -254,17 +252,16 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id) * RETURN: Status and the value read from specified Register. Value * returned is normalized to bit0 (is shifted all the way right) * - * DESCRIPTION: ACPI bit_register read function. + * DESCRIPTION: ACPI bit_register read function. Does not acquire the HW lock. * ******************************************************************************/ - -acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value) +acpi_status acpi_get_register_unlocked(u32 register_id, u32 *return_value) { u32 register_value = 0; struct acpi_bit_register_info *bit_reg_info; acpi_status status; - ACPI_FUNCTION_TRACE(acpi_get_register); + ACPI_FUNCTION_TRACE(acpi_get_register_unlocked); /* Get the info structure corresponding to the requested ACPI Register */ @@ -296,14 +293,31 @@ acpi_status acpi_get_register_unlocked(u32 register_id, u32 * return_value) return_ACPI_STATUS(status); } -acpi_status acpi_get_register(u32 register_id, u32 * return_value) +ACPI_EXPORT_SYMBOL(acpi_get_register_unlocked) + +/******************************************************************************* + * + * FUNCTION: acpi_get_register + * + * PARAMETERS: register_id - ID of ACPI bit_register to access + * return_value - Value that was read from the register + * + * RETURN: Status and the value read from specified Register. Value + * returned is normalized to bit0 (is shifted all the way right) + * + * DESCRIPTION: ACPI bit_register read function. + * + ******************************************************************************/ +acpi_status acpi_get_register(u32 register_id, u32 *return_value) { acpi_status status; acpi_cpu_flags flags; + flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); status = acpi_get_register_unlocked(register_id, return_value); acpi_os_release_lock(acpi_gbl_hardware_lock, flags); - return status; + + return (status); } ACPI_EXPORT_SYMBOL(acpi_get_register) @@ -370,8 +384,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value) bit_reg_info-> access_bit_mask); if (value) { - status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, - (u16) value); + status = + acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, + (u16) value); register_value = 0; } break; @@ -459,399 +474,120 @@ acpi_status acpi_set_register(u32 register_id, u32 value) ACPI_EXPORT_SYMBOL(acpi_set_register) -/****************************************************************************** +/******************************************************************************* * - * FUNCTION: acpi_hw_register_read + * FUNCTION: acpi_get_sleep_type_data * - * PARAMETERS: register_id - ACPI Register ID - * return_value - Where the register value is returned + * PARAMETERS: sleep_state - Numeric sleep state + * *sleep_type_a - Where SLP_TYPa is returned + * *sleep_type_b - Where SLP_TYPb is returned * - * RETURN: Status and the value read. + * RETURN: Status - ACPI status * - * DESCRIPTION: Read from the specified ACPI register + * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep + * state. * ******************************************************************************/ acpi_status -acpi_hw_register_read(u32 register_id, u32 * return_value) +acpi_get_sleep_type_data(u8 sleep_state, u8 *sleep_type_a, u8 *sleep_type_b) { - u32 value1 = 0; - u32 value2 = 0; - acpi_status status; - - ACPI_FUNCTION_TRACE(hw_register_read); - - switch (register_id) { - case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT.xpm1a_event_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT.xpm1b_event_block); - value1 |= value2; - break; - - case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable); - value1 |= value2; - break; - - case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_read(16, &value1, - &acpi_gbl_FADT.xpm1a_control_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - status = - acpi_hw_low_level_read(16, &value2, - &acpi_gbl_FADT.xpm1b_control_block); - value1 |= value2; - break; - - case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - - status = - acpi_hw_low_level_read(8, &value1, - &acpi_gbl_FADT.xpm2_control_block); - break; - - case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - - status = - acpi_hw_low_level_read(32, &value1, - &acpi_gbl_FADT.xpm_timer_block); - break; + acpi_status status = AE_OK; + struct acpi_evaluate_info *info; - case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + ACPI_FUNCTION_TRACE(acpi_get_sleep_type_data); - status = - acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8); - break; + /* Validate parameters */ - default: - ACPI_ERROR((AE_INFO, "Unknown Register ID: %X", register_id)); - status = AE_BAD_PARAMETER; - break; + if ((sleep_state > ACPI_S_STATES_MAX) || !sleep_type_a || !sleep_type_b) { + return_ACPI_STATUS(AE_BAD_PARAMETER); } - exit: + /* Allocate the evaluation information block */ - if (ACPI_SUCCESS(status)) { - *return_value = value1; + info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); + if (!info) { + return_ACPI_STATUS(AE_NO_MEMORY); } - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_register_write - * - * PARAMETERS: register_id - ACPI Register ID - * Value - The value to write - * - * RETURN: Status - * - * DESCRIPTION: Write to the specified ACPI register - * - * NOTE: In accordance with the ACPI specification, this function automatically - * preserves the value of the following bits, meaning that these bits cannot be - * changed via this interface: - * - * PM1_CONTROL[0] = SCI_EN - * PM1_CONTROL[9] - * PM1_STATUS[11] - * - * ACPI References: - * 1) Hardware Ignored Bits: When software writes to a register with ignored - * bit fields, it preserves the ignored bit fields - * 2) SCI_EN: OSPM always preserves this bit position - * - ******************************************************************************/ - -acpi_status acpi_hw_register_write(u32 register_id, u32 value) -{ - acpi_status status; - u32 read_value; - - ACPI_FUNCTION_TRACE(hw_register_write); - - switch (register_id) { - case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ - - /* Perform a read first to preserve certain bits (per ACPI spec) */ - - status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS, - &read_value); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* Insert the bits to be preserved */ - - ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS, - read_value); - - /* Now we can write the data */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_event_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_event_block); - break; - - case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* PM1B is optional */ - - status = - acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable); - break; - - case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ - - /* - * Perform a read first to preserve certain bits (per ACPI spec) - */ - status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL, - &read_value); - if (ACPI_FAILURE(status)) { - goto exit; - } - - /* Insert the bits to be preserved */ - - ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS, - read_value); - - /* Now we can write the data */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_control_block); - if (ACPI_FAILURE(status)) { - goto exit; - } - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_control_block); - break; - - case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1a_control_block); - break; - - case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ - - status = - acpi_hw_low_level_write(16, value, - &acpi_gbl_FADT.xpm1b_control_block); - break; - - case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ - - status = - acpi_hw_low_level_write(8, value, - &acpi_gbl_FADT.xpm2_control_block); - break; - - case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ - - status = - acpi_hw_low_level_write(32, value, - &acpi_gbl_FADT.xpm_timer_block); - break; - - case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ + info->pathname = + ACPI_CAST_PTR(char, acpi_gbl_sleep_state_names[sleep_state]); - /* SMI_CMD is currently always in IO space */ + /* Evaluate the namespace object containing the values for this state */ - status = - acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8); - break; + status = acpi_ns_evaluate(info); + if (ACPI_FAILURE(status)) { + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, + "%s while evaluating SleepState [%s]\n", + acpi_format_exception(status), + info->pathname)); - default: - status = AE_BAD_PARAMETER; - break; + goto cleanup; } - exit: - return_ACPI_STATUS(status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_low_level_read - * - * PARAMETERS: Width - 8, 16, or 32 - * Value - Where the value is returned - * Reg - GAS register structure - * - * RETURN: Status - * - * DESCRIPTION: Read from either memory or IO space. - * - ******************************************************************************/ - -acpi_status -acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg) -{ - u64 address; - acpi_status status; - - ACPI_FUNCTION_NAME(hw_low_level_read); + /* Must have a return object */ - /* - * Must have a valid pointer to a GAS structure, and - * a non-zero address within. However, don't return an error - * because the PM1A/B code must not fail if B isn't present. - */ - if (!reg) { - return (AE_OK); + if (!info->return_object) { + ACPI_ERROR((AE_INFO, "No Sleep State object returned from [%s]", + info->pathname)); + status = AE_NOT_EXIST; } - /* Get a local copy of the address. Handles possible alignment issues */ + /* It must be of type Package */ - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_OK); + else if (ACPI_GET_OBJECT_TYPE(info->return_object) != ACPI_TYPE_PACKAGE) { + ACPI_ERROR((AE_INFO, + "Sleep State return object is not a Package")); + status = AE_AML_OPERAND_TYPE; } - *value = 0; /* - * Two address spaces supported: Memory or IO. - * PCI_Config is not supported here because the GAS struct is insufficient + * The package must have at least two elements. NOTE (March 2005): This + * goes against the current ACPI spec which defines this object as a + * package with one encoded DWORD element. However, existing practice + * by BIOS vendors seems to be to have 2 or more elements, at least + * one per sleep type (A/B). */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - - status = acpi_os_read_memory((acpi_physical_address) address, - value, width); - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - - status = - acpi_os_read_port((acpi_io_address) address, value, width); - break; - - default: + else if (info->return_object->package.count < 2) { ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + "Sleep State return package does not have at least two elements")); + status = AE_AML_NO_OPERAND; } - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", - *value, width, ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->space_id))); - - return (status); -} - -/****************************************************************************** - * - * FUNCTION: acpi_hw_low_level_write - * - * PARAMETERS: Width - 8, 16, or 32 - * Value - To be written - * Reg - GAS register structure - * - * RETURN: Status - * - * DESCRIPTION: Write to either memory or IO space. - * - ******************************************************************************/ - -acpi_status -acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg) -{ - u64 address; - acpi_status status; - - ACPI_FUNCTION_NAME(hw_low_level_write); - - /* - * Must have a valid pointer to a GAS structure, and - * a non-zero address within. However, don't return an error - * because the PM1A/B code must not fail if B isn't present. - */ - if (!reg) { - return (AE_OK); - } + /* The first two elements must both be of type Integer */ - /* Get a local copy of the address. Handles possible alignment issues */ + else if ((ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[0]) + != ACPI_TYPE_INTEGER) || + (ACPI_GET_OBJECT_TYPE(info->return_object->package.elements[1]) + != ACPI_TYPE_INTEGER)) { + ACPI_ERROR((AE_INFO, + "Sleep State return package elements are not both Integers (%s, %s)", + acpi_ut_get_object_type_name(info->return_object-> + package.elements[0]), + acpi_ut_get_object_type_name(info->return_object-> + package.elements[1]))); + status = AE_AML_OPERAND_TYPE; + } else { + /* Valid _Sx_ package size, type, and value */ - ACPI_MOVE_64_TO_64(&address, ®->address); - if (!address) { - return (AE_OK); + *sleep_type_a = (u8) + (info->return_object->package.elements[0])->integer.value; + *sleep_type_b = (u8) + (info->return_object->package.elements[1])->integer.value; } - /* - * Two address spaces supported: Memory or IO. - * PCI_Config is not supported here because the GAS struct is insufficient - */ - switch (reg->space_id) { - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - - status = acpi_os_write_memory((acpi_physical_address) address, - value, width); - break; - - case ACPI_ADR_SPACE_SYSTEM_IO: - - status = acpi_os_write_port((acpi_io_address) address, value, - width); - break; - - default: - ACPI_ERROR((AE_INFO, - "Unsupported address space: %X", reg->space_id)); - return (AE_BAD_PARAMETER); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "While evaluating SleepState [%s], bad Sleep object %p type %s", + info->pathname, info->return_object, + acpi_ut_get_object_type_name(info-> + return_object))); } - ACPI_DEBUG_PRINT((ACPI_DB_IO, - "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, width, ACPI_FORMAT_UINT64(address), - acpi_ut_get_region_name(reg->space_id))); + acpi_ut_remove_reference(info->return_object); - return (status); + cleanup: + ACPI_FREE(info); + return_ACPI_STATUS(status); } + +ACPI_EXPORT_SYMBOL(acpi_get_sleep_type_data) diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index c39a7f68b88..88303ebe924 100644 --- a/drivers/acpi/namespace/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsaccess") @@ -165,12 +166,9 @@ acpi_status acpi_ns_root_initialize(void) obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY; - -#ifndef ACPI_DUMP_APP obj_desc->method.implementation = acpi_ut_osi_implementation; #endif -#endif break; case ACPI_TYPE_INTEGER: @@ -521,11 +519,11 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, } /* - * Search namespace for each segment of the name. Loop through and + * Search namespace for each segment of the name. Loop through and * verify (or add to the namespace) each name segment. * * The object type is significant only at the last name - * segment. (We don't care about the types along the path, only + * segment. (We don't care about the types along the path, only * the type of the final target object.) */ this_search_type = ACPI_TYPE_ANY; @@ -591,6 +589,10 @@ acpi_ns_lookup(union acpi_generic_state *scope_info, * segments). */ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) { + if (!this_node->object) { + return_ACPI_STATUS(AE_NOT_EXIST); + } + if (acpi_ns_opens_scope (((struct acpi_namespace_node *)this_node-> object)->type)) { diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 3a1740ac2ed..f976d848fe8 100644 --- a/drivers/acpi/namespace/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsalloc") diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/acpica/nsdump.c index cc0ae39440e..0da33c8e9ba 100644 --- a/drivers/acpi/namespace/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsdump") diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 428f50fde11..41994fe7fbb 100644 --- a/drivers/acpi/namespace/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" /* TBD: This entire module is apparently obsolete and should be removed */ @@ -49,7 +50,7 @@ ACPI_MODULE_NAME("nsdumpdv") #ifdef ACPI_OBSOLETE_FUNCTIONS #if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) -#include <acpi/acnamesp.h> +#include "acnamesp.h" /******************************************************************************* * * FUNCTION: acpi_ns_dump_one_device diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/acpica/nseval.c index 4cdf03ac2b4..0f3d5f9b596 100644 --- a/drivers/acpi/namespace/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acparser.h" +#include "acinterp.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nseval") @@ -89,6 +90,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) /* Initialize the return value to an invalid object */ info->return_object = NULL; + info->param_count = 0; /* * Get the actual namespace node for the target object. Handles these cases: @@ -141,41 +143,17 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) return_ACPI_STATUS(AE_NULL_OBJECT); } - /* - * Calculate the number of arguments being passed to the method - */ + /* Count the number of arguments being passed to the method */ - info->param_count = 0; if (info->parameters) { - while (info->parameters[info->param_count]) + while (info->parameters[info->param_count]) { + if (info->param_count > ACPI_METHOD_MAX_ARG) { + return_ACPI_STATUS(AE_LIMIT); + } info->param_count++; + } } - /* - * Warning if too few or too many arguments have been passed by the - * caller. We don't want to abort here with an error because an - * incorrect number of arguments may not cause the method to fail. - * However, the method will fail if there are too few arguments passed - * and the method attempts to use one of the missing ones. - */ - - if (info->param_count < info->obj_desc->method.param_count) { - ACPI_WARNING((AE_INFO, - "Insufficient arguments - " - "method [%4.4s] needs %d, found %d", - acpi_ut_get_node_name(info->resolved_node), - info->obj_desc->method.param_count, - info->param_count)); - } else if (info->param_count > - info->obj_desc->method.param_count) { - ACPI_WARNING((AE_INFO, - "Excess arguments - " - "method [%4.4s] needs %d, found %d", - acpi_ut_get_node_name(info-> - resolved_node), - info->obj_desc->method.param_count, - info->param_count)); - } ACPI_DUMP_PATHNAME(info->resolved_node, "Execute Method:", ACPI_LV_INFO, _COMPONENT); @@ -264,32 +242,13 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info * info) } } - /* Validation of return values for ACPI-predefined methods and objects */ - - if ((status == AE_OK) || (status == AE_CTRL_RETURN_VALUE)) { - /* - * If this is the first evaluation, check the return value. This - * ensures that any warnings will only be emitted during the very - * first evaluation of the object. - */ - if (!(node->flags & ANOBJ_EVALUATED)) { - /* - * Check for a predefined ACPI name. If found, validate the - * returned object. - * - * Note: Ignore return status for now, emit warnings if there are - * problems with the returned object. May change later to abort - * the method on invalid return object. - */ - (void)acpi_ns_check_predefined_names(node, - info-> - return_object); - } - - /* Mark the node as having been evaluated */ - - node->flags |= ANOBJ_EVALUATED; - } + /* + * Check input argument count against the ASL-defined count for a method. + * Also check predefined names: argument count and return value against + * the ACPI specification. Some incorrect return value types are repaired. + */ + (void)acpi_ns_check_predefined_names(node, info->param_count, + status, &info->return_object); /* Check if there is a return value that must be dealt with */ diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/acpica/nsinit.c index e4c57510d79..13501cb8186 100644 --- a/drivers/acpi/namespace/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "acinterp.h" #include <linux/nmi.h> #define _COMPONENT ACPI_NAMESPACE diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/acpica/nsload.c index a4a412b7c02..a0ba9e12379 100644 --- a/drivers/acpi/namespace/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acdispat.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsload") diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/acpica/nsnames.c index 42a39a7c96e..ae3dc10a7e8 100644 --- a/drivers/acpi/namespace/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "amlcode.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/acpica/nsobject.c index 15fe09e24f7..08a97a57f8f 100644 --- a/drivers/acpi/namespace/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsobject") diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/acpica/nsparse.c index a82271a9dbb..b9e8d0070b6 100644 --- a/drivers/acpi/namespace/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acparser.h" +#include "acdispat.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsparse") diff --git a/drivers/acpi/namespace/nspredef.c b/drivers/acpi/acpica/nspredef.c index 0f17cf0898c..452703290d3 100644 --- a/drivers/acpi/namespace/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acpredef.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acpredef.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nspredef") @@ -72,7 +73,7 @@ ACPI_MODULE_NAME("nspredef") /* Local prototypes */ static acpi_status acpi_ns_check_package(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, const union acpi_predefined_info *predefined); static acpi_status @@ -82,13 +83,18 @@ acpi_ns_check_package_elements(char *pathname, static acpi_status acpi_ns_check_object_type(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index); static acpi_status acpi_ns_check_reference(char *pathname, union acpi_operand_object *return_object); +static acpi_status +acpi_ns_repair_object(u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr); + /* * Names for the types that can be returned by the predefined objects. * Used for warning messages. Must be in the same order as the ACPI_RTYPEs @@ -108,8 +114,8 @@ static const char *acpi_rtype_names[] = { * FUNCTION: acpi_ns_check_predefined_names * * PARAMETERS: Node - Namespace node for the method/object - * return_object - Object returned from the evaluation of this - * method/object + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object * * RETURN: Status * @@ -119,8 +125,11 @@ static const char *acpi_rtype_names[] = { acpi_status acpi_ns_check_predefined_names(struct acpi_namespace_node *node, - union acpi_operand_object *return_object) + u32 user_param_count, + acpi_status return_status, + union acpi_operand_object **return_object_ptr) { + union acpi_operand_object *return_object = *return_object_ptr; acpi_status status = AE_OK; const union acpi_predefined_info *predefined; char *pathname; @@ -128,12 +137,6 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, /* Match the name for this method/object against the predefined list */ predefined = acpi_ns_check_for_predefined_name(node); - if (!predefined) { - - /* Name was not one of the predefined names */ - - return (AE_OK); - } /* Get the full pathname to the object, for use in error messages */ @@ -143,10 +146,37 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, } /* - * Check that the parameter count for this method is in accordance - * with the ACPI specification. + * Check that the parameter count for this method matches the ASL + * definition. For predefined names, ensure that both the caller and + * the method itself are in accordance with the ACPI specification. */ - acpi_ns_check_parameter_count(pathname, node, predefined); + acpi_ns_check_parameter_count(pathname, node, user_param_count, + predefined); + + /* If not a predefined name, we cannot validate the return object */ + + if (!predefined) { + goto exit; + } + + /* If the method failed, we cannot validate the return object */ + + if ((return_status != AE_OK) && (return_status != AE_CTRL_RETURN_VALUE)) { + goto exit; + } + + /* + * Only validate the return value on the first successful evaluation of + * the method. This ensures that any warnings will only be emitted during + * the very first evaluation of the method/object. + */ + if (node->flags & ANOBJ_EVALUATED) { + goto exit; + } + + /* Mark the node as having been successfully evaluated */ + + node->flags |= ANOBJ_EVALUATED; /* * If there is no return value, check if we require a return value for @@ -171,7 +201,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * We have a return value, but if one wasn't expected, just exit, this is * not a problem * - * For example, if "Implicit return value" is enabled, methods will + * For example, if the "Implicit Return" feature is enabled, methods will * always return a value */ if (!predefined->info.expected_btypes) { @@ -182,7 +212,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * Check that the type of the return object is what is expected for * this predefined name */ - status = acpi_ns_check_object_type(pathname, return_object, + status = acpi_ns_check_object_type(pathname, return_object_ptr, predefined->info.expected_btypes, ACPI_NOT_PACKAGE); if (ACPI_FAILURE(status)) { @@ -193,11 +223,12 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, if (ACPI_GET_OBJECT_TYPE(return_object) == ACPI_TYPE_PACKAGE) { status = - acpi_ns_check_package(pathname, return_object, predefined); + acpi_ns_check_package(pathname, return_object_ptr, + predefined); } exit: - if (pathname) { + if (pathname != predefined->info.name) { ACPI_FREE(pathname); } @@ -210,6 +241,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) * Node - Namespace node for the method/object + * user_param_count - Number of args passed in by the caller * Predefined - Pointer to entry in predefined name table * * RETURN: None @@ -223,32 +255,76 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, void acpi_ns_check_parameter_count(char *pathname, struct acpi_namespace_node *node, + u32 user_param_count, const union acpi_predefined_info *predefined) { u32 param_count; u32 required_params_current; u32 required_params_old; - /* - * Check that the ASL-defined parameter count is what is expected for - * this predefined name. - * - * Methods have 0-7 parameters. All other types have zero. - */ + /* Methods have 0-7 parameters. All other types have zero. */ + param_count = 0; if (node->type == ACPI_TYPE_METHOD) { param_count = node->object->method.param_count; } - /* Validate parameter count - allow two different legal counts (_SCP) */ + /* Argument count check for non-predefined methods/objects */ + + if (!predefined) { + /* + * Warning if too few or too many arguments have been passed by the + * caller. An incorrect number of arguments may not cause the method + * to fail. However, the method will fail if there are too few + * arguments and the method attempts to use one of the missing ones. + */ + if (user_param_count < param_count) { + ACPI_WARNING((AE_INFO, + "%s: Insufficient arguments - needs %d, found %d", + pathname, param_count, user_param_count)); + } else if (user_param_count > param_count) { + ACPI_WARNING((AE_INFO, + "%s: Excess arguments - needs %d, found %d", + pathname, param_count, user_param_count)); + } + return; + } + + /* Allow two different legal argument counts (_SCP, etc.) */ required_params_current = predefined->info.param_count & 0x0F; required_params_old = predefined->info.param_count >> 4; + if (user_param_count != ACPI_UINT32_MAX) { + + /* Validate the user-supplied parameter count */ + + if ((user_param_count != required_params_current) && + (user_param_count != required_params_old)) { + ACPI_WARNING((AE_INFO, + "%s: Parameter count mismatch - caller passed %d, ACPI requires %d", + pathname, user_param_count, + required_params_current)); + } + } + + /* + * Only validate the argument count on the first successful evaluation of + * the method. This ensures that any warnings will only be emitted during + * the very first evaluation of the method/object. + */ + if (node->flags & ANOBJ_EVALUATED) { + return; + } + + /* + * Check that the ASL-defined parameter count is what is expected for + * this predefined name. + */ if ((param_count != required_params_current) && (param_count != required_params_old)) { ACPI_WARNING((AE_INFO, - "%s: Parameter count mismatch - ASL declared %d, expected %d", + "%s: Parameter count mismatch - ASL declared %d, ACPI requires %d", pathname, param_count, required_params_current)); } } @@ -307,8 +383,8 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct * FUNCTION: acpi_ns_check_package * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) - * return_object - Object returned from the evaluation of a - * method or object + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object * Predefined - Pointer to entry in predefined name table * * RETURN: Status @@ -320,9 +396,10 @@ const union acpi_predefined_info *acpi_ns_check_for_predefined_name(struct static acpi_status acpi_ns_check_package(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, const union acpi_predefined_info *predefined) { + union acpi_operand_object *return_object = *return_object_ptr; const union acpi_predefined_info *package; union acpi_operand_object *sub_package; union acpi_operand_object **elements; @@ -408,7 +485,7 @@ acpi_ns_check_package(char *pathname, * elements must be of the same type */ for (i = 0; i < count; i++) { - status = acpi_ns_check_object_type(pathname, *elements, + status = acpi_ns_check_object_type(pathname, elements, package->ret_info. object_type1, i); if (ACPI_FAILURE(status)) { @@ -441,7 +518,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *elements, + elements, package-> ret_info3. object_type[i], @@ -454,7 +531,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *elements, + elements, package-> ret_info3. tail_object_type, @@ -471,7 +548,7 @@ acpi_ns_check_package(char *pathname, /* First element is the (Integer) count of sub-packages to follow */ - status = acpi_ns_check_object_type(pathname, *elements, + status = acpi_ns_check_object_type(pathname, elements, ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { return (status); @@ -509,7 +586,7 @@ acpi_ns_check_package(char *pathname, /* Each sub-object must be of type Package */ status = - acpi_ns_check_object_type(pathname, sub_package, + acpi_ns_check_object_type(pathname, &sub_package, ACPI_RTYPE_PACKAGE, i); if (ACPI_FAILURE(status)) { return (status); @@ -567,12 +644,8 @@ acpi_ns_check_package(char *pathname, for (j = 0; j < expected_count; j++) { status = acpi_ns_check_object_type(pathname, - sub_elements - [j], - package-> - ret_info2. - object_type - [j], j); + &sub_elements[j], + package->ret_info2.object_type[j], j); if (ACPI_FAILURE(status)) { return (status); } @@ -611,7 +684,7 @@ acpi_ns_check_package(char *pathname, status = acpi_ns_check_object_type(pathname, - *sub_elements, + sub_elements, ACPI_RTYPE_INTEGER, 0); if (ACPI_FAILURE(status)) { @@ -708,7 +781,7 @@ acpi_ns_check_package_elements(char *pathname, * The second group can have a count of zero. */ for (i = 0; i < count1; i++) { - status = acpi_ns_check_object_type(pathname, *this_element, + status = acpi_ns_check_object_type(pathname, this_element, type1, i); if (ACPI_FAILURE(status)) { return (status); @@ -717,7 +790,7 @@ acpi_ns_check_package_elements(char *pathname, } for (i = 0; i < count2; i++) { - status = acpi_ns_check_object_type(pathname, *this_element, + status = acpi_ns_check_object_type(pathname, this_element, type2, (i + count1)); if (ACPI_FAILURE(status)) { return (status); @@ -733,8 +806,8 @@ acpi_ns_check_package_elements(char *pathname, * FUNCTION: acpi_ns_check_object_type * * PARAMETERS: Pathname - Full pathname to the node (for error msgs) - * return_object - Object return from the execution of this - * method/object + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object * expected_btypes - Bitmap of expected return type(s) * package_index - Index of object within parent package (if * applicable - ACPI_NOT_PACKAGE otherwise) @@ -748,9 +821,10 @@ acpi_ns_check_package_elements(char *pathname, static acpi_status acpi_ns_check_object_type(char *pathname, - union acpi_operand_object *return_object, + union acpi_operand_object **return_object_ptr, u32 expected_btypes, u32 package_index) { + union acpi_operand_object *return_object = *return_object_ptr; acpi_status status = AE_OK; u32 return_btype; char type_buffer[48]; /* Room for 5 types */ @@ -814,6 +888,14 @@ acpi_ns_check_object_type(char *pathname, /* Is the object one of the expected types? */ if (!(return_btype & expected_btypes)) { + + /* Type mismatch -- attempt repair of the returned object */ + + status = acpi_ns_repair_object(expected_btypes, package_index, + return_object_ptr); + if (ACPI_SUCCESS(status)) { + return (status); + } goto type_error_exit; } @@ -898,3 +980,86 @@ acpi_ns_check_reference(char *pathname, return (AE_AML_OPERAND_TYPE); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_repair_object + * + * PARAMETERS: Pathname - Full pathname to the node (for error msgs) + * package_index - Used to determine if target is in a package + * return_object_ptr - Pointer to the object returned from the + * evaluation of a method or object + * + * RETURN: Status. AE_OK if repair was successful. + * + * DESCRIPTION: Attempt to repair/convert a return object of a type that was + * not expected. + * + ******************************************************************************/ + +static acpi_status +acpi_ns_repair_object(u32 expected_btypes, + u32 package_index, + union acpi_operand_object **return_object_ptr) +{ + union acpi_operand_object *return_object = *return_object_ptr; + union acpi_operand_object *new_object; + acpi_size length; + + switch (ACPI_GET_OBJECT_TYPE(return_object)) { + case ACPI_TYPE_BUFFER: + + if (!(expected_btypes & ACPI_RTYPE_STRING)) { + return (AE_AML_OPERAND_TYPE); + } + + /* + * Have a Buffer, expected a String, convert. Use a to_string + * conversion, no transform performed on the buffer data. The best + * example of this is the _BIF method, where the string data from + * the battery is often (incorrectly) returned as buffer object(s). + */ + length = 0; + while ((length < return_object->buffer.length) && + (return_object->buffer.pointer[length])) { + length++; + } + + /* Allocate a new string object */ + + new_object = acpi_ut_create_string_object(length); + if (!new_object) { + return (AE_NO_MEMORY); + } + + /* + * Copy the raw buffer data with no transform. String is already NULL + * terminated at Length+1. + */ + ACPI_MEMCPY(new_object->string.pointer, + return_object->buffer.pointer, length); + + /* Install the new return object */ + + acpi_ut_remove_reference(return_object); + *return_object_ptr = new_object; + + /* + * If the object is a package element, we need to: + * 1. Decrement the reference count of the orignal object, it was + * incremented when building the package + * 2. Increment the reference count of the new object, it will be + * decremented when releasing the package + */ + if (package_index != ACPI_NOT_PACKAGE) { + acpi_ut_remove_reference(return_object); + acpi_ut_add_reference(new_object); + } + return (AE_OK); + + default: + break; + } + + return (AE_AML_OPERAND_TYPE); +} diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/acpica/nssearch.c index a9a80bf811b..6fea13f3f52 100644 --- a/drivers/acpi/namespace/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nssearch") diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/acpica/nsutils.c index b0817e1127b..3e1149bf4aa 100644 --- a/drivers/acpi/namespace/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -43,9 +43,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/amlcode.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "amlcode.h" +#include "actables.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsutils") @@ -314,9 +315,15 @@ void acpi_ns_get_internal_name_length(struct acpi_namestring_info *info) * * strlen() + 1 covers the first name_seg, which has no path separator */ - if (acpi_ns_valid_root_prefix(next_external_char[0])) { + if (acpi_ns_valid_root_prefix(*next_external_char)) { info->fully_qualified = TRUE; next_external_char++; + + /* Skip redundant root_prefix, like \\_SB.PCI0.SBRG.EC0 */ + + while (acpi_ns_valid_root_prefix(*next_external_char)) { + next_external_char++; + } } else { /* * Handle Carat prefixes diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/acpica/nswalk.c index 3c905ce26d7..200895fa272 100644 --- a/drivers/acpi/namespace/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nswalk") diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index a085cc39c05..22a7171ac1e 100644 --- a/drivers/acpi/namespace/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfeval") diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 5efa4e7ddb0..9589fea2499 100644 --- a/drivers/acpi/namespace/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfname") diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 2b375ee80ce..1c7efc15225 100644 --- a/drivers/acpi/namespace/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -43,7 +43,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsxfobj") diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/acpica/psargs.c index d830b29b85b..b161f3544b5 100644 --- a/drivers/acpi/parser/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -42,10 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acdispat.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psargs") diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/acpica/psloop.c index 4647039a0d8..c5f6ce19a40 100644 --- a/drivers/acpi/parser/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -50,9 +50,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psloop") diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/acpica/psopcode.c index f425ab30eae..3bc3a60194d 100644 --- a/drivers/acpi/parser/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acopcode.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "acopcode.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psopcode") diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/acpica/psparse.c index 68e932f215e..70838e9b608 100644 --- a/drivers/acpi/parser/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -51,11 +51,12 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/amlcode.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "amlcode.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psparse") @@ -447,10 +448,22 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size)); + if (!walk_state->parser_state.aml) { + return_ACPI_STATUS(AE_NULL_OBJECT); + } + /* Create and initialize a new thread state */ thread = acpi_ut_create_thread_state(); if (!thread) { + if (walk_state->method_desc) { + + /* Executing a control method - additional cleanup */ + + acpi_ds_terminate_control_method( + walk_state->method_desc, walk_state); + } + acpi_ds_delete_walk_state(walk_state); return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/acpica/psscope.c index ee50e67c944..2feca5ca958 100644 --- a/drivers/acpi/parser/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "acparser.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psscope") diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/acpica/pstree.c index 1dd355ddd18..4d3389118ec 100644 --- a/drivers/acpi/parser/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("pstree") diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/acpica/psutils.c index 7cf1f65cd5b..e636e078ad3 100644 --- a/drivers/acpi/parser/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/amlcode.h> +#include "accommon.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psutils") diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/acpica/pswalk.c index 8b86ad5a320..78b8b791f2a 100644 --- a/drivers/acpi/parser/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> +#include "accommon.h" +#include "acparser.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("pswalk") diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/acpica/psxface.c index 270469aae84..ff06032c0f0 100644 --- a/drivers/acpi/parser/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -42,9 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acparser.h> -#include <acpi/acdispat.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acparser.h" +#include "acdispat.h" +#include "acinterp.h" +#include "amlcode.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psxface") @@ -278,6 +280,38 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) goto cleanup; } + /* Invoke an internal method if necessary */ + + if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { + status = info->obj_desc->method.implementation(walk_state); + info->return_object = walk_state->return_desc; + + /* Cleanup states */ + + acpi_ds_scope_stack_clear(walk_state); + acpi_ps_cleanup_scope(&walk_state->parser_state); + acpi_ds_terminate_control_method(walk_state->method_desc, + walk_state); + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + /* + * Start method evaluation with an implicit return of zero. + * This is done for Windows compatibility. + */ + if (acpi_gbl_enable_interpreter_slack) { + walk_state->implicit_return_obj = + acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); + if (!walk_state->implicit_return_obj) { + status = AE_NO_MEMORY; + acpi_ds_delete_walk_state(walk_state); + goto cleanup; + } + + walk_state->implicit_return_obj->integer.value = 0; + } + /* Parse the AML */ status = acpi_ps_parse_aml(walk_state); diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 7f96332822b..1e437bfd8db 100644 --- a/drivers/acpi/resources/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsaddr") diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/acpica/rscalc.c index 8eaaecf9200..52865ee6bc7 100644 --- a/drivers/acpi/resources/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rscalc") diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/acpica/rscreate.c index 08b8d73e6ee..61566b1a061 100644 --- a/drivers/acpi/resources/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rscreate") diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/acpica/rsdump.c index 6bbbb7b8941..3f0ca5a12d3 100644 --- a/drivers/acpi/resources/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsdump") diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 3f0a1fedbe0..77b25fdb459 100644 --- a/drivers/acpi/resources/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsinfo") diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/acpica/rsio.c index b66d42e7402..35a49aa9560 100644 --- a/drivers/acpi/resources/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsio") diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/acpica/rsirq.c index a8805efc036..2e0256983aa 100644 --- a/drivers/acpi/resources/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsirq") diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/acpica/rslist.c index b78c7e797a1..1b1dbc69f08 100644 --- a/drivers/acpi/resources/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rslist") diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 63b21abd90b..ddc76cebdc9 100644 --- a/drivers/acpi/resources/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsmemory") diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 96a6c035325..5bc49a55328 100644 --- a/drivers/acpi/resources/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsmisc") diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/acpica/rsutils.c index f7b3bcd59ba..bc03d596682 100644 --- a/drivers/acpi/resources/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acresrc.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acresrc.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsutils") diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/acpica/rsxface.c index f59f4c4e034..69a2aa5b5d8 100644 --- a/drivers/acpi/resources/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acresrc.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acresrc.h" +#include "acnamesp.h" #define _COMPONENT ACPI_RESOURCES ACPI_MODULE_NAME("rsxface") diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 2817158fb6a..3636e4f8fb7 100644 --- a/drivers/acpi/tables/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -42,15 +42,16 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbfadt") /* Local prototypes */ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 byte_width, u64 address); + u8 space_id, u8 byte_width, u64 address); static void acpi_tb_convert_fadt(void); @@ -60,9 +61,10 @@ static void acpi_tb_validate_fadt(void); typedef struct acpi_fadt_info { char *name; - u8 target; - u8 source; + u8 address64; + u8 address32; u8 length; + u8 default_length; u8 type; } acpi_fadt_info; @@ -71,37 +73,61 @@ typedef struct acpi_fadt_info { #define ACPI_FADT_SEPARATE_LENGTH 2 static struct acpi_fadt_info fadt_info_table[] = { - {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block), + {"Pm1aEventBlock", + ACPI_FADT_OFFSET(xpm1a_event_block), ACPI_FADT_OFFSET(pm1a_event_block), - ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm1_event_length), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + ACPI_FADT_REQUIRED}, - {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block), + {"Pm1bEventBlock", + ACPI_FADT_OFFSET(xpm1b_event_block), ACPI_FADT_OFFSET(pm1b_event_block), - ACPI_FADT_OFFSET(pm1_event_length), 0}, + ACPI_FADT_OFFSET(pm1_event_length), + ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ + 0}, - {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), + {"Pm1aControlBlock", + ACPI_FADT_OFFSET(xpm1a_control_block), ACPI_FADT_OFFSET(pm1a_control_block), - ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm1_control_length), + ACPI_PM1_REGISTER_WIDTH, + ACPI_FADT_REQUIRED}, - {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block), + {"Pm1bControlBlock", + ACPI_FADT_OFFSET(xpm1b_control_block), ACPI_FADT_OFFSET(pm1b_control_block), - ACPI_FADT_OFFSET(pm1_control_length), 0}, + ACPI_FADT_OFFSET(pm1_control_length), + ACPI_PM1_REGISTER_WIDTH, + 0}, - {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), + {"Pm2ControlBlock", + ACPI_FADT_OFFSET(xpm2_control_block), ACPI_FADT_OFFSET(pm2_control_block), - ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_OFFSET(pm2_control_length), + ACPI_PM2_REGISTER_WIDTH, + ACPI_FADT_SEPARATE_LENGTH}, - {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block), + {"PmTimerBlock", + ACPI_FADT_OFFSET(xpm_timer_block), ACPI_FADT_OFFSET(pm_timer_block), - ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED}, + ACPI_FADT_OFFSET(pm_timer_length), + ACPI_PM_TIMER_WIDTH, + ACPI_FADT_REQUIRED}, - {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block), + {"Gpe0Block", + ACPI_FADT_OFFSET(xgpe0_block), ACPI_FADT_OFFSET(gpe0_block), - ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH}, + ACPI_FADT_OFFSET(gpe0_block_length), + 0, + ACPI_FADT_SEPARATE_LENGTH}, - {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block), + {"Gpe1Block", + ACPI_FADT_OFFSET(xgpe1_block), ACPI_FADT_OFFSET(gpe1_block), - ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH} + ACPI_FADT_OFFSET(gpe1_block_length), + 0, + ACPI_FADT_SEPARATE_LENGTH} }; #define ACPI_FADT_INFO_ENTRIES (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info)) @@ -122,9 +148,9 @@ static struct acpi_fadt_info fadt_info_table[] = { * ******************************************************************************/ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, - u8 byte_width, u64 address) + u8 space_id, u8 byte_width, u64 address) { /* @@ -135,10 +161,10 @@ acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, /* All other fields are byte-wide */ - generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO; - generic_address->bit_width = byte_width << 3; + generic_address->space_id = space_id; + generic_address->bit_width = (u8)ACPI_MUL_8(byte_width); generic_address->bit_offset = 0; - generic_address->access_width = 0; + generic_address->access_width = 0; /* Access width ANY */ } /******************************************************************************* @@ -225,7 +251,8 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) */ if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, - "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX", + "FADT (revision %u) is longer than ACPI 2.0 version, " + "truncating length 0x%X to 0x%zX", table->revision, (unsigned)length, sizeof(struct acpi_table_fadt))); } @@ -244,7 +271,6 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) * 2) Validate some of the important values within the FADT */ acpi_tb_convert_fadt(); - acpi_tb_validate_fadt(); } /******************************************************************************* @@ -278,22 +304,36 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) static void acpi_tb_convert_fadt(void) { - u8 pm1_register_length; - struct acpi_generic_address *target; + u8 pm1_register_bit_width; + u8 pm1_register_byte_width; + struct acpi_generic_address *target64; u32 i; /* Update the local FADT table header length */ acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt); - /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */ - + /* + * Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary. + * Later code will always use the X 64-bit field. Also, check for an + * address mismatch between the 32-bit and 64-bit address fields + * (FIRMWARE_CTRL/X_FIRMWARE_CTRL, DSDT/X_DSDT) which would indicate + * the presence of two FACS or two DSDT tables. + */ if (!acpi_gbl_FADT.Xfacs) { acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs; + } else if (acpi_gbl_FADT.facs && + (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { + ACPI_WARNING((AE_INFO, + "32/64 FACS address mismatch in FADT - two FACS tables!")); } if (!acpi_gbl_FADT.Xdsdt) { acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; + } else if (acpi_gbl_FADT.dsdt && + (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { + ACPI_WARNING((AE_INFO, + "32/64 DSDT address mismatch in FADT - two DSDT tables!")); } /* @@ -312,18 +352,23 @@ static void acpi_tb_convert_fadt(void) } /* - * Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X" - * generic address structures as necessary. + * Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X" + * generic address structures as necessary. Later code will always use + * the 64-bit address structures. */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { - target = + target64 = ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, - fadt_info_table[i].target); + fadt_info_table[i].address64); - /* Expand only if the X target is null */ + /* Expand only if the 64-bit X target is null */ - if (!target->address) { - acpi_tb_init_generic_address(target, + if (!target64->address) { + + /* The space_id is always I/O for the 32-bit legacy address fields */ + + acpi_tb_init_generic_address(target64, + ACPI_ADR_SPACE_SYSTEM_IO, *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table @@ -332,11 +377,64 @@ static void acpi_tb_convert_fadt(void) &acpi_gbl_FADT, fadt_info_table [i]. - source)); + address32)); + } + } + + /* Validate FADT values now, before we make any changes */ + + acpi_tb_validate_fadt(); + + /* + * Optionally check all register lengths against the default values and + * update them if they are incorrect. + */ + if (acpi_gbl_use_default_register_widths) { + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + target64 = + ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); + + /* + * If a valid register (Address != 0) and the (default_length > 0) + * (Not a GPE register), then check the width against the default. + */ + if ((target64->address) && + (fadt_info_table[i].default_length > 0) && + (fadt_info_table[i].default_length != + target64->bit_width)) { + ACPI_WARNING((AE_INFO, + "Invalid length for %s: %d, using default %d", + fadt_info_table[i].name, + target64->bit_width, + fadt_info_table[i]. + default_length)); + + /* Incorrect size, set width to the default */ + + target64->bit_width = + fadt_info_table[i].default_length; + } } } /* + * Get the length of the individual PM1 registers (enable and status). + * Each register is defined to be (event block length / 2). + */ + pm1_register_bit_width = + (u8)ACPI_DIV_2(acpi_gbl_FADT.xpm1a_event_block.bit_width); + pm1_register_byte_width = (u8)ACPI_DIV_8(pm1_register_bit_width); + + /* + * Adjust the lengths of the PM1 Event Blocks so that they can be used to + * access the PM1 status register(s). Use (width / 2) + */ + acpi_gbl_FADT.xpm1a_event_block.bit_width = pm1_register_bit_width; + acpi_gbl_FADT.xpm1b_event_block.bit_width = pm1_register_bit_width; + + /* * Calculate separate GAS structs for the PM1 Enable registers. * These addresses do not appear (directly) in the FADT, so it is * useful to calculate them once, here. @@ -356,14 +454,14 @@ static void acpi_tb_convert_fadt(void) " PM1_EVT_LEN (%u)\n", acpi_gbl_FADT.xpm1a_event_block.bit_width, acpi_gbl_FADT.pm1_event_length); - pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length); /* The PM1A register block is required */ acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable, - pm1_register_length, + acpi_gbl_FADT.xpm1a_event_block.space_id, + pm1_register_byte_width, (acpi_gbl_FADT.xpm1a_event_block.address + - pm1_register_length)); + pm1_register_byte_width)); /* Don't forget to copy space_id of the GAS */ acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id; @@ -379,9 +477,10 @@ static void acpi_tb_convert_fadt(void) acpi_gbl_FADT.xpm1b_event_block.bit_width, acpi_gbl_FADT.pm1_event_length); acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable, - pm1_register_length, + acpi_gbl_FADT.xpm1b_event_block.space_id, + pm1_register_byte_width, (acpi_gbl_FADT.xpm1b_event_block. - address + pm1_register_length)); + address + pm1_register_byte_width)); /* Don't forget to copy space_id of the GAS */ acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1b_event_block.space_id; @@ -411,26 +510,63 @@ static void acpi_tb_convert_fadt(void) static void acpi_tb_validate_fadt(void) { + char *name; u32 *address32; struct acpi_generic_address *address64; u8 length; u32 i; - /* Examine all of the 64-bit extended address fields (X fields) */ + /* + * Check for FACS and DSDT address mismatches. An address mismatch between + * the 32-bit and 64-bit address fields (FIRMWARE_CTRL/X_FIRMWARE_CTRL and + * DSDT/X_DSDT) would indicate the presence of two FACS or two DSDT tables. + */ + if (acpi_gbl_FADT.facs && + (acpi_gbl_FADT.Xfacs != (u64) acpi_gbl_FADT.facs)) { + ACPI_WARNING((AE_INFO, + "32/64X FACS address mismatch in FADT - " + "two FACS tables! %8.8X/%8.8X%8.8X", + acpi_gbl_FADT.facs, + ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xfacs))); + } - for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + if (acpi_gbl_FADT.dsdt && + (acpi_gbl_FADT.Xdsdt != (u64) acpi_gbl_FADT.dsdt)) { + ACPI_WARNING((AE_INFO, + "32/64X DSDT address mismatch in FADT - " + "two DSDT tables! %8.8X/%8.8X%8.8X", + acpi_gbl_FADT.dsdt, + ACPI_FORMAT_UINT64(acpi_gbl_FADT.Xdsdt))); + } - /* Generate pointers to the 32-bit and 64-bit addresses and get the length */ + /* Examine all of the 64-bit extended address fields (X fields) */ - address64 = - ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT, - fadt_info_table[i].target); + for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { + /* + * Generate pointers to the 32-bit and 64-bit addresses, get the + * register length (width), and the register name + */ + address64 = ACPI_ADD_PTR(struct acpi_generic_address, + &acpi_gbl_FADT, + fadt_info_table[i].address64); address32 = ACPI_ADD_PTR(u32, &acpi_gbl_FADT, - fadt_info_table[i].source); + fadt_info_table[i].address32); length = *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, fadt_info_table[i].length); + name = fadt_info_table[i].name; + + /* + * For each extended field, check for length mismatch between the + * legacy length field and the corresponding 64-bit X length field. + */ + if (address64 && (address64->bit_width != ACPI_MUL_8(length))) { + ACPI_WARNING((AE_INFO, + "32/64X length mismatch in %s: %d/%d", + name, ACPI_MUL_8(length), + address64->bit_width)); + } if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) { /* @@ -439,8 +575,8 @@ static void acpi_tb_validate_fadt(void) */ if (!address64->address || !length) { ACPI_ERROR((AE_INFO, - "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X", - fadt_info_table[i].name, + "Required field %s has zero address and/or length: %8.8X%8.8X/%X", + name, ACPI_FORMAT_UINT64(address64-> address), length)); @@ -453,8 +589,8 @@ static void acpi_tb_validate_fadt(void) if ((address64->address && !length) || (!address64->address && length)) { ACPI_WARNING((AE_INFO, - "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X", - fadt_info_table[i].name, + "Optional field %s has zero address or length: %8.8X%8.8X/%X", + name, ACPI_FORMAT_UINT64(address64-> address), length)); @@ -466,8 +602,8 @@ static void acpi_tb_validate_fadt(void) if (address64->address && *address32 && (address64->address != (u64) * address32)) { ACPI_ERROR((AE_INFO, - "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X", - fadt_info_table[i].name, *address32, + "32/64X address mismatch in %s: %8.8X/%8.8X%8.8X, using 64X", + name, *address32, ACPI_FORMAT_UINT64(address64->address))); } } diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/acpica/tbfind.c index 531584defbb..1054dfd4920 100644 --- a/drivers/acpi/tables/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbfind") diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 18747ce8dd2..37374b21969 100644 --- a/drivers/acpi/tables/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbinstal") diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0cc92ef5236..9684cc82793 100644 --- a/drivers/acpi/tables/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbutils") @@ -113,6 +114,30 @@ acpi_tb_check_xsdt(acpi_physical_address address) /******************************************************************************* * + * FUNCTION: acpi_tb_initialize_facs + * + * PARAMETERS: None + * + * RETURN: Status + * + * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global + * for accessing the Global Lock and Firmware Waking Vector + * + ******************************************************************************/ + +acpi_status acpi_tb_initialize_facs(void) +{ + acpi_status status; + + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &acpi_gbl_FACS)); + return status; +} + +/******************************************************************************* + * * FUNCTION: acpi_tb_tables_loaded * * PARAMETERS: None @@ -420,7 +445,8 @@ acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags) /* Differentiate between RSDT and XSDT root tables */ - if (rsdp->revision > 1 && rsdp->xsdt_physical_address) { + if (rsdp->revision > 1 && rsdp->xsdt_physical_address + && !acpi_rsdt_forced) { /* * Root table is an XSDT (64-bit physical addresses). We must use the * XSDT if the revision is > 1 and the XSDT pointer is present, as per diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/acpica/tbxface.c index fd7770aa106..c3e841f3cde 100644 --- a/drivers/acpi/tables/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -43,8 +43,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxface") diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 2d157e0f98d..b7fc8dd4334 100644 --- a/drivers/acpi/tables/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "actables.h" #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxfroot") diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/acpica/utalloc.c index 241c535c175..7580f6b3069 100644 --- a/drivers/acpi/utilities/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acdebug.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utalloc") diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/acpica/utcopy.c index 5b2f7c27b70..b0dcfd3c872 100644 --- a/drivers/acpi/utilities/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/acpica/utdebug.c index fd66ecb6741..38821f53042 100644 --- a/drivers/acpi/utilities/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") @@ -136,7 +137,7 @@ static const char *acpi_ut_trim_function_name(const char *function_name) /******************************************************************************* * - * FUNCTION: acpi_ut_debug_print + * FUNCTION: acpi_debug_print * * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number (for error output) @@ -154,11 +155,11 @@ static const char *acpi_ut_trim_function_name(const char *function_name) ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...) +acpi_debug_print(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, const char *format, ...) { acpi_thread_id thread_id; va_list args; @@ -205,11 +206,11 @@ acpi_ut_debug_print(u32 requested_debug_level, va_end(args); } -ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) +ACPI_EXPORT_SYMBOL(acpi_debug_print) /******************************************************************************* * - * FUNCTION: acpi_ut_debug_print_raw + * FUNCTION: acpi_debug_print_raw * * PARAMETERS: requested_debug_level - Requested debug print level * line_number - Caller's line number @@ -226,11 +227,11 @@ ACPI_EXPORT_SYMBOL(acpi_ut_debug_print) * ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, const char *format, ...) +acpi_debug_print_raw(u32 requested_debug_level, + u32 line_number, + const char *function_name, + const char *module_name, + u32 component_id, const char *format, ...) { va_list args; @@ -244,7 +245,7 @@ acpi_ut_debug_print_raw(u32 requested_debug_level, va_end(args); } -ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw) +ACPI_EXPORT_SYMBOL(acpi_debug_print_raw) /******************************************************************************* * @@ -270,9 +271,9 @@ acpi_ut_trace(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s\n", acpi_gbl_fn_entry_str); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s\n", acpi_gbl_fn_entry_str); } ACPI_EXPORT_SYMBOL(acpi_ut_trace) @@ -301,10 +302,9 @@ acpi_ut_trace_ptr(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %p\n", acpi_gbl_fn_entry_str, - pointer); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %p\n", acpi_gbl_fn_entry_str, pointer); } /******************************************************************************* @@ -333,10 +333,9 @@ acpi_ut_trace_str(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %s\n", acpi_gbl_fn_entry_str, - string); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %s\n", acpi_gbl_fn_entry_str, string); } /******************************************************************************* @@ -365,10 +364,9 @@ acpi_ut_trace_u32(u32 line_number, acpi_gbl_nesting_level++; acpi_ut_track_stack_ptr(); - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %08X\n", acpi_gbl_fn_entry_str, - integer); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %08X\n", acpi_gbl_fn_entry_str, integer); } /******************************************************************************* @@ -393,9 +391,9 @@ acpi_ut_exit(u32 line_number, const char *module_name, u32 component_id) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s\n", acpi_gbl_fn_exit_str); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s\n", acpi_gbl_fn_exit_str); acpi_gbl_nesting_level--; } @@ -426,17 +424,16 @@ acpi_ut_status_exit(u32 line_number, { if (ACPI_SUCCESS(status)) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %s\n", - acpi_gbl_fn_exit_str, - acpi_format_exception(status)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, + component_id, "%s %s\n", acpi_gbl_fn_exit_str, + acpi_format_exception(status)); } else { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s ****Exception****: %s\n", - acpi_gbl_fn_exit_str, - acpi_format_exception(status)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, + component_id, "%s ****Exception****: %s\n", + acpi_gbl_fn_exit_str, + acpi_format_exception(status)); } acpi_gbl_nesting_level--; @@ -467,10 +464,10 @@ acpi_ut_value_exit(u32 line_number, u32 component_id, acpi_integer value) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %8.8X%8.8X\n", - acpi_gbl_fn_exit_str, ACPI_FORMAT_UINT64(value)); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str, + ACPI_FORMAT_UINT64(value)); acpi_gbl_nesting_level--; } @@ -499,9 +496,9 @@ acpi_ut_ptr_exit(u32 line_number, const char *module_name, u32 component_id, u8 *ptr) { - acpi_ut_debug_print(ACPI_LV_FUNCTIONS, - line_number, function_name, module_name, - component_id, "%s %p\n", acpi_gbl_fn_exit_str, ptr); + acpi_debug_print(ACPI_LV_FUNCTIONS, + line_number, function_name, module_name, component_id, + "%s %p\n", acpi_gbl_fn_exit_str, ptr); acpi_gbl_nesting_level--; } diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/acpica/utdelete.c index d197c6b29e1..a0be9e39531 100644 --- a/drivers/acpi/utilities/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acinterp.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> +#include "accommon.h" +#include "acinterp.h" +#include "acnamesp.h" +#include "acevents.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdelete") diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/acpica/uteval.c index 352747e49c7..da9450bc60f 100644 --- a/drivers/acpi/utilities/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -42,8 +42,9 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acinterp.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("uteval") @@ -129,7 +130,7 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) /* The interface is supported */ - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } } @@ -143,13 +144,13 @@ acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) /* The interface is supported */ - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } /* The interface is not supported */ return_desc->integer.value = 0; - return_ACPI_STATUS(AE_CTRL_TERMINATE); + return_ACPI_STATUS(AE_OK); } /******************************************************************************* diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/acpica/utglobal.c index 17ed5ac840f..a3ab9d9da29 100644 --- a/drivers/acpi/utilities/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -44,11 +44,11 @@ #define DEFINE_ACPI_GLOBALS #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" -ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) #define _COMPONENT ACPI_UTILITIES - ACPI_MODULE_NAME("utglobal") +ACPI_MODULE_NAME("utglobal") /******************************************************************************* * @@ -352,7 +352,7 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "PCI_Config", "EmbeddedControl", "SMBus", - "CMOS", + "SystemCMOS", "PCIBARTarget", "DataTable" }; @@ -756,6 +756,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_gpe_xrupt_list_head = NULL; acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL; + acpi_current_gpe_count = 0; /* Global handlers */ @@ -771,6 +772,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_global_lock_mutex = NULL; acpi_gbl_global_lock_acquired = FALSE; acpi_gbl_global_lock_handle = 0; + acpi_gbl_global_lock_present = FALSE; /* Miscellaneous variables */ @@ -815,5 +817,7 @@ acpi_status acpi_ut_init_globals(void) return_ACPI_STATUS(AE_OK); } +ACPI_EXPORT_SYMBOL(acpi_gbl_FADT) ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_layer) +ACPI_EXPORT_SYMBOL(acpi_current_gpe_count) diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/acpica/utinit.c index cae515fc02d..a54ca84eb36 100644 --- a/drivers/acpi/utilities/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -42,9 +42,10 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acevents.h> -#include <acpi/actables.h> +#include "accommon.h" +#include "acnamesp.h" +#include "acevents.h" +#include "actables.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utinit") diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/acpica/utmath.c index c927324fdd2..c9f682d640e 100644 --- a/drivers/acpi/utilities/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmath") diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/acpica/utmisc.c index 9089a158a87..c1f7f4e1a72 100644 --- a/drivers/acpi/utilities/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -44,7 +44,8 @@ #include <linux/module.h> #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmisc") @@ -1016,7 +1017,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, /******************************************************************************* * - * FUNCTION: acpi_ut_error, acpi_ut_warning, acpi_ut_info + * FUNCTION: acpi_error, acpi_exception, acpi_warning, acpi_info * * PARAMETERS: module_name - Caller's module name (for error output) * line_number - Caller's line number (for error output) @@ -1029,7 +1030,7 @@ acpi_ut_walk_package_tree(union acpi_operand_object * source_object, ******************************************************************************/ void ACPI_INTERNAL_VAR_XFACE -acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...) +acpi_error(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1042,8 +1043,8 @@ acpi_ut_error(const char *module_name, u32 line_number, const char *format, ...) } void ACPI_INTERNAL_VAR_XFACE -acpi_ut_exception(const char *module_name, - u32 line_number, acpi_status status, const char *format, ...) +acpi_exception(const char *module_name, + u32 line_number, acpi_status status, const char *format, ...) { va_list args; @@ -1056,11 +1057,8 @@ acpi_ut_exception(const char *module_name, va_end(args); } -EXPORT_SYMBOL(acpi_ut_exception); - void ACPI_INTERNAL_VAR_XFACE -acpi_ut_warning(const char *module_name, - u32 line_number, const char *format, ...) +acpi_warning(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1073,7 +1071,7 @@ acpi_ut_warning(const char *module_name, } void ACPI_INTERNAL_VAR_XFACE -acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...) +acpi_info(const char *module_name, u32 line_number, const char *format, ...) { va_list args; @@ -1088,3 +1086,8 @@ acpi_ut_info(const char *module_name, u32 line_number, const char *format, ...) acpi_os_printf("\n"); va_end(args); } + +ACPI_EXPORT_SYMBOL(acpi_error) +ACPI_EXPORT_SYMBOL(acpi_exception) +ACPI_EXPORT_SYMBOL(acpi_warning) +ACPI_EXPORT_SYMBOL(acpi_info) diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/acpica/utmutex.c index 7331dde9e1b..14eb52c4d64 100644 --- a/drivers/acpi/utilities/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utmutex") diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/acpica/utobject.c index 4bef3cfbacc..fd5ea7543e5 100644 --- a/drivers/acpi/utilities/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/acnamesp.h> +#include "accommon.h" +#include "acnamesp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utobject") diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/acpica/utresrc.c index c3e3e1308ed..91b7c00236f 100644 --- a/drivers/acpi/utilities/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -42,7 +42,8 @@ */ #include <acpi/acpi.h> -#include <acpi/amlresrc.h> +#include "accommon.h" +#include "amlresrc.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/acpica/utstate.c index 63a6d3d77d8..0440c958f5a 100644 --- a/drivers/acpi/utilities/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -42,6 +42,7 @@ */ #include <acpi/acpi.h> +#include "accommon.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utstate") diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/acpica/utxface.c index c198a4d4058..078a22728c6 100644 --- a/drivers/acpi/utilities/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -42,9 +42,11 @@ */ #include <acpi/acpi.h> -#include <acpi/acevents.h> -#include <acpi/acnamesp.h> -#include <acpi/acdebug.h> +#include "accommon.h" +#include "acevents.h" +#include "acnamesp.h" +#include "acdebug.h" +#include "actables.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utxface") @@ -148,6 +150,16 @@ acpi_status acpi_enable_subsystem(u32 flags) } /* + * Obtain a permanent mapping for the FACS. This is required for the + * Global Lock and the Firmware Waking Vector + */ + status = acpi_tb_initialize_facs(); + if (ACPI_FAILURE(status)) { + ACPI_WARNING((AE_INFO, "Could not map the FACS table")); + return_ACPI_STATUS(status); + } + + /* * Install the default op_region handlers. These are installed unless * other handlers have already been installed via the * install_address_space_handler interface. diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 1423b0c0cd2..65132f92045 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -471,7 +471,7 @@ static void sysfs_remove_battery(struct acpi_battery *battery) static int acpi_battery_update(struct acpi_battery *battery) { - int result; + int result, old_present = acpi_battery_present(battery); result = acpi_battery_get_status(battery); if (result) return result; @@ -482,7 +482,8 @@ static int acpi_battery_update(struct acpi_battery *battery) return 0; } #endif - if (!battery->update_time) { + if (!battery->update_time || + old_present != acpi_battery_present(battery)) { result = acpi_battery_get_info(battery); if (result) return result; diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 307963bd104..332fe4b2170 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -27,9 +27,6 @@ #include <linux/seq_file.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> -#include <acpi/acutils.h> ACPI_MODULE_NAME("cm_sbs"); #define ACPI_AC_CLASS "ac_adapter" diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index c4839689200..20223cbd0d1 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c @@ -9,7 +9,6 @@ #include <linux/moduleparam.h> #include <asm/uaccess.h> #include <acpi/acpi_drivers.h> -#include <acpi/acglobal.h> #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debug"); diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile deleted file mode 100644 index eb7e602a83c..00000000000 --- a/drivers/acpi/dispatcher/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ - dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ - dsinit.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 30f3ef236ec..8dfcbb8aff7 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -42,7 +42,6 @@ #include <asm/io.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/actypes.h> #define ACPI_EC_CLASS "embedded_controller" #define ACPI_EC_DEVICE_NAME "Embedded Controller" @@ -370,7 +369,7 @@ unlock: * Note: samsung nv5000 doesn't work with ec burst mode. * http://bugzilla.kernel.org/show_bug.cgi?id=4980 */ -int acpi_ec_burst_enable(struct acpi_ec *ec) +static int acpi_ec_burst_enable(struct acpi_ec *ec) { u8 d; struct transaction t = {.command = ACPI_EC_BURST_ENABLE, @@ -380,7 +379,7 @@ int acpi_ec_burst_enable(struct acpi_ec *ec) return acpi_ec_transaction(ec, &t, 0); } -int acpi_ec_burst_disable(struct acpi_ec *ec) +static int acpi_ec_burst_disable(struct acpi_ec *ec) { struct transaction t = {.command = ACPI_EC_BURST_DISABLE, .wdata = NULL, .rdata = NULL, @@ -756,10 +755,15 @@ static acpi_status acpi_ec_register_query_methods(acpi_handle handle, u32 level, void *context, void **return_value) { - struct acpi_namespace_node *node = handle; + char node_name[5]; + struct acpi_buffer buffer = { sizeof(node_name), node_name }; struct acpi_ec *ec = context; int value = 0; - if (sscanf(node->name.ascii, "_Q%x", &value) == 1) { + acpi_status status; + + status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + + if (ACPI_SUCCESS(status) && sscanf(node_name, "_Q%x", &value) == 1) { acpi_ec_add_query_handler(ec, value, handle, NULL, NULL); } return AE_OK; @@ -978,9 +982,9 @@ static const struct acpi_device_id ec_device_ids[] = { int __init acpi_ec_ecdt_probe(void) { - int ret; acpi_status status; struct acpi_table_ecdt *ecdt_ptr; + acpi_handle dummy; boot_ec = make_acpi_ec(); if (!boot_ec) @@ -1006,30 +1010,31 @@ int __init acpi_ec_ecdt_probe(void) boot_ec->gpe = ecdt_ptr->gpe; boot_ec->handle = ACPI_ROOT_OBJECT; acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle); - } else { - /* This workaround is needed only on some broken machines, - * which require early EC, but fail to provide ECDT */ - acpi_handle x; - printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); - status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, - boot_ec, NULL); - /* Check that acpi_get_devices actually find something */ - if (ACPI_FAILURE(status) || !boot_ec->handle) - goto error; - /* We really need to limit this workaround, the only ASUS, - * which needs it, has fake EC._INI method, so use it as flag. - * Keep boot_ec struct as it will be needed soon. - */ - if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &x))) - return -ENODEV; + /* Add some basic check against completely broken table */ + if (boot_ec->data_addr != boot_ec->command_addr) + goto install; + /* fall through */ } - - ret = ec_install_handlers(boot_ec); - if (!ret) { + /* This workaround is needed only on some broken machines, + * which require early EC, but fail to provide ECDT */ + printk(KERN_DEBUG PREFIX "Look up EC in DSDT\n"); + status = acpi_get_devices(ec_device_ids[0].id, ec_parse_device, + boot_ec, NULL); + /* Check that acpi_get_devices actually find something */ + if (ACPI_FAILURE(status) || !boot_ec->handle) + goto error; + /* We really need to limit this workaround, the only ASUS, + * which needs it, has fake EC._INI method, so use it as flag. + * Keep boot_ec struct as it will be needed soon. + */ + if (ACPI_FAILURE(acpi_get_handle(boot_ec->handle, "_INI", &dummy))) + return -ENODEV; +install: + if (!ec_install_handlers(boot_ec)) { first_ec = boot_ec; return 0; } - error: +error: kfree(boot_ec); boot_ec = NULL; return -ENODEV; diff --git a/drivers/acpi/events/Makefile b/drivers/acpi/events/Makefile deleted file mode 100644 index d29f2ee449c..00000000000 --- a/drivers/acpi/events/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := evevent.o evregion.o evsci.o evxfevnt.o \ - evmisc.o evrgnini.o evxface.o evxfregn.o \ - evgpe.o evgpeblk.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/executer/Makefile b/drivers/acpi/executer/Makefile deleted file mode 100644 index e09998aa012..00000000000 --- a/drivers/acpi/executer/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\ - exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\ - excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \ - exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/hardware/Makefile b/drivers/acpi/hardware/Makefile deleted file mode 100644 index 438ad373b9a..00000000000 --- a/drivers/acpi/hardware/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := hwacpi.o hwgpe.o hwregs.o hwsleep.o - -obj-$(ACPI_FUTURE_USAGE) += hwtimer.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/main.c index 28a691cc625..7e3c609cbef 100644 --- a/drivers/acpi/sleep/main.c +++ b/drivers/acpi/main.c @@ -101,13 +101,26 @@ void __init acpi_old_suspend_ordering(void) * cases. */ static bool set_sci_en_on_resume; +/* + * The ACPI specification wants us to save NVS memory regions during hibernation + * and to restore them during the subsequent resume. However, it is not certain + * if this mechanism is going to work on all machines, so we allow the user to + * disable this mechanism using the 'acpi_sleep=s4_nonvs' kernel command line + * option. + */ +static bool s4_no_nvs; + +void __init acpi_s4_no_nvs(void) +{ + s4_no_nvs = true; +} /** * acpi_pm_disable_gpes - Disable the GPEs. */ static int acpi_pm_disable_gpes(void) { - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); return 0; } @@ -135,7 +148,7 @@ static int acpi_pm_prepare(void) int error = __acpi_pm_prepare(); if (!error) - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); return error; } @@ -267,7 +280,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) * (like wakeup GPE) haven't handler, this can avoid such GPE misfire. * acpi_leave_sleep_state will reenable specific GPEs later */ - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); local_irq_restore(flags); printk(KERN_DEBUG "Back to C!\n"); @@ -394,9 +407,25 @@ void __init acpi_no_s4_hw_signature(void) static int acpi_hibernation_begin(void) { - acpi_target_sleep_state = ACPI_STATE_S4; - acpi_sleep_tts_switch(acpi_target_sleep_state); - return 0; + int error; + + error = s4_no_nvs ? 0 : hibernate_nvs_alloc(); + if (!error) { + acpi_target_sleep_state = ACPI_STATE_S4; + acpi_sleep_tts_switch(acpi_target_sleep_state); + } + + return error; +} + +static int acpi_hibernation_pre_snapshot(void) +{ + int error = acpi_pm_prepare(); + + if (!error) + hibernate_nvs_save(); + + return error; } static int acpi_hibernation_enter(void) @@ -417,6 +446,12 @@ static int acpi_hibernation_enter(void) return ACPI_SUCCESS(status) ? 0 : -EFAULT; } +static void acpi_hibernation_finish(void) +{ + hibernate_nvs_free(); + acpi_pm_finish(); +} + static void acpi_hibernation_leave(void) { /* @@ -432,18 +467,20 @@ static void acpi_hibernation_leave(void) "cannot resume!\n"); panic("ACPI S4 hardware signature mismatch"); } + /* Restore the NVS memory area */ + hibernate_nvs_restore(); } static void acpi_pm_enable_gpes(void) { - acpi_hw_enable_all_runtime_gpes(); + acpi_enable_all_runtime_gpes(); } static struct platform_hibernation_ops acpi_hibernation_ops = { .begin = acpi_hibernation_begin, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_prepare, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_prepare, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, @@ -469,8 +506,22 @@ static int acpi_hibernation_begin_old(void) error = acpi_sleep_prepare(ACPI_STATE_S4); + if (!error) { + if (!s4_no_nvs) + error = hibernate_nvs_alloc(); + if (!error) + acpi_target_sleep_state = ACPI_STATE_S4; + } + return error; +} + +static int acpi_hibernation_pre_snapshot_old(void) +{ + int error = acpi_pm_disable_gpes(); + if (!error) - acpi_target_sleep_state = ACPI_STATE_S4; + hibernate_nvs_save(); + return error; } @@ -481,8 +532,8 @@ static int acpi_hibernation_begin_old(void) static struct platform_hibernation_ops acpi_hibernation_ops_old = { .begin = acpi_hibernation_begin_old, .end = acpi_pm_end, - .pre_snapshot = acpi_pm_disable_gpes, - .finish = acpi_pm_finish, + .pre_snapshot = acpi_hibernation_pre_snapshot_old, + .finish = acpi_hibernation_finish, .prepare = acpi_pm_disable_gpes, .enter = acpi_hibernation_enter, .leave = acpi_hibernation_leave, @@ -622,7 +673,7 @@ static void acpi_power_off_prepare(void) { /* Prepare to power off the system */ acpi_sleep_prepare(ACPI_STATE_S5); - acpi_hw_disable_all_gpes(); + acpi_disable_all_gpes(); } static void acpi_power_off(void) @@ -671,7 +722,7 @@ int __init acpi_sleep_init(void) sleep_states[ACPI_STATE_S4] = 1; printk(" S4"); if (!nosigcheck) { - acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, + acpi_get_table(ACPI_SIG_FACS, 1, (struct acpi_table_header **)&facs); if (facs) s4_hardware_signature = diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile deleted file mode 100644 index 371a2daf837..00000000000 --- a/drivers/acpi/namespace/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \ - nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \ - nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \ - nsparse.o nspredef.o - -obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 25ceae9191e..c5e292aab0e 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -29,7 +29,6 @@ #include <linux/errno.h> #include <linux/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/acmacros.h> #define ACPI_NUMA 0x80000000 #define _COMPONENT ACPI_NUMA diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c8111424dcb..6729a4992f2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -726,7 +726,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); if (!dpc) - return_ACPI_STATUS(AE_NO_MEMORY); + return AE_NO_MEMORY; dpc->function = function; dpc->context = context; @@ -747,7 +747,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type, status = AE_ERROR; kfree(dpc); } - return_ACPI_STATUS(status); + return status; } acpi_status acpi_os_execute(acpi_execute_type type, diff --git a/drivers/acpi/parser/Makefile b/drivers/acpi/parser/Makefile deleted file mode 100644 index db24ee09cf1..00000000000 --- a/drivers/acpi/parser/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := psargs.o psparse.o psloop.o pstree.o pswalk.o \ - psopcode.o psscope.o psutils.o psxface.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c index 4b252ea0e95..95650f83ce2 100644 --- a/drivers/acpi/pci_bind.c +++ b/drivers/acpi/pci_bind.c @@ -99,7 +99,7 @@ acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id) */ ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %s has PCI address %02x:%02x:%02x.%02x\n", + "Device %s has PCI address %04x:%02x:%02x.%d\n", acpi_device_bid(device), id->segment, id->bus, id->device, id->function)); @@ -111,12 +111,11 @@ EXPORT_SYMBOL(acpi_get_pci_id); int acpi_pci_bind(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; - struct acpi_pci_data *data = NULL; - struct acpi_pci_data *pdata = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - acpi_handle handle = NULL; + acpi_status status; + struct acpi_pci_data *data; + struct acpi_pci_data *pdata; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + acpi_handle handle; struct pci_dev *dev; struct pci_bus *bus; @@ -124,21 +123,18 @@ int acpi_pci_bind(struct acpi_device *device) if (!device || !device->parent) return -EINVAL; - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) { - kfree(pathname); + if (!data) return -ENOMEM; + + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree(data); + return -ENODEV; } - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n", - pathname)); + (char *)buffer.pointer)); /* * Segment & Bus @@ -166,7 +162,7 @@ int acpi_pci_bind(struct acpi_device *device) data->id.device = device->pnp.bus_address >> 16; data->id.function = device->pnp.bus_address & 0xFFFF; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %02x:%02x:%02x.%02x\n", + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %04x:%02x:%02x.%d\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); @@ -196,7 +192,7 @@ int acpi_pci_bind(struct acpi_device *device) } if (!data->dev) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %02x:%02x:%02x.%02x not present in PCI namespace\n", + "Device %04x:%02x:%02x.%d not present in PCI namespace\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); result = -ENODEV; @@ -204,7 +200,7 @@ int acpi_pci_bind(struct acpi_device *device) } if (!data->dev->bus) { printk(KERN_ERR PREFIX - "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n", + "Device %04x:%02x:%02x.%d has invalid 'bus' field\n", data->id.segment, data->id.bus, data->id.device, data->id.function); result = -ENODEV; @@ -219,7 +215,7 @@ int acpi_pci_bind(struct acpi_device *device) */ if (data->dev->subordinate) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Device %02x:%02x:%02x.%02x is a PCI bridge\n", + "Device %04x:%02x:%02x.%d is a PCI bridge\n", data->id.segment, data->id.bus, data->id.device, data->id.function)); data->bus = data->dev->subordinate; @@ -262,7 +258,7 @@ int acpi_pci_bind(struct acpi_device *device) } end: - kfree(pathname); + kfree(buffer.pointer); if (result) kfree(data); @@ -272,25 +268,21 @@ int acpi_pci_bind(struct acpi_device *device) static int acpi_pci_unbind(struct acpi_device *device) { int result = 0; - acpi_status status = AE_OK; - struct acpi_pci_data *data = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; + acpi_status status; + struct acpi_pci_data *data; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; if (!device || !device->parent) return -EINVAL; - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n", - pathname)); - kfree(pathname); + (char *) buffer.pointer)); + kfree(buffer.pointer); status = acpi_get_data(device->handle, acpi_pci_data_handler, @@ -322,50 +314,44 @@ acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus) { int result = 0; - acpi_status status = AE_OK; + acpi_status status; struct acpi_pci_data *data = NULL; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; if (!device || !id || !bus) { - kfree(pathname); return -EINVAL; } data = kzalloc(sizeof(struct acpi_pci_data), GFP_KERNEL); - if (!data) { - kfree(pathname); + if (!data) return -ENOMEM; - } data->id = *id; data->bus = bus; device->ops.bind = acpi_pci_bind; device->ops.unbind = acpi_pci_unbind; - acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + status = acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) { + kfree (data); + return -ENODEV; + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to " - "%02x:%02x\n", pathname, id->segment, id->bus)); + "%04x:%02x\n", (char *)buffer.pointer, + id->segment, id->bus)); status = acpi_attach_data(device->handle, acpi_pci_data_handler, data); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to attach ACPI-PCI context to device %s", - pathname)); + (char *)buffer.pointer)); result = -ENODEV; goto end; } end: - kfree(pathname); + kfree(buffer.pointer); if (result != 0) kfree(data); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index bf79d83bdfb..891bdf6679f 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -4,6 +4,8 @@ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2002 Dominik Brodowski <devel@brodo.de> + * (c) Copyright 2008 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas <bjorn.helgaas@hp.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -41,29 +43,36 @@ #define _COMPONENT ACPI_PCI_COMPONENT ACPI_MODULE_NAME("pci_irq"); -static struct acpi_prt_list acpi_prt; +struct acpi_prt_entry { + struct list_head list; + struct acpi_pci_id id; + u8 pin; + acpi_handle link; + u32 index; /* GSI, or link _CRS index */ +}; + +static LIST_HEAD(acpi_prt_list); static DEFINE_SPINLOCK(acpi_prt_lock); +static inline char pin_name(int pin) +{ + return 'A' + pin - 1; +} + /* -------------------------------------------------------------------------- PCI IRQ Routing Table (PRT) Support -------------------------------------------------------------------------- */ -static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, - int bus, - int device, int pin) +static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev, + int pin) { - struct acpi_prt_entry *entry = NULL; - - if (!acpi_prt.count) - return NULL; + struct acpi_prt_entry *entry; + int segment = pci_domain_nr(dev->bus); + int bus = dev->bus->number; + int device = PCI_SLOT(dev->devfn); - /* - * Parse through all PRT entries looking for a match on the specified - * PCI device's segment, bus, device, and pin (don't care about func). - * - */ spin_lock(&acpi_prt_lock); - list_for_each_entry(entry, &acpi_prt.entries, node) { + list_for_each_entry(entry, &acpi_prt_list, list) { if ((segment == entry->id.segment) && (bus == entry->id.bus) && (device == entry->id.device) @@ -72,7 +81,6 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment, return entry; } } - spin_unlock(&acpi_prt_lock); return NULL; } @@ -124,25 +132,27 @@ struct prt_quirk { char *actual_source; }; +#define PCI_INTX_PIN(c) (c - 'A' + 1) + /* * These systems have incorrect _PRT entries. The BIOS claims the PCI * interrupt at the listed segment/bus/device/pin is connected to the first * link device, but it is actually connected to the second. */ static struct prt_quirk prt_quirks[] = { - { medion_md9580, 0, 0, 9, 'A', + { medion_md9580, 0, 0, 9, PCI_INTX_PIN('A'), "\\_SB_.PCI0.ISA_.LNKA", "\\_SB_.PCI0.ISA_.LNKB"}, - { dell_optiplex, 0, 0, 0xd, 'A', + { dell_optiplex, 0, 0, 0xd, PCI_INTX_PIN('A'), "\\_SB_.LNKB", "\\_SB_.LNKA"}, - { hp_t5710, 0, 0, 1, 'A', + { hp_t5710, 0, 0, 1, PCI_INTX_PIN('A'), "\\_SB_.PCI0.LNK1", "\\_SB_.PCI0.LNK3"}, }; -static void -do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) +static void do_prt_fixups(struct acpi_prt_entry *entry, + struct acpi_pci_routing_table *prt) { int i; struct prt_quirk *quirk; @@ -158,42 +168,43 @@ do_prt_fixups(struct acpi_prt_entry *entry, struct acpi_pci_routing_table *prt) entry->id.segment == quirk->segment && entry->id.bus == quirk->bus && entry->id.device == quirk->device && - entry->pin + 'A' == quirk->pin && + entry->pin == quirk->pin && !strcmp(prt->source, quirk->source) && strlen(prt->source) >= strlen(quirk->actual_source)) { printk(KERN_WARNING PREFIX "firmware reports " "%04x:%02x:%02x PCI INT %c connected to %s; " "changing to %s\n", entry->id.segment, entry->id.bus, - entry->id.device, 'A' + entry->pin, + entry->id.device, pin_name(entry->pin), prt->source, quirk->actual_source); strcpy(prt->source, quirk->actual_source); } } } -static int -acpi_pci_irq_add_entry(acpi_handle handle, - int segment, int bus, struct acpi_pci_routing_table *prt) +static int acpi_pci_irq_add_entry(acpi_handle handle, int segment, int bus, + struct acpi_pci_routing_table *prt) { - struct acpi_prt_entry *entry = NULL; - - - if (!prt) - return -EINVAL; + struct acpi_prt_entry *entry; entry = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL); if (!entry) return -ENOMEM; + /* + * Note that the _PRT uses 0=INTA, 1=INTB, etc, while PCI uses + * 1=INTA, 2=INTB. We use the PCI encoding throughout, so convert + * it here. + */ entry->id.segment = segment; entry->id.bus = bus; entry->id.device = (prt->address >> 16) & 0xFFFF; - entry->id.function = prt->address & 0xFFFF; - entry->pin = prt->pin; + entry->pin = prt->pin + 1; do_prt_fixups(entry, prt); + entry->index = prt->source_index; + /* * Type 1: Dynamic * --------------- @@ -207,10 +218,9 @@ acpi_pci_irq_add_entry(acpi_handle handle, * (e.g. exists somewhere 'below' this _PRT entry in the ACPI * namespace). */ - if (prt->source[0]) { - acpi_get_handle(handle, prt->source, &entry->link.handle); - entry->link.index = prt->source_index; - } + if (prt->source[0]) + acpi_get_handle(handle, prt->source, &entry->link); + /* * Type 2: Static * -------------- @@ -218,84 +228,38 @@ acpi_pci_irq_add_entry(acpi_handle handle, * the IRQ value, which is hardwired to specific interrupt inputs on * the interrupt controller. */ - else - entry->link.index = prt->source_index; ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, - " %02X:%02X:%02X[%c] -> %s[%d]\n", + " %04x:%02x:%02x[%c] -> %s[%d]\n", entry->id.segment, entry->id.bus, - entry->id.device, ('A' + entry->pin), prt->source, - entry->link.index)); + entry->id.device, pin_name(entry->pin), + prt->source, entry->index)); spin_lock(&acpi_prt_lock); - list_add_tail(&entry->node, &acpi_prt.entries); - acpi_prt.count++; + list_add_tail(&entry->list, &acpi_prt_list); spin_unlock(&acpi_prt_lock); return 0; } -static void -acpi_pci_irq_del_entry(int segment, int bus, struct acpi_prt_entry *entry) -{ - if (segment == entry->id.segment && bus == entry->id.bus) { - acpi_prt.count--; - list_del(&entry->node); - kfree(entry); - } -} - int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) { - acpi_status status = AE_OK; - char *pathname = NULL; - struct acpi_buffer buffer = { 0, NULL }; - struct acpi_pci_routing_table *prt = NULL; - struct acpi_pci_routing_table *entry = NULL; - static int first_time = 1; - - - pathname = kzalloc(ACPI_PATHNAME_MAX, GFP_KERNEL); - if (!pathname) - return -ENOMEM; - - if (first_time) { - acpi_prt.count = 0; - INIT_LIST_HEAD(&acpi_prt.entries); - first_time = 0; - } - - /* - * NOTE: We're given a 'handle' to the _PRT object's parent device - * (either a PCI root bridge or PCI-PCI bridge). - */ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_pci_routing_table *entry; - buffer.length = ACPI_PATHNAME_MAX; - buffer.pointer = pathname; - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + /* 'handle' is the _PRT's parent (root bridge or PCI-PCI bridge) */ + status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n", - pathname); + (char *) buffer.pointer); - /* - * Evaluate this _PRT and add its entries to our global list (acpi_prt). - */ + kfree(buffer.pointer); - buffer.length = 0; + buffer.length = ACPI_ALLOCATE_BUFFER; buffer.pointer = NULL; - kfree(pathname); - status = acpi_get_irq_routing_table(handle, &buffer); - if (status != AE_BUFFER_OVERFLOW) { - ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRT [%s]", - acpi_format_exception(status))); - return -ENODEV; - } - - prt = kzalloc(buffer.length, GFP_KERNEL); - if (!prt) { - return -ENOMEM; - } - buffer.pointer = prt; status = acpi_get_irq_routing_table(handle, &buffer); if (ACPI_FAILURE(status)) { @@ -305,36 +269,30 @@ int acpi_pci_irq_add_prt(acpi_handle handle, int segment, int bus) return -ENODEV; } - entry = prt; - + entry = buffer.pointer; while (entry && (entry->length > 0)) { acpi_pci_irq_add_entry(handle, segment, bus, entry); entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } - kfree(prt); - + kfree(buffer.pointer); return 0; } void acpi_pci_irq_del_prt(int segment, int bus) { - struct list_head *node = NULL, *n = NULL; - struct acpi_prt_entry *entry = NULL; - - if (!acpi_prt.count) { - return; - } + struct acpi_prt_entry *entry, *tmp; printk(KERN_DEBUG - "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n", segment, - bus); + "ACPI: Delete PCI Interrupt Routing Table for %04x:%02x\n", + segment, bus); spin_lock(&acpi_prt_lock); - list_for_each_safe(node, n, &acpi_prt.entries) { - entry = list_entry(node, struct acpi_prt_entry, node); - - acpi_pci_irq_del_entry(segment, bus, entry); + list_for_each_entry_safe(entry, tmp, &acpi_prt_list, list) { + if (segment == entry->id.segment && bus == entry->id.bus) { + list_del(&entry->list); + kfree(entry); + } } spin_unlock(&acpi_prt_lock); } @@ -342,162 +300,26 @@ void acpi_pci_irq_del_prt(int segment, int bus) /* -------------------------------------------------------------------------- PCI Interrupt Routing Support -------------------------------------------------------------------------- */ -typedef int (*irq_lookup_func) (struct acpi_prt_entry *, int *, int *, char **); - -static int -acpi_pci_allocate_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) -{ - int irq; - - - if (entry->link.handle) { - irq = acpi_pci_link_allocate_irq(entry->link.handle, - entry->link.index, triggering, - polarity, link); - if (irq < 0) { - printk(KERN_WARNING PREFIX - "Invalid IRQ link routing entry\n"); - return -1; - } - } else { - irq = entry->link.index; - *triggering = ACPI_LEVEL_SENSITIVE; - *polarity = ACPI_ACTIVE_LOW; - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq)); - return irq; -} - -static int -acpi_pci_free_irq(struct acpi_prt_entry *entry, - int *triggering, int *polarity, char **link) -{ - int irq; - - if (entry->link.handle) { - irq = acpi_pci_link_free_irq(entry->link.handle); - } else { - irq = entry->link.index; - } - return irq; -} - -#ifdef CONFIG_X86_IO_APIC -extern int noioapicquirk; - -static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) +static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin) { - struct pci_bus *bus_it; - - for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { - if (!bus_it->self) - return 0; - - printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor, - bus_it->self->device); - - if (bus_it->self->irq_reroute_variant) - return bus_it->self->irq_reroute_variant; - } - return 0; -} -#endif /* CONFIG_X86_IO_APIC */ - -/* - * acpi_pci_irq_lookup - * success: return IRQ >= 0 - * failure: return -1 - */ -static int -acpi_pci_irq_lookup(struct pci_bus *bus, - int device, - int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct acpi_prt_entry *entry = NULL; - int segment = pci_domain_nr(bus); - int bus_nr = bus->number; - int ret; - - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Searching for PRT entry for %02x:%02x:%02x[%c]\n", - segment, bus_nr, device, ('A' + pin))); - - entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin); - if (!entry) { - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n")); - return -1; - } - - ret = func(entry, triggering, polarity, link); - -#ifdef CONFIG_X86_IO_APIC - /* - * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the - * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel - * does during interrupt handling). When this INTx generation cannot be - * disabled, we reroute these interrupts to their legacy equivalent to - * get rid of spurious interrupts. - */ - if (!noioapicquirk) { - switch (bridge_has_boot_interrupt_variant(bus)) { - case 0: - /* no rerouting necessary */ - break; - - case INTEL_IRQ_REROUTE_VARIANT: - /* - * Remap according to INTx routing table in 6700PXH - * specs, intel order number 302628-002, section - * 2.15.2. Other chipsets (80332, ...) have the same - * mapping and are handled here as well. - */ - printk(KERN_INFO "pci irq %d -> rerouted to legacy " - "irq %d\n", ret, (ret % 4) + 16); - ret = (ret % 4) + 16; - break; - - default: - printk(KERN_INFO "not rerouting irq %d to legacy irq: " - "unknown mapping\n", ret); - break; - } + struct acpi_prt_entry *entry; + struct pci_dev *bridge; + u8 bridge_pin, orig_pin = pin; + + entry = acpi_pci_irq_find_prt_entry(dev, pin); + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n", + pci_name(dev), pin_name(pin))); + return entry; } -#endif /* CONFIG_X86_IO_APIC */ - - return ret; -} - -/* - * acpi_pci_irq_derive - * success: return IRQ >= 0 - * failure: return < 0 - */ -static int -acpi_pci_irq_derive(struct pci_dev *dev, - int pin, - int *triggering, - int *polarity, char **link, irq_lookup_func func) -{ - struct pci_dev *bridge = dev; - int irq = -1; - u8 bridge_pin = 0, orig_pin = pin; - - - if (!dev) - return -EINVAL; /* * Attempt to derive an IRQ for this device from a parent bridge's * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge). */ - while (irq < 0 && bridge->bus->self) { - pin = (pin + PCI_SLOT(bridge->devfn)) % 4; - bridge = bridge->bus->self; + bridge = dev->bus->self; + while (bridge) { + pin = (((pin - 1) + PCI_SLOT(dev->devfn)) % 4) + 1; if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) { /* PC card has the same IRQ as its cardbridge */ @@ -506,50 +328,40 @@ acpi_pci_irq_derive(struct pci_dev *dev, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", pci_name(bridge))); - return -1; + return NULL; } - /* Pin is from 0 to 3 */ - bridge_pin--; pin = bridge_pin; } - irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), - pin, triggering, polarity, - link, func); - } + entry = acpi_pci_irq_find_prt_entry(bridge, pin); + if (entry) { + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Derived GSI for %s INT %c from %s\n", + pci_name(dev), pin_name(orig_pin), + pci_name(bridge))); + return entry; + } - if (irq < 0) { - dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", - 'A' + orig_pin); - return -1; + dev = bridge; + bridge = dev->bus->self; } - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n", - irq, pci_name(dev), pci_name(bridge))); - - return irq; + dev_warn(&dev->dev, "can't derive routing for PCI INT %c\n", + pin_name(orig_pin)); + return NULL; } -/* - * acpi_pci_irq_enable - * success: return 0 - * failure: return < 0 - */ - int acpi_pci_irq_enable(struct pci_dev *dev) { - int irq = 0; - u8 pin = 0; + struct acpi_prt_entry *entry; + int gsi; + u8 pin; int triggering = ACPI_LEVEL_SENSITIVE; int polarity = ACPI_ACTIVE_LOW; char *link = NULL; char link_desc[16]; int rc; - - if (!dev) - return -EINVAL; - pin = dev->pin; if (!pin) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, @@ -557,31 +369,9 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pci_name(dev))); return 0; } - pin--; - - if (!dev->bus) { - dev_err(&dev->dev, "invalid (NULL) 'bus' field\n"); - return -ENODEV; - } - - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT - * values override any BIOS-assigned IRQs set during boot. - */ - irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &triggering, &polarity, &link, - acpi_pci_allocate_irq); - - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (irq < 0) - irq = acpi_pci_irq_derive(dev, pin, &triggering, - &polarity, &link, - acpi_pci_allocate_irq); - if (irq < 0) { + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) { /* * IDE legacy mode controller IRQs are magic. Why do compat * extensions always make such a nasty mess. @@ -590,12 +380,24 @@ int acpi_pci_irq_enable(struct pci_dev *dev) (dev->class & 0x05) == 0) return 0; } + + if (entry) { + if (entry->link) + gsi = acpi_pci_link_allocate_irq(entry->link, + entry->index, + &triggering, &polarity, + &link); + else + gsi = entry->index; + } else + gsi = -1; + /* * No IRQ known to the ACPI subsystem - maybe the BIOS / * driver reported one, then use it. Exit in any case. */ - if (irq < 0) { - dev_warn(&dev->dev, "PCI INT %c: no GSI", 'A' + pin); + if (gsi < 0) { + dev_warn(&dev->dev, "PCI INT %c: no GSI", pin_name(pin)); /* Interrupt Line values above 0xF are forbidden */ if (dev->irq > 0 && (dev->irq <= 0xF)) { printk(" - using IRQ %d\n", dev->irq); @@ -608,10 +410,10 @@ int acpi_pci_irq_enable(struct pci_dev *dev) } } - rc = acpi_register_gsi(irq, triggering, polarity); + rc = acpi_register_gsi(gsi, triggering, polarity); if (rc < 0) { dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n", - 'A' + pin); + pin_name(pin)); return rc; } dev->irq = rc; @@ -622,7 +424,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) link_desc[0] = '\0'; dev_info(&dev->dev, "PCI INT %c%s -> GSI %u (%s, %s) -> IRQ %d\n", - 'A' + pin, link_desc, irq, + pin_name(pin), link_desc, gsi, (triggering == ACPI_LEVEL_SENSITIVE) ? "level" : "edge", (polarity == ACPI_ACTIVE_LOW) ? "low" : "high", dev->irq); @@ -636,42 +438,28 @@ void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) void acpi_pci_irq_disable(struct pci_dev *dev) { - int gsi = 0; - u8 pin = 0; - int triggering = ACPI_LEVEL_SENSITIVE; - int polarity = ACPI_ACTIVE_LOW; - - - if (!dev || !dev->bus) - return; + struct acpi_prt_entry *entry; + int gsi; + u8 pin; pin = dev->pin; if (!pin) return; - pin--; - /* - * First we check the PCI IRQ routing table (PRT) for an IRQ. - */ - gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - /* - * If no PRT entry was found, we'll try to derive an IRQ from the - * device's parent bridge. - */ - if (gsi < 0) - gsi = acpi_pci_irq_derive(dev, pin, - &triggering, &polarity, NULL, - acpi_pci_free_irq); - if (gsi < 0) + entry = acpi_pci_irq_lookup(dev, pin); + if (!entry) return; + if (entry->link) + gsi = acpi_pci_link_free_irq(entry->link); + else + gsi = entry->index; + /* * TBD: It might be worth clearing dev->irq by magic constant * (e.g. PCI_UNDEFINED_IRQ). */ - dev_info(&dev->dev, "PCI INT %c disabled\n", 'A' + pin); + dev_info(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); acpi_unregister_gsi(gsi); } diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index e52ad91ce2d..1c6e73c7865 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -796,10 +796,6 @@ static int irqrouter_resume(struct sys_device *dev) struct list_head *node = NULL; struct acpi_pci_link *link = NULL; - - /* Make sure SCI is enabled again (Apple firmware bug?) */ - acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1); - list_for_each(node, &acpi_link.entries) { link = list_entry(node, struct acpi_pci_link, node); if (!link) { @@ -912,7 +908,7 @@ static int __init acpi_irq_nobalance_set(char *str) __setup("acpi_irq_nobalance", acpi_irq_nobalance_set); -int __init acpi_irq_balance_set(char *str) +static int __init acpi_irq_balance_set(char *str) { acpi_irq_balance = 1; return 1; diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index bb7d50dd281..c926e7d4a0d 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -139,6 +139,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state) { acpi_status status = AE_OK; unsigned long long sta = 0; + char node_name[5]; + struct acpi_buffer buffer = { sizeof(node_name), node_name }; if (!handle || !state) @@ -151,8 +153,10 @@ static int acpi_power_get_state(acpi_handle handle, int *state) *state = (sta & 0x01)?ACPI_POWER_RESOURCE_STATE_ON: ACPI_POWER_RESOURCE_STATE_OFF; + acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n", - acpi_ut_get_node_name(handle), + node_name, *state ? "on" : "off")); return 0; diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/proc.c index 4dbc2271acf..428c911dba0 100644 --- a/drivers/acpi/sleep/proc.c +++ b/drivers/acpi/proc.c @@ -28,8 +28,6 @@ static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset) { int i; - ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show"); - for (i = 0; i <= ACPI_STATE_S5; i++) { if (sleep_states[i]) { seq_printf(seq, "S%d ", i); @@ -86,49 +84,44 @@ acpi_system_write_sleep(struct file *file, #ifdef HAVE_ACPI_LEGACY_ALARM +static u32 cmos_bcd_read(int offset, int rtc_control); + static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) { u32 sec, min, hr; u32 day, mo, yr, cent = 0; + u32 today = 0; unsigned char rtc_control = 0; unsigned long flags; - ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show"); - spin_lock_irqsave(&rtc_lock, flags); - sec = CMOS_READ(RTC_SECONDS_ALARM); - min = CMOS_READ(RTC_MINUTES_ALARM); - hr = CMOS_READ(RTC_HOURS_ALARM); rtc_control = CMOS_READ(RTC_CONTROL); + sec = cmos_bcd_read(RTC_SECONDS_ALARM, rtc_control); + min = cmos_bcd_read(RTC_MINUTES_ALARM, rtc_control); + hr = cmos_bcd_read(RTC_HOURS_ALARM, rtc_control); /* If we ever get an FACP with proper values... */ - if (acpi_gbl_FADT.day_alarm) + if (acpi_gbl_FADT.day_alarm) { /* ACPI spec: only low 6 its should be cared */ day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F; - else - day = CMOS_READ(RTC_DAY_OF_MONTH); + if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) + day = bcd2bin(day); + } else + day = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); if (acpi_gbl_FADT.month_alarm) - mo = CMOS_READ(acpi_gbl_FADT.month_alarm); - else - mo = CMOS_READ(RTC_MONTH); + mo = cmos_bcd_read(acpi_gbl_FADT.month_alarm, rtc_control); + else { + mo = cmos_bcd_read(RTC_MONTH, rtc_control); + today = cmos_bcd_read(RTC_DAY_OF_MONTH, rtc_control); + } if (acpi_gbl_FADT.century) - cent = CMOS_READ(acpi_gbl_FADT.century); + cent = cmos_bcd_read(acpi_gbl_FADT.century, rtc_control); - yr = CMOS_READ(RTC_YEAR); + yr = cmos_bcd_read(RTC_YEAR, rtc_control); spin_unlock_irqrestore(&rtc_lock, flags); - if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { - sec = bcd2bin(sec); - min = bcd2bin(min); - hr = bcd2bin(hr); - day = bcd2bin(day); - mo = bcd2bin(mo); - yr = bcd2bin(yr); - cent = bcd2bin(cent); - } - /* we're trusting the FADT (see above) */ if (!acpi_gbl_FADT.century) /* If we're not trusting the FADT, we should at least make it @@ -153,6 +146,20 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset) else yr += cent * 100; + /* + * Show correct dates for alarms up to a month into the future. + * This solves issues for nearly all situations with the common + * 30-day alarm clocks in PC hardware. + */ + if (day < today) { + if (mo < 12) { + mo += 1; + } else { + mo = 1; + yr += 1; + } + } + seq_printf(seq, "%4.4u-", yr); (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo); (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day); @@ -227,13 +234,11 @@ acpi_system_write_alarm(struct file *file, int adjust = 0; unsigned char rtc_control = 0; - ACPI_FUNCTION_TRACE("acpi_system_write_alarm"); - if (count > sizeof(alarm_string) - 1) - return_VALUE(-EINVAL); + return -EINVAL; if (copy_from_user(alarm_string, buffer, count)) - return_VALUE(-EFAULT); + return -EFAULT; alarm_string[count] = '\0'; @@ -334,7 +339,7 @@ acpi_system_write_alarm(struct file *file, result = 0; end: - return_VALUE(result ? result : count); + return result ? result : count; } #endif /* HAVE_ACPI_LEGACY_ALARM */ diff --git a/drivers/acpi/reboot.c b/drivers/acpi/reboot.c index a6b662c00b6..93f91142d7a 100644 --- a/drivers/acpi/reboot.c +++ b/drivers/acpi/reboot.c @@ -42,7 +42,7 @@ void acpi_reboot(void) case ACPI_ADR_SPACE_SYSTEM_MEMORY: case ACPI_ADR_SPACE_SYSTEM_IO: printk(KERN_DEBUG "ACPI MEMORY or I/O RESET_REG.\n"); - acpi_hw_low_level_write(8, reset_value, rr); + acpi_reset(); break; } /* Wait ten seconds */ diff --git a/drivers/acpi/resources/Makefile b/drivers/acpi/resources/Makefile deleted file mode 100644 index 8de4f69dfa0..00000000000 --- a/drivers/acpi/resources/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ - rscalc.o rsirq.o rsmemory.o rsutils.o - -obj-$(ACPI_FUTURE_USAGE) += rsdump.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index e53e590252c..0619734895b 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -10,7 +10,6 @@ #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> -#include <acpi/actypes.h> #include <linux/wait.h> #include <linux/delay.h> #include <linux/interrupt.h> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 39b7233c348..c54d7b6c406 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -10,7 +10,6 @@ #include <linux/kthread.h> #include <acpi/acpi_drivers.h> -#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("scan"); diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep.h index cfaf8f5b0a1..cfaf8f5b0a1 100644 --- a/drivers/acpi/sleep/sleep.h +++ b/drivers/acpi/sleep.h diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile deleted file mode 100644 index f1fb888c2d2..00000000000 --- a/drivers/acpi/sleep/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-y := wakeup.o -obj-y += main.o -obj-$(CONFIG_ACPI_SLEEP) += proc.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c index 6e4107f8240..391d0358a59 100644 --- a/drivers/acpi/system.c +++ b/drivers/acpi/system.c @@ -192,65 +192,6 @@ static struct attribute_group interrupt_stats_attr_group = { }; static struct kobj_attribute *counter_attrs; -static int count_num_gpes(void) -{ - int count = 0; - struct acpi_gpe_xrupt_info *gpe_xrupt_info; - struct acpi_gpe_block_info *gpe_block; - acpi_cpu_flags flags; - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_info) { - gpe_block = gpe_xrupt_info->gpe_block_list_head; - while (gpe_block) { - count += gpe_block->register_count * - ACPI_GPE_REGISTER_WIDTH; - gpe_block = gpe_block->next; - } - gpe_xrupt_info = gpe_xrupt_info->next; - } - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - - return count; -} - -static int get_gpe_device(int index, acpi_handle *handle) -{ - struct acpi_gpe_xrupt_info *gpe_xrupt_info; - struct acpi_gpe_block_info *gpe_block; - acpi_cpu_flags flags; - struct acpi_namespace_node *node; - - flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); - - gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; - while (gpe_xrupt_info) { - gpe_block = gpe_xrupt_info->gpe_block_list_head; - node = gpe_block->node; - while (gpe_block) { - index -= gpe_block->register_count * - ACPI_GPE_REGISTER_WIDTH; - if (index < 0) { - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - /* return NULL if it's FADT GPE */ - if (node->type != ACPI_TYPE_DEVICE) - *handle = NULL; - else - *handle = node; - return 0; - } - node = gpe_block->node; - gpe_block = gpe_block->next; - } - gpe_xrupt_info = gpe_xrupt_info->next; - } - acpi_os_release_lock(acpi_gbl_gpe_lock, flags); - - return -ENODEV; -} - static void delete_gpe_attr_array(void) { struct event_counter *tmp = all_counters; @@ -309,7 +250,7 @@ static int get_status(u32 index, acpi_event_status *status, acpi_handle *handle) goto end; if (index < num_gpes) { - result = get_gpe_device(index, handle); + result = acpi_get_gpe_device(index, handle); if (result) { ACPI_EXCEPTION((AE_INFO, AE_NOT_FOUND, "Invalid GPE 0x%x\n", index)); @@ -436,7 +377,7 @@ void acpi_irq_stats_init(void) if (all_counters) return; - num_gpes = count_num_gpes(); + num_gpes = acpi_current_gpe_count; num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA; all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1), diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile deleted file mode 100644 index 7385efa6162..00000000000 --- a/drivers/acpi/tables/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/utilities/Makefile b/drivers/acpi/utilities/Makefile deleted file mode 100644 index 88eff14c489..00000000000 --- a/drivers/acpi/utilities/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for all Linux ACPI interpreter subdirectories -# - -obj-y := utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \ - utcopy.o utdelete.o utglobal.o utmath.o utobject.o \ - utstate.o utmutex.o utobject.o utcache.o utresrc.o - -EXTRA_CFLAGS += $(ACPI_CFLAGS) diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c deleted file mode 100644 index 245fa80cf60..00000000000 --- a/drivers/acpi/utilities/utcache.c +++ /dev/null @@ -1,314 +0,0 @@ -/****************************************************************************** - * - * Module Name: utcache - local cache allocation routines - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2008, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. - */ - -#include <acpi/acpi.h> - -#define _COMPONENT ACPI_UTILITIES -ACPI_MODULE_NAME("utcache") -#ifdef ACPI_USE_LOCAL_CACHE -/******************************************************************************* - * - * FUNCTION: acpi_os_create_cache - * - * PARAMETERS: cache_name - Ascii name for the cache - * object_size - Size of each cached object - * max_depth - Maximum depth of the cache (in objects) - * return_cache - Where the new cache object is returned - * - * RETURN: Status - * - * DESCRIPTION: Create a cache object - * - ******************************************************************************/ -acpi_status -acpi_os_create_cache(char *cache_name, - u16 object_size, - u16 max_depth, struct acpi_memory_list ** return_cache) -{ - struct acpi_memory_list *cache; - - ACPI_FUNCTION_ENTRY(); - - if (!cache_name || !return_cache || (object_size < 16)) { - return (AE_BAD_PARAMETER); - } - - /* Create the cache object */ - - cache = acpi_os_allocate(sizeof(struct acpi_memory_list)); - if (!cache) { - return (AE_NO_MEMORY); - } - - /* Populate the cache object and return it */ - - ACPI_MEMSET(cache, 0, sizeof(struct acpi_memory_list)); - cache->link_offset = 8; - cache->list_name = cache_name; - cache->object_size = object_size; - cache->max_depth = max_depth; - - *return_cache = cache; - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_purge_cache - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: Status - * - * DESCRIPTION: Free all objects within the requested cache. - * - ******************************************************************************/ - -acpi_status acpi_os_purge_cache(struct acpi_memory_list * cache) -{ - char *next; - - ACPI_FUNCTION_ENTRY(); - - if (!cache) { - return (AE_BAD_PARAMETER); - } - - /* Walk the list of objects in this cache */ - - while (cache->list_head) { - - /* Delete and unlink one cached state object */ - - next = *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *)cache-> - list_head)[cache-> - link_offset]))); - ACPI_FREE(cache->list_head); - - cache->list_head = next; - cache->current_depth--; - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_delete_cache - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: Status - * - * DESCRIPTION: Free all objects within the requested cache and delete the - * cache object. - * - ******************************************************************************/ - -acpi_status acpi_os_delete_cache(struct acpi_memory_list * cache) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - /* Purge all objects in the cache */ - - status = acpi_os_purge_cache(cache); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Now we can delete the cache object */ - - ACPI_FREE(cache); - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_release_object - * - * PARAMETERS: Cache - Handle to cache object - * Object - The object to be released - * - * RETURN: None - * - * DESCRIPTION: Release an object to the specified cache. If cache is full, - * the object is deleted. - * - ******************************************************************************/ - -acpi_status -acpi_os_release_object(struct acpi_memory_list * cache, void *object) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - if (!cache || !object) { - return (AE_BAD_PARAMETER); - } - - /* If cache is full, just free this object */ - - if (cache->current_depth >= cache->max_depth) { - ACPI_FREE(object); - ACPI_MEM_TRACKING(cache->total_freed++); - } - - /* Otherwise put this object back into the cache */ - - else { - status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (status); - } - - /* Mark the object as cached */ - - ACPI_MEMSET(object, 0xCA, cache->object_size); - ACPI_SET_DESCRIPTOR_TYPE(object, ACPI_DESC_TYPE_CACHED); - - /* Put the object at the head of the cache list */ - - *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *)object)[cache-> - link_offset]))) = - cache->list_head; - cache->list_head = object; - cache->current_depth++; - - (void)acpi_ut_release_mutex(ACPI_MTX_CACHES); - } - - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_os_acquire_object - * - * PARAMETERS: Cache - Handle to cache object - * - * RETURN: the acquired object. NULL on error - * - * DESCRIPTION: Get an object from the specified cache. If cache is empty, - * the object is allocated. - * - ******************************************************************************/ - -void *acpi_os_acquire_object(struct acpi_memory_list *cache) -{ - acpi_status status; - void *object; - - ACPI_FUNCTION_NAME(os_acquire_object); - - if (!cache) { - return (NULL); - } - - status = acpi_ut_acquire_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - ACPI_MEM_TRACKING(cache->requests++); - - /* Check the cache first */ - - if (cache->list_head) { - - /* There is an object available, use it */ - - object = cache->list_head; - cache->list_head = *(ACPI_CAST_INDIRECT_PTR(char, - &(((char *) - object)[cache-> - link_offset]))); - - cache->current_depth--; - - ACPI_MEM_TRACKING(cache->hits++); - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, - "Object %p from %s cache\n", object, - cache->list_name)); - - status = acpi_ut_release_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - /* Clear (zero) the previously used Object */ - - ACPI_MEMSET(object, 0, cache->object_size); - } else { - /* The cache is empty, create a new object */ - - ACPI_MEM_TRACKING(cache->total_allocated++); - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - if ((cache->total_allocated - cache->total_freed) > - cache->max_occupied) { - cache->max_occupied = - cache->total_allocated - cache->total_freed; - } -#endif - - /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */ - - status = acpi_ut_release_mutex(ACPI_MTX_CACHES); - if (ACPI_FAILURE(status)) { - return (NULL); - } - - object = ACPI_ALLOCATE_ZEROED(cache->object_size); - if (!object) { - return (NULL); - } - } - - return (object); -} -#endif /* ACPI_USE_LOCAL_CACHE */ diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index baa44192972..f261737636d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -36,6 +36,7 @@ #include <linux/backlight.h> #include <linux/thermal.h> #include <linux/video_output.h> +#include <linux/sort.h> #include <asm/uaccess.h> #include <acpi/acpi_bus.h> @@ -481,6 +482,7 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) int status = AE_OK; union acpi_object arg0 = { ACPI_TYPE_INTEGER }; struct acpi_object_list args = { 1, &arg0 }; + int state; arg0.integer.value = level; @@ -489,6 +491,10 @@ acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level) status = acpi_evaluate_object(device->dev->handle, "_BCM", &args, NULL); device->brightness->curr = level; + for (state = 2; state < device->brightness->count; state++) + if (level == device->brightness->levels[state]) + device->backlight->props.brightness = state - 2; + return status; } @@ -626,6 +632,16 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag) } /* + * Simple comparison function used to sort backlight levels. + */ + +static int +acpi_video_cmp_level(const void *a, const void *b) +{ + return *(int *)a - *(int *)b; +} + +/* * Arg: * device : video output device (LCD, CRT, ..) * @@ -676,6 +692,10 @@ acpi_video_init_brightness(struct acpi_video_device *device) count++; } + /* don't sort the first two brightness levels */ + sort(&br->levels[2], count - 2, sizeof(br->levels[2]), + acpi_video_cmp_level, NULL); + if (count < 2) goto out_free_levels; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index f022eb6f563..50e3d2dbf3a 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -234,7 +234,7 @@ EXPORT_SYMBOL(acpi_video_display_switch_support); * To force that backlight or display output switching is processed by vendor * specific acpi drivers or video.ko driver. */ -int __init acpi_backlight(char *str) +static int __init acpi_backlight(char *str) { if (str == NULL || *str == '\0') return 1; @@ -250,7 +250,7 @@ int __init acpi_backlight(char *str) } __setup("acpi_backlight=", acpi_backlight); -int __init acpi_display_output(char *str) +static int __init acpi_display_output(char *str) { if (str == NULL || *str == '\0') return 1; diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/wakeup.c index dea4c23df76..2d34806d45d 100644 --- a/drivers/acpi/sleep/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -8,7 +8,6 @@ #include <acpi/acpi_drivers.h> #include <linux/kernel.h> #include <linux/types.h> -#include <acpi/acevents.h> #include "sleep.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT @@ -28,8 +27,6 @@ void acpi_enable_wakeup_device_prep(u8 sleep_state) { struct list_head *node, *next; - ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep"); - spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = container_of(node, @@ -61,7 +58,6 @@ void acpi_enable_wakeup_device(u8 sleep_state) * Caution: this routine must be invoked when interrupt is disabled * Refer ACPI2.0: P212 */ - ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device"); spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = @@ -103,8 +99,6 @@ void acpi_disable_wakeup_device(u8 sleep_state) { struct list_head *node, *next; - ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device"); - spin_lock(&acpi_device_lock); list_for_each_safe(node, next, &acpi_wakeup_device_list) { struct acpi_device *dev = diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c index 6b94fb7be5f..00c46e0b40e 100644 --- a/drivers/amba/bus.c +++ b/drivers/amba/bus.c @@ -12,9 +12,10 @@ #include <linux/device.h> #include <linux/string.h> #include <linux/slab.h> +#include <linux/io.h> #include <linux/amba/bus.h> -#include <asm/io.h> +#include <asm/irq.h> #include <asm/sizes.h> #define to_amba_device(d) container_of(d, struct amba_device, dev) diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 656448c7fef..96039671e3b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -105,7 +105,7 @@ enum { board_ahci_ign_iferr = 2, board_ahci_sb600 = 3, board_ahci_mv = 4, - board_ahci_sb700 = 5, + board_ahci_sb700 = 5, /* for SB700 and SB800 */ board_ahci_mcp65 = 6, board_ahci_nopmp = 7, @@ -439,7 +439,7 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, - /* board_ahci_sb700 */ + /* board_ahci_sb700, for SB700 and SB800 */ { AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL), .flags = AHCI_FLAG_COMMON, @@ -2446,6 +2446,8 @@ static void ahci_print_info(struct ata_host *host) speed_s = "1.5"; else if (speed == 2) speed_s = "3"; + else if (speed == 3) + speed_s = "6"; else speed_s = "?"; @@ -2610,6 +2612,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) (pdev->revision == 0xa1 || pdev->revision == 0xa2)) hpriv->flags |= AHCI_HFLAG_NO_MSI; + /* SB800 does NOT need the workaround to ignore SERR_INTERNAL */ + if (board_id == board_ahci_sb700 && pdev->revision >= 0x40) + hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL; + if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev)) pci_intx(pdev, 1); @@ -2654,6 +2660,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) host->iomap = pcim_iomap_table(pdev); host->private_data = hpriv; + if (!(hpriv->cap & HOST_CAP_SSS)) + host->flags |= ATA_HOST_PARALLEL_SCAN; + if (pi.flags & ATA_FLAG_EM) ahci_reset_em(host); diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c index 5fdf1678d0c..887d8f46a28 100644 --- a/drivers/ata/ata_piix.c +++ b/drivers/ata/ata_piix.c @@ -154,11 +154,13 @@ struct piix_map_db { struct piix_host_priv { const int *map; + u32 saved_iocfg; void __iomem *sidpr; }; static int piix_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void piix_remove_one(struct pci_dev *pdev); static int piix_pata_prereset(struct ata_link *link, unsigned long deadline); static void piix_set_piomode(struct ata_port *ap, struct ata_device *adev); static void piix_set_dmamode(struct ata_port *ap, struct ata_device *adev); @@ -296,7 +298,7 @@ static struct pci_driver piix_pci_driver = { .name = DRV_NAME, .id_table = piix_pci_tbl, .probe = piix_init_one, - .remove = ata_pci_remove_one, + .remove = piix_remove_one, #ifdef CONFIG_PM .suspend = piix_pci_device_suspend, .resume = piix_pci_device_resume, @@ -308,7 +310,7 @@ static struct scsi_host_template piix_sht = { }; static struct ata_port_operations piix_pata_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, @@ -610,8 +612,9 @@ static const struct ich_laptop ich_laptop[] = { static int ich_pata_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct piix_host_priv *hpriv = ap->host->private_data; const struct ich_laptop *lap = &ich_laptop[0]; - u8 tmp, mask; + u8 mask; /* Check for specials - Acer Aspire 5602WLMi */ while (lap->device) { @@ -625,8 +628,7 @@ static int ich_pata_cable_detect(struct ata_port *ap) /* check BIOS cable detect results */ mask = ap->port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC; - pci_read_config_byte(pdev, PIIX_IOCFG, &tmp); - if ((tmp & mask) == 0) + if ((hpriv->saved_iocfg & mask) == 0) return ATA_CBL_PATA40; return ATA_CBL_PATA80; } @@ -1350,7 +1352,7 @@ static int __devinit piix_init_sidpr(struct ata_host *host) return 0; } -static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) +static void piix_iocfg_bit18_quirk(struct ata_host *host) { static const struct dmi_system_id sysids[] = { { @@ -1367,7 +1369,8 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) { } /* terminate list */ }; - u32 iocfg; + struct pci_dev *pdev = to_pci_dev(host->dev); + struct piix_host_priv *hpriv = host->private_data; if (!dmi_check_system(sysids)) return; @@ -1376,12 +1379,11 @@ static void piix_iocfg_bit18_quirk(struct pci_dev *pdev) * seem to use it to disable a channel. Clear the bit on the * affected systems. */ - pci_read_config_dword(pdev, PIIX_IOCFG, &iocfg); - if (iocfg & (1 << 18)) { + if (hpriv->saved_iocfg & (1 << 18)) { dev_printk(KERN_INFO, &pdev->dev, "applying IOCFG bit18 quirk\n"); - iocfg &= ~(1 << 18); - pci_write_config_dword(pdev, PIIX_IOCFG, iocfg); + pci_write_config_dword(pdev, PIIX_IOCFG, + hpriv->saved_iocfg & ~(1 << 18)); } } @@ -1430,6 +1432,17 @@ static int __devinit piix_init_one(struct pci_dev *pdev, if (rc) return rc; + hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); + if (!hpriv) + return -ENOMEM; + + /* Save IOCFG, this will be used for cable detection, quirk + * detection and restoration on detach. This is necessary + * because some ACPI implementations mess up cable related + * bits on _STM. Reported on kernel bz#11879. + */ + pci_read_config_dword(pdev, PIIX_IOCFG, &hpriv->saved_iocfg); + /* ICH6R may be driven by either ata_piix or ahci driver * regardless of BIOS configuration. Make sure AHCI mode is * off. @@ -1441,10 +1454,6 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } /* SATA map init can change port_info, do it before prepping host */ - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); - if (!hpriv) - return -ENOMEM; - if (port_flags & ATA_FLAG_SATA) hpriv->map = piix_init_sata_map(pdev, port_info, piix_map_db_table[ent->driver_data]); @@ -1463,7 +1472,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev, } /* apply IOCFG bit18 quirk */ - piix_iocfg_bit18_quirk(pdev); + piix_iocfg_bit18_quirk(host); /* On ICH5, some BIOSen disable the interrupt using the * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3. @@ -1488,6 +1497,16 @@ static int __devinit piix_init_one(struct pci_dev *pdev, return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht); } +static void piix_remove_one(struct pci_dev *pdev) +{ + struct ata_host *host = dev_get_drvdata(&pdev->dev); + struct piix_host_priv *hpriv = host->private_data; + + pci_write_config_dword(pdev, PIIX_IOCFG, hpriv->saved_iocfg); + + ata_pci_remove_one(pdev); +} + static int __init piix_init(void) { int rc; diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index ef02e488d46..6273d98d00e 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -19,12 +19,6 @@ #include "libata.h" #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> enum { ATA_ACPI_FILTER_SETXFER = 1 << 0, diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f178a450ec0..71218d76d75 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1007,6 +1007,7 @@ static const char *sata_spd_string(unsigned int spd) static const char * const spd_str[] = { "1.5 Gbps", "3.0 Gbps", + "6.0 Gbps", }; if (spd == 0 || (spd - 1) >= ARRAY_SIZE(spd_str)) @@ -2000,6 +2001,10 @@ unsigned int ata_pio_need_iordy(const struct ata_device *adev) as the caller should know this */ if (adev->link->ap->flags & ATA_FLAG_NO_IORDY) return 0; + /* CF spec. r4.1 Table 22 says no iordy on PIO5 and PIO6. */ + if (ata_id_is_cfa(adev->id) + && (adev->pio_mode == XFER_PIO_5 || adev->pio_mode == XFER_PIO_6)) + return 0; /* PIO3 and higher it is mandatory */ if (adev->pio_mode > XFER_PIO_2) return 1; @@ -4551,7 +4556,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc) struct scatterlist *sg = qc->sg; int dir = qc->dma_dir; - WARN_ON(sg == NULL); + WARN_ON_ONCE(sg == NULL); VPRINTK("unmapping %u sg elements\n", qc->n_elem); @@ -4771,7 +4776,7 @@ void ata_qc_free(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; unsigned int tag; - WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ qc->flags = 0; tag = qc->tag; @@ -4786,8 +4791,8 @@ void __ata_qc_complete(struct ata_queued_cmd *qc) struct ata_port *ap = qc->ap; struct ata_link *link = qc->dev->link; - WARN_ON(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ - WARN_ON(!(qc->flags & ATA_QCFLAG_ACTIVE)); + WARN_ON_ONCE(qc == NULL); /* ata_qc_from_tag _might_ return NULL */ + WARN_ON_ONCE(!(qc->flags & ATA_QCFLAG_ACTIVE)); if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); @@ -4873,7 +4878,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc) struct ata_device *dev = qc->dev; struct ata_eh_info *ehi = &dev->link->eh_info; - WARN_ON(ap->pflags & ATA_PFLAG_FROZEN); + WARN_ON_ONCE(ap->pflags & ATA_PFLAG_FROZEN); if (unlikely(qc->err_mask)) qc->flags |= ATA_QCFLAG_FAILED; @@ -4995,16 +5000,16 @@ void ata_qc_issue(struct ata_queued_cmd *qc) * check is skipped for old EH because it reuses active qc to * request ATAPI sense. */ - WARN_ON(ap->ops->error_handler && ata_tag_valid(link->active_tag)); + WARN_ON_ONCE(ap->ops->error_handler && ata_tag_valid(link->active_tag)); if (ata_is_ncq(prot)) { - WARN_ON(link->sactive & (1 << qc->tag)); + WARN_ON_ONCE(link->sactive & (1 << qc->tag)); if (!link->sactive) ap->nr_active_links++; link->sactive |= 1 << qc->tag; } else { - WARN_ON(link->sactive); + WARN_ON_ONCE(link->sactive); ap->nr_active_links++; link->active_tag = qc->tag; @@ -5915,6 +5920,17 @@ static void async_port_probe(void *data, async_cookie_t cookie) { int rc; struct ata_port *ap = data; + + /* + * If we're not allowed to scan this host in parallel, + * we need to wait until all previous scans have completed + * before going further. + * Jeff Garzik says this is only within a controller, so we + * don't need to wait for port 0, only for later ports. + */ + if (!(ap->host->flags & ATA_HOST_PARALLEL_SCAN) && ap->port_no != 0) + async_synchronize_cookie(cookie); + /* probe */ if (ap->ops->error_handler) { struct ata_eh_info *ehi = &ap->link.eh_info; diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 9033d164c4e..5a4aad123c4 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -66,6 +66,7 @@ const struct ata_port_operations ata_sff_port_ops = { .port_start = ata_sff_port_start, }; +EXPORT_SYMBOL_GPL(ata_sff_port_ops); const struct ata_port_operations ata_bmdma_port_ops = { .inherits = &ata_sff_port_ops, @@ -77,6 +78,14 @@ const struct ata_port_operations ata_bmdma_port_ops = { .bmdma_stop = ata_bmdma_stop, .bmdma_status = ata_bmdma_status, }; +EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); + +const struct ata_port_operations ata_bmdma32_port_ops = { + .inherits = &ata_bmdma_port_ops, + + .sff_data_xfer = ata_sff_data_xfer32, +}; +EXPORT_SYMBOL_GPL(ata_bmdma32_port_ops); /** * ata_fill_sg - Fill PCI IDE PRD table @@ -166,8 +175,9 @@ static void ata_fill_sg_dumb(struct ata_queued_cmd *qc) blen = len & 0xffff; ap->prd[pi].addr = cpu_to_le32(addr); if (blen == 0) { - /* Some PATA chipsets like the CS5530 can't - cope with 0x0000 meaning 64K as the spec says */ + /* Some PATA chipsets like the CS5530 can't + cope with 0x0000 meaning 64K as the spec + says */ ap->prd[pi].flags_len = cpu_to_le32(0x8000); blen = 0x8000; ap->prd[++pi].addr = cpu_to_le32(addr + 0x8000); @@ -200,6 +210,7 @@ void ata_sff_qc_prep(struct ata_queued_cmd *qc) ata_fill_sg(qc); } +EXPORT_SYMBOL_GPL(ata_sff_qc_prep); /** * ata_sff_dumb_qc_prep - Prepare taskfile for submission @@ -217,6 +228,7 @@ void ata_sff_dumb_qc_prep(struct ata_queued_cmd *qc) ata_fill_sg_dumb(qc); } +EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep); /** * ata_sff_check_status - Read device status reg & clear interrupt @@ -233,6 +245,7 @@ u8 ata_sff_check_status(struct ata_port *ap) { return ioread8(ap->ioaddr.status_addr); } +EXPORT_SYMBOL_GPL(ata_sff_check_status); /** * ata_sff_altstatus - Read device alternate status reg @@ -275,7 +288,7 @@ static u8 ata_sff_irq_status(struct ata_port *ap) status = ata_sff_altstatus(ap); /* Not us: We are busy */ if (status & ATA_BUSY) - return status; + return status; } /* Clear INTRQ latch */ status = ap->ops->sff_check_status(ap); @@ -319,6 +332,7 @@ void ata_sff_pause(struct ata_port *ap) ata_sff_sync(ap); ndelay(400); } +EXPORT_SYMBOL_GPL(ata_sff_pause); /** * ata_sff_dma_pause - Pause before commencing DMA @@ -327,7 +341,7 @@ void ata_sff_pause(struct ata_port *ap) * Perform I/O fencing and ensure sufficient cycle delays occur * for the HDMA1:0 transition */ - + void ata_sff_dma_pause(struct ata_port *ap) { if (ap->ops->sff_check_altstatus || ap->ioaddr.altstatus_addr) { @@ -341,6 +355,7 @@ void ata_sff_dma_pause(struct ata_port *ap) corruption. */ BUG(); } +EXPORT_SYMBOL_GPL(ata_sff_dma_pause); /** * ata_sff_busy_sleep - sleep until BSY clears, or timeout @@ -396,6 +411,7 @@ int ata_sff_busy_sleep(struct ata_port *ap, return 0; } +EXPORT_SYMBOL_GPL(ata_sff_busy_sleep); static int ata_sff_check_ready(struct ata_link *link) { @@ -422,6 +438,7 @@ int ata_sff_wait_ready(struct ata_link *link, unsigned long deadline) { return ata_wait_ready(link, deadline, ata_sff_check_ready); } +EXPORT_SYMBOL_GPL(ata_sff_wait_ready); /** * ata_sff_dev_select - Select device 0/1 on ATA bus @@ -449,6 +466,7 @@ void ata_sff_dev_select(struct ata_port *ap, unsigned int device) iowrite8(tmp, ap->ioaddr.device_addr); ata_sff_pause(ap); /* needed; also flushes, for mmio */ } +EXPORT_SYMBOL_GPL(ata_sff_dev_select); /** * ata_dev_select - Select device 0/1 on ATA bus @@ -513,6 +531,7 @@ u8 ata_sff_irq_on(struct ata_port *ap) return tmp; } +EXPORT_SYMBOL_GPL(ata_sff_irq_on); /** * ata_sff_irq_clear - Clear PCI IDE BMDMA interrupt. @@ -534,6 +553,7 @@ void ata_sff_irq_clear(struct ata_port *ap) iowrite8(ioread8(mmio + ATA_DMA_STATUS), mmio + ATA_DMA_STATUS); } +EXPORT_SYMBOL_GPL(ata_sff_irq_clear); /** * ata_sff_tf_load - send taskfile registers to host controller @@ -558,7 +578,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) } if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) { - WARN_ON(!ioaddr->ctl_addr); + WARN_ON_ONCE(!ioaddr->ctl_addr); iowrite8(tf->hob_feature, ioaddr->feature_addr); iowrite8(tf->hob_nsect, ioaddr->nsect_addr); iowrite8(tf->hob_lbal, ioaddr->lbal_addr); @@ -593,6 +613,7 @@ void ata_sff_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) ata_wait_idle(ap); } +EXPORT_SYMBOL_GPL(ata_sff_tf_load); /** * ata_sff_tf_read - input device's ATA taskfile shadow registers @@ -630,9 +651,10 @@ void ata_sff_tf_read(struct ata_port *ap, struct ata_taskfile *tf) iowrite8(tf->ctl, ioaddr->ctl_addr); ap->last_ctl = tf->ctl; } else - WARN_ON(1); + WARN_ON_ONCE(1); } } +EXPORT_SYMBOL_GPL(ata_sff_tf_read); /** * ata_sff_exec_command - issue ATA command to host controller @@ -652,6 +674,7 @@ void ata_sff_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) iowrite8(tf->command, ap->ioaddr.command_addr); ata_sff_pause(ap); } +EXPORT_SYMBOL_GPL(ata_sff_exec_command); /** * ata_tf_to_host - issue ATA taskfile to host controller @@ -717,6 +740,53 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf, return words << 1; } +EXPORT_SYMBOL_GPL(ata_sff_data_xfer); + +/** + * ata_sff_data_xfer32 - Transfer data by PIO + * @dev: device to target + * @buf: data buffer + * @buflen: buffer length + * @rw: read/write + * + * Transfer data from/to the device data register by PIO using 32bit + * I/O operations. + * + * LOCKING: + * Inherited from caller. + * + * RETURNS: + * Bytes consumed. + */ + +unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf, + unsigned int buflen, int rw) +{ + struct ata_port *ap = dev->link->ap; + void __iomem *data_addr = ap->ioaddr.data_addr; + unsigned int words = buflen >> 2; + int slop = buflen & 3; + + /* Transfer multiple of 4 bytes */ + if (rw == READ) + ioread32_rep(data_addr, buf, words); + else + iowrite32_rep(data_addr, buf, words); + + if (unlikely(slop)) { + __le32 pad; + if (rw == READ) { + pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr)); + memcpy(buf + buflen - slop, &pad, slop); + } else { + memcpy(&pad, buf + buflen - slop, slop); + iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr); + } + words++; + } + return words << 2; +} +EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); /** * ata_sff_data_xfer_noirq - Transfer data by PIO @@ -746,6 +816,7 @@ unsigned int ata_sff_data_xfer_noirq(struct ata_device *dev, unsigned char *buf, return consumed; } +EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq); /** * ata_pio_sector - Transfer a sector of data. @@ -820,7 +891,7 @@ static void ata_pio_sectors(struct ata_queued_cmd *qc) /* READ/WRITE MULTIPLE */ unsigned int nsect; - WARN_ON(qc->dev->multi_count == 0); + WARN_ON_ONCE(qc->dev->multi_count == 0); nsect = min((qc->nbytes - qc->curbytes) / qc->sect_size, qc->dev->multi_count); @@ -847,7 +918,7 @@ static void atapi_send_cdb(struct ata_port *ap, struct ata_queued_cmd *qc) { /* send SCSI cdb */ DPRINTK("send cdb\n"); - WARN_ON(qc->dev->cdb_len < 12); + WARN_ON_ONCE(qc->dev->cdb_len < 12); ap->ops->sff_data_xfer(qc->dev, qc->cdb, qc->dev->cdb_len, 1); ata_sff_sync(ap); @@ -922,13 +993,15 @@ next_sg: buf = kmap_atomic(page, KM_IRQ0); /* do the actual data transfer */ - consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw); + consumed = ap->ops->sff_data_xfer(dev, buf + offset, + count, rw); kunmap_atomic(buf, KM_IRQ0); local_irq_restore(flags); } else { buf = page_address(page); - consumed = ap->ops->sff_data_xfer(dev, buf + offset, count, rw); + consumed = ap->ops->sff_data_xfer(dev, buf + offset, + count, rw); } bytes -= min(bytes, consumed); @@ -940,9 +1013,12 @@ next_sg: qc->cursg_ofs = 0; } - /* consumed can be larger than count only for the last transfer */ - WARN_ON(qc->cursg && count != consumed); - + /* + * There used to be a WARN_ON_ONCE(qc->cursg && count != consumed); + * Unfortunately __atapi_pio_bytes doesn't know enough to do the WARN + * check correctly as it doesn't know if it is the last request being + * made. Somebody should implement a proper sanity check. + */ if (bytes) goto next_sg; return 0; @@ -1013,18 +1089,19 @@ static void atapi_pio_bytes(struct ata_queued_cmd *qc) * RETURNS: * 1 if ok in workqueue, 0 otherwise. */ -static inline int ata_hsm_ok_in_wq(struct ata_port *ap, struct ata_queued_cmd *qc) +static inline int ata_hsm_ok_in_wq(struct ata_port *ap, + struct ata_queued_cmd *qc) { if (qc->tf.flags & ATA_TFLAG_POLLING) return 1; if (ap->hsm_task_state == HSM_ST_FIRST) { if (qc->tf.protocol == ATA_PROT_PIO && - (qc->tf.flags & ATA_TFLAG_WRITE)) + (qc->tf.flags & ATA_TFLAG_WRITE)) return 1; if (ata_is_atapi(qc->tf.protocol) && - !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) + !(qc->dev->flags & ATA_DFLAG_CDB_INTR)) return 1; } @@ -1098,13 +1175,13 @@ int ata_sff_hsm_move(struct ata_port *ap, struct ata_queued_cmd *qc, unsigned long flags = 0; int poll_next; - WARN_ON((qc->flags & ATA_QCFLAG_ACTIVE) == 0); + WARN_ON_ONCE((qc->flags & ATA_QCFLAG_ACTIVE) == 0); /* Make sure ata_sff_qc_issue() does not throw things * like DMA polling into the workqueue. Notice that * in_wq is not equivalent to (qc->tf.flags & ATA_TFLAG_POLLING). */ - WARN_ON(in_wq != ata_hsm_ok_in_wq(ap, qc)); + WARN_ON_ONCE(in_wq != ata_hsm_ok_in_wq(ap, qc)); fsm_start: DPRINTK("ata%u: protocol %d task_state %d (dev_stat 0x%X)\n", @@ -1313,7 +1390,7 @@ fsm_start: DPRINTK("ata%u: dev %u command complete, drv_stat 0x%x\n", ap->print_id, qc->dev->devno, status); - WARN_ON(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)); + WARN_ON_ONCE(qc->err_mask & (AC_ERR_DEV | AC_ERR_HSM)); ap->hsm_task_state = HSM_ST_IDLE; @@ -1338,6 +1415,7 @@ fsm_start: return poll_next; } +EXPORT_SYMBOL_GPL(ata_sff_hsm_move); void ata_pio_task(struct work_struct *work) { @@ -1348,7 +1426,7 @@ void ata_pio_task(struct work_struct *work) int poll_next; fsm_start: - WARN_ON(ap->hsm_task_state == HSM_ST_IDLE); + WARN_ON_ONCE(ap->hsm_task_state == HSM_ST_IDLE); /* * This is purely heuristic. This is a fast path. @@ -1437,7 +1515,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; case ATA_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -1489,7 +1567,7 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; case ATAPI_PROT_DMA: - WARN_ON(qc->tf.flags & ATA_TFLAG_POLLING); + WARN_ON_ONCE(qc->tf.flags & ATA_TFLAG_POLLING); ap->ops->sff_tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ @@ -1501,12 +1579,13 @@ unsigned int ata_sff_qc_issue(struct ata_queued_cmd *qc) break; default: - WARN_ON(1); + WARN_ON_ONCE(1); return AC_ERR_SYSTEM; } return 0; } +EXPORT_SYMBOL_GPL(ata_sff_qc_issue); /** * ata_sff_qc_fill_rtf - fill result TF using ->sff_tf_read @@ -1526,6 +1605,7 @@ bool ata_sff_qc_fill_rtf(struct ata_queued_cmd *qc) qc->ap->ops->sff_tf_read(qc->ap, &qc->result_tf); return true; } +EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); /** * ata_sff_host_intr - Handle host interrupt for given (port, task) @@ -1623,6 +1703,7 @@ idle_irq: #endif return 0; /* irq not handled */ } +EXPORT_SYMBOL_GPL(ata_sff_host_intr); /** * ata_sff_interrupt - Default ATA host interrupt handler @@ -1667,6 +1748,7 @@ irqreturn_t ata_sff_interrupt(int irq, void *dev_instance) return IRQ_RETVAL(handled); } +EXPORT_SYMBOL_GPL(ata_sff_interrupt); /** * ata_sff_freeze - Freeze SFF controller port @@ -1695,6 +1777,7 @@ void ata_sff_freeze(struct ata_port *ap) ap->ops->sff_irq_clear(ap); } +EXPORT_SYMBOL_GPL(ata_sff_freeze); /** * ata_sff_thaw - Thaw SFF controller port @@ -1712,6 +1795,7 @@ void ata_sff_thaw(struct ata_port *ap) ap->ops->sff_irq_clear(ap); ap->ops->sff_irq_on(ap); } +EXPORT_SYMBOL_GPL(ata_sff_thaw); /** * ata_sff_prereset - prepare SFF link for reset @@ -1753,6 +1837,7 @@ int ata_sff_prereset(struct ata_link *link, unsigned long deadline) return 0; } +EXPORT_SYMBOL_GPL(ata_sff_prereset); /** * ata_devchk - PATA device presence detection @@ -1865,6 +1950,7 @@ unsigned int ata_sff_dev_classify(struct ata_device *dev, int present, return class; } +EXPORT_SYMBOL_GPL(ata_sff_dev_classify); /** * ata_sff_wait_after_reset - wait for devices to become ready after reset @@ -1941,6 +2027,7 @@ int ata_sff_wait_after_reset(struct ata_link *link, unsigned int devmask, return ret; } +EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset); static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask, unsigned long deadline) @@ -2013,6 +2100,7 @@ int ata_sff_softreset(struct ata_link *link, unsigned int *classes, DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]); return 0; } +EXPORT_SYMBOL_GPL(ata_sff_softreset); /** * sata_sff_hardreset - reset host port via SATA phy reset @@ -2045,6 +2133,7 @@ int sata_sff_hardreset(struct ata_link *link, unsigned int *class, DPRINTK("EXIT, class=%u\n", *class); return rc; } +EXPORT_SYMBOL_GPL(sata_sff_hardreset); /** * ata_sff_postreset - SFF postreset callback @@ -2080,6 +2169,7 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes) if (ap->ioaddr.ctl_addr) iowrite8(ap->ctl, ap->ioaddr.ctl_addr); } +EXPORT_SYMBOL_GPL(ata_sff_postreset); /** * ata_sff_error_handler - Stock error handler for BMDMA controller @@ -2152,6 +2242,7 @@ void ata_sff_error_handler(struct ata_port *ap) ata_do_eh(ap, ap->ops->prereset, softreset, hardreset, ap->ops->postreset); } +EXPORT_SYMBOL_GPL(ata_sff_error_handler); /** * ata_sff_post_internal_cmd - Stock post_internal_cmd for SFF controller @@ -2174,6 +2265,7 @@ void ata_sff_post_internal_cmd(struct ata_queued_cmd *qc) spin_unlock_irqrestore(ap->lock, flags); } +EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd); /** * ata_sff_port_start - Set port up for dma. @@ -2194,6 +2286,7 @@ int ata_sff_port_start(struct ata_port *ap) return ata_port_start(ap); return 0; } +EXPORT_SYMBOL_GPL(ata_sff_port_start); /** * ata_sff_std_ports - initialize ioaddr with standard port offsets. @@ -2219,6 +2312,7 @@ void ata_sff_std_ports(struct ata_ioports *ioaddr) ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS; ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD; } +EXPORT_SYMBOL_GPL(ata_sff_std_ports); unsigned long ata_bmdma_mode_filter(struct ata_device *adev, unsigned long xfer_mask) @@ -2230,6 +2324,7 @@ unsigned long ata_bmdma_mode_filter(struct ata_device *adev, xfer_mask &= ~(ATA_MASK_MWDMA | ATA_MASK_UDMA); return xfer_mask; } +EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter); /** * ata_bmdma_setup - Set up PCI IDE BMDMA transaction @@ -2258,6 +2353,7 @@ void ata_bmdma_setup(struct ata_queued_cmd *qc) /* issue r/w command */ ap->ops->sff_exec_command(ap, &qc->tf); } +EXPORT_SYMBOL_GPL(ata_bmdma_setup); /** * ata_bmdma_start - Start a PCI IDE BMDMA transaction @@ -2290,6 +2386,7 @@ void ata_bmdma_start(struct ata_queued_cmd *qc) * unneccessarily delayed for MMIO */ } +EXPORT_SYMBOL_GPL(ata_bmdma_start); /** * ata_bmdma_stop - Stop PCI IDE BMDMA transfer @@ -2314,6 +2411,7 @@ void ata_bmdma_stop(struct ata_queued_cmd *qc) /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ ata_sff_dma_pause(ap); } +EXPORT_SYMBOL_GPL(ata_bmdma_stop); /** * ata_bmdma_status - Read PCI IDE BMDMA status @@ -2330,6 +2428,7 @@ u8 ata_bmdma_status(struct ata_port *ap) { return ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); } +EXPORT_SYMBOL_GPL(ata_bmdma_status); /** * ata_bus_reset - reset host port and associated ATA channel @@ -2422,6 +2521,7 @@ err_out: DPRINTK("EXIT\n"); } +EXPORT_SYMBOL_GPL(ata_bus_reset); #ifdef CONFIG_PCI @@ -2449,6 +2549,7 @@ int ata_pci_bmdma_clear_simplex(struct pci_dev *pdev) return -EOPNOTSUPP; return 0; } +EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex); /** * ata_pci_bmdma_init - acquire PCI BMDMA resources and init ATA host @@ -2501,11 +2602,12 @@ int ata_pci_bmdma_init(struct ata_host *host) host->flags |= ATA_HOST_SIMPLEX; ata_port_desc(ap, "bmdma 0x%llx", - (unsigned long long)pci_resource_start(pdev, 4) + 8 * i); + (unsigned long long)pci_resource_start(pdev, 4) + 8 * i); } return 0; } +EXPORT_SYMBOL_GPL(ata_pci_bmdma_init); static int ata_resources_present(struct pci_dev *pdev, int port) { @@ -2513,7 +2615,7 @@ static int ata_resources_present(struct pci_dev *pdev, int port) /* Check the PCI resources for this channel are enabled */ port = port * 2; - for (i = 0; i < 2; i ++) { + for (i = 0; i < 2; i++) { if (pci_resource_start(pdev, port + i) == 0 || pci_resource_len(pdev, port + i) == 0) return 0; @@ -2598,6 +2700,7 @@ int ata_pci_sff_init_host(struct ata_host *host) return 0; } +EXPORT_SYMBOL_GPL(ata_pci_sff_init_host); /** * ata_pci_sff_prepare_host - helper to prepare native PCI ATA host @@ -2615,7 +2718,7 @@ int ata_pci_sff_init_host(struct ata_host *host) * 0 on success, -errno otherwise. */ int ata_pci_sff_prepare_host(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, + const struct ata_port_info * const *ppi, struct ata_host **r_host) { struct ata_host *host; @@ -2645,17 +2748,18 @@ int ata_pci_sff_prepare_host(struct pci_dev *pdev, *r_host = host; return 0; - err_bmdma: +err_bmdma: /* This is necessary because PCI and iomap resources are * merged and releasing the top group won't release the * acquired resources if some of those have been acquired * before entering this function. */ pcim_iounmap_regions(pdev, 0xf); - err_out: +err_out: devres_release_group(&pdev->dev, NULL); return rc; } +EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host); /** * ata_pci_sff_activate_host - start SFF host, request IRQ and register it @@ -2741,7 +2845,7 @@ int ata_pci_sff_activate_host(struct ata_host *host, } rc = ata_host_register(host, sht); - out: +out: if (rc == 0) devres_remove_group(dev, NULL); else @@ -2749,6 +2853,7 @@ int ata_pci_sff_activate_host(struct ata_host *host, return rc; } +EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host); /** * ata_pci_sff_init_one - Initialize/register PCI IDE host controller @@ -2776,7 +2881,7 @@ int ata_pci_sff_activate_host(struct ata_host *host, * Zero on success, negative on errno-based value on error. */ int ata_pci_sff_init_one(struct pci_dev *pdev, - const struct ata_port_info * const * ppi, + const struct ata_port_info * const *ppi, struct scsi_host_template *sht, void *host_priv) { struct device *dev = &pdev->dev; @@ -2815,7 +2920,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev, pci_set_master(pdev); rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht); - out: +out: if (rc == 0) devres_remove_group(&pdev->dev, NULL); else @@ -2823,54 +2928,7 @@ int ata_pci_sff_init_one(struct pci_dev *pdev, return rc; } +EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); #endif /* CONFIG_PCI */ -EXPORT_SYMBOL_GPL(ata_sff_port_ops); -EXPORT_SYMBOL_GPL(ata_bmdma_port_ops); -EXPORT_SYMBOL_GPL(ata_sff_qc_prep); -EXPORT_SYMBOL_GPL(ata_sff_dumb_qc_prep); -EXPORT_SYMBOL_GPL(ata_sff_dev_select); -EXPORT_SYMBOL_GPL(ata_sff_check_status); -EXPORT_SYMBOL_GPL(ata_sff_dma_pause); -EXPORT_SYMBOL_GPL(ata_sff_pause); -EXPORT_SYMBOL_GPL(ata_sff_busy_sleep); -EXPORT_SYMBOL_GPL(ata_sff_wait_ready); -EXPORT_SYMBOL_GPL(ata_sff_tf_load); -EXPORT_SYMBOL_GPL(ata_sff_tf_read); -EXPORT_SYMBOL_GPL(ata_sff_exec_command); -EXPORT_SYMBOL_GPL(ata_sff_data_xfer); -EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq); -EXPORT_SYMBOL_GPL(ata_sff_irq_on); -EXPORT_SYMBOL_GPL(ata_sff_irq_clear); -EXPORT_SYMBOL_GPL(ata_sff_hsm_move); -EXPORT_SYMBOL_GPL(ata_sff_qc_issue); -EXPORT_SYMBOL_GPL(ata_sff_qc_fill_rtf); -EXPORT_SYMBOL_GPL(ata_sff_host_intr); -EXPORT_SYMBOL_GPL(ata_sff_interrupt); -EXPORT_SYMBOL_GPL(ata_sff_freeze); -EXPORT_SYMBOL_GPL(ata_sff_thaw); -EXPORT_SYMBOL_GPL(ata_sff_prereset); -EXPORT_SYMBOL_GPL(ata_sff_dev_classify); -EXPORT_SYMBOL_GPL(ata_sff_wait_after_reset); -EXPORT_SYMBOL_GPL(ata_sff_softreset); -EXPORT_SYMBOL_GPL(sata_sff_hardreset); -EXPORT_SYMBOL_GPL(ata_sff_postreset); -EXPORT_SYMBOL_GPL(ata_sff_error_handler); -EXPORT_SYMBOL_GPL(ata_sff_post_internal_cmd); -EXPORT_SYMBOL_GPL(ata_sff_port_start); -EXPORT_SYMBOL_GPL(ata_sff_std_ports); -EXPORT_SYMBOL_GPL(ata_bmdma_mode_filter); -EXPORT_SYMBOL_GPL(ata_bmdma_setup); -EXPORT_SYMBOL_GPL(ata_bmdma_start); -EXPORT_SYMBOL_GPL(ata_bmdma_stop); -EXPORT_SYMBOL_GPL(ata_bmdma_status); -EXPORT_SYMBOL_GPL(ata_bus_reset); -#ifdef CONFIG_PCI -EXPORT_SYMBOL_GPL(ata_pci_bmdma_clear_simplex); -EXPORT_SYMBOL_GPL(ata_pci_bmdma_init); -EXPORT_SYMBOL_GPL(ata_pci_sff_init_host); -EXPORT_SYMBOL_GPL(ata_pci_sff_prepare_host); -EXPORT_SYMBOL_GPL(ata_pci_sff_activate_host); -EXPORT_SYMBOL_GPL(ata_pci_sff_init_one); -#endif /* CONFIG_PCI */ diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index e2e332d8ff9..8b77a9802df 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -13,12 +13,6 @@ #include <linux/device.h> #include <scsi/scsi_host.h> #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> #include <linux/libata.h> #include <linux/ata.h> diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c index 73c466e452c..a7999c19f0c 100644 --- a/drivers/ata/pata_ali.c +++ b/drivers/ata/pata_ali.c @@ -19,7 +19,9 @@ * * TODO/CHECK * Cannot have ATAPI on both master & slave for rev < c2 (???) but - * otherwise should do atapi DMA. + * otherwise should do atapi DMA (For now for old we do PIO only for + * ATAPI) + * Review Sunblade workaround. */ #include <linux/kernel.h> @@ -33,12 +35,14 @@ #include <linux/dmi.h> #define DRV_NAME "pata_ali" -#define DRV_VERSION "0.7.5" +#define DRV_VERSION "0.7.8" static int ali_atapi_dma = 0; module_param_named(atapi_dma, ali_atapi_dma, int, 0644); MODULE_PARM_DESC(atapi_dma, "Enable ATAPI DMA (0=disable, 1=enable)"); +static struct pci_dev *isa_bridge; + /* * Cable special cases */ @@ -147,8 +151,7 @@ static void ali_fifo_control(struct ata_port *ap, struct ata_device *adev, int o pci_read_config_byte(pdev, pio_fifo, &fifo); fifo &= ~(0x0F << shift); - if (on) - fifo |= (on << shift); + fifo |= (on << shift); pci_write_config_byte(pdev, pio_fifo, fifo); } @@ -337,6 +340,23 @@ static int ali_check_atapi_dma(struct ata_queued_cmd *qc) return 0; } +static void ali_c2_c3_postreset(struct ata_link *link, unsigned int *classes) +{ + u8 r; + int port_bit = 4 << link->ap->port_no; + + /* If our bridge is an ALI 1533 then do the extra work */ + if (isa_bridge) { + /* Tristate and re-enable the bus signals */ + pci_read_config_byte(isa_bridge, 0x58, &r); + r &= ~port_bit; + pci_write_config_byte(isa_bridge, 0x58, r); + r |= port_bit; + pci_write_config_byte(isa_bridge, 0x58, r); + } + ata_sff_postreset(link, classes); +} + static struct scsi_host_template ali_sht = { ATA_BMDMA_SHT(DRV_NAME), }; @@ -349,10 +369,11 @@ static struct ata_port_operations ali_early_port_ops = { .inherits = &ata_sff_port_ops, .cable_detect = ata_cable_40wire, .set_piomode = ali_set_piomode, + .sff_data_xfer = ata_sff_data_xfer32, }; static const struct ata_port_operations ali_dma_base_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .set_piomode = ali_set_piomode, .set_dmamode = ali_set_dmamode, }; @@ -377,6 +398,17 @@ static struct ata_port_operations ali_c2_port_ops = { .check_atapi_dma = ali_check_atapi_dma, .cable_detect = ali_c2_cable_detect, .dev_config = ali_lock_sectors, + .postreset = ali_c2_c3_postreset, +}; + +/* + * Port operations for DMA capable ALi with cable detect + */ +static struct ata_port_operations ali_c4_port_ops = { + .inherits = &ali_dma_base_ops, + .check_atapi_dma = ali_check_atapi_dma, + .cable_detect = ali_c2_cable_detect, + .dev_config = ali_lock_sectors, }; /* @@ -401,52 +433,49 @@ static struct ata_port_operations ali_c5_port_ops = { static void ali_init_chipset(struct pci_dev *pdev) { u8 tmp; - struct pci_dev *north, *isa_bridge; + struct pci_dev *north; /* * The chipset revision selects the driver operations and * mode data. */ - if (pdev->revision >= 0x20 && pdev->revision < 0xC2) { - /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ - pci_read_config_byte(pdev, 0x4B, &tmp); - /* Clear CD-ROM DMA write bit */ - tmp &= 0x7F; - pci_write_config_byte(pdev, 0x4B, tmp); - } else if (pdev->revision >= 0xC2) { - /* Enable cable detection logic */ + if (pdev->revision <= 0x20) { + pci_read_config_byte(pdev, 0x53, &tmp); + tmp |= 0x03; + pci_write_config_byte(pdev, 0x53, tmp); + } else { + pci_read_config_byte(pdev, 0x4a, &tmp); + pci_write_config_byte(pdev, 0x4a, tmp | 0x20); pci_read_config_byte(pdev, 0x4B, &tmp); - pci_write_config_byte(pdev, 0x4B, tmp | 0x08); - } - north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); - isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); - - if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { - /* Configure the ALi bridge logic. For non ALi rely on BIOS. - Set the south bridge enable bit */ - pci_read_config_byte(isa_bridge, 0x79, &tmp); - if (pdev->revision == 0xC2) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); - else if (pdev->revision > 0xC2 && pdev->revision < 0xC5) - pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); - } - if (pdev->revision >= 0x20) { + if (pdev->revision < 0xC2) + /* 1543-E/F, 1543C-C, 1543C-D, 1543C-E */ + /* Clear CD-ROM DMA write bit */ + tmp &= 0x7F; + /* Cable and UDMA */ + pci_write_config_byte(pdev, 0x4B, tmp | 0x09); /* * CD_ROM DMA on (0x53 bit 0). Enable this even if we want * to use PIO. 0x53 bit 1 (rev 20 only) - enable FIFO control * via 0x54/55. */ pci_read_config_byte(pdev, 0x53, &tmp); - if (pdev->revision <= 0x20) - tmp &= ~0x02; if (pdev->revision >= 0xc7) tmp |= 0x03; else tmp |= 0x01; /* CD_ROM enable for DMA */ pci_write_config_byte(pdev, 0x53, tmp); } - pci_dev_put(isa_bridge); + north = pci_get_bus_and_slot(0, PCI_DEVFN(0,0)); + if (north && north->vendor == PCI_VENDOR_ID_AL && isa_bridge) { + /* Configure the ALi bridge logic. For non ALi rely on BIOS. + Set the south bridge enable bit */ + pci_read_config_byte(isa_bridge, 0x79, &tmp); + if (pdev->revision == 0xC2) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x04); + else if (pdev->revision > 0xC2 && pdev->revision < 0xC5) + pci_write_config_byte(isa_bridge, 0x79, tmp | 0x02); + } pci_dev_put(north); ata_pci_bmdma_clear_simplex(pdev); } @@ -503,7 +532,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA5, - .port_ops = &ali_c2_port_ops + .port_ops = &ali_c4_port_ops }; /* Revision 0xC5 is UDMA133 with LBA48 DMA */ static const struct ata_port_info info_c5 = { @@ -516,7 +545,6 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) const struct ata_port_info *ppi[] = { NULL, NULL }; u8 tmp; - struct pci_dev *isa_bridge; int rc; rc = pcim_enable_device(pdev); @@ -543,14 +571,12 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id) ali_init_chipset(pdev); - isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); if (isa_bridge && pdev->revision >= 0x20 && pdev->revision < 0xC2) { /* Are we paired with a UDMA capable chip */ pci_read_config_byte(isa_bridge, 0x5E, &tmp); if ((tmp & 0x1E) == 0x12) ppi[0] = &info_20_udma; } - pci_dev_put(isa_bridge); return ata_pci_sff_init_one(pdev, ppi, &ali_sht, NULL); } @@ -590,13 +616,20 @@ static struct pci_driver ali_pci_driver = { static int __init ali_init(void) { - return pci_register_driver(&ali_pci_driver); + int ret; + isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL); + + ret = pci_register_driver(&ali_pci_driver); + if (ret < 0) + pci_dev_put(isa_bridge); + return ret; } static void __exit ali_exit(void) { pci_unregister_driver(&ali_pci_driver); + pci_dev_put(isa_bridge); } diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c index 0ec9c7d9fe9..63719ab9ea4 100644 --- a/drivers/ata/pata_amd.c +++ b/drivers/ata/pata_amd.c @@ -24,7 +24,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_amd" -#define DRV_VERSION "0.3.10" +#define DRV_VERSION "0.3.11" /** * timing_setup - shared timing computation and load @@ -345,7 +345,7 @@ static struct scsi_host_template amd_sht = { }; static const struct ata_port_operations amd_base_port_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .prereset = amd_pre_reset, }; diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c index e0c4f05d7d5..65c28e5a6cd 100644 --- a/drivers/ata/pata_hpt366.c +++ b/drivers/ata/pata_hpt366.c @@ -30,7 +30,7 @@ #define DRV_VERSION "0.6.2" struct hpt_clock { - u8 xfer_speed; + u8 xfer_mode; u32 timing; }; @@ -189,28 +189,6 @@ static unsigned long hpt366_filter(struct ata_device *adev, unsigned long mask) return ata_bmdma_mode_filter(adev, mask); } -/** - * hpt36x_find_mode - reset the hpt36x bus - * @ap: ATA port - * @speed: transfer mode - * - * Return the 32bit register programming information for this channel - * that matches the speed provided. - */ - -static u32 hpt36x_find_mode(struct ata_port *ap, int speed) -{ - struct hpt_clock *clocks = ap->host->private_data; - - while(clocks->xfer_speed) { - if (clocks->xfer_speed == speed) - return clocks->timing; - clocks++; - } - BUG(); - return 0xffffffffU; /* silence compiler warning */ -} - static int hpt36x_cable_detect(struct ata_port *ap) { struct pci_dev *pdev = to_pci_dev(ap->host->dev); @@ -226,25 +204,16 @@ static int hpt36x_cable_detect(struct ata_port *ap) return ATA_CBL_PATA80; } -/** - * hpt366_set_piomode - PIO setup - * @ap: ATA interface - * @adev: device on the interface - * - * Perform PIO mode setup. - */ - -static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) +static void hpt366_set_mode(struct ata_port *ap, struct ata_device *adev, + u8 mode) { + struct hpt_clock *clocks = ap->host->private_data; struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 addr1, addr2; - u32 reg; - u32 mode; + u32 addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); + u32 addr2 = 0x51 + 4 * ap->port_no; + u32 mask, reg; u8 fast; - addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); - addr2 = 0x51 + 4 * ap->port_no; - /* Fast interrupt prediction disable, hold off interrupt disable */ pci_read_config_byte(pdev, addr2, &fast); if (fast & 0x80) { @@ -252,12 +221,43 @@ static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) pci_write_config_byte(pdev, addr2, fast); } + /* determine timing mask and find matching clock entry */ + if (mode < XFER_MW_DMA_0) + mask = 0xc1f8ffff; + else if (mode < XFER_UDMA_0) + mask = 0x303800ff; + else + mask = 0x30070000; + + while (clocks->xfer_mode) { + if (clocks->xfer_mode == mode) + break; + clocks++; + } + if (!clocks->xfer_mode) + BUG(); + + /* + * Combine new mode bits with old config bits and disable + * on-chip PIO FIFO/buffer (and PIO MST mode as well) to avoid + * problems handling I/O errors later. + */ pci_read_config_dword(pdev, addr1, ®); - mode = hpt36x_find_mode(ap, adev->pio_mode); - mode &= ~0x8000000; /* No FIFO in PIO */ - mode &= ~0x30070000; /* Leave config bits alone */ - reg &= 0x30070000; /* Strip timing bits */ - pci_write_config_dword(pdev, addr1, reg | mode); + reg = ((reg & ~mask) | (clocks->timing & mask)) & ~0xc0000000; + pci_write_config_dword(pdev, addr1, reg); +} + +/** + * hpt366_set_piomode - PIO setup + * @ap: ATA interface + * @adev: device on the interface + * + * Perform PIO mode setup. + */ + +static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + hpt366_set_mode(ap, adev, adev->pio_mode); } /** @@ -271,28 +271,7 @@ static void hpt366_set_piomode(struct ata_port *ap, struct ata_device *adev) static void hpt366_set_dmamode(struct ata_port *ap, struct ata_device *adev) { - struct pci_dev *pdev = to_pci_dev(ap->host->dev); - u32 addr1, addr2; - u32 reg; - u32 mode; - u8 fast; - - addr1 = 0x40 + 4 * (adev->devno + 2 * ap->port_no); - addr2 = 0x51 + 4 * ap->port_no; - - /* Fast interrupt prediction disable, hold off interrupt disable */ - pci_read_config_byte(pdev, addr2, &fast); - if (fast & 0x80) { - fast &= ~0x80; - pci_write_config_byte(pdev, addr2, fast); - } - - pci_read_config_dword(pdev, addr1, ®); - mode = hpt36x_find_mode(ap, adev->dma_mode); - mode |= 0x8000000; /* FIFO in MWDMA or UDMA */ - mode &= ~0xC0000000; /* Leave config bits alone */ - reg &= 0xC0000000; /* Strip timing bits */ - pci_write_config_dword(pdev, addr1, reg | mode); + hpt366_set_mode(ap, adev, adev->dma_mode); } static struct scsi_host_template hpt36x_sht = { diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c index f11a320337c..f19cc645881 100644 --- a/drivers/ata/pata_hpt3x3.c +++ b/drivers/ata/pata_hpt3x3.c @@ -23,7 +23,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_hpt3x3" -#define DRV_VERSION "0.5.3" +#define DRV_VERSION "0.6.1" /** * hpt3x3_set_piomode - PIO setup @@ -80,14 +80,48 @@ static void hpt3x3_set_dmamode(struct ata_port *ap, struct ata_device *adev) r2 &= ~(0x11 << dn); /* Clear MWDMA and UDMA bits */ if (adev->dma_mode >= XFER_UDMA_0) - r2 |= (0x10 << dn); /* Ultra mode */ + r2 |= (0x01 << dn); /* Ultra mode */ else - r2 |= (0x01 << dn); /* MWDMA */ + r2 |= (0x10 << dn); /* MWDMA */ pci_write_config_dword(pdev, 0x44, r1); pci_write_config_dword(pdev, 0x48, r2); } -#endif /* CONFIG_PATA_HPT3X3_DMA */ + +/** + * hpt3x3_freeze - DMA workaround + * @ap: port to freeze + * + * When freezing an HPT3x3 we must stop any pending DMA before + * writing to the control register or the chip will hang + */ + +static void hpt3x3_freeze(struct ata_port *ap) +{ + void __iomem *mmio = ap->ioaddr.bmdma_addr; + + iowrite8(ioread8(mmio + ATA_DMA_CMD) & ~ ATA_DMA_START, + mmio + ATA_DMA_CMD); + ata_sff_dma_pause(ap); + ata_sff_freeze(ap); +} + +/** + * hpt3x3_bmdma_setup - DMA workaround + * @qc: Queued command + * + * When issuing BMDMA we must clean up the error/active bits in + * software on this device + */ + +static void hpt3x3_bmdma_setup(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + u8 r = ioread8(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + r |= ATA_DMA_INTR | ATA_DMA_ERR; + iowrite8(r, ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + return ata_bmdma_setup(qc); +} /** * hpt3x3_atapi_dma - ATAPI DMA check @@ -101,18 +135,23 @@ static int hpt3x3_atapi_dma(struct ata_queued_cmd *qc) return 1; } +#endif /* CONFIG_PATA_HPT3X3_DMA */ + static struct scsi_host_template hpt3x3_sht = { ATA_BMDMA_SHT(DRV_NAME), }; static struct ata_port_operations hpt3x3_port_ops = { .inherits = &ata_bmdma_port_ops, - .check_atapi_dma= hpt3x3_atapi_dma, .cable_detect = ata_cable_40wire, .set_piomode = hpt3x3_set_piomode, #if defined(CONFIG_PATA_HPT3X3_DMA) .set_dmamode = hpt3x3_set_dmamode, + .bmdma_setup = hpt3x3_bmdma_setup, + .check_atapi_dma= hpt3x3_atapi_dma, + .freeze = hpt3x3_freeze, #endif + }; /** diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c index f828a29d775..f1bb2f9fecb 100644 --- a/drivers/ata/pata_it821x.c +++ b/drivers/ata/pata_it821x.c @@ -80,7 +80,7 @@ #define DRV_NAME "pata_it821x" -#define DRV_VERSION "0.4.0" +#define DRV_VERSION "0.4.2" struct it821x_dev { @@ -494,8 +494,6 @@ static int it821x_smart_set_mode(struct ata_link *link, struct ata_device **unus * special. In our case we need to lock the sector count to avoid * blowing the brains out of the firmware with large LBA48 requests * - * FIXME: When FUA appears we need to block FUA too. And SMART and - * basically we need to filter commands for this chip. */ static void it821x_dev_config(struct ata_device *adev) @@ -890,6 +888,13 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) .flags = ATA_FLAG_SLAVE_POSS, .pio_mask = 0x1f, .mwdma_mask = 0x07, + .udma_mask = ATA_UDMA6, + .port_ops = &it821x_rdc_port_ops + }; + static const struct ata_port_info info_rdc_11 = { + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = 0x1f, + .mwdma_mask = 0x07, /* No UDMA */ .port_ops = &it821x_rdc_port_ops }; @@ -903,7 +908,11 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id) return rc; if (pdev->vendor == PCI_VENDOR_ID_RDC) { - ppi[0] = &info_rdc; + /* Deal with Vortex86SX */ + if (pdev->revision == 0x11) + ppi[0] = &info_rdc_11; + else + ppi[0] = &info_rdc; } else { /* Force the card into bypass mode if so requested */ if (it8212_noraid) { diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c index 7c8faa48b5f..aa576cac4d1 100644 --- a/drivers/ata/pata_mpiix.c +++ b/drivers/ata/pata_mpiix.c @@ -35,7 +35,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_mpiix" -#define DRV_VERSION "0.7.6" +#define DRV_VERSION "0.7.7" enum { IDETIM = 0x6C, /* IDE control register */ @@ -146,6 +146,7 @@ static struct ata_port_operations mpiix_port_ops = { .cable_detect = ata_cable_40wire, .set_piomode = mpiix_set_piomode, .prereset = mpiix_pre_reset, + .sff_data_xfer = ata_sff_data_xfer32, }; static int mpiix_init_one(struct pci_dev *dev, const struct pci_device_id *id) diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index 6afa07a3764..d8d743af322 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -186,7 +186,7 @@ EXPORT_SYMBOL_GPL(__pata_platform_probe); * A platform bus ATA device has been unplugged. Perform the needed * cleanup. Also called on module unload for any active devices. */ -int __devexit __pata_platform_remove(struct device *dev) +int __pata_platform_remove(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c index 83580a59db5..9e764e5747e 100644 --- a/drivers/ata/pata_sil680.c +++ b/drivers/ata/pata_sil680.c @@ -32,7 +32,7 @@ #include <linux/libata.h> #define DRV_NAME "pata_sil680" -#define DRV_VERSION "0.4.8" +#define DRV_VERSION "0.4.9" #define SIL680_MMIO_BAR 5 @@ -195,7 +195,7 @@ static struct scsi_host_template sil680_sht = { }; static struct ata_port_operations sil680_port_ops = { - .inherits = &ata_bmdma_port_ops, + .inherits = &ata_bmdma32_port_ops, .cable_detect = sil680_cable_detect, .set_piomode = sil680_set_piomode, .set_dmamode = sil680_set_dmamode, diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c index ccee930f1e1..2590c2279fa 100644 --- a/drivers/ata/sata_sil24.c +++ b/drivers/ata/sata_sil24.c @@ -51,13 +51,6 @@ struct sil24_sge { __le32 flags; }; -/* - * Port multiplier - */ -struct sil24_port_multiplier { - __le32 diag; - __le32 sactive; -}; enum { SIL24_HOST_BAR = 0, diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index 088885ed51b..e1c7611e914 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -64,7 +64,7 @@ #include <linux/jiffies.h> #include "iphase.h" #include "suni.h" -#define swap(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) +#define swap_byte_order(x) (((x & 0xff) << 8) | ((x & 0xff00) >> 8)) #define PRIV(dev) ((struct suni_priv *) dev->phy_data) @@ -1306,7 +1306,7 @@ static void rx_dle_intr(struct atm_dev *dev) // get real pkt length pwang_test trailer = (struct cpcs_trailer*)((u_char *)skb->data + skb->len - sizeof(*trailer)); - length = swap(trailer->length); + length = swap_byte_order(trailer->length); if ((length > iadev->rx_buf_sz) || (length > (skb->len - sizeof(struct cpcs_trailer)))) { @@ -2995,7 +2995,7 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) { skb->len, PCI_DMA_TODEVICE); wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) | buf_desc_ptr->buf_start_lo; - /* wr_ptr->bytes = swap(total_len); didn't seem to affect ?? */ + /* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */ wr_ptr->bytes = skb->len; /* hw bug - DLEs of 0x2d, 0x2e, 0x2f cause DMA lockup */ diff --git a/drivers/base/base.h b/drivers/base/base.h index b676f8f801f..0a5f055dffb 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -63,32 +63,6 @@ struct class_private { #define to_class(obj) \ container_of(obj, struct class_private, class_subsys.kobj) -/** - * struct device_private - structure to hold the private to the driver core portions of the device structure. - * - * @klist_children - klist containing all children of this device - * @knode_parent - node in sibling list - * @knode_driver - node in driver list - * @knode_bus - node in bus list - * @device - pointer back to the struct class that this structure is - * associated with. - * - * Nothing outside of the driver core should ever touch these fields. - */ -struct device_private { - struct klist klist_children; - struct klist_node knode_parent; - struct klist_node knode_driver; - struct klist_node knode_bus; - struct device *device; -}; -#define to_device_private_parent(obj) \ - container_of(obj, struct device_private, knode_parent) -#define to_device_private_driver(obj) \ - container_of(obj, struct device_private, knode_driver) -#define to_device_private_bus(obj) \ - container_of(obj, struct device_private, knode_bus) - /* initialisation functions */ extern int devices_init(void); extern int buses_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 0f0a5044467..83f32b891fa 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -253,14 +253,7 @@ static ssize_t store_drivers_probe(struct bus_type *bus, static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *dev_prv; - - if (n) { - dev_prv = to_device_private_bus(n); - dev = dev_prv->device; - } - return dev; + return n ? container_of(n, struct device, knode_bus) : NULL; } /** @@ -293,7 +286,7 @@ int bus_for_each_dev(struct bus_type *bus, struct device *start, return -EINVAL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->p->knode_bus : NULL)); + (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -327,7 +320,7 @@ struct device *bus_find_device(struct bus_type *bus, return NULL; klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->p->knode_bus : NULL)); + (start ? &start->knode_bus : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; @@ -514,8 +507,7 @@ void bus_attach_device(struct device *dev) ret = device_attach(dev); WARN_ON(ret < 0); if (ret >= 0) - klist_add_tail(&dev->p->knode_bus, - &bus->p->klist_devices); + klist_add_tail(&dev->knode_bus, &bus->p->klist_devices); } } @@ -536,8 +528,8 @@ void bus_remove_device(struct device *dev) sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev_name(dev)); device_remove_attrs(dev->bus, dev); - if (klist_node_attached(&dev->p->knode_bus)) - klist_del(&dev->p->knode_bus); + if (klist_node_attached(&dev->knode_bus)) + klist_del(&dev->knode_bus); pr_debug("bus: '%s': remove device %s\n", dev->bus->name, dev_name(dev)); @@ -839,16 +831,14 @@ static void bus_remove_attrs(struct bus_type *bus) static void klist_devices_get(struct klist_node *n) { - struct device_private *dev_prv = to_device_private_bus(n); - struct device *dev = dev_prv->device; + struct device *dev = container_of(n, struct device, knode_bus); get_device(dev); } static void klist_devices_put(struct klist_node *n) { - struct device_private *dev_prv = to_device_private_bus(n); - struct device *dev = dev_prv->device; + struct device *dev = container_of(n, struct device, knode_bus); put_device(dev); } @@ -1003,20 +993,18 @@ static void device_insertion_sort_klist(struct device *a, struct list_head *list { struct list_head *pos; struct klist_node *n; - struct device_private *dev_prv; struct device *b; list_for_each(pos, list) { n = container_of(pos, struct klist_node, n_node); - dev_prv = to_device_private_bus(n); - b = dev_prv->device; + b = container_of(n, struct device, knode_bus); if (compare(a, b) <= 0) { - list_move_tail(&a->p->knode_bus.n_node, - &b->p->knode_bus.n_node); + list_move_tail(&a->knode_bus.n_node, + &b->knode_bus.n_node); return; } } - list_move_tail(&a->p->knode_bus.n_node, list); + list_move_tail(&a->knode_bus.n_node, list); } void bus_sort_breadthfirst(struct bus_type *bus, @@ -1026,7 +1014,6 @@ void bus_sort_breadthfirst(struct bus_type *bus, LIST_HEAD(sorted_devices); struct list_head *pos, *tmp; struct klist_node *n; - struct device_private *dev_prv; struct device *dev; struct klist *device_klist; @@ -1035,8 +1022,7 @@ void bus_sort_breadthfirst(struct bus_type *bus, spin_lock(&device_klist->k_lock); list_for_each_safe(pos, tmp, &device_klist->k_list) { n = container_of(pos, struct klist_node, n_node); - dev_prv = to_device_private_bus(n); - dev = dev_prv->device; + dev = container_of(n, struct device, knode_bus); device_insertion_sort_klist(dev, &sorted_devices, compare); } list_splice(&sorted_devices, &device_klist->k_list); diff --git a/drivers/base/core.c b/drivers/base/core.c index 61df508fa62..8079afca497 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -109,7 +109,6 @@ static struct sysfs_ops dev_sysfs_ops = { static void device_release(struct kobject *kobj) { struct device *dev = to_dev(kobj); - struct device_private *p = dev->p; if (dev->release) dev->release(dev); @@ -121,7 +120,6 @@ static void device_release(struct kobject *kobj) WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", dev_name(dev)); - kfree(p); } static struct kobj_type device_ktype = { @@ -509,16 +507,14 @@ EXPORT_SYMBOL_GPL(device_schedule_callback_owner); static void klist_children_get(struct klist_node *n) { - struct device_private *p = to_device_private_parent(n); - struct device *dev = p->device; + struct device *dev = container_of(n, struct device, knode_parent); get_device(dev); } static void klist_children_put(struct klist_node *n) { - struct device_private *p = to_device_private_parent(n); - struct device *dev = p->device; + struct device *dev = container_of(n, struct device, knode_parent); put_device(dev); } @@ -540,15 +536,9 @@ static void klist_children_put(struct klist_node *n) */ void device_initialize(struct device *dev) { - dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); - if (!dev->p) { - WARN_ON(1); - return; - } - dev->p->device = dev; dev->kobj.kset = devices_kset; kobject_init(&dev->kobj, &device_ktype); - klist_init(&dev->p->klist_children, klist_children_get, + klist_init(&dev->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); init_MUTEX(&dev->sem); @@ -932,8 +922,7 @@ int device_add(struct device *dev) kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) - klist_add_tail(&dev->p->knode_parent, - &parent->p->klist_children); + klist_add_tail(&dev->knode_parent, &parent->klist_children); if (dev->class) { mutex_lock(&dev->class->p->class_mutex); @@ -1047,7 +1036,7 @@ void device_del(struct device *dev) device_pm_remove(dev); dpm_sysfs_remove(dev); if (parent) - klist_del(&dev->p->knode_parent); + klist_del(&dev->knode_parent); if (MAJOR(dev->devt)) { device_remove_sys_dev_entry(dev); device_remove_file(dev, &devt_attr); @@ -1108,14 +1097,7 @@ void device_unregister(struct device *dev) static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *p; - - if (n) { - p = to_device_private_parent(n); - dev = p->device; - } - return dev; + return n ? container_of(n, struct device, knode_parent) : NULL; } /** @@ -1137,7 +1119,7 @@ int device_for_each_child(struct device *parent, void *data, struct device *child; int error = 0; - klist_iter_init(&parent->p->klist_children, &i); + klist_iter_init(&parent->klist_children, &i); while ((child = next_device(&i)) && !error) error = fn(child, data); klist_iter_exit(&i); @@ -1168,7 +1150,7 @@ struct device *device_find_child(struct device *parent, void *data, if (!parent) return NULL; - klist_iter_init(&parent->p->klist_children, &i); + klist_iter_init(&parent->klist_children, &i); while ((child = next_device(&i))) if (match(child, data) && get_device(child)) break; @@ -1582,10 +1564,9 @@ int device_move(struct device *dev, struct device *new_parent) old_parent = dev->parent; dev->parent = new_parent; if (old_parent) - klist_remove(&dev->p->knode_parent); + klist_remove(&dev->knode_parent); if (new_parent) { - klist_add_tail(&dev->p->knode_parent, - &new_parent->p->klist_children); + klist_add_tail(&dev->knode_parent, &new_parent->klist_children); set_dev_node(dev, dev_to_node(new_parent)); } @@ -1597,11 +1578,11 @@ int device_move(struct device *dev, struct device *new_parent) device_move_class_links(dev, new_parent, old_parent); if (!kobject_move(&dev->kobj, &old_parent->kobj)) { if (new_parent) - klist_remove(&dev->p->knode_parent); + klist_remove(&dev->knode_parent); dev->parent = old_parent; if (old_parent) { - klist_add_tail(&dev->p->knode_parent, - &old_parent->p->klist_children); + klist_add_tail(&dev->knode_parent, + &old_parent->klist_children); set_dev_node(dev, dev_to_node(old_parent)); } } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 6fdaf76f033..315bed8d5e7 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -28,7 +28,7 @@ static void driver_bound(struct device *dev) { - if (klist_node_attached(&dev->p->knode_driver)) { + if (klist_node_attached(&dev->knode_driver)) { printk(KERN_WARNING "%s: device %s already bound\n", __func__, kobject_name(&dev->kobj)); return; @@ -41,7 +41,7 @@ static void driver_bound(struct device *dev) blocking_notifier_call_chain(&dev->bus->p->bus_notifier, BUS_NOTIFY_BOUND_DRIVER, dev); - klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); + klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices); } static int driver_sysfs_add(struct device *dev) @@ -310,7 +310,7 @@ static void __device_release_driver(struct device *dev) drv->remove(dev); devres_release_all(dev); dev->driver = NULL; - klist_remove(&dev->p->knode_driver); + klist_remove(&dev->knode_driver); } } @@ -340,7 +340,6 @@ EXPORT_SYMBOL_GPL(device_release_driver); */ void driver_detach(struct device_driver *drv) { - struct device_private *dev_prv; struct device *dev; for (;;) { @@ -349,10 +348,8 @@ void driver_detach(struct device_driver *drv) spin_unlock(&drv->p->klist_devices.k_lock); break; } - dev_prv = list_entry(drv->p->klist_devices.k_list.prev, - struct device_private, - knode_driver.n_node); - dev = dev_prv->device; + dev = list_entry(drv->p->klist_devices.k_list.prev, + struct device, knode_driver.n_node); get_device(dev); spin_unlock(&drv->p->klist_devices.k_lock); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index b76cc69f110..1e2bda780e4 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -19,14 +19,7 @@ static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *dev_prv; - - if (n) { - dev_prv = to_device_private_driver(n); - dev = dev_prv->device; - } - return dev; + return n ? container_of(n, struct device, knode_driver) : NULL; } /** @@ -49,7 +42,7 @@ int driver_for_each_device(struct device_driver *drv, struct device *start, return -EINVAL; klist_iter_init_node(&drv->p->klist_devices, &i, - start ? &start->p->knode_driver : NULL); + start ? &start->knode_driver : NULL); while ((dev = next_device(&i)) && !error) error = fn(dev, data); klist_iter_exit(&i); @@ -83,7 +76,7 @@ struct device *driver_find_device(struct device_driver *drv, return NULL; klist_iter_init_node(&drv->p->klist_devices, &i, - (start ? &start->p->knode_driver : NULL)); + (start ? &start->knode_driver : NULL)); while ((dev = next_device(&i))) if (match(dev, data) && get_device(dev)) break; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 4b1d4ac960f..8df436ff706 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -156,7 +156,7 @@ static volatile int fdc_busy = -1; static volatile int fdc_nested; static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); -static DECLARE_WAIT_QUEUE_HEAD(motor_wait); +static DECLARE_COMPLETION(motor_on_completion); static volatile int selected = -1; /* currently selected drive */ @@ -184,8 +184,7 @@ static unsigned char mfmencode[16]={ static unsigned char mfmdecode[128]; /* floppy internal millisecond timer stuff */ -static volatile int ms_busy = -1; -static DECLARE_WAIT_QUEUE_HEAD(ms_wait); +static DECLARE_COMPLETION(ms_wait_completion); #define MS_TICKS ((amiga_eclock+50)/1000) /* @@ -211,8 +210,7 @@ static int fd_device[4] = { 0, 0, 0, 0 }; static irqreturn_t ms_isr(int irq, void *dummy) { - ms_busy = -1; - wake_up(&ms_wait); + complete(&ms_wait_completion); return IRQ_HANDLED; } @@ -220,19 +218,17 @@ static irqreturn_t ms_isr(int irq, void *dummy) A more generic routine would do a schedule a la timer.device */ static void ms_delay(int ms) { - unsigned long flags; int ticks; + static DEFINE_MUTEX(mutex); + if (ms > 0) { - local_irq_save(flags); - while (ms_busy == 0) - sleep_on(&ms_wait); - ms_busy = 0; - local_irq_restore(flags); + mutex_lock(&mutex); ticks = MS_TICKS*ms-1; ciaa.tblo=ticks%256; ciaa.tbhi=ticks/256; ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */ - sleep_on(&ms_wait); + wait_for_completion(&ms_wait_completion); + mutex_unlock(&mutex); } } @@ -254,8 +250,7 @@ static void get_fdc(int drive) printk("get_fdc: drive %d fdc_busy %d fdc_nested %d\n",drive,fdc_busy,fdc_nested); #endif local_irq_save(flags); - while (!try_fdc(drive)) - sleep_on(&fdc_wait); + wait_event(fdc_wait, try_fdc(drive)); fdc_busy = drive; fdc_nested++; local_irq_restore(flags); @@ -330,7 +325,7 @@ static void fd_deselect (int drive) static void motor_on_callback(unsigned long nr) { if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) { - wake_up (&motor_wait); + complete_all(&motor_on_completion); } else { motor_on_timer.expires = jiffies + HZ/10; add_timer(&motor_on_timer); @@ -347,11 +342,12 @@ static int fd_motor_on(int nr) unit[nr].motor = 1; fd_select(nr); + INIT_COMPLETION(motor_on_completion); motor_on_timer.data = nr; mod_timer(&motor_on_timer, jiffies + HZ/2); on_attempts = 10; - sleep_on (&motor_wait); + wait_for_completion(&motor_on_completion); fd_deselect(nr); } @@ -582,8 +578,7 @@ static void raw_read(int drive) { drive&=3; get_fdc(drive); - while (block_flag) - sleep_on(&wait_fd_block); + wait_event(wait_fd_block, !block_flag); fd_select(drive); /* setup adkcon bits correctly */ custom.adkcon = ADK_MSBSYNC; @@ -598,8 +593,7 @@ static void raw_read(int drive) block_flag = 1; - while (block_flag) - sleep_on (&wait_fd_block); + wait_event(wait_fd_block, !block_flag); custom.dsklen = 0; fd_deselect(drive); @@ -616,8 +610,7 @@ static int raw_write(int drive) rel_fdc(); return 0; } - while (block_flag) - sleep_on(&wait_fd_block); + wait_event(wait_fd_block, !block_flag); fd_select(drive); /* clear adkcon bits */ custom.adkcon = ADK_PRECOMP1|ADK_PRECOMP0|ADK_WORDSYNC|ADK_MSBSYNC; @@ -1294,8 +1287,7 @@ static int non_int_flush_track (unsigned long nr) writepending = 0; return 0; } - while (block_flag == 2) - sleep_on (&wait_fd_block); + wait_event(wait_fd_block, block_flag != 2); } else { local_irq_restore(flags); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 35914b6e1d2..f5be8081cd8 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -616,6 +616,7 @@ config HVC_ISERIES default y select HVC_DRIVER select HVC_IRQ + select VIOPATH help iSeries machines support a hypervisor virtual console. diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 4e0cfdeab14..a58869ea851 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1963,6 +1963,7 @@ static int __init rs_init(void) { unsigned long flags; struct serial_state * state; + int error; if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_SERIAL)) return -ENODEV; @@ -1975,8 +1976,11 @@ static int __init rs_init(void) * We request SERDAT and SERPER only, because the serial registers are * too spreaded over the custom register space */ - if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, "amiserial [Paula]")) - return -EBUSY; + if (!request_mem_region(CUSTOM_PHYSADDR+0x30, 4, + "amiserial [Paula]")) { + error = -EBUSY; + goto fail_put_tty_driver; + } IRQ_ports = NULL; @@ -1997,8 +2001,9 @@ static int __init rs_init(void) serial_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(serial_driver, &serial_ops); - if (tty_register_driver(serial_driver)) - panic("Couldn't register serial driver\n"); + error = tty_register_driver(serial_driver); + if (error) + goto fail_release_mem_region; state = rs_table; state->magic = SSTATE_MAGIC; @@ -2024,8 +2029,14 @@ static int __init rs_init(void) local_irq_save(flags); /* set ISRs, and then disable the rx interrupts */ - request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); - request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, "serial RX", state); + error = request_irq(IRQ_AMIGA_TBE, ser_tx_int, 0, "serial TX", state); + if (error) + goto fail_unregister; + + error = request_irq(IRQ_AMIGA_RBF, ser_rx_int, IRQF_DISABLED, + "serial RX", state); + if (error) + goto fail_free_irq; /* turn off Rx and Tx interrupts */ custom.intena = IF_RBF | IF_TBE; @@ -2045,6 +2056,16 @@ static int __init rs_init(void) ciab.ddra &= ~(SER_DCD | SER_CTS | SER_DSR); /* inputs */ return 0; + +fail_free_irq: + free_irq(IRQ_AMIGA_TBE, state); +fail_unregister: + tty_unregister_driver(serial_driver); +fail_release_mem_region: + release_mem_region(CUSTOM_PHYSADDR+0x30, 4); +fail_put_tty_driver: + put_tty_driver(serial_driver); + return error; } static __exit void rs_exit(void) @@ -2064,6 +2085,9 @@ static __exit void rs_exit(void) kfree(info); } + free_irq(IRQ_AMIGA_TBE, rs_table); + free_irq(IRQ_AMIGA_RBF, rs_table); + release_mem_region(CUSTOM_PHYSADDR+0x30, 4); } diff --git a/drivers/char/hvc_beat.c b/drivers/char/hvc_beat.c index 91cdb35a920..0afc8b82212 100644 --- a/drivers/char/hvc_beat.c +++ b/drivers/char/hvc_beat.c @@ -44,7 +44,7 @@ static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) static unsigned char q[sizeof(unsigned long) * 2] __attribute__((aligned(sizeof(unsigned long)))); static int qlen = 0; - unsigned long got; + u64 got; again: if (qlen) { @@ -63,7 +63,7 @@ again: } } if (beat_get_term_char(vtermno, &got, - ((unsigned long *)q), ((unsigned long *)q) + 1) == 0) { + ((u64 *)q), ((u64 *)q) + 1) == 0) { qlen = got; goto again; } diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 5ea7d7713fc..a53496828b7 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -1,26 +1,30 @@ /* - * hvc_iucv.c - z/VM IUCV back-end for the Hypervisor Console (HVC) + * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver * - * This back-end for HVC provides terminal access via + * This HVC device driver provides terminal access using * z/VM IUCV communication paths. * - * Copyright IBM Corp. 2008. + * Copyright IBM Corp. 2008 * * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> */ #define KMSG_COMPONENT "hvc_iucv" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include <linux/types.h> #include <asm/ebcdic.h> +#include <linux/delay.h> +#include <linux/init.h> #include <linux/mempool.h> #include <linux/module.h> #include <linux/tty.h> +#include <linux/wait.h> #include <net/iucv/iucv.h> #include "hvc_console.h" -/* HVC backend for z/VM IUCV */ +/* General device driver settings */ #define HVC_IUCV_MAGIC 0xc9e4c3e5 #define MAX_HVC_IUCV_LINES HVC_ALLOC_TTY_ADAPTERS #define MEMPOOL_MIN_NR (PAGE_SIZE / sizeof(struct iucv_tty_buffer)/4) @@ -33,14 +37,14 @@ #define MSG_TYPE_WINSIZE 0x08 /* Terminal window size update */ #define MSG_TYPE_DATA 0x10 /* Terminal data */ -#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data)) struct iucv_tty_msg { u8 version; /* Message version */ u8 type; /* Message type */ -#define MSG_MAX_DATALEN (~(u16)0) +#define MSG_MAX_DATALEN ((u16)(~0)) u16 datalen; /* Payload length */ u8 data[]; /* Payload buffer */ } __attribute__((packed)); +#define MSG_SIZE(s) ((s) + offsetof(struct iucv_tty_msg, data)) enum iucv_state_t { IUCV_DISCONN = 0, @@ -54,19 +58,26 @@ enum tty_state_t { }; struct hvc_iucv_private { - struct hvc_struct *hvc; /* HVC console struct reference */ + struct hvc_struct *hvc; /* HVC struct reference */ u8 srv_name[8]; /* IUCV service name (ebcdic) */ + unsigned char is_console; /* Linux console usage flag */ enum iucv_state_t iucv_state; /* IUCV connection status */ enum tty_state_t tty_state; /* TTY status */ struct iucv_path *path; /* IUCV path pointer */ spinlock_t lock; /* hvc_iucv_private lock */ +#define SNDBUF_SIZE (PAGE_SIZE) /* must be < MSG_MAX_DATALEN */ + void *sndbuf; /* send buffer */ + size_t sndbuf_len; /* length of send buffer */ +#define QUEUE_SNDBUF_DELAY (HZ / 25) + struct delayed_work sndbuf_work; /* work: send iucv msg(s) */ + wait_queue_head_t sndbuf_waitq; /* wait for send completion */ struct list_head tty_outqueue; /* outgoing IUCV messages */ struct list_head tty_inqueue; /* incoming IUCV messages */ }; struct iucv_tty_buffer { struct list_head list; /* list pointer */ - struct iucv_message msg; /* store an incoming IUCV message */ + struct iucv_message msg; /* store an IUCV message */ size_t offset; /* data buffer offset */ struct iucv_tty_msg *mbuf; /* buffer to store input/output data */ }; @@ -78,11 +89,12 @@ static void hvc_iucv_msg_pending(struct iucv_path *, struct iucv_message *); static void hvc_iucv_msg_complete(struct iucv_path *, struct iucv_message *); -/* Kernel module parameters */ -static unsigned long hvc_iucv_devices; +/* Kernel module parameter: use one terminal device as default */ +static unsigned long hvc_iucv_devices = 1; /* Array of allocated hvc iucv tty lines... */ static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES]; +#define IUCV_HVC_CON_IDX (0) /* Kmem cache and mempool for iucv_tty_buffer elements */ static struct kmem_cache *hvc_iucv_buffer_cache; @@ -112,7 +124,7 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) } /** - * alloc_tty_buffer() - Returns a new struct iucv_tty_buffer element. + * alloc_tty_buffer() - Return a new struct iucv_tty_buffer element. * @size: Size of the internal buffer used to store data. * @flags: Memory allocation flags passed to mempool. * @@ -120,7 +132,6 @@ struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) * allocates an internal data buffer with the specified size @size. * Note: The total message size arises from the internal buffer size and the * members of the iucv_tty_msg structure. - * * The function returns NULL if memory allocation has failed. */ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) @@ -130,7 +141,7 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) bufp = mempool_alloc(hvc_iucv_mempool, flags); if (!bufp) return NULL; - memset(bufp, 0, sizeof(struct iucv_tty_buffer)); + memset(bufp, 0, sizeof(*bufp)); if (size > 0) { bufp->msg.length = MSG_SIZE(size); @@ -149,9 +160,6 @@ static struct iucv_tty_buffer *alloc_tty_buffer(size_t size, gfp_t flags) /** * destroy_tty_buffer() - destroy struct iucv_tty_buffer element. * @bufp: Pointer to a struct iucv_tty_buffer element, SHALL NOT be NULL. - * - * The destroy_tty_buffer() function frees the internal data buffer and returns - * the struct iucv_tty_buffer element back to the mempool for freeing. */ static void destroy_tty_buffer(struct iucv_tty_buffer *bufp) { @@ -161,11 +169,7 @@ static void destroy_tty_buffer(struct iucv_tty_buffer *bufp) /** * destroy_tty_buffer_list() - call destroy_tty_buffer() for each list element. - * @list: List head pointer to a list containing struct iucv_tty_buffer - * elements. - * - * Calls destroy_tty_buffer() for each struct iucv_tty_buffer element in the - * list @list. + * @list: List containing struct iucv_tty_buffer elements. */ static void destroy_tty_buffer_list(struct list_head *list) { @@ -178,24 +182,24 @@ static void destroy_tty_buffer_list(struct list_head *list) } /** - * hvc_iucv_write() - Receive IUCV message write data to HVC console buffer. - * @priv: Pointer to hvc_iucv_private structure. - * @buf: HVC console buffer for writing received terminal data. - * @count: HVC console buffer size. + * hvc_iucv_write() - Receive IUCV message & write data to HVC buffer. + * @priv: Pointer to struct hvc_iucv_private + * @buf: HVC buffer for writing received terminal data. + * @count: HVC buffer size. * @has_more_data: Pointer to an int variable. * * The function picks up pending messages from the input queue and receives * the message data that is then written to the specified buffer @buf. - * If the buffer size @count is less than the data message size, then the + * If the buffer size @count is less than the data message size, the * message is kept on the input queue and @has_more_data is set to 1. - * If the message data has been entirely written, the message is removed from + * If all message data has been written, the message is removed from * the input queue. * * The function returns the number of bytes written to the terminal, zero if * there are no pending data messages available or if there is no established * IUCV path. * If the IUCV path has been severed, then -EPIPE is returned to cause a - * hang up (that is issued by the HVC console layer). + * hang up (that is issued by the HVC layer). */ static int hvc_iucv_write(struct hvc_iucv_private *priv, char *buf, int count, int *has_more_data) @@ -204,12 +208,12 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv, int written; int rc; - /* Immediately return if there is no IUCV connection */ + /* immediately return if there is no IUCV connection */ if (priv->iucv_state == IUCV_DISCONN) return 0; - /* If the IUCV path has been severed, return -EPIPE to inform the - * hvc console layer to hang up the tty device. */ + /* if the IUCV path has been severed, return -EPIPE to inform the + * HVC layer to hang up the tty device. */ if (priv->iucv_state == IUCV_SEVERED) return -EPIPE; @@ -217,7 +221,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv, if (list_empty(&priv->tty_inqueue)) return 0; - /* receive a iucv message and flip data to the tty (ldisc) */ + /* receive an iucv message and flip data to the tty (ldisc) */ rb = list_first_entry(&priv->tty_inqueue, struct iucv_tty_buffer, list); written = 0; @@ -260,7 +264,7 @@ static int hvc_iucv_write(struct hvc_iucv_private *priv, case MSG_TYPE_WINSIZE: if (rb->mbuf->datalen != sizeof(struct winsize)) break; - hvc_resize(priv->hvc, *((struct winsize *)rb->mbuf->data)); + hvc_resize(priv->hvc, *((struct winsize *) rb->mbuf->data)); break; case MSG_TYPE_ERROR: /* ignored ... */ @@ -284,10 +288,9 @@ out_written: * @buf: Pointer to a buffer to store data * @count: Size of buffer available for writing * - * The hvc_console thread calls this method to read characters from - * the terminal backend. If an IUCV communication path has been established, - * pending IUCV messages are received and data is copied into buffer @buf - * up to @count bytes. + * The HVC thread calls this method to read characters from the back-end. + * If an IUCV communication path has been established, pending IUCV messages + * are received and data is copied into buffer @buf up to @count bytes. * * Locking: The routine gets called under an irqsave() spinlock; and * the routine locks the struct hvc_iucv_private->lock to call @@ -318,66 +321,122 @@ static int hvc_iucv_get_chars(uint32_t vtermno, char *buf, int count) } /** - * hvc_iucv_send() - Send an IUCV message containing terminal data. + * hvc_iucv_queue() - Buffer terminal data for sending. * @priv: Pointer to struct hvc_iucv_private instance. * @buf: Buffer containing data to send. - * @size: Size of buffer and amount of data to send. + * @count: Size of buffer and amount of data to send. + * + * The function queues data for sending. To actually send the buffered data, + * a work queue function is scheduled (with QUEUE_SNDBUF_DELAY). + * The function returns the number of data bytes that has been buffered. * - * If an IUCV communication path is established, the function copies the buffer - * data to a newly allocated struct iucv_tty_buffer element, sends the data and - * puts the element to the outqueue. + * If the device is not connected, data is ignored and the function returns + * @count. + * If the buffer is full, the function returns 0. + * If an existing IUCV communicaton path has been severed, -EPIPE is returned + * (that can be passed to HVC layer to cause a tty hangup). + */ +static int hvc_iucv_queue(struct hvc_iucv_private *priv, const char *buf, + int count) +{ + size_t len; + + if (priv->iucv_state == IUCV_DISCONN) + return count; /* ignore data */ + + if (priv->iucv_state == IUCV_SEVERED) + return -EPIPE; + + len = min_t(size_t, count, SNDBUF_SIZE - priv->sndbuf_len); + if (!len) + return 0; + + memcpy(priv->sndbuf + priv->sndbuf_len, buf, len); + priv->sndbuf_len += len; + + if (priv->iucv_state == IUCV_CONNECTED) + schedule_delayed_work(&priv->sndbuf_work, QUEUE_SNDBUF_DELAY); + + return len; +} + +/** + * hvc_iucv_send() - Send an IUCV message containing terminal data. + * @priv: Pointer to struct hvc_iucv_private instance. * - * If there is no IUCV communication path established, the function returns 0. - * If an existing IUCV communicaton path has been severed, the function returns - * -EPIPE (can be passed to HVC layer to cause a tty hangup). + * If an IUCV communication path has been established, the buffered output data + * is sent via an IUCV message and the number of bytes sent is returned. + * Returns 0 if there is no established IUCV communication path or + * -EPIPE if an existing IUCV communicaton path has been severed. */ -static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf, - int count) +static int hvc_iucv_send(struct hvc_iucv_private *priv) { struct iucv_tty_buffer *sb; - int rc; - u16 len; + int rc, len; if (priv->iucv_state == IUCV_SEVERED) return -EPIPE; if (priv->iucv_state == IUCV_DISCONN) - return 0; + return -EIO; - len = min_t(u16, MSG_MAX_DATALEN, count); + if (!priv->sndbuf_len) + return 0; /* allocate internal buffer to store msg data and also compute total * message length */ - sb = alloc_tty_buffer(len, GFP_ATOMIC); + sb = alloc_tty_buffer(priv->sndbuf_len, GFP_ATOMIC); if (!sb) return -ENOMEM; - sb->mbuf->datalen = len; - memcpy(sb->mbuf->data, buf, len); + memcpy(sb->mbuf->data, priv->sndbuf, priv->sndbuf_len); + sb->mbuf->datalen = (u16) priv->sndbuf_len; + sb->msg.length = MSG_SIZE(sb->mbuf->datalen); list_add_tail(&sb->list, &priv->tty_outqueue); rc = __iucv_message_send(priv->path, &sb->msg, 0, 0, (void *) sb->mbuf, sb->msg.length); if (rc) { + /* drop the message here; however we might want to handle + * 0x03 (msg limit reached) by trying again... */ list_del(&sb->list); destroy_tty_buffer(sb); - len = 0; } + len = priv->sndbuf_len; + priv->sndbuf_len = 0; return len; } /** + * hvc_iucv_sndbuf_work() - Send buffered data over IUCV + * @work: Work structure. + * + * This work queue function sends buffered output data over IUCV and, + * if not all buffered data could be sent, reschedules itself. + */ +static void hvc_iucv_sndbuf_work(struct work_struct *work) +{ + struct hvc_iucv_private *priv; + + priv = container_of(work, struct hvc_iucv_private, sndbuf_work.work); + if (!priv) + return; + + spin_lock_bh(&priv->lock); + hvc_iucv_send(priv); + spin_unlock_bh(&priv->lock); +} + +/** * hvc_iucv_put_chars() - HVC put_chars operation. * @vtermno: HVC virtual terminal number. * @buf: Pointer to an buffer to read data from * @count: Size of buffer available for reading * - * The hvc_console thread calls this method to write characters from - * to the terminal backend. - * The function calls hvc_iucv_send() under the lock of the - * struct hvc_iucv_private instance that corresponds to the tty @vtermno. + * The HVC thread calls this method to write characters to the back-end. + * The function calls hvc_iucv_queue() to queue terminal data for sending. * * Locking: The method gets called under an irqsave() spinlock; and * locks struct hvc_iucv_private->lock. @@ -385,7 +444,7 @@ static int hvc_iucv_send(struct hvc_iucv_private *priv, const char *buf, static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) { struct hvc_iucv_private *priv = hvc_iucv_get_private(vtermno); - int sent; + int queued; if (count <= 0) return 0; @@ -394,10 +453,10 @@ static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) return -ENODEV; spin_lock(&priv->lock); - sent = hvc_iucv_send(priv, buf, count); + queued = hvc_iucv_queue(priv, buf, count); spin_unlock(&priv->lock); - return sent; + return queued; } /** @@ -406,7 +465,7 @@ static int hvc_iucv_put_chars(uint32_t vtermno, const char *buf, int count) * @id: Additional data (originally passed to hvc_alloc): the index of an struct * hvc_iucv_private instance. * - * The function sets the tty state to TTY_OPEN for the struct hvc_iucv_private + * The function sets the tty state to TTY_OPENED for the struct hvc_iucv_private * instance that is derived from @id. Always returns 0. * * Locking: struct hvc_iucv_private->lock, spin_lock_bh @@ -427,12 +486,8 @@ static int hvc_iucv_notifier_add(struct hvc_struct *hp, int id) } /** - * hvc_iucv_cleanup() - Clean up function if the tty portion is finally closed. + * hvc_iucv_cleanup() - Clean up and reset a z/VM IUCV HVC instance. * @priv: Pointer to the struct hvc_iucv_private instance. - * - * The functions severs the established IUCV communication path (if any), and - * destroy struct iucv_tty_buffer elements from the in- and outqueue. Finally, - * the functions resets the states to TTY_CLOSED and IUCV_DISCONN. */ static void hvc_iucv_cleanup(struct hvc_iucv_private *priv) { @@ -441,25 +496,62 @@ static void hvc_iucv_cleanup(struct hvc_iucv_private *priv) priv->tty_state = TTY_CLOSED; priv->iucv_state = IUCV_DISCONN; + + priv->sndbuf_len = 0; } /** - * hvc_iucv_notifier_hangup() - HVC notifier for tty hangups. - * @hp: Pointer to the HVC device (struct hvc_struct) - * @id: Additional data (originally passed to hvc_alloc): the index of an struct - * hvc_iucv_private instance. + * tty_outqueue_empty() - Test if the tty outq is empty + * @priv: Pointer to struct hvc_iucv_private instance. + */ +static inline int tty_outqueue_empty(struct hvc_iucv_private *priv) +{ + int rc; + + spin_lock_bh(&priv->lock); + rc = list_empty(&priv->tty_outqueue); + spin_unlock_bh(&priv->lock); + + return rc; +} + +/** + * flush_sndbuf_sync() - Flush send buffer and wait for completion + * @priv: Pointer to struct hvc_iucv_private instance. * - * This routine notifies the HVC backend that a tty hangup (carrier loss, - * virtual or otherwise) has occured. + * The routine cancels a pending sndbuf work, calls hvc_iucv_send() + * to flush any buffered terminal output data and waits for completion. + */ +static void flush_sndbuf_sync(struct hvc_iucv_private *priv) +{ + int sync_wait; + + cancel_delayed_work_sync(&priv->sndbuf_work); + + spin_lock_bh(&priv->lock); + hvc_iucv_send(priv); /* force sending buffered data */ + sync_wait = !list_empty(&priv->tty_outqueue); /* anything queued ? */ + spin_unlock_bh(&priv->lock); + + if (sync_wait) + wait_event_timeout(priv->sndbuf_waitq, + tty_outqueue_empty(priv), HZ); +} + +/** + * hvc_iucv_notifier_hangup() - HVC notifier for TTY hangups. + * @hp: Pointer to the HVC device (struct hvc_struct) + * @id: Additional data (originally passed to hvc_alloc): + * the index of an struct hvc_iucv_private instance. * - * The HVC backend for z/VM IUCV ignores virtual hangups (vhangup()), to keep - * an existing IUCV communication path established. + * This routine notifies the HVC back-end that a tty hangup (carrier loss, + * virtual or otherwise) has occured. + * The z/VM IUCV HVC device driver ignores virtual hangups (vhangup()) + * to keep an existing IUCV communication path established. * (Background: vhangup() is called from user space (by getty or login) to * disable writing to the tty by other applications). - * - * If the tty has been opened (e.g. getty) and an established IUCV path has been - * severed (we caused the tty hangup in that case), then the functions invokes - * hvc_iucv_cleanup() to clean up. + * If the tty has been opened and an established IUCV path has been severed + * (we caused the tty hangup), the function calls hvc_iucv_cleanup(). * * Locking: struct hvc_iucv_private->lock */ @@ -471,12 +563,12 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) if (!priv) return; + flush_sndbuf_sync(priv); + spin_lock_bh(&priv->lock); /* NOTE: If the hangup was scheduled by ourself (from the iucv - * path_servered callback [IUCV_SEVERED]), then we have to - * finally clean up the tty backend structure and set state to - * TTY_CLOSED. - * + * path_servered callback [IUCV_SEVERED]), we have to clean up + * our structure and to set state to TTY_CLOSED. * If the tty was hung up otherwise (e.g. vhangup()), then we * ignore this hangup and keep an established IUCV path open... * (...the reason is that we are not able to connect back to the @@ -494,10 +586,9 @@ static void hvc_iucv_notifier_hangup(struct hvc_struct *hp, int id) * @id: Additional data (originally passed to hvc_alloc): * the index of an struct hvc_iucv_private instance. * - * This routine notifies the HVC backend that the last tty device file - * descriptor has been closed. - * The function calls hvc_iucv_cleanup() to clean up the struct hvc_iucv_private - * instance. + * This routine notifies the HVC back-end that the last tty device fd has been + * closed. The function calls hvc_iucv_cleanup() to clean up the struct + * hvc_iucv_private instance. * * Locking: struct hvc_iucv_private->lock */ @@ -510,6 +601,8 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) if (!priv) return; + flush_sndbuf_sync(priv); + spin_lock_bh(&priv->lock); path = priv->path; /* save reference to IUCV path */ priv->path = NULL; @@ -527,20 +620,18 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id) /** * hvc_iucv_path_pending() - IUCV handler to process a connection request. * @path: Pending path (struct iucv_path) - * @ipvmid: Originator z/VM system identifier + * @ipvmid: z/VM system identifier of originator * @ipuser: User specified data for this path * (AF_IUCV: port/service name and originator port) * - * The function uses the @ipuser data to check to determine if the pending - * path belongs to a terminal managed by this HVC backend. - * If the check is successful, then an additional check is done to ensure - * that a terminal cannot be accessed multiple times (only one connection - * to a terminal is allowed). In that particular case, the pending path is - * severed. If it is the first connection, the pending path is accepted and - * associated to the struct hvc_iucv_private. The iucv state is updated to - * reflect that a communication path has been established. + * The function uses the @ipuser data to determine if the pending path belongs + * to a terminal managed by this device driver. + * If the path belongs to this driver, ensure that the terminal is not accessed + * multiple times (only one connection to a terminal is allowed). + * If the terminal is not yet connected, the pending path is accepted and is + * associated to the appropriate struct hvc_iucv_private instance. * - * Returns 0 if the path belongs to a terminal managed by the this HVC backend; + * Returns 0 if @path belongs to a terminal managed by the this device driver; * otherwise returns -ENODEV in order to dispatch this path to other handlers. * * Locking: struct hvc_iucv_private->lock @@ -559,7 +650,6 @@ static int hvc_iucv_path_pending(struct iucv_path *path, priv = hvc_iucv_table[i]; break; } - if (!priv) return -ENODEV; @@ -588,6 +678,9 @@ static int hvc_iucv_path_pending(struct iucv_path *path, priv->path = path; priv->iucv_state = IUCV_CONNECTED; + /* flush buffered output data... */ + schedule_delayed_work(&priv->sndbuf_work, 5); + out_path_handled: spin_unlock(&priv->lock); return 0; @@ -603,8 +696,7 @@ out_path_handled: * sets the iucv state to IUCV_SEVERED for the associated struct * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). - * - * If tty portion of the HVC is closed then clean up the outqueue in addition. + * If tty portion of the HVC is closed, clean up the outqueue. * * Locking: struct hvc_iucv_private->lock */ @@ -615,15 +707,25 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) spin_lock(&priv->lock); priv->iucv_state = IUCV_SEVERED; - /* NOTE: If the tty has not yet been opened by a getty program - * (e.g. to see console messages), then cleanup the - * hvc_iucv_private structure to allow re-connects. + /* If the tty has not yet been opened, clean up the hvc_iucv_private + * structure to allow re-connects. + * This is also done for our console device because console hangups + * are handled specially and no notifier is called by HVC. + * The tty session is active (TTY_OPEN) and ready for re-connects... * - * If the tty has been opened, the get_chars() callback returns - * -EPIPE to signal the hvc console layer to hang up the tty. */ + * If it has been opened, let get_chars() return -EPIPE to signal the + * HVC layer to hang up the tty. + * If so, we need to wake up the HVC thread to call get_chars()... + */ priv->path = NULL; if (priv->tty_state == TTY_CLOSED) hvc_iucv_cleanup(priv); + else + if (priv->is_console) { + hvc_iucv_cleanup(priv); + priv->tty_state = TTY_OPENED; + } else + hvc_kick(); spin_unlock(&priv->lock); /* finally sever path (outside of priv->lock due to lock ordering) */ @@ -636,9 +738,9 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) * @path: Pending path (struct iucv_path) * @msg: Pointer to the IUCV message * - * The function stores an incoming message on the input queue for later + * The function puts an incoming message on the input queue for later * processing (by hvc_iucv_get_chars() / hvc_iucv_write()). - * However, if the tty has not yet been opened, the message is rejected. + * If the tty has not yet been opened, the message is rejected. * * Locking: struct hvc_iucv_private->lock */ @@ -648,6 +750,12 @@ static void hvc_iucv_msg_pending(struct iucv_path *path, struct hvc_iucv_private *priv = path->private; struct iucv_tty_buffer *rb; + /* reject messages that exceed max size of iucv_tty_msg->datalen */ + if (msg->length > MSG_SIZE(MSG_MAX_DATALEN)) { + iucv_message_reject(path, msg); + return; + } + spin_lock(&priv->lock); /* reject messages if tty has not yet been opened */ @@ -656,7 +764,7 @@ static void hvc_iucv_msg_pending(struct iucv_path *path, goto unlock_return; } - /* allocate buffer an empty buffer element */ + /* allocate tty buffer to save iucv msg only */ rb = alloc_tty_buffer(0, GFP_ATOMIC); if (!rb) { iucv_message_reject(path, msg); @@ -666,7 +774,7 @@ static void hvc_iucv_msg_pending(struct iucv_path *path, list_add_tail(&rb->list, &priv->tty_inqueue); - hvc_kick(); /* wakup hvc console thread */ + hvc_kick(); /* wake up hvc thread */ unlock_return: spin_unlock(&priv->lock); @@ -677,10 +785,10 @@ unlock_return: * @path: Pending path (struct iucv_path) * @msg: Pointer to the IUCV message * - * The function is called upon completion of message delivery and the - * message is removed from the outqueue. Additional delivery information - * can be found in msg->audit: rejected messages (0x040000 (IPADRJCT)) and - * purged messages (0x010000 (IPADPGNR)). + * The function is called upon completion of message delivery to remove the + * message from the outqueue. Additional delivery information can be found + * msg->audit: rejected messages (0x040000 (IPADRJCT)), and + * purged messages (0x010000 (IPADPGNR)). * * Locking: struct hvc_iucv_private->lock */ @@ -697,6 +805,7 @@ static void hvc_iucv_msg_complete(struct iucv_path *path, list_move(&ent->list, &list_remove); break; } + wake_up(&priv->sndbuf_waitq); spin_unlock(&priv->lock); destroy_tty_buffer_list(&list_remove); } @@ -713,13 +822,14 @@ static struct hv_ops hvc_iucv_ops = { /** * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance - * @id: hvc_iucv_table index + * @id: hvc_iucv_table index + * @is_console: Flag if the instance is used as Linux console * - * This function allocates a new hvc_iucv_private struct and put the - * instance into hvc_iucv_table at index @id. + * This function allocates a new hvc_iucv_private structure and stores + * the instance in hvc_iucv_table at index @id. * Returns 0 on success; otherwise non-zero. */ -static int __init hvc_iucv_alloc(int id) +static int __init hvc_iucv_alloc(int id, unsigned int is_console) { struct hvc_iucv_private *priv; char name[9]; @@ -732,18 +842,33 @@ static int __init hvc_iucv_alloc(int id) spin_lock_init(&priv->lock); INIT_LIST_HEAD(&priv->tty_outqueue); INIT_LIST_HEAD(&priv->tty_inqueue); + INIT_DELAYED_WORK(&priv->sndbuf_work, hvc_iucv_sndbuf_work); + init_waitqueue_head(&priv->sndbuf_waitq); + + priv->sndbuf = (void *) get_zeroed_page(GFP_KERNEL); + if (!priv->sndbuf) { + kfree(priv); + return -ENOMEM; + } + + /* set console flag */ + priv->is_console = is_console; - /* Finally allocate hvc */ - priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, - HVC_IUCV_MAGIC + id, &hvc_iucv_ops, PAGE_SIZE); + /* finally allocate hvc */ + priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ + HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); if (IS_ERR(priv->hvc)) { rc = PTR_ERR(priv->hvc); + free_page((unsigned long) priv->sndbuf); kfree(priv); return rc; } + /* notify HVC thread instead of using polling */ + priv->hvc->irq_requested = 1; + /* setup iucv related information */ - snprintf(name, 9, "ihvc%-4d", id); + snprintf(name, 9, "lnxhvc%-2d", id); memcpy(priv->srv_name, name, 8); ASCEBC(priv->srv_name, 8); @@ -752,15 +877,16 @@ static int __init hvc_iucv_alloc(int id) } /** - * hvc_iucv_init() - Initialization of HVC backend for z/VM IUCV + * hvc_iucv_init() - z/VM IUCV HVC device driver initialization */ static int __init hvc_iucv_init(void) { - int rc, i; + int rc; + unsigned int i; if (!MACHINE_IS_VM) { - pr_warning("The z/VM IUCV Hypervisor console cannot be " - "used without z/VM.\n"); + pr_info("The z/VM IUCV HVC device driver cannot " + "be used without z/VM\n"); return -ENODEV; } @@ -774,26 +900,33 @@ static int __init hvc_iucv_init(void) sizeof(struct iucv_tty_buffer), 0, 0, NULL); if (!hvc_iucv_buffer_cache) { - pr_err("Not enough memory for driver initialization " - "(rs=%d).\n", 1); + pr_err("Allocating memory failed with reason code=%d\n", 1); return -ENOMEM; } hvc_iucv_mempool = mempool_create_slab_pool(MEMPOOL_MIN_NR, hvc_iucv_buffer_cache); if (!hvc_iucv_mempool) { - pr_err("Not enough memory for driver initialization " - "(rs=%d).\n", 2); + pr_err("Allocating memory failed with reason code=%d\n", 2); kmem_cache_destroy(hvc_iucv_buffer_cache); return -ENOMEM; } + /* register the first terminal device as console + * (must be done before allocating hvc terminal devices) */ + rc = hvc_instantiate(HVC_IUCV_MAGIC, IUCV_HVC_CON_IDX, &hvc_iucv_ops); + if (rc) { + pr_err("Registering HVC terminal device as " + "Linux console failed\n"); + goto out_error_memory; + } + /* allocate hvc_iucv_private structs */ for (i = 0; i < hvc_iucv_devices; i++) { - rc = hvc_iucv_alloc(i); + rc = hvc_iucv_alloc(i, (i == IUCV_HVC_CON_IDX) ? 1 : 0); if (rc) { - pr_err("Could not create new z/VM IUCV HVC backend " - "rc=%d.\n", rc); + pr_err("Creating a new HVC terminal device " + "failed with error code=%d\n", rc); goto out_error_hvc; } } @@ -801,7 +934,8 @@ static int __init hvc_iucv_init(void) /* register IUCV callback handler */ rc = iucv_register(&hvc_iucv_handler, 0); if (rc) { - pr_err("Could not register iucv handler (rc=%d).\n", rc); + pr_err("Registering IUCV handlers failed with error code=%d\n", + rc); goto out_error_iucv; } @@ -816,22 +950,13 @@ out_error_hvc: hvc_remove(hvc_iucv_table[i]->hvc); kfree(hvc_iucv_table[i]); } +out_error_memory: mempool_destroy(hvc_iucv_mempool); kmem_cache_destroy(hvc_iucv_buffer_cache); return rc; } /** - * hvc_iucv_console_init() - Early console initialization - */ -static int __init hvc_iucv_console_init(void) -{ - if (!MACHINE_IS_VM || !hvc_iucv_devices) - return -ENODEV; - return hvc_instantiate(HVC_IUCV_MAGIC, 0, &hvc_iucv_ops); -} - -/** * hvc_iucv_config() - Parsing of hvc_iucv= kernel command line parameter * @val: Parameter value (numeric) */ @@ -841,10 +966,5 @@ static int __init hvc_iucv_config(char *val) } -module_init(hvc_iucv_init); -console_initcall(hvc_iucv_console_init); +device_initcall(hvc_iucv_init); __setup("hvc_iucv=", hvc_iucv_config); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("HVC back-end for z/VM IUCV."); -MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>"); diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 112a6ba9a96..31038a0052a 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -32,7 +32,7 @@ /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS -struct tty_driver *ptm_driver; +static struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; #endif @@ -230,9 +230,7 @@ static void pty_set_termios(struct tty_struct *tty, /** * pty_do_resize - resize event * @tty: tty being resized - * @real_tty: real tty (not the same as tty if using a pty/tty pair) - * @rows: rows (character) - * @cols: cols (character) + * @ws: window size being set. * * Update the termios variables and send the neccessary signals to * peform a terminal resize correctly diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 20d6efb6324..e0d0f8b2696 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -48,9 +48,10 @@ * CONFIG_HPET_EMULATE_RTC * 1.12a Maciej W. Rozycki: Handle memory-mapped chips properly. * 1.12ac Alan Cox: Allow read access to the day of week register + * 1.12b David John: Remove calls to the BKL. */ -#define RTC_VERSION "1.12ac" +#define RTC_VERSION "1.12b" /* * Note that *all* calls to CMOS_READ and CMOS_WRITE are done with @@ -73,7 +74,6 @@ #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <linux/spinlock.h> -#include <linux/smp_lock.h> #include <linux/sysctl.h> #include <linux/wait.h> #include <linux/bcd.h> @@ -182,8 +182,8 @@ static int rtc_proc_open(struct inode *inode, struct file *file); /* * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is - * protected by the big kernel lock. However, ioctl can still disable the timer - * in rtc_status and then with del_timer after the interrupt has read + * protected by the spin lock rtc_lock. However, ioctl can still disable the + * timer in rtc_status and then with del_timer after the interrupt has read * rtc_status but before mod_timer is called, which would then reenable the * timer (but you would need to have an awful timing before you'd trip on it) */ @@ -720,9 +720,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; - lock_kernel(); ret = rtc_do_ioctl(cmd, arg, 0); - unlock_kernel(); return ret; } @@ -731,12 +729,8 @@ static long rtc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) * Also clear the previous interrupt data on an open, and clean * up things on a close. */ - -/* We use rtc_lock to protect against concurrent opens. So the BKL is not - * needed here. Or anywhere else in this driver. */ static int rtc_open(struct inode *inode, struct file *file) { - lock_kernel(); spin_lock_irq(&rtc_lock); if (rtc_status & RTC_IS_OPEN) @@ -746,12 +740,10 @@ static int rtc_open(struct inode *inode, struct file *file) rtc_irq_data = 0; spin_unlock_irq(&rtc_lock); - unlock_kernel(); return 0; out_busy: spin_unlock_irq(&rtc_lock); - unlock_kernel(); return -EBUSY; } @@ -800,7 +792,6 @@ no_irq: } #ifdef RTC_IRQ -/* Called without the kernel lock - fine */ static unsigned int rtc_poll(struct file *file, poll_table *wait) { unsigned long l; diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 33872a219df..33a2b531802 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -718,6 +718,7 @@ static int __init a2232board_init(void) u_char *from; volatile u_char *to; volatile struct a2232memory *mem; + int error, i; #ifdef CONFIG_SMP return -ENODEV; /* This driver is not SMP aware. Is there an SMP ZorroII-bus-machine? */ @@ -797,8 +798,15 @@ static int __init a2232board_init(void) */ if (a2232_init_drivers()) return -ENODEV; // maybe we should use a different -Exxx? - request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, "A2232 serial VBL", a2232_driver_ID); - return 0; + error = request_irq(IRQ_AMIGA_VERTB, a2232_vbl_inter, 0, + "A2232 serial VBL", a2232_driver_ID); + if (error) { + for (i = 0; i < nr_a2232; i++) + zorro_release_device(zd_a2232[i]); + tty_unregister_driver(a2232_driver); + put_tty_driver(a2232_driver); + } + return error; } static void __exit a2232board_exit(void) diff --git a/drivers/char/tpm/tpm_bios.c b/drivers/char/tpm/tpm_bios.c index 68f052b42ed..ed306eb1057 100644 --- a/drivers/char/tpm/tpm_bios.c +++ b/drivers/char/tpm/tpm_bios.c @@ -23,8 +23,6 @@ #include <linux/security.h> #include <linux/module.h> #include <acpi/acpi.h> -#include <acpi/actypes.h> -#include <acpi/actbl.h> #include "tpm.h" #define TCG_EVENT_NAME_LEN_MAX 255 diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index ab18c1e7b11..70efba2ee05 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -273,12 +273,23 @@ static void tpm_nsc_remove(struct device *dev) } } -static struct device_driver nsc_drv = { - .name = "tpm_nsc", - .bus = &platform_bus_type, - .owner = THIS_MODULE, - .suspend = tpm_pm_suspend, - .resume = tpm_pm_resume, +static int tpm_nsc_suspend(struct platform_device *dev, pm_message_t msg) +{ + return tpm_pm_suspend(&dev->dev, msg); +} + +static int tpm_nsc_resume(struct platform_device *dev) +{ + return tpm_pm_resume(&dev->dev); +} + +static struct platform_driver nsc_drv = { + .suspend = tpm_nsc_suspend, + .resume = tpm_nsc_resume, + .driver = { + .name = "tpm_nsc", + .owner = THIS_MODULE, + }, }; static int __init init_nsc(void) @@ -297,7 +308,7 @@ static int __init init_nsc(void) return -ENODEV; } - err = driver_register(&nsc_drv); + err = platform_driver_register(&nsc_drv); if (err) return err; @@ -308,17 +319,15 @@ static int __init init_nsc(void) /* enable the DPM module */ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); - pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + pdev = platform_device_alloc("tpm_nscl0", -1); if (!pdev) { rc = -ENOMEM; goto err_unreg_drv; } - pdev->name = "tpm_nscl0"; - pdev->id = -1; pdev->num_resources = 0; + pdev->dev.driver = &nsc_drv.driver; pdev->dev.release = tpm_nsc_remove; - pdev->dev.driver = &nsc_drv; if ((rc = platform_device_register(pdev)) < 0) goto err_free_dev; @@ -377,7 +386,7 @@ err_unreg_dev: err_free_dev: kfree(pdev); err_unreg_drv: - driver_unregister(&nsc_drv); + platform_driver_unregister(&nsc_drv); return rc; } @@ -390,7 +399,7 @@ static void __exit cleanup_nsc(void) pdev = NULL; } - driver_unregister(&nsc_drv); + platform_driver_unregister(&nsc_drv); } module_init(init_nsc); diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c index 0e8234bd0e1..994e1a58b98 100644 --- a/drivers/char/vme_scc.c +++ b/drivers/char/vme_scc.c @@ -198,6 +198,7 @@ static void scc_init_portstructs(void) static int mvme147_scc_init(void) { struct scc_port *port; + int error; printk(KERN_INFO "SCC: MVME147 Serial Driver\n"); /* Init channel A */ @@ -207,14 +208,23 @@ static int mvme147_scc_init(void) port->datap = port->ctrlp + 1; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(MVME147_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, "SCC-A TX", port); - request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail; + error = request_irq(MVME147_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, "SCC-A status", port); - request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_a_tx; + error = request_irq(MVME147_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, "SCC-A RX", port); - request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-A special cond", port); + if (error) + goto fail_free_a_stat; + error = request_irq(MVME147_IRQ_SCCA_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-A special cond", port); + if (error) + goto fail_free_a_rx; + { SCC_ACCESS_INIT(port); @@ -234,14 +244,23 @@ static int mvme147_scc_init(void) port->datap = port->ctrlp + 1; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(MVME147_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, "SCC-B TX", port); - request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail_free_a_spcond; + error = request_irq(MVME147_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, "SCC-B status", port); - request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_b_tx; + error = request_irq(MVME147_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, "SCC-B RX", port); - request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-B special cond", port); + if (error) + goto fail_free_b_stat; + error = request_irq(MVME147_IRQ_SCCB_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-B special cond", port); + if (error) + goto fail_free_b_rx; + { SCC_ACCESS_INIT(port); @@ -257,6 +276,23 @@ static int mvme147_scc_init(void) scc_init_drivers(); return 0; + +fail_free_b_rx: + free_irq(MVME147_IRQ_SCCB_RX, port); +fail_free_b_stat: + free_irq(MVME147_IRQ_SCCB_STAT, port); +fail_free_b_tx: + free_irq(MVME147_IRQ_SCCB_TX, port); +fail_free_a_spcond: + free_irq(MVME147_IRQ_SCCA_SPCOND, port); +fail_free_a_rx: + free_irq(MVME147_IRQ_SCCA_RX, port); +fail_free_a_stat: + free_irq(MVME147_IRQ_SCCA_STAT, port); +fail_free_a_tx: + free_irq(MVME147_IRQ_SCCA_TX, port); +fail: + return error; } #endif @@ -265,6 +301,7 @@ static int mvme147_scc_init(void) static int mvme162_scc_init(void) { struct scc_port *port; + int error; if (!(mvme16x_config & MVME16x_CONFIG_GOT_SCCA)) return (-ENODEV); @@ -277,14 +314,23 @@ static int mvme162_scc_init(void) port->datap = port->ctrlp + 2; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(MVME162_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, "SCC-A TX", port); - request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail; + error = request_irq(MVME162_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, "SCC-A status", port); - request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_a_tx; + error = request_irq(MVME162_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, "SCC-A RX", port); - request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-A special cond", port); + if (error) + goto fail_free_a_stat; + error = request_irq(MVME162_IRQ_SCCA_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-A special cond", port); + if (error) + goto fail_free_a_rx; + { SCC_ACCESS_INIT(port); @@ -304,14 +350,22 @@ static int mvme162_scc_init(void) port->datap = port->ctrlp + 2; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(MVME162_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, "SCC-B TX", port); - request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail_free_a_spcond; + error = request_irq(MVME162_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, "SCC-B status", port); - request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_b_tx; + error = request_irq(MVME162_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, "SCC-B RX", port); - request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-B special cond", port); + if (error) + goto fail_free_b_stat; + error = request_irq(MVME162_IRQ_SCCB_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-B special cond", port); + if (error) + goto fail_free_b_rx; { SCC_ACCESS_INIT(port); /* Either channel will do */ @@ -328,6 +382,23 @@ static int mvme162_scc_init(void) scc_init_drivers(); return 0; + +fail_free_b_rx: + free_irq(MVME162_IRQ_SCCB_RX, port); +fail_free_b_stat: + free_irq(MVME162_IRQ_SCCB_STAT, port); +fail_free_b_tx: + free_irq(MVME162_IRQ_SCCB_TX, port); +fail_free_a_spcond: + free_irq(MVME162_IRQ_SCCA_SPCOND, port); +fail_free_a_rx: + free_irq(MVME162_IRQ_SCCA_RX, port); +fail_free_a_stat: + free_irq(MVME162_IRQ_SCCA_STAT, port); +fail_free_a_tx: + free_irq(MVME162_IRQ_SCCA_TX, port); +fail: + return error; } #endif @@ -336,6 +407,7 @@ static int mvme162_scc_init(void) static int bvme6000_scc_init(void) { struct scc_port *port; + int error; printk(KERN_INFO "SCC: BVME6000 Serial Driver\n"); /* Init channel A */ @@ -345,14 +417,23 @@ static int bvme6000_scc_init(void) port->datap = port->ctrlp + 4; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(BVME_IRQ_SCCA_TX, scc_tx_int, IRQF_DISABLED, "SCC-A TX", port); - request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail; + error = request_irq(BVME_IRQ_SCCA_STAT, scc_stat_int, IRQF_DISABLED, "SCC-A status", port); - request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_a_tx; + error = request_irq(BVME_IRQ_SCCA_RX, scc_rx_int, IRQF_DISABLED, "SCC-A RX", port); - request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-A special cond", port); + if (error) + goto fail_free_a_stat; + error = request_irq(BVME_IRQ_SCCA_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-A special cond", port); + if (error) + goto fail_free_a_rx; + { SCC_ACCESS_INIT(port); @@ -372,14 +453,22 @@ static int bvme6000_scc_init(void) port->datap = port->ctrlp + 4; port->port_a = &scc_ports[0]; port->port_b = &scc_ports[1]; - request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, + error = request_irq(BVME_IRQ_SCCB_TX, scc_tx_int, IRQF_DISABLED, "SCC-B TX", port); - request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, + if (error) + goto fail_free_a_spcond; + error = request_irq(BVME_IRQ_SCCB_STAT, scc_stat_int, IRQF_DISABLED, "SCC-B status", port); - request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, + if (error) + goto fail_free_b_tx; + error = request_irq(BVME_IRQ_SCCB_RX, scc_rx_int, IRQF_DISABLED, "SCC-B RX", port); - request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, IRQF_DISABLED, - "SCC-B special cond", port); + if (error) + goto fail_free_b_stat; + error = request_irq(BVME_IRQ_SCCB_SPCOND, scc_spcond_int, + IRQF_DISABLED, "SCC-B special cond", port); + if (error) + goto fail_free_b_rx; { SCC_ACCESS_INIT(port); /* Either channel will do */ @@ -393,6 +482,23 @@ static int bvme6000_scc_init(void) scc_init_drivers(); return 0; + +fail: + free_irq(BVME_IRQ_SCCA_STAT, port); +fail_free_a_tx: + free_irq(BVME_IRQ_SCCA_RX, port); +fail_free_a_stat: + free_irq(BVME_IRQ_SCCA_SPCOND, port); +fail_free_a_rx: + free_irq(BVME_IRQ_SCCB_TX, port); +fail_free_a_spcond: + free_irq(BVME_IRQ_SCCB_STAT, port); +fail_free_b_tx: + free_irq(BVME_IRQ_SCCB_RX, port); +fail_free_b_stat: + free_irq(BVME_IRQ_SCCB_SPCOND, port); +fail_free_b_rx: + return error; } #endif diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 80014213fb5..7900bd63b36 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -969,8 +969,7 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) * Takes the console sem and the called methods then take the tty * termios_mutex and the tty ctrl_lock in that order. */ - -int vt_resize(struct tty_struct *tty, struct winsize *ws) +static int vt_resize(struct tty_struct *tty, struct winsize *ws) { struct vc_data *vc = tty->driver_data; int ret; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 01dde80597f..b55cb67435b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -584,12 +584,12 @@ out: return i; } -static ssize_t show_cpus(cpumask_t mask, char *buf) +static ssize_t show_cpus(const struct cpumask *mask, char *buf) { ssize_t i = 0; unsigned int cpu; - for_each_cpu_mask_nr(cpu, mask) { + for_each_cpu(cpu, mask) { if (i) i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); @@ -606,7 +606,7 @@ static ssize_t show_cpus(cpumask_t mask, char *buf) */ static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf) { - if (cpus_empty(policy->related_cpus)) + if (cpumask_empty(policy->related_cpus)) return show_cpus(policy->cpus, buf); return show_cpus(policy->related_cpus, buf); } @@ -806,9 +806,20 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) ret = -ENOMEM; goto nomem_out; } + if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) { + kfree(policy); + ret = -ENOMEM; + goto nomem_out; + } + if (!alloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) { + free_cpumask_var(policy->cpus); + kfree(policy); + ret = -ENOMEM; + goto nomem_out; + } policy->cpu = cpu; - policy->cpus = cpumask_of_cpu(cpu); + cpumask_copy(policy->cpus, cpumask_of(cpu)); /* Initially set CPU itself as the policy_cpu */ per_cpu(policy_cpu, cpu) = cpu; @@ -843,7 +854,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) } #endif - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { if (cpu == j) continue; @@ -861,7 +872,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) goto err_out_driver_exit; spin_lock_irqsave(&cpufreq_driver_lock, flags); - managed_policy->cpus = policy->cpus; + cpumask_copy(managed_policy->cpus, policy->cpus); per_cpu(cpufreq_cpu_data, cpu) = managed_policy; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -916,14 +927,14 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) } spin_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { per_cpu(cpufreq_cpu_data, j) = policy; per_cpu(policy_cpu, j) = policy->cpu; } spin_unlock_irqrestore(&cpufreq_driver_lock, flags); /* symlink affected CPUs */ - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { if (j == cpu) continue; if (!cpu_online(j)) @@ -963,7 +974,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev) err_out_unregister: spin_lock_irqsave(&cpufreq_driver_lock, flags); - for_each_cpu_mask_nr(j, policy->cpus) + for_each_cpu(j, policy->cpus) per_cpu(cpufreq_cpu_data, j) = NULL; spin_unlock_irqrestore(&cpufreq_driver_lock, flags); @@ -1024,7 +1035,7 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) */ if (unlikely(cpu != data->cpu)) { dprintk("removing link\n"); - cpu_clear(cpu, data->cpus); + cpumask_clear_cpu(cpu, data->cpus); spin_unlock_irqrestore(&cpufreq_driver_lock, flags); sysfs_remove_link(&sys_dev->kobj, "cpufreq"); cpufreq_cpu_put(data); @@ -1045,8 +1056,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) * per_cpu(cpufreq_cpu_data) while holding the lock, and remove * the sysfs links afterwards. */ - if (unlikely(cpus_weight(data->cpus) > 1)) { - for_each_cpu_mask_nr(j, data->cpus) { + if (unlikely(cpumask_weight(data->cpus) > 1)) { + for_each_cpu(j, data->cpus) { if (j == cpu) continue; per_cpu(cpufreq_cpu_data, j) = NULL; @@ -1055,8 +1066,8 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) spin_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (unlikely(cpus_weight(data->cpus) > 1)) { - for_each_cpu_mask_nr(j, data->cpus) { + if (unlikely(cpumask_weight(data->cpus) > 1)) { + for_each_cpu(j, data->cpus) { if (j == cpu) continue; dprintk("removing link for cpu %u\n", j); @@ -1090,7 +1101,10 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) if (cpufreq_driver->exit) cpufreq_driver->exit(data); + free_cpumask_var(data->related_cpus); + free_cpumask_var(data->cpus); kfree(data); + per_cpu(cpufreq_cpu_data, cpu) = NULL; cpufreq_debug_enable_ratelimit(); return 0; diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index e2657837d95..0320962c4ec 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -498,7 +498,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return rc; } - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); j_dbs_info->cur_policy = policy; diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 2ab3c12b88a..6a2b036c938 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -400,7 +400,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info) /* Get Absolute Load - in terms of freq */ max_load_freq = 0; - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { struct cpu_dbs_info_s *j_dbs_info; cputime64_t cur_wall_time, cur_idle_time; unsigned int idle_time, wall_time; @@ -568,7 +568,7 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, return rc; } - for_each_cpu_mask_nr(j, policy->cpus) { + for_each_cpu(j, policy->cpus) { struct cpu_dbs_info_s *j_dbs_info; j_dbs_info = &per_cpu(cpu_dbs_info, j); j_dbs_info->cur_policy = policy; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 8d7cf3f3145..f1df59f59a3 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -15,12 +15,14 @@ #include <linux/tick.h> #define BREAK_FUZZ 4 /* 4 us */ +#define PRED_HISTORY_PCT 50 struct menu_device { int last_state_idx; unsigned int expected_us; unsigned int predicted_us; + unsigned int current_predicted_us; unsigned int last_measured_us; unsigned int elapsed_us; }; @@ -47,6 +49,12 @@ static int menu_select(struct cpuidle_device *dev) data->expected_us = (u32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000; + /* Recalculate predicted_us based on prediction_history_pct */ + data->predicted_us *= PRED_HISTORY_PCT; + data->predicted_us += (100 - PRED_HISTORY_PCT) * + data->current_predicted_us; + data->predicted_us /= 100; + /* find the deepest idle state that satisfies our constraints */ for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) { struct cpuidle_state *s = &dev->states[i]; @@ -97,7 +105,7 @@ static void menu_reflect(struct cpuidle_device *dev) measured_us = -1; /* Predict time until next break event */ - data->predicted_us = max(measured_us, data->last_measured_us); + data->current_predicted_us = max(measured_us, data->last_measured_us); if (last_idle_us + BREAK_FUZZ < data->expected_us - target->exit_latency) { diff --git a/drivers/dca/dca-core.c b/drivers/dca/dca-core.c index d883e1b8bb8..55433849bfa 100644 --- a/drivers/dca/dca-core.c +++ b/drivers/dca/dca-core.c @@ -270,6 +270,6 @@ static void __exit dca_exit(void) dca_sysfs_exit(); } -subsys_initcall(dca_init); +arch_initcall(dca_init); module_exit(dca_exit); diff --git a/drivers/dio/dio-sysfs.c b/drivers/dio/dio-sysfs.c index f4646303884..ee1a3b59bd4 100644 --- a/drivers/dio/dio-sysfs.c +++ b/drivers/dio/dio-sysfs.c @@ -58,20 +58,25 @@ static ssize_t dio_show_resource(struct device *dev, struct device_attribute *at struct dio_dev *d = to_dio_dev(dev); return sprintf(buf, "0x%08lx 0x%08lx 0x%08lx\n", - dio_resource_start(d), dio_resource_end(d), + (unsigned long)dio_resource_start(d), + (unsigned long)dio_resource_end(d), dio_resource_flags(d)); } static DEVICE_ATTR(resource, S_IRUGO, dio_show_resource, NULL); -void dio_create_sysfs_dev_files(struct dio_dev *d) +int dio_create_sysfs_dev_files(struct dio_dev *d) { struct device *dev = &d->dev; + int error; /* current configuration's attributes */ - device_create_file(dev, &dev_attr_id); - device_create_file(dev, &dev_attr_ipl); - device_create_file(dev, &dev_attr_secid); - device_create_file(dev, &dev_attr_name); - device_create_file(dev, &dev_attr_resource); + if ((error = device_create_file(dev, &dev_attr_id)) || + (error = device_create_file(dev, &dev_attr_ipl)) || + (error = device_create_file(dev, &dev_attr_secid)) || + (error = device_create_file(dev, &dev_attr_name)) || + (error = device_create_file(dev, &dev_attr_resource))) + return error; + + return 0; } diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c index 07f274f853d..10c3c498358 100644 --- a/drivers/dio/dio.c +++ b/drivers/dio/dio.c @@ -173,6 +173,7 @@ static int __init dio_init(void) mm_segment_t fs; int i; struct dio_dev *dev; + int error; if (!MACH_IS_HP300) return 0; @@ -182,7 +183,11 @@ static int __init dio_init(void) /* Initialize the DIO bus */ INIT_LIST_HEAD(&dio_bus.devices); strcpy(dio_bus.dev.bus_id, "dio"); - device_register(&dio_bus.dev); + error = device_register(&dio_bus.dev); + if (error) { + pr_err("DIO: Error registering dio_bus\n"); + return error; + } /* Request all resources */ dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2); @@ -252,8 +257,15 @@ static int __init dio_init(void) if (scode >= DIOII_SCBASE) iounmap(va); - device_register(&dev->dev); - dio_create_sysfs_dev_files(dev); + error = device_register(&dev->dev); + if (error) { + pr_err("DIO: Error registering device %s\n", + dev->name); + continue; + } + error = dio_create_sysfs_dev_files(dev); + if (error) + dev_err(&dev->dev, "Error creating sysfs files\n"); } return 0; } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 904e57558bb..e34b0642081 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -33,7 +33,6 @@ config INTEL_IOATDMA config INTEL_IOP_ADMA tristate "Intel IOP ADMA support" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX - select ASYNC_CORE select DMA_ENGINE help Enable support for the Intel(R) IOP Series RAID engines. @@ -59,7 +58,6 @@ config FSL_DMA config MV_XOR bool "Marvell XOR engine support" depends on PLAT_ORION - select ASYNC_CORE select DMA_ENGINE ---help--- Enable support for the Marvell XOR engine. diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 65799651737..403dbe78112 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -31,32 +31,18 @@ * * LOCKING: * - * The subsystem keeps two global lists, dma_device_list and dma_client_list. - * Both of these are protected by a mutex, dma_list_mutex. + * The subsystem keeps a global list of dma_device structs it is protected by a + * mutex, dma_list_mutex. + * + * A subsystem can get access to a channel by calling dmaengine_get() followed + * by dma_find_channel(), or if it has need for an exclusive channel it can call + * dma_request_channel(). Once a channel is allocated a reference is taken + * against its corresponding driver to disable removal. * * Each device has a channels list, which runs unlocked but is never modified * once the device is registered, it's just setup by the driver. * - * Each client is responsible for keeping track of the channels it uses. See - * the definition of dma_event_callback in dmaengine.h. - * - * Each device has a kref, which is initialized to 1 when the device is - * registered. A kref_get is done for each device registered. When the - * device is released, the corresponding kref_put is done in the release - * method. Every time one of the device's channels is allocated to a client, - * a kref_get occurs. When the channel is freed, the corresponding kref_put - * happens. The device's release function does a completion, so - * unregister_device does a remove event, device_unregister, a kref_put - * for the first reference, then waits on the completion for all other - * references to finish. - * - * Each channel has an open-coded implementation of Rusty Russell's "bigref," - * with a kref and a per_cpu local_t. A dma_chan_get is called when a client - * signals that it wants to use a channel, and dma_chan_put is called when - * a channel is removed or a client using it is unregistered. A client can - * take extra references per outstanding transaction, as is the case with - * the NET DMA client. The release function does a kref_put on the device. - * -ChrisL, DanW + * See Documentation/dmaengine.txt for more details */ #include <linux/init.h> @@ -70,54 +56,85 @@ #include <linux/rcupdate.h> #include <linux/mutex.h> #include <linux/jiffies.h> +#include <linux/rculist.h> +#include <linux/idr.h> static DEFINE_MUTEX(dma_list_mutex); static LIST_HEAD(dma_device_list); -static LIST_HEAD(dma_client_list); +static long dmaengine_ref_count; +static struct idr dma_idr; /* --- sysfs implementation --- */ +/** + * dev_to_dma_chan - convert a device pointer to the its sysfs container object + * @dev - device node + * + * Must be called under dma_list_mutex + */ +static struct dma_chan *dev_to_dma_chan(struct device *dev) +{ + struct dma_chan_dev *chan_dev; + + chan_dev = container_of(dev, typeof(*chan_dev), device); + return chan_dev->chan; +} + static ssize_t show_memcpy_count(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); + struct dma_chan *chan; unsigned long count = 0; int i; + int err; - for_each_possible_cpu(i) - count += per_cpu_ptr(chan->local, i)->memcpy_count; + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) { + for_each_possible_cpu(i) + count += per_cpu_ptr(chan->local, i)->memcpy_count; + err = sprintf(buf, "%lu\n", count); + } else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); - return sprintf(buf, "%lu\n", count); + return err; } static ssize_t show_bytes_transferred(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); + struct dma_chan *chan; unsigned long count = 0; int i; + int err; - for_each_possible_cpu(i) - count += per_cpu_ptr(chan->local, i)->bytes_transferred; + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) { + for_each_possible_cpu(i) + count += per_cpu_ptr(chan->local, i)->bytes_transferred; + err = sprintf(buf, "%lu\n", count); + } else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); - return sprintf(buf, "%lu\n", count); + return err; } static ssize_t show_in_use(struct device *dev, struct device_attribute *attr, char *buf) { - struct dma_chan *chan = to_dma_chan(dev); - int in_use = 0; - - if (unlikely(chan->slow_ref) && - atomic_read(&chan->refcount.refcount) > 1) - in_use = 1; - else { - if (local_read(&(per_cpu_ptr(chan->local, - get_cpu())->refcount)) > 0) - in_use = 1; - put_cpu(); - } + struct dma_chan *chan; + int err; - return sprintf(buf, "%d\n", in_use); + mutex_lock(&dma_list_mutex); + chan = dev_to_dma_chan(dev); + if (chan) + err = sprintf(buf, "%d\n", chan->client_count); + else + err = -ENODEV; + mutex_unlock(&dma_list_mutex); + + return err; } static struct device_attribute dma_attrs[] = { @@ -127,76 +144,110 @@ static struct device_attribute dma_attrs[] = { __ATTR_NULL }; -static void dma_async_device_cleanup(struct kref *kref); - -static void dma_dev_release(struct device *dev) +static void chan_dev_release(struct device *dev) { - struct dma_chan *chan = to_dma_chan(dev); - kref_put(&chan->device->refcount, dma_async_device_cleanup); + struct dma_chan_dev *chan_dev; + + chan_dev = container_of(dev, typeof(*chan_dev), device); + if (atomic_dec_and_test(chan_dev->idr_ref)) { + mutex_lock(&dma_list_mutex); + idr_remove(&dma_idr, chan_dev->dev_id); + mutex_unlock(&dma_list_mutex); + kfree(chan_dev->idr_ref); + } + kfree(chan_dev); } static struct class dma_devclass = { .name = "dma", .dev_attrs = dma_attrs, - .dev_release = dma_dev_release, + .dev_release = chan_dev_release, }; /* --- client and device registration --- */ -#define dma_chan_satisfies_mask(chan, mask) \ - __dma_chan_satisfies_mask((chan), &(mask)) +#define dma_device_satisfies_mask(device, mask) \ + __dma_device_satisfies_mask((device), &(mask)) static int -__dma_chan_satisfies_mask(struct dma_chan *chan, dma_cap_mask_t *want) +__dma_device_satisfies_mask(struct dma_device *device, dma_cap_mask_t *want) { dma_cap_mask_t has; - bitmap_and(has.bits, want->bits, chan->device->cap_mask.bits, + bitmap_and(has.bits, want->bits, device->cap_mask.bits, DMA_TX_TYPE_END); return bitmap_equal(want->bits, has.bits, DMA_TX_TYPE_END); } +static struct module *dma_chan_to_owner(struct dma_chan *chan) +{ + return chan->device->dev->driver->owner; +} + /** - * dma_client_chan_alloc - try to allocate channels to a client - * @client: &dma_client + * balance_ref_count - catch up the channel reference count + * @chan - channel to balance ->client_count versus dmaengine_ref_count * - * Called with dma_list_mutex held. + * balance_ref_count must be called under dma_list_mutex */ -static void dma_client_chan_alloc(struct dma_client *client) +static void balance_ref_count(struct dma_chan *chan) { - struct dma_device *device; - struct dma_chan *chan; - int desc; /* allocated descriptor count */ - enum dma_state_client ack; + struct module *owner = dma_chan_to_owner(chan); - /* Find a channel */ - list_for_each_entry(device, &dma_device_list, global_node) { - /* Does the client require a specific DMA controller? */ - if (client->slave && client->slave->dma_dev - && client->slave->dma_dev != device->dev) - continue; + while (chan->client_count < dmaengine_ref_count) { + __module_get(owner); + chan->client_count++; + } +} - list_for_each_entry(chan, &device->channels, device_node) { - if (!dma_chan_satisfies_mask(chan, client->cap_mask)) - continue; +/** + * dma_chan_get - try to grab a dma channel's parent driver module + * @chan - channel to grab + * + * Must be called under dma_list_mutex + */ +static int dma_chan_get(struct dma_chan *chan) +{ + int err = -ENODEV; + struct module *owner = dma_chan_to_owner(chan); + + if (chan->client_count) { + __module_get(owner); + err = 0; + } else if (try_module_get(owner)) + err = 0; + + if (err == 0) + chan->client_count++; + + /* allocate upon first client reference */ + if (chan->client_count == 1 && err == 0) { + int desc_cnt = chan->device->device_alloc_chan_resources(chan); + + if (desc_cnt < 0) { + err = desc_cnt; + chan->client_count = 0; + module_put(owner); + } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask)) + balance_ref_count(chan); + } - desc = chan->device->device_alloc_chan_resources( - chan, client); - if (desc >= 0) { - ack = client->event_callback(client, - chan, - DMA_RESOURCE_AVAILABLE); + return err; +} - /* we are done once this client rejects - * an available resource - */ - if (ack == DMA_ACK) { - dma_chan_get(chan); - chan->client_count++; - } else if (ack == DMA_NAK) - return; - } - } - } +/** + * dma_chan_put - drop a reference to a dma channel's parent driver module + * @chan - channel to release + * + * Must be called under dma_list_mutex + */ +static void dma_chan_put(struct dma_chan *chan) +{ + if (!chan->client_count) + return; /* this channel failed alloc_chan_resources */ + chan->client_count--; + module_put(dma_chan_to_owner(chan)); + if (chan->client_count == 0) + chan->device->device_free_chan_resources(chan); } enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) @@ -218,138 +269,342 @@ enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) EXPORT_SYMBOL(dma_sync_wait); /** - * dma_chan_cleanup - release a DMA channel's resources - * @kref: kernel reference structure that contains the DMA channel device + * dma_cap_mask_all - enable iteration over all operation types + */ +static dma_cap_mask_t dma_cap_mask_all; + +/** + * dma_chan_tbl_ent - tracks channel allocations per core/operation + * @chan - associated channel for this entry + */ +struct dma_chan_tbl_ent { + struct dma_chan *chan; +}; + +/** + * channel_table - percpu lookup table for memory-to-memory offload providers */ -void dma_chan_cleanup(struct kref *kref) +static struct dma_chan_tbl_ent *channel_table[DMA_TX_TYPE_END]; + +static int __init dma_channel_table_init(void) { - struct dma_chan *chan = container_of(kref, struct dma_chan, refcount); - chan->device->device_free_chan_resources(chan); - kref_put(&chan->device->refcount, dma_async_device_cleanup); + enum dma_transaction_type cap; + int err = 0; + + bitmap_fill(dma_cap_mask_all.bits, DMA_TX_TYPE_END); + + /* 'interrupt', 'private', and 'slave' are channel capabilities, + * but are not associated with an operation so they do not need + * an entry in the channel_table + */ + clear_bit(DMA_INTERRUPT, dma_cap_mask_all.bits); + clear_bit(DMA_PRIVATE, dma_cap_mask_all.bits); + clear_bit(DMA_SLAVE, dma_cap_mask_all.bits); + + for_each_dma_cap_mask(cap, dma_cap_mask_all) { + channel_table[cap] = alloc_percpu(struct dma_chan_tbl_ent); + if (!channel_table[cap]) { + err = -ENOMEM; + break; + } + } + + if (err) { + pr_err("dmaengine: initialization failure\n"); + for_each_dma_cap_mask(cap, dma_cap_mask_all) + if (channel_table[cap]) + free_percpu(channel_table[cap]); + } + + return err; } -EXPORT_SYMBOL(dma_chan_cleanup); +arch_initcall(dma_channel_table_init); -static void dma_chan_free_rcu(struct rcu_head *rcu) +/** + * dma_find_channel - find a channel to carry out the operation + * @tx_type: transaction type + */ +struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) { - struct dma_chan *chan = container_of(rcu, struct dma_chan, rcu); - int bias = 0x7FFFFFFF; - int i; - for_each_possible_cpu(i) - bias -= local_read(&per_cpu_ptr(chan->local, i)->refcount); - atomic_sub(bias, &chan->refcount.refcount); - kref_put(&chan->refcount, dma_chan_cleanup); + struct dma_chan *chan; + int cpu; + + WARN_ONCE(dmaengine_ref_count == 0, + "client called %s without a reference", __func__); + + cpu = get_cpu(); + chan = per_cpu_ptr(channel_table[tx_type], cpu)->chan; + put_cpu(); + + return chan; } +EXPORT_SYMBOL(dma_find_channel); -static void dma_chan_release(struct dma_chan *chan) +/** + * dma_issue_pending_all - flush all pending operations across all channels + */ +void dma_issue_pending_all(void) { - atomic_add(0x7FFFFFFF, &chan->refcount.refcount); - chan->slow_ref = 1; - call_rcu(&chan->rcu, dma_chan_free_rcu); + struct dma_device *device; + struct dma_chan *chan; + + WARN_ONCE(dmaengine_ref_count == 0, + "client called %s without a reference", __func__); + + rcu_read_lock(); + list_for_each_entry_rcu(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + if (chan->client_count) + device->device_issue_pending(chan); + } + rcu_read_unlock(); } +EXPORT_SYMBOL(dma_issue_pending_all); /** - * dma_chans_notify_available - broadcast available channels to the clients + * nth_chan - returns the nth channel of the given capability + * @cap: capability to match + * @n: nth channel desired + * + * Defaults to returning the channel with the desired capability and the + * lowest reference count when 'n' cannot be satisfied. Must be called + * under dma_list_mutex. */ -static void dma_clients_notify_available(void) +static struct dma_chan *nth_chan(enum dma_transaction_type cap, int n) { - struct dma_client *client; + struct dma_device *device; + struct dma_chan *chan; + struct dma_chan *ret = NULL; + struct dma_chan *min = NULL; - mutex_lock(&dma_list_mutex); + list_for_each_entry(device, &dma_device_list, global_node) { + if (!dma_has_cap(cap, device->cap_mask) || + dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) { + if (!chan->client_count) + continue; + if (!min) + min = chan; + else if (chan->table_count < min->table_count) + min = chan; + + if (n-- == 0) { + ret = chan; + break; /* done */ + } + } + if (ret) + break; /* done */ + } - list_for_each_entry(client, &dma_client_list, global_node) - dma_client_chan_alloc(client); + if (!ret) + ret = min; - mutex_unlock(&dma_list_mutex); + if (ret) + ret->table_count++; + + return ret; } /** - * dma_chans_notify_available - tell the clients that a channel is going away - * @chan: channel on its way out + * dma_channel_rebalance - redistribute the available channels + * + * Optimize for cpu isolation (each cpu gets a dedicated channel for an + * operation type) in the SMP case, and operation isolation (avoid + * multi-tasking channels) in the non-SMP case. Must be called under + * dma_list_mutex. */ -static void dma_clients_notify_removed(struct dma_chan *chan) +static void dma_channel_rebalance(void) { - struct dma_client *client; - enum dma_state_client ack; + struct dma_chan *chan; + struct dma_device *device; + int cpu; + int cap; + int n; - mutex_lock(&dma_list_mutex); + /* undo the last distribution */ + for_each_dma_cap_mask(cap, dma_cap_mask_all) + for_each_possible_cpu(cpu) + per_cpu_ptr(channel_table[cap], cpu)->chan = NULL; + + list_for_each_entry(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + chan->table_count = 0; + } - list_for_each_entry(client, &dma_client_list, global_node) { - ack = client->event_callback(client, chan, - DMA_RESOURCE_REMOVED); + /* don't populate the channel_table if no clients are available */ + if (!dmaengine_ref_count) + return; - /* client was holding resources for this channel so - * free it - */ - if (ack == DMA_ACK) { - dma_chan_put(chan); - chan->client_count--; + /* redistribute available channels */ + n = 0; + for_each_dma_cap_mask(cap, dma_cap_mask_all) + for_each_online_cpu(cpu) { + if (num_possible_cpus() > 1) + chan = nth_chan(cap, n++); + else + chan = nth_chan(cap, -1); + + per_cpu_ptr(channel_table[cap], cpu)->chan = chan; + } +} + +static struct dma_chan *private_candidate(dma_cap_mask_t *mask, struct dma_device *dev, + dma_filter_fn fn, void *fn_param) +{ + struct dma_chan *chan; + + if (!__dma_device_satisfies_mask(dev, mask)) { + pr_debug("%s: wrong capabilities\n", __func__); + return NULL; + } + /* devices with multiple channels need special handling as we need to + * ensure that all channels are either private or public. + */ + if (dev->chancnt > 1 && !dma_has_cap(DMA_PRIVATE, dev->cap_mask)) + list_for_each_entry(chan, &dev->channels, device_node) { + /* some channels are already publicly allocated */ + if (chan->client_count) + return NULL; } + + list_for_each_entry(chan, &dev->channels, device_node) { + if (chan->client_count) { + pr_debug("%s: %s busy\n", + __func__, dma_chan_name(chan)); + continue; + } + if (fn && !fn(chan, fn_param)) { + pr_debug("%s: %s filter said false\n", + __func__, dma_chan_name(chan)); + continue; + } + return chan; } - mutex_unlock(&dma_list_mutex); + return NULL; } /** - * dma_async_client_register - register a &dma_client - * @client: ptr to a client structure with valid 'event_callback' and 'cap_mask' + * dma_request_channel - try to allocate an exclusive channel + * @mask: capabilities that the channel must satisfy + * @fn: optional callback to disposition available channels + * @fn_param: opaque parameter to pass to dma_filter_fn */ -void dma_async_client_register(struct dma_client *client) +struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) { - /* validate client data */ - BUG_ON(dma_has_cap(DMA_SLAVE, client->cap_mask) && - !client->slave); + struct dma_device *device, *_d; + struct dma_chan *chan = NULL; + int err; + /* Find a channel */ + mutex_lock(&dma_list_mutex); + list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { + chan = private_candidate(mask, device, fn, fn_param); + if (chan) { + /* Found a suitable channel, try to grab, prep, and + * return it. We first set DMA_PRIVATE to disable + * balance_ref_count as this channel will not be + * published in the general-purpose allocator + */ + dma_cap_set(DMA_PRIVATE, device->cap_mask); + err = dma_chan_get(chan); + + if (err == -ENODEV) { + pr_debug("%s: %s module removed\n", __func__, + dma_chan_name(chan)); + list_del_rcu(&device->global_node); + } else if (err) + pr_err("dmaengine: failed to get %s: (%d)\n", + dma_chan_name(chan), err); + else + break; + chan = NULL; + } + } + mutex_unlock(&dma_list_mutex); + + pr_debug("%s: %s (%s)\n", __func__, chan ? "success" : "fail", + chan ? dma_chan_name(chan) : NULL); + + return chan; +} +EXPORT_SYMBOL_GPL(__dma_request_channel); + +void dma_release_channel(struct dma_chan *chan) +{ mutex_lock(&dma_list_mutex); - list_add_tail(&client->global_node, &dma_client_list); + WARN_ONCE(chan->client_count != 1, + "chan reference count %d != 1\n", chan->client_count); + dma_chan_put(chan); mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_register); +EXPORT_SYMBOL_GPL(dma_release_channel); /** - * dma_async_client_unregister - unregister a client and free the &dma_client - * @client: &dma_client to free - * - * Force frees any allocated DMA channels, frees the &dma_client memory + * dmaengine_get - register interest in dma_channels */ -void dma_async_client_unregister(struct dma_client *client) +void dmaengine_get(void) { - struct dma_device *device; + struct dma_device *device, *_d; struct dma_chan *chan; - enum dma_state_client ack; - - if (!client) - return; + int err; mutex_lock(&dma_list_mutex); - /* free all channels the client is holding */ - list_for_each_entry(device, &dma_device_list, global_node) - list_for_each_entry(chan, &device->channels, device_node) { - ack = client->event_callback(client, chan, - DMA_RESOURCE_REMOVED); + dmaengine_ref_count++; - if (ack == DMA_ACK) { - dma_chan_put(chan); - chan->client_count--; - } + /* try to grab channels */ + list_for_each_entry_safe(device, _d, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) { + err = dma_chan_get(chan); + if (err == -ENODEV) { + /* module removed before we could use it */ + list_del_rcu(&device->global_node); + break; + } else if (err) + pr_err("dmaengine: failed to get %s: (%d)\n", + dma_chan_name(chan), err); } + } - list_del(&client->global_node); + /* if this is the first reference and there were channels + * waiting we need to rebalance to get those channels + * incorporated into the channel table + */ + if (dmaengine_ref_count == 1) + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_unregister); +EXPORT_SYMBOL(dmaengine_get); /** - * dma_async_client_chan_request - send all available channels to the - * client that satisfy the capability mask - * @client - requester + * dmaengine_put - let dma drivers be removed when ref_count == 0 */ -void dma_async_client_chan_request(struct dma_client *client) +void dmaengine_put(void) { + struct dma_device *device; + struct dma_chan *chan; + mutex_lock(&dma_list_mutex); - dma_client_chan_alloc(client); + dmaengine_ref_count--; + BUG_ON(dmaengine_ref_count < 0); + /* drop channel references */ + list_for_each_entry(device, &dma_device_list, global_node) { + if (dma_has_cap(DMA_PRIVATE, device->cap_mask)) + continue; + list_for_each_entry(chan, &device->channels, device_node) + dma_chan_put(chan); + } mutex_unlock(&dma_list_mutex); } -EXPORT_SYMBOL(dma_async_client_chan_request); +EXPORT_SYMBOL(dmaengine_put); /** * dma_async_device_register - registers DMA devices found @@ -357,9 +612,9 @@ EXPORT_SYMBOL(dma_async_client_chan_request); */ int dma_async_device_register(struct dma_device *device) { - static int id; int chancnt = 0, rc; struct dma_chan* chan; + atomic_t *idr_ref; if (!device) return -ENODEV; @@ -386,57 +641,83 @@ int dma_async_device_register(struct dma_device *device) BUG_ON(!device->device_issue_pending); BUG_ON(!device->dev); - init_completion(&device->done); - kref_init(&device->refcount); - + idr_ref = kmalloc(sizeof(*idr_ref), GFP_KERNEL); + if (!idr_ref) + return -ENOMEM; + atomic_set(idr_ref, 0); + idr_retry: + if (!idr_pre_get(&dma_idr, GFP_KERNEL)) + return -ENOMEM; mutex_lock(&dma_list_mutex); - device->dev_id = id++; + rc = idr_get_new(&dma_idr, NULL, &device->dev_id); mutex_unlock(&dma_list_mutex); + if (rc == -EAGAIN) + goto idr_retry; + else if (rc != 0) + return rc; /* represent channels in sysfs. Probably want devs too */ list_for_each_entry(chan, &device->channels, device_node) { chan->local = alloc_percpu(typeof(*chan->local)); if (chan->local == NULL) continue; + chan->dev = kzalloc(sizeof(*chan->dev), GFP_KERNEL); + if (chan->dev == NULL) { + free_percpu(chan->local); + continue; + } chan->chan_id = chancnt++; - chan->dev.class = &dma_devclass; - chan->dev.parent = device->dev; - dev_set_name(&chan->dev, "dma%dchan%d", + chan->dev->device.class = &dma_devclass; + chan->dev->device.parent = device->dev; + chan->dev->chan = chan; + chan->dev->idr_ref = idr_ref; + chan->dev->dev_id = device->dev_id; + atomic_inc(idr_ref); + dev_set_name(&chan->dev->device, "dma%dchan%d", device->dev_id, chan->chan_id); - rc = device_register(&chan->dev); + rc = device_register(&chan->dev->device); if (rc) { - chancnt--; free_percpu(chan->local); chan->local = NULL; goto err_out; } - - /* One for the channel, one of the class device */ - kref_get(&device->refcount); - kref_get(&device->refcount); - kref_init(&chan->refcount); chan->client_count = 0; - chan->slow_ref = 0; - INIT_RCU_HEAD(&chan->rcu); } + device->chancnt = chancnt; mutex_lock(&dma_list_mutex); - list_add_tail(&device->global_node, &dma_device_list); + /* take references on public channels */ + if (dmaengine_ref_count && !dma_has_cap(DMA_PRIVATE, device->cap_mask)) + list_for_each_entry(chan, &device->channels, device_node) { + /* if clients are already waiting for channels we need + * to take references on their behalf + */ + if (dma_chan_get(chan) == -ENODEV) { + /* note we can only get here for the first + * channel as the remaining channels are + * guaranteed to get a reference + */ + rc = -ENODEV; + mutex_unlock(&dma_list_mutex); + goto err_out; + } + } + list_add_tail_rcu(&device->global_node, &dma_device_list); + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); - dma_clients_notify_available(); - return 0; err_out: list_for_each_entry(chan, &device->channels, device_node) { if (chan->local == NULL) continue; - kref_put(&device->refcount, dma_async_device_cleanup); - device_unregister(&chan->dev); - chancnt--; + mutex_lock(&dma_list_mutex); + chan->dev->chan = NULL; + mutex_unlock(&dma_list_mutex); + device_unregister(&chan->dev->device); free_percpu(chan->local); } return rc; @@ -444,37 +725,30 @@ err_out: EXPORT_SYMBOL(dma_async_device_register); /** - * dma_async_device_cleanup - function called when all references are released - * @kref: kernel reference object - */ -static void dma_async_device_cleanup(struct kref *kref) -{ - struct dma_device *device; - - device = container_of(kref, struct dma_device, refcount); - complete(&device->done); -} - -/** - * dma_async_device_unregister - unregisters DMA devices + * dma_async_device_unregister - unregister a DMA device * @device: &dma_device + * + * This routine is called by dma driver exit routines, dmaengine holds module + * references to prevent it being called while channels are in use. */ void dma_async_device_unregister(struct dma_device *device) { struct dma_chan *chan; mutex_lock(&dma_list_mutex); - list_del(&device->global_node); + list_del_rcu(&device->global_node); + dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); list_for_each_entry(chan, &device->channels, device_node) { - dma_clients_notify_removed(chan); - device_unregister(&chan->dev); - dma_chan_release(chan); + WARN_ONCE(chan->client_count, + "%s called while %d clients hold a reference\n", + __func__, chan->client_count); + mutex_lock(&dma_list_mutex); + chan->dev->chan = NULL; + mutex_unlock(&dma_list_mutex); + device_unregister(&chan->dev->device); } - - kref_put(&device->refcount, dma_async_device_cleanup); - wait_for_completion(&device->done); } EXPORT_SYMBOL(dma_async_device_unregister); @@ -626,10 +900,96 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, } EXPORT_SYMBOL(dma_async_tx_descriptor_init); +/* dma_wait_for_async_tx - spin wait for a transaction to complete + * @tx: in-flight transaction to wait on + * + * This routine assumes that tx was obtained from a call to async_memcpy, + * async_xor, async_memset, etc which ensures that tx is "in-flight" (prepped + * and submitted). Walking the parent chain is only meant to cover for DMA + * drivers that do not implement the DMA_INTERRUPT capability and may race with + * the driver's descriptor cleanup routine. + */ +enum dma_status +dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) +{ + enum dma_status status; + struct dma_async_tx_descriptor *iter; + struct dma_async_tx_descriptor *parent; + + if (!tx) + return DMA_SUCCESS; + + WARN_ONCE(tx->parent, "%s: speculatively walking dependency chain for" + " %s\n", __func__, dma_chan_name(tx->chan)); + + /* poll through the dependency chain, return when tx is complete */ + do { + iter = tx; + + /* find the root of the unsubmitted dependency chain */ + do { + parent = iter->parent; + if (!parent) + break; + else + iter = parent; + } while (parent); + + /* there is a small window for ->parent == NULL and + * ->cookie == -EBUSY + */ + while (iter->cookie == -EBUSY) + cpu_relax(); + + status = dma_sync_wait(iter->chan, iter->cookie); + } while (status == DMA_IN_PROGRESS || (iter != tx)); + + return status; +} +EXPORT_SYMBOL_GPL(dma_wait_for_async_tx); + +/* dma_run_dependencies - helper routine for dma drivers to process + * (start) dependent operations on their target channel + * @tx: transaction with dependencies + */ +void dma_run_dependencies(struct dma_async_tx_descriptor *tx) +{ + struct dma_async_tx_descriptor *dep = tx->next; + struct dma_async_tx_descriptor *dep_next; + struct dma_chan *chan; + + if (!dep) + return; + + chan = dep->chan; + + /* keep submitting up until a channel switch is detected + * in that case we will be called again as a result of + * processing the interrupt from async_tx_channel_switch + */ + for (; dep; dep = dep_next) { + spin_lock_bh(&dep->lock); + dep->parent = NULL; + dep_next = dep->next; + if (dep_next && dep_next->chan == chan) + dep->next = NULL; /* ->next will be submitted */ + else + dep_next = NULL; /* submit current dep and terminate */ + spin_unlock_bh(&dep->lock); + + dep->tx_submit(dep); + } + + chan->device->device_issue_pending(chan); +} +EXPORT_SYMBOL_GPL(dma_run_dependencies); + static int __init dma_bus_init(void) { + idr_init(&dma_idr); mutex_init(&dma_list_mutex); return class_register(&dma_devclass); } -subsys_initcall(dma_bus_init); +arch_initcall(dma_bus_init); + diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index ed9636bfb54..3603f1ea5b2 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -35,7 +35,7 @@ MODULE_PARM_DESC(threads_per_chan, static unsigned int max_channels; module_param(max_channels, uint, S_IRUGO); -MODULE_PARM_DESC(nr_channels, +MODULE_PARM_DESC(max_channels, "Maximum number of channels to use (default: all)"); /* @@ -71,7 +71,7 @@ struct dmatest_chan { /* * These are protected by dma_list_mutex since they're only used by - * the DMA client event callback + * the DMA filter function callback */ static LIST_HEAD(dmatest_channels); static unsigned int nr_channels; @@ -80,7 +80,7 @@ static bool dmatest_match_channel(struct dma_chan *chan) { if (test_channel[0] == '\0') return true; - return strcmp(dev_name(&chan->dev), test_channel) == 0; + return strcmp(dma_chan_name(chan), test_channel) == 0; } static bool dmatest_match_device(struct dma_device *device) @@ -215,7 +215,6 @@ static int dmatest_func(void *data) smp_rmb(); chan = thread->chan; - dma_chan_get(chan); while (!kthread_should_stop()) { total_tests++; @@ -293,7 +292,6 @@ static int dmatest_func(void *data) } ret = 0; - dma_chan_put(chan); kfree(thread->dstbuf); err_dstbuf: kfree(thread->srcbuf); @@ -319,21 +317,16 @@ static void dmatest_cleanup_channel(struct dmatest_chan *dtc) kfree(dtc); } -static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) +static int dmatest_add_channel(struct dma_chan *chan) { struct dmatest_chan *dtc; struct dmatest_thread *thread; unsigned int i; - /* Have we already been told about this channel? */ - list_for_each_entry(dtc, &dmatest_channels, node) - if (dtc->chan == chan) - return DMA_DUP; - dtc = kmalloc(sizeof(struct dmatest_chan), GFP_KERNEL); if (!dtc) { - pr_warning("dmatest: No memory for %s\n", dev_name(&chan->dev)); - return DMA_NAK; + pr_warning("dmatest: No memory for %s\n", dma_chan_name(chan)); + return -ENOMEM; } dtc->chan = chan; @@ -343,16 +336,16 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) thread = kzalloc(sizeof(struct dmatest_thread), GFP_KERNEL); if (!thread) { pr_warning("dmatest: No memory for %s-test%u\n", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); break; } thread->chan = dtc->chan; smp_wmb(); thread->task = kthread_run(dmatest_func, thread, "%s-test%u", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); if (IS_ERR(thread->task)) { pr_warning("dmatest: Failed to run thread %s-test%u\n", - dev_name(&chan->dev), i); + dma_chan_name(chan), i); kfree(thread); break; } @@ -362,86 +355,62 @@ static enum dma_state_client dmatest_add_channel(struct dma_chan *chan) list_add_tail(&thread->node, &dtc->threads); } - pr_info("dmatest: Started %u threads using %s\n", i, dev_name(&chan->dev)); + pr_info("dmatest: Started %u threads using %s\n", i, dma_chan_name(chan)); list_add_tail(&dtc->node, &dmatest_channels); nr_channels++; - return DMA_ACK; -} - -static enum dma_state_client dmatest_remove_channel(struct dma_chan *chan) -{ - struct dmatest_chan *dtc, *_dtc; - - list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { - if (dtc->chan == chan) { - list_del(&dtc->node); - dmatest_cleanup_channel(dtc); - pr_debug("dmatest: lost channel %s\n", - dev_name(&chan->dev)); - return DMA_ACK; - } - } - - return DMA_DUP; + return 0; } -/* - * Start testing threads as new channels are assigned to us, and kill - * them when the channels go away. - * - * When we unregister the client, all channels are removed so this - * will also take care of cleaning things up when the module is - * unloaded. - */ -static enum dma_state_client -dmatest_event(struct dma_client *client, struct dma_chan *chan, - enum dma_state state) +static bool filter(struct dma_chan *chan, void *param) { - enum dma_state_client ack = DMA_NAK; - - switch (state) { - case DMA_RESOURCE_AVAILABLE: - if (!dmatest_match_channel(chan) - || !dmatest_match_device(chan->device)) - ack = DMA_DUP; - else if (max_channels && nr_channels >= max_channels) - ack = DMA_NAK; - else - ack = dmatest_add_channel(chan); - break; - - case DMA_RESOURCE_REMOVED: - ack = dmatest_remove_channel(chan); - break; - - default: - pr_info("dmatest: Unhandled event %u (%s)\n", - state, dev_name(&chan->dev)); - break; - } - - return ack; + if (!dmatest_match_channel(chan) || !dmatest_match_device(chan->device)) + return false; + else + return true; } -static struct dma_client dmatest_client = { - .event_callback = dmatest_event, -}; - static int __init dmatest_init(void) { - dma_cap_set(DMA_MEMCPY, dmatest_client.cap_mask); - dma_async_client_register(&dmatest_client); - dma_async_client_chan_request(&dmatest_client); + dma_cap_mask_t mask; + struct dma_chan *chan; + int err = 0; + + dma_cap_zero(mask); + dma_cap_set(DMA_MEMCPY, mask); + for (;;) { + chan = dma_request_channel(mask, filter, NULL); + if (chan) { + err = dmatest_add_channel(chan); + if (err == 0) + continue; + else { + dma_release_channel(chan); + break; /* add_channel failed, punt */ + } + } else + break; /* no more channels available */ + if (max_channels && nr_channels >= max_channels) + break; /* we have all we need */ + } - return 0; + return err; } -module_init(dmatest_init); +/* when compiled-in wait for drivers to load first */ +late_initcall(dmatest_init); static void __exit dmatest_exit(void) { - dma_async_client_unregister(&dmatest_client); + struct dmatest_chan *dtc, *_dtc; + + list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) { + list_del(&dtc->node); + dmatest_cleanup_channel(dtc); + pr_debug("dmatest: dropped channel %s\n", + dma_chan_name(dtc->chan)); + dma_release_channel(dtc->chan); + } } module_exit(dmatest_exit); diff --git a/drivers/dma/dw_dmac.c b/drivers/dma/dw_dmac.c index 0778d99aea7..6b702cc46b3 100644 --- a/drivers/dma/dw_dmac.c +++ b/drivers/dma/dw_dmac.c @@ -70,6 +70,15 @@ * the controller, though. */ +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} +static struct device *chan2parent(struct dma_chan *chan) +{ + return chan->dev->device.parent; +} + static struct dw_desc *dwc_first_active(struct dw_dma_chan *dwc) { return list_entry(dwc->active_list.next, struct dw_desc, desc_node); @@ -93,12 +102,12 @@ static struct dw_desc *dwc_desc_get(struct dw_dma_chan *dwc) ret = desc; break; } - dev_dbg(&dwc->chan.dev, "desc %p not ACKed\n", desc); + dev_dbg(chan2dev(&dwc->chan), "desc %p not ACKed\n", desc); i++; } spin_unlock_bh(&dwc->lock); - dev_vdbg(&dwc->chan.dev, "scanned %u descriptors on freelist\n", i); + dev_vdbg(chan2dev(&dwc->chan), "scanned %u descriptors on freelist\n", i); return ret; } @@ -108,10 +117,10 @@ static void dwc_sync_desc_for_cpu(struct dw_dma_chan *dwc, struct dw_desc *desc) struct dw_desc *child; list_for_each_entry(child, &desc->txd.tx_list, desc_node) - dma_sync_single_for_cpu(dwc->chan.dev.parent, + dma_sync_single_for_cpu(chan2parent(&dwc->chan), child->txd.phys, sizeof(child->lli), DMA_TO_DEVICE); - dma_sync_single_for_cpu(dwc->chan.dev.parent, + dma_sync_single_for_cpu(chan2parent(&dwc->chan), desc->txd.phys, sizeof(desc->lli), DMA_TO_DEVICE); } @@ -129,11 +138,11 @@ static void dwc_desc_put(struct dw_dma_chan *dwc, struct dw_desc *desc) spin_lock_bh(&dwc->lock); list_for_each_entry(child, &desc->txd.tx_list, desc_node) - dev_vdbg(&dwc->chan.dev, + dev_vdbg(chan2dev(&dwc->chan), "moving child desc %p to freelist\n", child); list_splice_init(&desc->txd.tx_list, &dwc->free_list); - dev_vdbg(&dwc->chan.dev, "moving desc %p to freelist\n", desc); + dev_vdbg(chan2dev(&dwc->chan), "moving desc %p to freelist\n", desc); list_add(&desc->desc_node, &dwc->free_list); spin_unlock_bh(&dwc->lock); } @@ -163,9 +172,9 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first) /* ASSERT: channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: Attempted to start non-idle channel\n"); - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), " SAR: 0x%x DAR: 0x%x LLP: 0x%x CTL: 0x%x:%08x\n", channel_readl(dwc, SAR), channel_readl(dwc, DAR), @@ -193,7 +202,7 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) void *param; struct dma_async_tx_descriptor *txd = &desc->txd; - dev_vdbg(&dwc->chan.dev, "descriptor %u complete\n", txd->cookie); + dev_vdbg(chan2dev(&dwc->chan), "descriptor %u complete\n", txd->cookie); dwc->completed = txd->cookie; callback = txd->callback; @@ -208,11 +217,11 @@ dwc_descriptor_complete(struct dw_dma_chan *dwc, struct dw_desc *desc) * mapped before they were submitted... */ if (!(txd->flags & DMA_COMPL_SKIP_DEST_UNMAP)) - dma_unmap_page(dwc->chan.dev.parent, desc->lli.dar, desc->len, - DMA_FROM_DEVICE); + dma_unmap_page(chan2parent(&dwc->chan), desc->lli.dar, + desc->len, DMA_FROM_DEVICE); if (!(txd->flags & DMA_COMPL_SKIP_SRC_UNMAP)) - dma_unmap_page(dwc->chan.dev.parent, desc->lli.sar, desc->len, - DMA_TO_DEVICE); + dma_unmap_page(chan2parent(&dwc->chan), desc->lli.sar, + desc->len, DMA_TO_DEVICE); /* * The API requires that no submissions are done from a @@ -228,7 +237,7 @@ static void dwc_complete_all(struct dw_dma *dw, struct dw_dma_chan *dwc) LIST_HEAD(list); if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: XFER bit set, but channel not idle!\n"); /* Try to continue after resetting the channel... */ @@ -273,7 +282,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) return; } - dev_vdbg(&dwc->chan.dev, "scan_descriptors: llp=0x%x\n", llp); + dev_vdbg(chan2dev(&dwc->chan), "scan_descriptors: llp=0x%x\n", llp); list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) { if (desc->lli.llp == llp) @@ -292,7 +301,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) dwc_descriptor_complete(dwc, desc); } - dev_err(&dwc->chan.dev, + dev_err(chan2dev(&dwc->chan), "BUG: All descriptors done, but channel not idle!\n"); /* Try to continue after resetting the channel... */ @@ -308,7 +317,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc) static void dwc_dump_lli(struct dw_dma_chan *dwc, struct dw_lli *lli) { - dev_printk(KERN_CRIT, &dwc->chan.dev, + dev_printk(KERN_CRIT, chan2dev(&dwc->chan), " desc: s0x%x d0x%x l0x%x c0x%x:%x\n", lli->sar, lli->dar, lli->llp, lli->ctlhi, lli->ctllo); @@ -342,9 +351,9 @@ static void dwc_handle_error(struct dw_dma *dw, struct dw_dma_chan *dwc) * controller flagged an error instead of scribbling over * random memory locations. */ - dev_printk(KERN_CRIT, &dwc->chan.dev, + dev_printk(KERN_CRIT, chan2dev(&dwc->chan), "Bad descriptor submitted for DMA!\n"); - dev_printk(KERN_CRIT, &dwc->chan.dev, + dev_printk(KERN_CRIT, chan2dev(&dwc->chan), " cookie: %d\n", bad_desc->txd.cookie); dwc_dump_lli(dwc, &bad_desc->lli); list_for_each_entry(child, &bad_desc->txd.tx_list, desc_node) @@ -442,12 +451,12 @@ static dma_cookie_t dwc_tx_submit(struct dma_async_tx_descriptor *tx) * for DMA. But this is hard to do in a race-free manner. */ if (list_empty(&dwc->active_list)) { - dev_vdbg(&tx->chan->dev, "tx_submit: started %u\n", + dev_vdbg(chan2dev(tx->chan), "tx_submit: started %u\n", desc->txd.cookie); dwc_dostart(dwc, desc); list_add_tail(&desc->desc_node, &dwc->active_list); } else { - dev_vdbg(&tx->chan->dev, "tx_submit: queued %u\n", + dev_vdbg(chan2dev(tx->chan), "tx_submit: queued %u\n", desc->txd.cookie); list_add_tail(&desc->desc_node, &dwc->queue); @@ -472,11 +481,11 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, unsigned int dst_width; u32 ctllo; - dev_vdbg(&chan->dev, "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n", + dev_vdbg(chan2dev(chan), "prep_dma_memcpy d0x%x s0x%x l0x%zx f0x%lx\n", dest, src, len, flags); if (unlikely(!len)) { - dev_dbg(&chan->dev, "prep_dma_memcpy: length is zero!\n"); + dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n"); return NULL; } @@ -516,7 +525,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); list_add_tail(&desc->desc_node, @@ -531,7 +540,7 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, prev->lli.ctllo |= DWC_CTLL_INT_EN; prev->lli.llp = 0; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -562,15 +571,15 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, struct scatterlist *sg; size_t total_len = 0; - dev_vdbg(&chan->dev, "prep_dma_slave\n"); + dev_vdbg(chan2dev(chan), "prep_dma_slave\n"); if (unlikely(!dws || !sg_len)) return NULL; - reg_width = dws->slave.reg_width; + reg_width = dws->reg_width; prev = first = NULL; - sg_len = dma_map_sg(chan->dev.parent, sgl, sg_len, direction); + sg_len = dma_map_sg(chan2parent(chan), sgl, sg_len, direction); switch (direction) { case DMA_TO_DEVICE: @@ -579,7 +588,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_DST_FIX | DWC_CTLL_SRC_INC | DWC_CTLL_FC_M2P); - reg = dws->slave.tx_reg; + reg = dws->tx_reg; for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; u32 len; @@ -587,7 +596,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc = dwc_desc_get(dwc); if (!desc) { - dev_err(&chan->dev, + dev_err(chan2dev(chan), "not enough descriptors available\n"); goto err_desc_get; } @@ -607,7 +616,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -625,7 +634,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, | DWC_CTLL_SRC_FIX | DWC_CTLL_FC_P2M); - reg = dws->slave.rx_reg; + reg = dws->rx_reg; for_each_sg(sgl, sg, sg_len, i) { struct dw_desc *desc; u32 len; @@ -633,7 +642,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc = dwc_desc_get(dwc); if (!desc) { - dev_err(&chan->dev, + dev_err(chan2dev(chan), "not enough descriptors available\n"); goto err_desc_get; } @@ -653,7 +662,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first = desc; } else { prev->lli.llp = desc->txd.phys; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -673,7 +682,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, prev->lli.ctllo |= DWC_CTLL_INT_EN; prev->lli.llp = 0; - dma_sync_single_for_device(chan->dev.parent, + dma_sync_single_for_device(chan2parent(chan), prev->txd.phys, sizeof(prev->lli), DMA_TO_DEVICE); @@ -758,29 +767,21 @@ static void dwc_issue_pending(struct dma_chan *chan) spin_unlock_bh(&dwc->lock); } -static int dwc_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int dwc_alloc_chan_resources(struct dma_chan *chan) { struct dw_dma_chan *dwc = to_dw_dma_chan(chan); struct dw_dma *dw = to_dw_dma(chan->device); struct dw_desc *desc; - struct dma_slave *slave; struct dw_dma_slave *dws; int i; u32 cfghi; u32 cfglo; - dev_vdbg(&chan->dev, "alloc_chan_resources\n"); - - /* Channels doing slave DMA can only handle one client. */ - if (dwc->dws || client->slave) { - if (chan->client_count) - return -EBUSY; - } + dev_vdbg(chan2dev(chan), "alloc_chan_resources\n"); /* ASSERT: channel is idle */ if (dma_readl(dw, CH_EN) & dwc->mask) { - dev_dbg(&chan->dev, "DMA channel not idle?\n"); + dev_dbg(chan2dev(chan), "DMA channel not idle?\n"); return -EIO; } @@ -789,23 +790,17 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, cfghi = DWC_CFGH_FIFO_MODE; cfglo = 0; - slave = client->slave; - if (slave) { + dws = dwc->dws; + if (dws) { /* * We need controller-specific data to set up slave * transfers. */ - BUG_ON(!slave->dma_dev || slave->dma_dev != dw->dma.dev); - - dws = container_of(slave, struct dw_dma_slave, slave); + BUG_ON(!dws->dma_dev || dws->dma_dev != dw->dma.dev); - dwc->dws = dws; cfghi = dws->cfg_hi; cfglo = dws->cfg_lo; - } else { - dwc->dws = NULL; } - channel_writel(dwc, CFG_LO, cfglo); channel_writel(dwc, CFG_HI, cfghi); @@ -822,7 +817,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, desc = kzalloc(sizeof(struct dw_desc), GFP_KERNEL); if (!desc) { - dev_info(&chan->dev, + dev_info(chan2dev(chan), "only allocated %d descriptors\n", i); spin_lock_bh(&dwc->lock); break; @@ -832,7 +827,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, desc->txd.tx_submit = dwc_tx_submit; desc->txd.flags = DMA_CTRL_ACK; INIT_LIST_HEAD(&desc->txd.tx_list); - desc->txd.phys = dma_map_single(chan->dev.parent, &desc->lli, + desc->txd.phys = dma_map_single(chan2parent(chan), &desc->lli, sizeof(desc->lli), DMA_TO_DEVICE); dwc_desc_put(dwc, desc); @@ -847,7 +842,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan, spin_unlock_bh(&dwc->lock); - dev_dbg(&chan->dev, + dev_dbg(chan2dev(chan), "alloc_chan_resources allocated %d descriptors\n", i); return i; @@ -860,7 +855,7 @@ static void dwc_free_chan_resources(struct dma_chan *chan) struct dw_desc *desc, *_desc; LIST_HEAD(list); - dev_dbg(&chan->dev, "free_chan_resources (descs allocated=%u)\n", + dev_dbg(chan2dev(chan), "free_chan_resources (descs allocated=%u)\n", dwc->descs_allocated); /* ASSERT: channel is idle */ @@ -881,13 +876,13 @@ static void dwc_free_chan_resources(struct dma_chan *chan) spin_unlock_bh(&dwc->lock); list_for_each_entry_safe(desc, _desc, &list, desc_node) { - dev_vdbg(&chan->dev, " freeing descriptor %p\n", desc); - dma_unmap_single(chan->dev.parent, desc->txd.phys, + dev_vdbg(chan2dev(chan), " freeing descriptor %p\n", desc); + dma_unmap_single(chan2parent(chan), desc->txd.phys, sizeof(desc->lli), DMA_TO_DEVICE); kfree(desc); } - dev_vdbg(&chan->dev, "free_chan_resources done\n"); + dev_vdbg(chan2dev(chan), "free_chan_resources done\n"); } /*----------------------------------------------------------------------*/ diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c index 0b95dcce447..ca70a21afc6 100644 --- a/drivers/dma/fsldma.c +++ b/drivers/dma/fsldma.c @@ -366,8 +366,7 @@ static struct fsl_desc_sw *fsl_dma_alloc_descriptor( * * Return - The number of descriptors allocated. */ -static int fsl_dma_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int fsl_dma_alloc_chan_resources(struct dma_chan *chan) { struct fsl_dma_chan *fsl_chan = to_fsl_chan(chan); @@ -823,7 +822,7 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev, */ WARN_ON(fdev->feature != new_fsl_chan->feature); - new_fsl_chan->dev = &new_fsl_chan->common.dev; + new_fsl_chan->dev = &new_fsl_chan->common.dev->device; new_fsl_chan->reg_base = ioremap(new_fsl_chan->reg.start, new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1); diff --git a/drivers/dma/ioat.c b/drivers/dma/ioat.c index 9b16a3af9a0..4105d6575b6 100644 --- a/drivers/dma/ioat.c +++ b/drivers/dma/ioat.c @@ -75,60 +75,10 @@ static int ioat_dca_enabled = 1; module_param(ioat_dca_enabled, int, 0644); MODULE_PARM_DESC(ioat_dca_enabled, "control support of dca service (default: 1)"); -static int ioat_setup_functionality(struct pci_dev *pdev, void __iomem *iobase) -{ - struct ioat_device *device = pci_get_drvdata(pdev); - u8 version; - int err = 0; - - version = readb(iobase + IOAT_VER_OFFSET); - switch (version) { - case IOAT_VER_1_2: - device->dma = ioat_dma_probe(pdev, iobase); - if (device->dma && ioat_dca_enabled) - device->dca = ioat_dca_init(pdev, iobase); - break; - case IOAT_VER_2_0: - device->dma = ioat_dma_probe(pdev, iobase); - if (device->dma && ioat_dca_enabled) - device->dca = ioat2_dca_init(pdev, iobase); - break; - case IOAT_VER_3_0: - device->dma = ioat_dma_probe(pdev, iobase); - if (device->dma && ioat_dca_enabled) - device->dca = ioat3_dca_init(pdev, iobase); - break; - default: - err = -ENODEV; - break; - } - if (!device->dma) - err = -ENODEV; - return err; -} - -static void ioat_shutdown_functionality(struct pci_dev *pdev) -{ - struct ioat_device *device = pci_get_drvdata(pdev); - - dev_err(&pdev->dev, "Removing dma and dca services\n"); - if (device->dca) { - unregister_dca_provider(device->dca); - free_dca_provider(device->dca); - device->dca = NULL; - } - - if (device->dma) { - ioat_dma_remove(device->dma); - device->dma = NULL; - } -} - static struct pci_driver ioat_pci_driver = { .name = "ioatdma", .id_table = ioat_pci_tbl, .probe = ioat_probe, - .shutdown = ioat_shutdown_functionality, .remove = __devexit_p(ioat_remove), }; @@ -179,7 +129,29 @@ static int __devinit ioat_probe(struct pci_dev *pdev, pci_set_master(pdev); - err = ioat_setup_functionality(pdev, iobase); + switch (readb(iobase + IOAT_VER_OFFSET)) { + case IOAT_VER_1_2: + device->dma = ioat_dma_probe(pdev, iobase); + if (device->dma && ioat_dca_enabled) + device->dca = ioat_dca_init(pdev, iobase); + break; + case IOAT_VER_2_0: + device->dma = ioat_dma_probe(pdev, iobase); + if (device->dma && ioat_dca_enabled) + device->dca = ioat2_dca_init(pdev, iobase); + break; + case IOAT_VER_3_0: + device->dma = ioat_dma_probe(pdev, iobase); + if (device->dma && ioat_dca_enabled) + device->dca = ioat3_dca_init(pdev, iobase); + break; + default: + err = -ENODEV; + break; + } + if (!device->dma) + err = -ENODEV; + if (err) goto err_version; @@ -198,17 +170,21 @@ err_enable_device: return err; } -/* - * It is unsafe to remove this module: if removed while a requested - * dma is outstanding, esp. from tcp, it is possible to hang while - * waiting for something that will never finish. However, if you're - * feeling lucky, this usually works just fine. - */ static void __devexit ioat_remove(struct pci_dev *pdev) { struct ioat_device *device = pci_get_drvdata(pdev); - ioat_shutdown_functionality(pdev); + dev_err(&pdev->dev, "Removing dma and dca services\n"); + if (device->dca) { + unregister_dca_provider(device->dca); + free_dca_provider(device->dca); + device->dca = NULL; + } + + if (device->dma) { + ioat_dma_remove(device->dma); + device->dma = NULL; + } kfree(device); } diff --git a/drivers/dma/ioat_dma.c b/drivers/dma/ioat_dma.c index 6607fdd00b1..b3759c4b653 100644 --- a/drivers/dma/ioat_dma.c +++ b/drivers/dma/ioat_dma.c @@ -734,8 +734,7 @@ static void ioat2_dma_massage_chan_desc(struct ioat_dma_chan *ioat_chan) * ioat_dma_alloc_chan_resources - returns the number of allocated descriptors * @chan: the channel to be filled out */ -static int ioat_dma_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int ioat_dma_alloc_chan_resources(struct dma_chan *chan) { struct ioat_dma_chan *ioat_chan = to_ioat_chan(chan); struct ioat_desc_sw *desc; @@ -1341,12 +1340,11 @@ static void ioat_dma_start_null_desc(struct ioat_dma_chan *ioat_chan) */ #define IOAT_TEST_SIZE 2000 -DECLARE_COMPLETION(test_completion); static void ioat_dma_test_callback(void *dma_async_param) { - printk(KERN_ERR "ioatdma: ioat_dma_test_callback(%p)\n", - dma_async_param); - complete(&test_completion); + struct completion *cmp = dma_async_param; + + complete(cmp); } /** @@ -1363,6 +1361,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) dma_addr_t dma_dest, dma_src; dma_cookie_t cookie; int err = 0; + struct completion cmp; src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL); if (!src) @@ -1381,7 +1380,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (device->common.device_alloc_chan_resources(dma_chan, NULL) < 1) { + if (device->common.device_alloc_chan_resources(dma_chan) < 1) { dev_err(&device->pdev->dev, "selftest cannot allocate chan resource\n"); err = -ENODEV; @@ -1402,8 +1401,9 @@ static int ioat_dma_self_test(struct ioatdma_device *device) } async_tx_ack(tx); + init_completion(&cmp); tx->callback = ioat_dma_test_callback; - tx->callback_param = (void *)0x8086; + tx->callback_param = &cmp; cookie = tx->tx_submit(tx); if (cookie < 0) { dev_err(&device->pdev->dev, @@ -1413,7 +1413,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device) } device->common.device_issue_pending(dma_chan); - wait_for_completion_timeout(&test_completion, msecs_to_jiffies(3000)); + wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000)); if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL) != DMA_SUCCESS) { diff --git a/drivers/dma/iop-adma.c b/drivers/dma/iop-adma.c index 6be31726220..ea5440dd10d 100644 --- a/drivers/dma/iop-adma.c +++ b/drivers/dma/iop-adma.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/async_tx.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> @@ -116,7 +115,7 @@ iop_adma_run_tx_complete_actions(struct iop_adma_desc_slot *desc, } /* run dependent operations */ - async_tx_run_dependencies(&desc->async_tx); + dma_run_dependencies(&desc->async_tx); return cookie; } @@ -270,8 +269,6 @@ static void __iop_adma_slot_cleanup(struct iop_adma_chan *iop_chan) break; } - BUG_ON(!seen_current); - if (cookie > 0) { iop_chan->completed_cookie = cookie; pr_debug("\tcompleted cookie %d\n", cookie); @@ -471,8 +468,7 @@ static void iop_chan_start_null_xor(struct iop_adma_chan *iop_chan); * greater than 2x the number slots needed to satisfy a device->max_xor * request. * */ -static int iop_adma_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int iop_adma_alloc_chan_resources(struct dma_chan *chan) { char *hw_desc; int idx; @@ -866,7 +862,7 @@ static int __devinit iop_adma_memcpy_self_test(struct iop_adma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) { + if (iop_adma_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -964,7 +960,7 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (iop_adma_alloc_chan_resources(dma_chan, NULL) < 1) { + if (iop_adma_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1115,26 +1111,13 @@ static int __devexit iop_adma_remove(struct platform_device *dev) struct iop_adma_device *device = platform_get_drvdata(dev); struct dma_chan *chan, *_chan; struct iop_adma_chan *iop_chan; - int i; struct iop_adma_platform_data *plat_data = dev->dev.platform_data; dma_async_device_unregister(&device->common); - for (i = 0; i < 3; i++) { - unsigned int irq; - irq = platform_get_irq(dev, i); - free_irq(irq, device); - } - dma_free_coherent(&dev->dev, plat_data->pool_size, device->dma_desc_pool_virt, device->dma_desc_pool); - do { - struct resource *res; - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - release_mem_region(res->start, res->end - res->start); - } while (0); - list_for_each_entry_safe(chan, _chan, &device->common.channels, device_node) { iop_chan = to_iop_adma_chan(chan); @@ -1255,7 +1238,6 @@ static int __devinit iop_adma_probe(struct platform_device *pdev) spin_lock_init(&iop_chan->lock); INIT_LIST_HEAD(&iop_chan->chain); INIT_LIST_HEAD(&iop_chan->all_slots); - INIT_RCU_HEAD(&iop_chan->common.rcu); iop_chan->common.device = dma_dev; list_add_tail(&iop_chan->common.device_node, &dma_dev->channels); @@ -1431,16 +1413,12 @@ static int __init iop_adma_init (void) return platform_driver_register(&iop_adma_driver); } -/* it's currently unsafe to unload this module */ -#if 0 static void __exit iop_adma_exit (void) { platform_driver_unregister(&iop_adma_driver); return; } module_exit(iop_adma_exit); -#endif - module_init(iop_adma_init); MODULE_AUTHOR("Intel Corporation"); diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index bcda1742641..d35cbd1ff0b 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -18,7 +18,6 @@ #include <linux/init.h> #include <linux/module.h> -#include <linux/async_tx.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> @@ -340,7 +339,7 @@ mv_xor_run_tx_complete_actions(struct mv_xor_desc_slot *desc, } /* run dependent operations */ - async_tx_run_dependencies(&desc->async_tx); + dma_run_dependencies(&desc->async_tx); return cookie; } @@ -607,8 +606,7 @@ submit_done: } /* returns the number of allocated descriptors */ -static int mv_xor_alloc_chan_resources(struct dma_chan *chan, - struct dma_client *client) +static int mv_xor_alloc_chan_resources(struct dma_chan *chan) { char *hw_desc; int idx; @@ -958,7 +956,7 @@ static int __devinit mv_xor_memcpy_self_test(struct mv_xor_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) { + if (mv_xor_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1053,7 +1051,7 @@ mv_xor_xor_self_test(struct mv_xor_device *device) dma_chan = container_of(device->common.channels.next, struct dma_chan, device_node); - if (mv_xor_alloc_chan_resources(dma_chan, NULL) < 1) { + if (mv_xor_alloc_chan_resources(dma_chan) < 1) { err = -ENODEV; goto out; } @@ -1221,7 +1219,6 @@ static int __devinit mv_xor_probe(struct platform_device *pdev) INIT_LIST_HEAD(&mv_chan->chain); INIT_LIST_HEAD(&mv_chan->completed_slots); INIT_LIST_HEAD(&mv_chan->all_slots); - INIT_RCU_HEAD(&mv_chan->common.rcu); mv_chan->common.device = dma_dev; list_add_tail(&mv_chan->common.device_node, &dma_dev->channels); diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 799f94424c8..6bd91a15d5e 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c @@ -209,6 +209,8 @@ fw_card_bm_work(struct work_struct *work) unsigned long flags; int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; bool do_reset = false; + bool root_device_is_running; + bool root_device_is_cmc; __be32 lock_data[2]; spin_lock_irqsave(&card->lock, flags); @@ -224,8 +226,9 @@ fw_card_bm_work(struct work_struct *work) generation = card->generation; root_device = root_node->data; - if (root_device) - fw_device_get(root_device); + root_device_is_running = root_device && + atomic_read(&root_device->state) == FW_DEVICE_RUNNING; + root_device_is_cmc = root_device && root_device->cmc; root_id = root_node->node_id; grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); @@ -308,14 +311,14 @@ fw_card_bm_work(struct work_struct *work) * config rom. In either case, pick another root. */ new_root_id = local_node->node_id; - } else if (atomic_read(&root_device->state) != FW_DEVICE_RUNNING) { + } else if (!root_device_is_running) { /* * If we haven't probed this device yet, bail out now * and let's try again once that's done. */ spin_unlock_irqrestore(&card->lock, flags); goto out; - } else if (root_device->cmc) { + } else if (root_device_is_cmc) { /* * FIXME: I suppose we should set the cmstr bit in the * STATE_CLEAR register of this node, as described in @@ -362,8 +365,6 @@ fw_card_bm_work(struct work_struct *work) fw_core_initiate_bus_reset(card, 1); } out: - if (root_device) - fw_device_put(root_device); fw_node_put(root_node); fw_node_put(local_node); out_put_card: diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index c173be38372..2af5a8d1e01 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c @@ -159,7 +159,8 @@ static void fw_device_release(struct device *dev) /* * Take the card lock so we don't set this to NULL while a - * FW_NODE_UPDATED callback is being handled. + * FW_NODE_UPDATED callback is being handled or while the + * bus manager work looks at this node. */ spin_lock_irqsave(&card->lock, flags); device->node->data = NULL; @@ -695,12 +696,13 @@ static void fw_device_init(struct work_struct *work) return; } - err = -ENOMEM; + device_initialize(&device->device); fw_device_get(device); down_write(&fw_device_rwsem); - if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) - err = idr_get_new(&fw_device_idr, device, &minor); + err = idr_pre_get(&fw_device_idr, GFP_KERNEL) ? + idr_get_new(&fw_device_idr, device, &minor) : + -ENOMEM; up_write(&fw_device_rwsem); if (err < 0) @@ -911,13 +913,14 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) /* * Do minimal intialization of the device here, the - * rest will happen in fw_device_init(). We need the - * card and node so we can read the config rom and we - * need to do device_initialize() now so - * device_for_each_child() in FW_NODE_UPDATED is - * doesn't freak out. + * rest will happen in fw_device_init(). + * + * Attention: A lot of things, even fw_device_get(), + * cannot be done before fw_device_init() finished! + * You can basically just check device->state and + * schedule work until then, but only while holding + * card->lock. */ - device_initialize(&device->device); atomic_set(&device->state, FW_DEVICE_INITIALIZING); device->card = fw_card_get(card); device->node = fw_node_get(node); diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 50a071f1c94..777fba48d2d 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -238,11 +238,11 @@ static ssize_t host_control_on_shutdown_store(struct device *dev, } /** - * smi_request: generate SMI request + * dcdbas_smi_request: generate SMI request * * Called with smi_data_lock. */ -static int smi_request(struct smi_cmd *smi_cmd) +int dcdbas_smi_request(struct smi_cmd *smi_cmd) { cpumask_t old_mask; int ret = 0; @@ -309,14 +309,14 @@ static ssize_t smi_request_store(struct device *dev, switch (val) { case 2: /* Raw SMI */ - ret = smi_request(smi_cmd); + ret = dcdbas_smi_request(smi_cmd); if (!ret) ret = count; break; case 1: /* Calling Interface SMI */ smi_cmd->ebx = (u32) virt_to_phys(smi_cmd->command_buffer); - ret = smi_request(smi_cmd); + ret = dcdbas_smi_request(smi_cmd); if (!ret) ret = count; break; @@ -333,6 +333,7 @@ out: mutex_unlock(&smi_data_lock); return ret; } +EXPORT_SYMBOL(dcdbas_smi_request); /** * host_control_smi: generate host control SMI diff --git a/drivers/firmware/dcdbas.h b/drivers/firmware/dcdbas.h index 87bc3417de2..ca3cb0a54ab 100644 --- a/drivers/firmware/dcdbas.h +++ b/drivers/firmware/dcdbas.h @@ -101,5 +101,7 @@ struct apm_cmd { } __attribute__ ((packed)) parameters; } __attribute__ ((packed)); +int dcdbas_smi_request(struct smi_cmd *smi_cmd); + #endif /* _DCDBAS_H_ */ diff --git a/drivers/firmware/memmap.c b/drivers/firmware/memmap.c index 3bf8ee120d4..261b9aa3f24 100644 --- a/drivers/firmware/memmap.c +++ b/drivers/firmware/memmap.c @@ -56,9 +56,9 @@ struct memmap_attribute { ssize_t (*show)(struct firmware_map_entry *entry, char *buf); }; -struct memmap_attribute memmap_start_attr = __ATTR_RO(start); -struct memmap_attribute memmap_end_attr = __ATTR_RO(end); -struct memmap_attribute memmap_type_attr = __ATTR_RO(type); +static struct memmap_attribute memmap_start_attr = __ATTR_RO(start); +static struct memmap_attribute memmap_end_attr = __ATTR_RO(end); +static struct memmap_attribute memmap_type_attr = __ATTR_RO(type); /* * These are default attributes that are added for every memmap entry. diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 8fd124eff64..19cb1ace3eb 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -49,7 +49,7 @@ obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o obj-$(CONFIG_SENSORS_IT87) += it87.o obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o -obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o +obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o hp_accel.o obj-$(CONFIG_SENSORS_LM63) += lm63.o obj-$(CONFIG_SENSORS_LM70) += lm70.o obj-$(CONFIG_SENSORS_LM75) += lm75.o diff --git a/drivers/hwmon/hp_accel.c b/drivers/hwmon/hp_accel.c new file mode 100644 index 00000000000..bf8d4058057 --- /dev/null +++ b/drivers/hwmon/hp_accel.c @@ -0,0 +1,265 @@ +/* + * hp_accel.c - Interface between LIS3LV02DL driver and HP ACPI BIOS + * + * Copyright (C) 2007-2008 Yan Burman + * Copyright (C) 2008 Eric Piel + * Copyright (C) 2008 Pavel Machek + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/dmi.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/kthread.h> +#include <linux/semaphore.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/poll.h> +#include <linux/freezer.h> +#include <linux/version.h> +#include <linux/uaccess.h> +#include <acpi/acpi_drivers.h> +#include <asm/atomic.h> +#include "lis3lv02d.h" + +#define DRIVER_NAME "lis3lv02d" +#define ACPI_MDPS_CLASS "accelerometer" + + +/* For automatic insertion of the module */ +static struct acpi_device_id lis3lv02d_device_ids[] = { + {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); + + +/** + * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. + * @handle: the handle of the device + * + * Returns AE_OK on success. + */ +acpi_status lis3lv02d_acpi_init(acpi_handle handle) +{ + return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); +} + +/** + * lis3lv02d_acpi_read - ACPI ALRD method: read a register + * @handle: the handle of the device + * @reg: the register to read + * @ret: result of the operation + * + * Returns AE_OK on success. + */ +acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) +{ + union acpi_object arg0 = { ACPI_TYPE_INTEGER }; + struct acpi_object_list args = { 1, &arg0 }; + unsigned long long lret; + acpi_status status; + + arg0.integer.value = reg; + + status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); + *ret = lret; + return status; +} + +/** + * lis3lv02d_acpi_write - ACPI ALWR method: write to a register + * @handle: the handle of the device + * @reg: the register to write to + * @val: the value to write + * + * Returns AE_OK on success. + */ +acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) +{ + unsigned long long ret; /* Not used when writting */ + union acpi_object in_obj[2]; + struct acpi_object_list args = { 2, in_obj }; + + in_obj[0].type = ACPI_TYPE_INTEGER; + in_obj[0].integer.value = reg; + in_obj[1].type = ACPI_TYPE_INTEGER; + in_obj[1].integer.value = val; + + return acpi_evaluate_integer(handle, "ALWR", &args, &ret); +} + +static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) +{ + adev.ac = *((struct axis_conversion *)dmi->driver_data); + printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); + + return 1; +} + +/* Represents, for each axis seen by userspace, the corresponding hw axis (+1). + * If the value is negative, the opposite of the hw value is used. */ +static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3}; +static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; +static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; +static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; +static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; +static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; + +#define AXIS_DMI_MATCH(_ident, _name, _axis) { \ + .ident = _ident, \ + .callback = lis3lv02d_dmi_matched, \ + .matches = { \ + DMI_MATCH(DMI_PRODUCT_NAME, _name) \ + }, \ + .driver_data = &lis3lv02d_axis_##_axis \ +} +static struct dmi_system_id lis3lv02d_dmi_ids[] = { + /* product names are truncated to match all kinds of a same model */ + AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), + AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), + AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), + AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), + AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), + AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), + AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), + { NULL, } +/* Laptop models without axis info (yet): + * "NC651xx" "HP Compaq 651" + * "NC671xx" "HP Compaq 671" + * "NC6910" "HP Compaq 6910" + * HP Compaq 8710x Notebook PC / Mobile Workstation + * "NC2400" "HP Compaq nc2400" + * "NX74x0" "HP Compaq nx74" + * "NX6325" "HP Compaq nx6325" + * "NC4400" "HP Compaq nc4400" + */ +}; + + +static int lis3lv02d_add(struct acpi_device *device) +{ + u8 val; + + if (!device) + return -EINVAL; + + adev.device = device; + adev.init = lis3lv02d_acpi_init; + adev.read = lis3lv02d_acpi_read; + adev.write = lis3lv02d_acpi_write; + strcpy(acpi_device_name(device), DRIVER_NAME); + strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); + device->driver_data = &adev; + + lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val); + if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) { + printk(KERN_ERR DRIVER_NAME + ": Accelerometer chip not LIS3LV02D{L,Q}\n"); + } + + /* If possible use a "standard" axes order */ + if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { + printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " + "using default axes configuration\n"); + adev.ac = lis3lv02d_axis_normal; + } + + return lis3lv02d_init_device(&adev); +} + +static int lis3lv02d_remove(struct acpi_device *device, int type) +{ + if (!device) + return -EINVAL; + + lis3lv02d_joystick_disable(); + lis3lv02d_poweroff(device->handle); + + return lis3lv02d_remove_fs(); +} + + +#ifdef CONFIG_PM +static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) +{ + /* make sure the device is off when we suspend */ + lis3lv02d_poweroff(device->handle); + return 0; +} + +static int lis3lv02d_resume(struct acpi_device *device) +{ + /* put back the device in the right state (ACPI might turn it on) */ + mutex_lock(&adev.lock); + if (adev.usage > 0) + lis3lv02d_poweron(device->handle); + else + lis3lv02d_poweroff(device->handle); + mutex_unlock(&adev.lock); + return 0; +} +#else +#define lis3lv02d_suspend NULL +#define lis3lv02d_resume NULL +#endif + +/* For the HP MDPS aka 3D Driveguard */ +static struct acpi_driver lis3lv02d_driver = { + .name = DRIVER_NAME, + .class = ACPI_MDPS_CLASS, + .ids = lis3lv02d_device_ids, + .ops = { + .add = lis3lv02d_add, + .remove = lis3lv02d_remove, + .suspend = lis3lv02d_suspend, + .resume = lis3lv02d_resume, + } +}; + +static int __init lis3lv02d_init_module(void) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + + ret = acpi_bus_register_driver(&lis3lv02d_driver); + if (ret < 0) + return ret; + + printk(KERN_INFO DRIVER_NAME " driver loaded.\n"); + + return 0; +} + +static void __exit lis3lv02d_exit_module(void) +{ + acpi_bus_unregister_driver(&lis3lv02d_driver); +} + +MODULE_DESCRIPTION("Glue between LIS3LV02Dx and HP ACPI BIOS"); +MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek"); +MODULE_LICENSE("GPL"); + +module_init(lis3lv02d_init_module); +module_exit(lis3lv02d_exit_module); + diff --git a/drivers/hwmon/lis3lv02d.c b/drivers/hwmon/lis3lv02d.c index c002144c76b..219d2d0d5a6 100644 --- a/drivers/hwmon/lis3lv02d.c +++ b/drivers/hwmon/lis3lv02d.c @@ -3,6 +3,7 @@ * * Copyright (C) 2007-2008 Yan Burman * Copyright (C) 2008 Eric Piel + * Copyright (C) 2008 Pavel Machek * * 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 @@ -39,7 +40,6 @@ #include "lis3lv02d.h" #define DRIVER_NAME "lis3lv02d" -#define ACPI_MDPS_CLASS "accelerometer" /* joystick device poll interval in milliseconds */ #define MDPS_POLL_INTERVAL 50 @@ -55,100 +55,17 @@ /* Maximum value our axis may get for the input device (signed 12 bits) */ #define MDPS_MAX_VAL 2048 -struct axis_conversion { - s8 x; - s8 y; - s8 z; -}; - -struct acpi_lis3lv02d { - struct acpi_device *device; /* The ACPI device */ - struct input_dev *idev; /* input device */ - struct task_struct *kthread; /* kthread for input */ - struct mutex lock; - struct platform_device *pdev; /* platform device */ - atomic_t count; /* interrupt count after last read */ - int xcalib; /* calibrated null value for x */ - int ycalib; /* calibrated null value for y */ - int zcalib; /* calibrated null value for z */ - unsigned char is_on; /* whether the device is on or off */ - unsigned char usage; /* usage counter */ - struct axis_conversion ac; /* hw -> logical axis */ -}; +struct acpi_lis3lv02d adev; +EXPORT_SYMBOL_GPL(adev); -static struct acpi_lis3lv02d adev; - -static int lis3lv02d_remove_fs(void); static int lis3lv02d_add_fs(struct acpi_device *device); -/* For automatic insertion of the module */ -static struct acpi_device_id lis3lv02d_device_ids[] = { - {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */ - {"", 0}, -}; -MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids); - -/** - * lis3lv02d_acpi_init - ACPI _INI method: initialize the device. - * @handle: the handle of the device - * - * Returns AE_OK on success. - */ -static inline acpi_status lis3lv02d_acpi_init(acpi_handle handle) -{ - return acpi_evaluate_object(handle, METHOD_NAME__INI, NULL, NULL); -} - -/** - * lis3lv02d_acpi_read - ACPI ALRD method: read a register - * @handle: the handle of the device - * @reg: the register to read - * @ret: result of the operation - * - * Returns AE_OK on success. - */ -static acpi_status lis3lv02d_acpi_read(acpi_handle handle, int reg, u8 *ret) -{ - union acpi_object arg0 = { ACPI_TYPE_INTEGER }; - struct acpi_object_list args = { 1, &arg0 }; - unsigned long long lret; - acpi_status status; - - arg0.integer.value = reg; - - status = acpi_evaluate_integer(handle, "ALRD", &args, &lret); - *ret = lret; - return status; -} - -/** - * lis3lv02d_acpi_write - ACPI ALWR method: write to a register - * @handle: the handle of the device - * @reg: the register to write to - * @val: the value to write - * - * Returns AE_OK on success. - */ -static acpi_status lis3lv02d_acpi_write(acpi_handle handle, int reg, u8 val) -{ - unsigned long long ret; /* Not used when writting */ - union acpi_object in_obj[2]; - struct acpi_object_list args = { 2, in_obj }; - - in_obj[0].type = ACPI_TYPE_INTEGER; - in_obj[0].integer.value = reg; - in_obj[1].type = ACPI_TYPE_INTEGER; - in_obj[1].integer.value = val; - - return acpi_evaluate_integer(handle, "ALWR", &args, &ret); -} - static s16 lis3lv02d_read_16(acpi_handle handle, int reg) { u8 lo, hi; - lis3lv02d_acpi_read(handle, reg, &lo); - lis3lv02d_acpi_read(handle, reg + 1, &hi); + adev.read(handle, reg, &lo); + adev.read(handle, reg + 1, &hi); /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */ return (s16)((hi << 8) | lo); } @@ -190,54 +107,31 @@ static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z) *z = lis3lv02d_get_axis(adev.ac.z, position); } -static inline void lis3lv02d_poweroff(acpi_handle handle) +void lis3lv02d_poweroff(acpi_handle handle) { adev.is_on = 0; /* disable X,Y,Z axis and power down */ - lis3lv02d_acpi_write(handle, CTRL_REG1, 0x00); + adev.write(handle, CTRL_REG1, 0x00); } +EXPORT_SYMBOL_GPL(lis3lv02d_poweroff); -static void lis3lv02d_poweron(acpi_handle handle) +void lis3lv02d_poweron(acpi_handle handle) { u8 val; adev.is_on = 1; - lis3lv02d_acpi_init(handle); - lis3lv02d_acpi_write(handle, FF_WU_CFG, 0); + adev.init(handle); + adev.write(handle, FF_WU_CFG, 0); /* * BDU: LSB and MSB values are not updated until both have been read. * So the value read will always be correct. * IEN: Interrupt for free-fall and DD, not for data-ready. */ - lis3lv02d_acpi_read(handle, CTRL_REG2, &val); + adev.read(handle, CTRL_REG2, &val); val |= CTRL2_BDU | CTRL2_IEN; - lis3lv02d_acpi_write(handle, CTRL_REG2, val); -} - -#ifdef CONFIG_PM -static int lis3lv02d_suspend(struct acpi_device *device, pm_message_t state) -{ - /* make sure the device is off when we suspend */ - lis3lv02d_poweroff(device->handle); - return 0; -} - -static int lis3lv02d_resume(struct acpi_device *device) -{ - /* put back the device in the right state (ACPI might turn it on) */ - mutex_lock(&adev.lock); - if (adev.usage > 0) - lis3lv02d_poweron(device->handle); - else - lis3lv02d_poweroff(device->handle); - mutex_unlock(&adev.lock); - return 0; + adev.write(handle, CTRL_REG2, val); } -#else -#define lis3lv02d_suspend NULL -#define lis3lv02d_resume NULL -#endif - +EXPORT_SYMBOL_GPL(lis3lv02d_poweron); /* * To be called before starting to use the device. It makes sure that the @@ -315,7 +209,7 @@ static inline void lis3lv02d_calibrate_joystick(void) lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib); } -static int lis3lv02d_joystick_enable(void) +int lis3lv02d_joystick_enable(void) { int err; @@ -349,8 +243,9 @@ static int lis3lv02d_joystick_enable(void) return err; } +EXPORT_SYMBOL_GPL(lis3lv02d_joystick_enable); -static void lis3lv02d_joystick_disable(void) +void lis3lv02d_joystick_disable(void) { if (!adev.idev) return; @@ -358,13 +253,13 @@ static void lis3lv02d_joystick_disable(void) input_unregister_device(adev.idev); adev.idev = NULL; } - +EXPORT_SYMBOL_GPL(lis3lv02d_joystick_disable); /* * Initialise the accelerometer and the various subsystems. * Should be rather independant of the bus system. */ -static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) +int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) { mutex_init(&dev->lock); lis3lv02d_add_fs(dev->device); @@ -376,93 +271,7 @@ static int lis3lv02d_init_device(struct acpi_lis3lv02d *dev) lis3lv02d_decrease_use(dev); return 0; } - -static int lis3lv02d_dmi_matched(const struct dmi_system_id *dmi) -{ - adev.ac = *((struct axis_conversion *)dmi->driver_data); - printk(KERN_INFO DRIVER_NAME ": hardware type %s found.\n", dmi->ident); - - return 1; -} - -/* Represents, for each axis seen by userspace, the corresponding hw axis (+1). - * If the value is negative, the opposite of the hw value is used. */ -static struct axis_conversion lis3lv02d_axis_normal = {1, 2, 3}; -static struct axis_conversion lis3lv02d_axis_y_inverted = {1, -2, 3}; -static struct axis_conversion lis3lv02d_axis_x_inverted = {-1, 2, 3}; -static struct axis_conversion lis3lv02d_axis_z_inverted = {1, 2, -3}; -static struct axis_conversion lis3lv02d_axis_xy_rotated_left = {-2, 1, 3}; -static struct axis_conversion lis3lv02d_axis_xy_swap_inverted = {-2, -1, 3}; - -#define AXIS_DMI_MATCH(_ident, _name, _axis) { \ - .ident = _ident, \ - .callback = lis3lv02d_dmi_matched, \ - .matches = { \ - DMI_MATCH(DMI_PRODUCT_NAME, _name) \ - }, \ - .driver_data = &lis3lv02d_axis_##_axis \ -} -static struct dmi_system_id lis3lv02d_dmi_ids[] = { - /* product names are truncated to match all kinds of a same model */ - AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted), - AXIS_DMI_MATCH("NC84x0", "HP Compaq nc84", z_inverted), - AXIS_DMI_MATCH("NX9420", "HP Compaq nx9420", x_inverted), - AXIS_DMI_MATCH("NW9440", "HP Compaq nw9440", x_inverted), - AXIS_DMI_MATCH("NC2510", "HP Compaq 2510", y_inverted), - AXIS_DMI_MATCH("NC8510", "HP Compaq 8510", xy_swap_inverted), - AXIS_DMI_MATCH("HP2133", "HP 2133", xy_rotated_left), - { NULL, } -/* Laptop models without axis info (yet): - * "NC651xx" "HP Compaq 651" - * "NC671xx" "HP Compaq 671" - * "NC6910" "HP Compaq 6910" - * HP Compaq 8710x Notebook PC / Mobile Workstation - * "NC2400" "HP Compaq nc2400" - * "NX74x0" "HP Compaq nx74" - * "NX6325" "HP Compaq nx6325" - * "NC4400" "HP Compaq nc4400" - */ -}; - -static int lis3lv02d_add(struct acpi_device *device) -{ - u8 val; - - if (!device) - return -EINVAL; - - adev.device = device; - strcpy(acpi_device_name(device), DRIVER_NAME); - strcpy(acpi_device_class(device), ACPI_MDPS_CLASS); - device->driver_data = &adev; - - lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val); - if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) { - printk(KERN_ERR DRIVER_NAME - ": Accelerometer chip not LIS3LV02D{L,Q}\n"); - } - - /* If possible use a "standard" axes order */ - if (dmi_check_system(lis3lv02d_dmi_ids) == 0) { - printk(KERN_INFO DRIVER_NAME ": laptop model unknown, " - "using default axes configuration\n"); - adev.ac = lis3lv02d_axis_normal; - } - - return lis3lv02d_init_device(&adev); -} - -static int lis3lv02d_remove(struct acpi_device *device, int type) -{ - if (!device) - return -EINVAL; - - lis3lv02d_joystick_disable(); - lis3lv02d_poweroff(device->handle); - - return lis3lv02d_remove_fs(); -} - +EXPORT_SYMBOL_GPL(lis3lv02d_init_device); /* Sysfs stuff */ static ssize_t lis3lv02d_position_show(struct device *dev, @@ -501,7 +310,7 @@ static ssize_t lis3lv02d_rate_show(struct device *dev, int val; lis3lv02d_increase_use(&adev); - lis3lv02d_acpi_read(adev.device->handle, CTRL_REG1, &ctrl); + adev.read(adev.device->handle, CTRL_REG1, &ctrl); lis3lv02d_decrease_use(&adev); val = (ctrl & (CTRL1_DF0 | CTRL1_DF1)) >> 4; return sprintf(buf, "%d\n", lis3lv02dl_df_val[val]); @@ -523,6 +332,7 @@ static struct attribute_group lis3lv02d_attribute_group = { .attrs = lis3lv02d_attributes }; + static int lis3lv02d_add_fs(struct acpi_device *device) { adev.pdev = platform_device_register_simple(DRIVER_NAME, -1, NULL, 0); @@ -532,50 +342,15 @@ static int lis3lv02d_add_fs(struct acpi_device *device) return sysfs_create_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); } -static int lis3lv02d_remove_fs(void) +int lis3lv02d_remove_fs(void) { sysfs_remove_group(&adev.pdev->dev.kobj, &lis3lv02d_attribute_group); platform_device_unregister(adev.pdev); return 0; } - -/* For the HP MDPS aka 3D Driveguard */ -static struct acpi_driver lis3lv02d_driver = { - .name = DRIVER_NAME, - .class = ACPI_MDPS_CLASS, - .ids = lis3lv02d_device_ids, - .ops = { - .add = lis3lv02d_add, - .remove = lis3lv02d_remove, - .suspend = lis3lv02d_suspend, - .resume = lis3lv02d_resume, - } -}; - -static int __init lis3lv02d_init_module(void) -{ - int ret; - - if (acpi_disabled) - return -ENODEV; - - ret = acpi_bus_register_driver(&lis3lv02d_driver); - if (ret < 0) - return ret; - - printk(KERN_INFO DRIVER_NAME " driver loaded.\n"); - - return 0; -} - -static void __exit lis3lv02d_exit_module(void) -{ - acpi_bus_unregister_driver(&lis3lv02d_driver); -} +EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs); MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver"); MODULE_AUTHOR("Yan Burman and Eric Piel"); MODULE_LICENSE("GPL"); -module_init(lis3lv02d_init_module); -module_exit(lis3lv02d_exit_module); diff --git a/drivers/hwmon/lis3lv02d.h b/drivers/hwmon/lis3lv02d.h index 330cfc60e94..223f1c0763b 100644 --- a/drivers/hwmon/lis3lv02d.h +++ b/drivers/hwmon/lis3lv02d.h @@ -23,7 +23,7 @@ * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to * be connected via SPI. There exists also several similar chips (such as LIS302DL or * LIS3L02DQ) but not in the HP laptops and they have slightly different registers. - * They can also be connected via I²C. + * They can also be connected via I²C. */ #define LIS3LV02DL_ID 0x3A /* Also the LIS3LV02DQ */ @@ -147,3 +147,36 @@ enum lis3lv02d_dd_src { DD_SRC_IA = 0x40, }; +struct axis_conversion { + s8 x; + s8 y; + s8 z; +}; + +struct acpi_lis3lv02d { + struct acpi_device *device; /* The ACPI device */ + acpi_status (*init) (acpi_handle handle); + acpi_status (*write) (acpi_handle handle, int reg, u8 val); + acpi_status (*read) (acpi_handle handle, int reg, u8 *ret); + + struct input_dev *idev; /* input device */ + struct task_struct *kthread; /* kthread for input */ + struct mutex lock; + struct platform_device *pdev; /* platform device */ + atomic_t count; /* interrupt count after last read */ + int xcalib; /* calibrated null value for x */ + int ycalib; /* calibrated null value for y */ + int zcalib; /* calibrated null value for z */ + unsigned char is_on; /* whether the device is on or off */ + unsigned char usage; /* usage counter */ + struct axis_conversion ac; /* hw -> logical axis */ +}; + +int lis3lv02d_init_device(struct acpi_lis3lv02d *dev); +int lis3lv02d_joystick_enable(void); +void lis3lv02d_joystick_disable(void); +void lis3lv02d_poweroff(acpi_handle handle); +void lis3lv02d_poweron(acpi_handle handle); +int lis3lv02d_remove_fs(void); + +extern struct acpi_lis3lv02d adev; diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 2f9e941968d..d8f295bdad7 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -18,12 +18,6 @@ #include <linux/dmi.h> #include <acpi/acpi_bus.h> -#include <acpi/acnames.h> -#include <acpi/acnamesp.h> -#include <acpi/acparser.h> -#include <acpi/acexcep.h> -#include <acpi/acmacros.h> -#include <acpi/actypes.h> #define REGS_PER_GTF 7 struct taskfile_array { diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c index a074bfd5f82..1a919df809f 100644 --- a/drivers/ieee1394/eth1394.c +++ b/drivers/ieee1394/eth1394.c @@ -245,12 +245,6 @@ static int ether1394_stop(struct net_device *dev) return 0; } -/* Return statistics to the caller */ -static struct net_device_stats *ether1394_stats(struct net_device *dev) -{ - return &(((struct eth1394_priv *)netdev_priv(dev))->stats); -} - /* FIXME: What to do if we timeout? I think a host reset is probably in order, * so that's what we do. Should we increment the stat counters too? */ static void ether1394_tx_timeout(struct net_device *dev) @@ -516,16 +510,19 @@ static const struct header_ops ether1394_header_ops = { .parse = ether1394_header_parse, }; +static const struct net_device_ops ether1394_netdev_ops = { + .ndo_open = ether1394_open, + .ndo_stop = ether1394_stop, + .ndo_start_xmit = ether1394_tx, + .ndo_tx_timeout = ether1394_tx_timeout, + .ndo_change_mtu = ether1394_change_mtu, +}; + static void ether1394_init_dev(struct net_device *dev) { - dev->open = ether1394_open; - dev->stop = ether1394_stop; - dev->hard_start_xmit = ether1394_tx; - dev->get_stats = ether1394_stats; - dev->tx_timeout = ether1394_tx_timeout; - dev->change_mtu = ether1394_change_mtu; dev->header_ops = ðer1394_header_ops; + dev->netdev_ops = ðer1394_netdev_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); @@ -1075,7 +1072,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, HPSB_PRINT(KERN_ERR, "ether1394 rx: sender nodeid " "lookup failure: " NODE_BUS_FMT, NODE_BUS_ARGS(priv->host, srcid)); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; return -1; } ud = node->ud; @@ -1098,7 +1095,7 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, skb = dev_alloc_skb(len + dev->hard_header_len + 15); if (unlikely(!skb)) { ETH1394_PRINT_G(KERN_ERR, "Out of memory\n"); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; return -1; } skb_reserve(skb, (dev->hard_header_len + 15) & ~15); @@ -1217,15 +1214,15 @@ static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, spin_lock_irqsave(&priv->lock, flags); if (!skb->protocol) { - priv->stats.rx_errors++; - priv->stats.rx_dropped++; + dev->stats.rx_errors++; + dev->stats.rx_dropped++; dev_kfree_skb_any(skb); } else if (netif_rx(skb) == NET_RX_DROP) { - priv->stats.rx_errors++; - priv->stats.rx_dropped++; + dev->stats.rx_errors++; + dev->stats.rx_dropped++; } else { - priv->stats.rx_packets++; - priv->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; } spin_unlock_irqrestore(&priv->lock, flags); @@ -1234,8 +1231,6 @@ bad_proto: if (netif_queue_stopped(dev)) netif_wake_queue(dev); - dev->last_rx = jiffies; - return 0; } @@ -1509,17 +1504,18 @@ static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) static void ether1394_dg_complete(struct packet_task *ptask, int fail) { struct sk_buff *skb = ptask->skb; - struct eth1394_priv *priv = netdev_priv(skb->dev); + struct net_device *dev = skb->dev; + struct eth1394_priv *priv = netdev_priv(dev); unsigned long flags; /* Statistics */ spin_lock_irqsave(&priv->lock, flags); if (fail) { - priv->stats.tx_dropped++; - priv->stats.tx_errors++; + dev->stats.tx_dropped++; + dev->stats.tx_errors++; } else { - priv->stats.tx_bytes += skb->len; - priv->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; } spin_unlock_irqrestore(&priv->lock, flags); @@ -1696,8 +1692,8 @@ fail: dev_kfree_skb(skb); spin_lock_irqsave(&priv->lock, flags); - priv->stats.tx_dropped++; - priv->stats.tx_errors++; + dev->stats.tx_dropped++; + dev->stats.tx_errors++; spin_unlock_irqrestore(&priv->lock, flags); /* diff --git a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h index e1b5ea80f62..d53bac47b86 100644 --- a/drivers/ieee1394/eth1394.h +++ b/drivers/ieee1394/eth1394.h @@ -54,7 +54,6 @@ enum eth1394_bc_states { ETHER1394_BC_ERROR, /* Private structure for our ethernet driver */ struct eth1394_priv { - struct net_device_stats stats; /* Device stats */ struct hpsb_host *host; /* The card for this dev */ u16 bc_maxpayload; /* Max broadcast payload */ u8 bc_sspd; /* Max broadcast speed */ diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c index 3b77b674cbf..c7b8a506af6 100644 --- a/drivers/infiniband/hw/ehca/ehca_main.c +++ b/drivers/infiniband/hw/ehca/ehca_main.c @@ -955,7 +955,7 @@ void ehca_poll_eqs(unsigned long data) struct ehca_eq *eq = &shca->eq; int max = 3; volatile u64 q_ofs, q_ofs2; - u64 flags; + unsigned long flags; spin_lock_irqsave(&eq->spinlock, flags); q_ofs = eq->ipz_queue.current_q_offset; spin_unlock_irqrestore(&eq->spinlock, flags); diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index dcefe1fceb5..61588bd273b 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -543,14 +543,21 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) { static int mlx4_ib_version_printed; struct mlx4_ib_dev *ibdev; + int num_ports = 0; int i; - if (!mlx4_ib_version_printed) { printk(KERN_INFO "%s", mlx4_ib_version); ++mlx4_ib_version_printed; } + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) + num_ports++; + + /* No point in registering a device with no ports... */ + if (num_ports == 0) + return NULL; + ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev); if (!ibdev) { dev_err(&dev->pdev->dev, "Device struct alloc failed\n"); @@ -574,9 +581,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.owner = THIS_MODULE; ibdev->ib_dev.node_type = RDMA_NODE_IB_CA; ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey; - ibdev->num_ports = 0; - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) - ibdev->num_ports++; + ibdev->num_ports = num_ports; ibdev->ib_dev.phys_port_cnt = ibdev->num_ports; ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; ibdev->ib_dev.dma_device = &dev->pdev->dev; diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index a812db24347..a01b4488208 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -778,12 +778,13 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core, unsigned long flags; struct list_head *hte; struct nes_cm_node *cm_node; + __be32 tmp_addr = cpu_to_be32(loc_addr); /* get a handle on the hte */ hte = &cm_core->connected_nodes; nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n", - &loc_addr, loc_port, cm_core, hte); + &tmp_addr, loc_port, cm_core, hte); /* walk list and find cm_node associated with this session ID */ spin_lock_irqsave(&cm_core->ht_lock, flags); @@ -816,6 +817,7 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, { unsigned long flags; struct nes_cm_listener *listen_node; + __be32 tmp_addr = cpu_to_be32(dst_addr); /* walk list and find cm_node associated with this session ID */ spin_lock_irqsave(&cm_core->listen_list_lock, flags); @@ -833,7 +835,7 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n", - &dst_addr, dst_port); + &tmp_addr, dst_port); /* no listener */ return NULL; @@ -2059,6 +2061,7 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, struct tcphdr *tcph; struct nes_cm_info nfo; int skb_handled = 1; + __be32 tmp_daddr, tmp_saddr; if (!skb) return 0; @@ -2074,8 +2077,11 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, nfo.rem_addr = ntohl(iph->saddr); nfo.rem_port = ntohs(tcph->source); + tmp_daddr = cpu_to_be32(iph->daddr); + tmp_saddr = cpu_to_be32(iph->saddr); + nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n", - &iph->daddr, tcph->dest, &iph->saddr, tcph->source); + &tmp_daddr, tcph->dest, &tmp_saddr, tcph->source); do { cm_node = find_node(cm_core, @@ -2705,7 +2711,7 @@ int nes_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) sizeof(struct ietf_mpa_frame)); - /* notify OF layer that accept event was successfull */ + /* notify OF layer that accept event was successful */ cm_id->add_ref(cm_id); cm_event.event = IW_CM_EVENT_ESTABLISHED; diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index aa9b7348c72..6f3bc1b6bf2 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -655,6 +655,7 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti struct nes_adapter *nesadapter = nesdev->nesadapter; int arp_index; int err = 0; + __be32 tmp_addr; for (arp_index = 0; (u32) arp_index < nesadapter->arp_table_size; arp_index++) { if (nesadapter->arp_table[arp_index].ip_addr == ip_addr) @@ -682,8 +683,9 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti /* DELETE or RESOLVE */ if (arp_index == nesadapter->arp_table_size) { + tmp_addr = cpu_to_be32(ip_addr); nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n", - &ip_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete"); + &tmp_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete"); return -1; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 19e06bc38b3..dce0443f9d6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -711,26 +711,26 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) neigh = *to_ipoib_neigh(skb->dst->neighbour); - if (neigh->ah) - if (unlikely((memcmp(&neigh->dgid.raw, - skb->dst->neighbour->ha + 4, - sizeof(union ib_gid))) || - (neigh->dev != dev))) { - spin_lock_irqsave(&priv->lock, flags); - /* - * It's safe to call ipoib_put_ah() inside - * priv->lock here, because we know that - * path->ah will always hold one more reference, - * so ipoib_put_ah() will never do more than - * decrement the ref count. - */ + if (unlikely((memcmp(&neigh->dgid.raw, + skb->dst->neighbour->ha + 4, + sizeof(union ib_gid))) || + (neigh->dev != dev))) { + spin_lock_irqsave(&priv->lock, flags); + /* + * It's safe to call ipoib_put_ah() inside + * priv->lock here, because we know that + * path->ah will always hold one more reference, + * so ipoib_put_ah() will never do more than + * decrement the ref count. + */ + if (neigh->ah) ipoib_put_ah(neigh->ah); - list_del(&neigh->list); - ipoib_neigh_free(dev, neigh); - spin_unlock_irqrestore(&priv->lock, flags); - ipoib_path_lookup(skb, dev); - return NETDEV_TX_OK; - } + list_del(&neigh->list); + ipoib_neigh_free(dev, neigh); + spin_unlock_irqrestore(&priv->lock, flags); + ipoib_path_lookup(skb, dev); + return NETDEV_TX_OK; + } if (ipoib_cm_get(neigh)) { if (ipoib_cm_up(neigh)) { diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index a2eb3b9789e..59d02e0b8df 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -529,6 +529,9 @@ void ipoib_mcast_join_task(struct work_struct *work) if (!priv->broadcast) { struct ipoib_mcast *broadcast; + if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) + return; + broadcast = ipoib_mcast_alloc(dev, 1); if (!broadcast) { ipoib_warn(priv, "failed to allocate broadcast group\n"); diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig index 77dedba829e..b411c51842d 100644 --- a/drivers/infiniband/ulp/iser/Kconfig +++ b/drivers/infiniband/ulp/iser/Kconfig @@ -1,6 +1,6 @@ config INFINIBAND_ISER tristate "iSCSI Extensions for RDMA (iSER)" - depends on SCSI && INET + depends on SCSI && INET && INFINIBAND_ADDR_TRANS select SCSI_ISCSI_ATTRS ---help--- Support for the iSCSI Extensions for RDMA (iSER) Protocol diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 199055db508..67e5553f699 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -220,4 +220,11 @@ config HP_SDC_RTC Say Y here if you want to support the built-in real time clock of the HP SDC controller. +config INPUT_PCF50633_PMU + tristate "PCF50633 PMU events" + depends on MFD_PCF50633 + help + Say Y to include support for delivering PMU events via input + layer on NXP PCF50633. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index d7db2aeb8a9..bb62e6efacf 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -21,3 +21,4 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o +obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c new file mode 100644 index 00000000000..039dcb00ebd --- /dev/null +++ b/drivers/input/misc/pcf50633-input.c @@ -0,0 +1,132 @@ +/* NXP PCF50633 Input Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte, Andy Green and Werner Almesberger + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/input.h> + +#include <linux/mfd/pcf50633/core.h> + +#define PCF50633_OOCSTAT_ONKEY 0x01 +#define PCF50633_REG_OOCSTAT 0x12 +#define PCF50633_REG_OOCMODE 0x10 + +struct pcf50633_input { + struct pcf50633 *pcf; + struct input_dev *input_dev; +}; + +static void +pcf50633_input_irq(int irq, void *data) +{ + struct pcf50633_input *input; + int onkey_released; + + input = data; + + /* We report only one event depending on the key press status */ + onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT) + & PCF50633_OOCSTAT_ONKEY; + + if (irq == PCF50633_IRQ_ONKEYF && !onkey_released) + input_report_key(input->input_dev, KEY_POWER, 1); + else if (irq == PCF50633_IRQ_ONKEYR && onkey_released) + input_report_key(input->input_dev, KEY_POWER, 0); + + input_sync(input->input_dev); +} + +static int __devinit pcf50633_input_probe(struct platform_device *pdev) +{ + struct pcf50633_input *input; + struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; + struct input_dev *input_dev; + int ret; + + + input = kzalloc(sizeof(*input), GFP_KERNEL); + if (!input) + return -ENOMEM; + + input_dev = input_allocate_device(); + if (!input_dev) { + kfree(input); + return -ENOMEM; + } + + platform_set_drvdata(pdev, input); + input->pcf = pdata->pcf; + input->input_dev = input_dev; + + input_dev->name = "PCF50633 PMU events"; + input_dev->id.bustype = BUS_I2C; + input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR); + set_bit(KEY_POWER, input_dev->keybit); + + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + kfree(input); + return ret; + } + pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYR, + pcf50633_input_irq, input); + pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ONKEYF, + pcf50633_input_irq, input); + + return 0; +} + +static int __devexit pcf50633_input_remove(struct platform_device *pdev) +{ + struct pcf50633_input *input = platform_get_drvdata(pdev); + + pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR); + pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF); + + input_unregister_device(input->input_dev); + kfree(input); + + return 0; +} + +static struct platform_driver pcf50633_input_driver = { + .driver = { + .name = "pcf50633-input", + }, + .probe = pcf50633_input_probe, + .remove = __devexit_p(pcf50633_input_remove), +}; + +static int __init pcf50633_input_init(void) +{ + return platform_driver_register(&pcf50633_input_driver); +} +module_init(pcf50633_input_init); + +static void __exit pcf50633_input_exit(void) +{ + platform_driver_unregister(&pcf50633_input_driver); +} +module_exit(pcf50633_input_exit); + +MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); +MODULE_DESCRIPTION("PCF50633 input driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-input"); diff --git a/drivers/input/mouse/pxa930_trkball.c b/drivers/input/mouse/pxa930_trkball.c index a0f45c4fc19..d297accf9a7 100644 --- a/drivers/input/mouse/pxa930_trkball.c +++ b/drivers/input/mouse/pxa930_trkball.c @@ -186,7 +186,7 @@ static int __devinit pxa930_trkball_probe(struct platform_device *pdev) error = request_irq(irq, pxa930_trkball_interrupt, IRQF_DISABLED, pdev->name, trkball); if (error) { - dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + dev_err(&pdev->dev, "failed to request irq: %d\n", error); goto failed_free_io; } @@ -227,7 +227,7 @@ failed_free_io: iounmap(trkball->mmio_base); failed: kfree(trkball); - return ret; + return error; } static int __devexit pxa930_trkball_remove(struct platform_device *pdev) diff --git a/drivers/isdn/hardware/eicon/debuglib.h b/drivers/isdn/hardware/eicon/debuglib.h index 016410cf227..8ea587783e1 100644 --- a/drivers/isdn/hardware/eicon/debuglib.h +++ b/drivers/isdn/hardware/eicon/debuglib.h @@ -235,7 +235,7 @@ typedef void ( * DbgOld) (unsigned short, char *, va_list) ; typedef void ( * DbgEv) (unsigned short, unsigned long, va_list) ; typedef void ( * DbgIrq) (unsigned short, int, char *, va_list) ; typedef struct _DbgHandle_ -{ char Registered ; /* driver successfull registered */ +{ char Registered ; /* driver successfully registered */ #define DBG_HANDLE_REG_NEW 0x01 /* this (new) structure */ #define DBG_HANDLE_REG_OLD 0x7f /* old structure (see below) */ char Version; /* version of this structure */ diff --git a/drivers/isdn/hardware/eicon/os_4bri.c b/drivers/isdn/hardware/eicon/os_4bri.c index 7b4ec3f60db..c964b8d91ad 100644 --- a/drivers/isdn/hardware/eicon/os_4bri.c +++ b/drivers/isdn/hardware/eicon/os_4bri.c @@ -997,7 +997,7 @@ diva_4bri_start_adapter(PISDN_ADAPTER IoAdapter, diva_xdi_display_adapter_features(IoAdapter->ANum); for (i = 0; i < IoAdapter->tasks; i++) { - DBG_LOG(("A(%d) %s adapter successfull started", + DBG_LOG(("A(%d) %s adapter successfully started", IoAdapter->QuadroList->QuadroAdapter[i]->ANum, (IoAdapter->tasks == 1) ? "BRI 2.0" : "4BRI")) diva_xdi_didd_register_adapter(IoAdapter->QuadroList->QuadroAdapter[i]->ANum); diff --git a/drivers/isdn/hardware/eicon/os_bri.c b/drivers/isdn/hardware/eicon/os_bri.c index f31bba5b16f..08f01993f46 100644 --- a/drivers/isdn/hardware/eicon/os_bri.c +++ b/drivers/isdn/hardware/eicon/os_bri.c @@ -736,7 +736,7 @@ diva_bri_start_adapter(PISDN_ADAPTER IoAdapter, IoAdapter->Properties.Features = (word) features; diva_xdi_display_adapter_features(IoAdapter->ANum); - DBG_LOG(("A(%d) BRI adapter successfull started", IoAdapter->ANum)) + DBG_LOG(("A(%d) BRI adapter successfully started", IoAdapter->ANum)) /* Register with DIDD */ diff --git a/drivers/isdn/hardware/eicon/os_pri.c b/drivers/isdn/hardware/eicon/os_pri.c index 903356547b7..5d65405c75f 100644 --- a/drivers/isdn/hardware/eicon/os_pri.c +++ b/drivers/isdn/hardware/eicon/os_pri.c @@ -513,7 +513,7 @@ diva_pri_start_adapter(PISDN_ADAPTER IoAdapter, diva_xdi_display_adapter_features(IoAdapter->ANum); - DBG_LOG(("A(%d) PRI adapter successfull started", IoAdapter->ANum)) + DBG_LOG(("A(%d) PRI adapter successfully started", IoAdapter->ANum)) /* Register with DIDD */ diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig index 14793480c45..fd112ae252c 100644 --- a/drivers/isdn/hardware/mISDN/Kconfig +++ b/drivers/isdn/hardware/mISDN/Kconfig @@ -23,3 +23,10 @@ config MISDN_HFCMULTI * HFC-8S (8 S/T interfaces on one chip) * HFC-E1 (E1 interface for 2Mbit ISDN) +config MISDN_HFCUSB + tristate "Support for HFC-S USB based TAs" + depends on USB + help + Enable support for USB ISDN TAs with Cologne Chip AG's + HFC-S USB ISDN Controller + diff --git a/drivers/isdn/hardware/mISDN/Makefile b/drivers/isdn/hardware/mISDN/Makefile index 1e7ca5332ad..b0403526bbb 100644 --- a/drivers/isdn/hardware/mISDN/Makefile +++ b/drivers/isdn/hardware/mISDN/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_MISDN_HFCPCI) += hfcpci.o obj-$(CONFIG_MISDN_HFCMULTI) += hfcmulti.o +obj-$(CONFIG_MISDN_HFCUSB) += hfcsusb.o diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index 7bbf7300593..663b77f578b 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -2,10 +2,6 @@ * see notice in hfc_multi.c */ -extern void ztdummy_extern_interrupt(void); -extern void ztdummy_register_interrupt(void); -extern int ztdummy_unregister_interrupt(void); - #define DEBUG_HFCMULTI_FIFO 0x00010000 #define DEBUG_HFCMULTI_CRC 0x00020000 #define DEBUG_HFCMULTI_INIT 0x00040000 @@ -13,6 +9,7 @@ extern int ztdummy_unregister_interrupt(void); #define DEBUG_HFCMULTI_MODE 0x00100000 #define DEBUG_HFCMULTI_MSG 0x00200000 #define DEBUG_HFCMULTI_STATE 0x00400000 +#define DEBUG_HFCMULTI_FILL 0x00800000 #define DEBUG_HFCMULTI_SYNC 0x01000000 #define DEBUG_HFCMULTI_DTMF 0x02000000 #define DEBUG_HFCMULTI_LOCK 0x80000000 @@ -170,6 +167,8 @@ struct hfc_multi { u_long chip; /* chip configuration */ int masterclk; /* port that provides master clock -1=off */ + unsigned char silence;/* silence byte */ + unsigned char silence_data[128];/* silence block */ int dtmf; /* flag that dtmf is currently in process */ int Flen; /* F-buffer size */ int Zlen; /* Z-buffer size (must be int for calculation)*/ @@ -198,6 +197,9 @@ struct hfc_multi { spinlock_t lock; /* the lock */ + struct mISDNclock *iclock; /* isdn clock support */ + int iclock_on; + /* * the channel index is counted from 0, regardless where the channel * is located on the hfc-channel. diff --git a/drivers/isdn/hardware/mISDN/hfc_pci.h b/drivers/isdn/hardware/mISDN/hfc_pci.h index 5783d22a18f..3132ddc99fc 100644 --- a/drivers/isdn/hardware/mISDN/hfc_pci.h +++ b/drivers/isdn/hardware/mISDN/hfc_pci.h @@ -26,7 +26,7 @@ * change mask and threshold simultaneously */ #define HFCPCI_BTRANS_THRESHOLD 128 -#define HFCPCI_BTRANS_MAX 256 +#define HFCPCI_FILLEMPTY 64 #define HFCPCI_BTRANS_THRESMASK 0x00 /* defines for PCI config */ diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index c63e2f49da8..595ba8eb4a0 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -133,6 +133,12 @@ * Give the value of the clock control register (A_ST_CLK_DLY) * of the S/T interfaces in TE mode. * This register is needed for the TBR3 certification, so don't change it. + * + * clock: + * NOTE: only one clock value must be given once + * Selects interface with clock source for mISDN and applications. + * Set to card number starting with 1. Set to -1 to disable. + * By default, the first card is used as clock source. */ /* @@ -140,7 +146,7 @@ * #define HFC_REGISTER_DEBUG */ -static const char *hfcmulti_revision = "2.02"; +#define HFC_MULTI_VERSION "2.03" #include <linux/module.h> #include <linux/pci.h> @@ -165,10 +171,6 @@ static LIST_HEAD(HFClist); static spinlock_t HFClock; /* global hfc list lock */ static void ph_state_change(struct dchannel *); -static void (*hfc_interrupt)(void); -static void (*register_interrupt)(void); -static int (*unregister_interrupt)(void); -static int interrupt_registered; static struct hfc_multi *syncmaster; static int plxsd_master; /* if we have a master card (yet) */ @@ -184,7 +186,6 @@ static int nt_t1_count[] = { 3840, 1920, 960, 480, 240, 120, 60, 30 }; #define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ #define CLKDEL_NT 0x6c /* CLKDEL in NT mode (0x60 MUST be included!) */ -static u_char silence = 0xff; /* silence by LAW */ #define DIP_4S 0x1 /* DIP Switches for Beronet 1S/2S/4S cards */ #define DIP_8S 0x2 /* DIP Switches for Beronet 8S+ cards */ @@ -195,12 +196,13 @@ static u_char silence = 0xff; /* silence by LAW */ */ static uint type[MAX_CARDS]; -static uint pcm[MAX_CARDS]; -static uint dslot[MAX_CARDS]; +static int pcm[MAX_CARDS]; +static int dslot[MAX_CARDS]; static uint iomode[MAX_CARDS]; static uint port[MAX_PORTS]; static uint debug; static uint poll; +static int clock; static uint timer; static uint clockdelay_te = CLKDEL_TE; static uint clockdelay_nt = CLKDEL_NT; @@ -209,14 +211,16 @@ static int HFC_cnt, Port_cnt, PCM_cnt = 99; MODULE_AUTHOR("Andreas Eversberg"); MODULE_LICENSE("GPL"); +MODULE_VERSION(HFC_MULTI_VERSION); module_param(debug, uint, S_IRUGO | S_IWUSR); module_param(poll, uint, S_IRUGO | S_IWUSR); +module_param(clock, int, S_IRUGO | S_IWUSR); module_param(timer, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_te, uint, S_IRUGO | S_IWUSR); module_param(clockdelay_nt, uint, S_IRUGO | S_IWUSR); module_param_array(type, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(pcm, uint, NULL, S_IRUGO | S_IWUSR); -module_param_array(dslot, uint, NULL, S_IRUGO | S_IWUSR); +module_param_array(pcm, int, NULL, S_IRUGO | S_IWUSR); +module_param_array(dslot, int, NULL, S_IRUGO | S_IWUSR); module_param_array(iomode, uint, NULL, S_IRUGO | S_IWUSR); module_param_array(port, uint, NULL, S_IRUGO | S_IWUSR); @@ -1419,19 +1423,6 @@ controller_fail: HFC_outb(hc, R_TI_WD, poll_timer); hc->hw.r_irqmsk_misc |= V_TI_IRQMSK; - /* - * set up 125us interrupt, only if function pointer is available - * and module parameter timer is set - */ - if (timer && hfc_interrupt && register_interrupt) { - /* only one chip should use this interrupt */ - timer = 0; - interrupt_registered = 1; - hc->hw.r_irqmsk_misc |= V_PROC_IRQMSK; - /* deactivate other interrupts in ztdummy */ - register_interrupt(); - } - /* set E1 state machine IRQ */ if (hc->type == 1) hc->hw.r_irqmsk_misc |= V_STA_IRQMSK; @@ -1991,6 +1982,17 @@ next_frame: return; /* no data */ } + /* "fill fifo if empty" feature */ + if (bch && test_bit(FLG_FILLEMPTY, &bch->Flags) + && !test_bit(FLG_HDLC, &bch->Flags) && z2 == z1) { + if (debug & DEBUG_HFCMULTI_FILL) + printk(KERN_DEBUG "%s: buffer empty, so we have " + "underrun\n", __func__); + /* fill buffer, to prevent future underrun */ + hc->write_fifo(hc, hc->silence_data, poll >> 1); + Zspace -= (poll >> 1); + } + /* if audio data and connected slot */ if (bch && (!test_bit(FLG_HDLC, &bch->Flags)) && (!*txpending) && slot_tx >= 0) { @@ -2027,7 +2029,6 @@ next_frame: __func__, hc->id + 1, ch, Zspace, z1, z2, ii-i, len-i, temp ? "HDLC":"TRANS"); - /* Have to prep the audio data */ hc->write_fifo(hc, d, ii - i); *idxp = ii; @@ -2066,7 +2067,7 @@ next_frame: * no more data at all. this prevents sending an undefined value. */ if (bch && test_bit(FLG_TRANSPARENT, &bch->Flags)) - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); } @@ -2583,7 +2584,6 @@ hfcmulti_interrupt(int intno, void *dev_id) static int iq1 = 0, iq2 = 0, iq3 = 0, iq4 = 0, iq5 = 0, iq6 = 0, iqcnt = 0; #endif - static int count; struct hfc_multi *hc = dev_id; struct dchannel *dch; u_char r_irq_statech, status, r_irq_misc, r_irq_oview; @@ -2637,6 +2637,7 @@ hfcmulti_interrupt(int intno, void *dev_id) iqcnt = 0; } #endif + if (!r_irq_statech && !(status & (V_DTMF_STA | V_LOST_STA | V_EXT_IRQSTA | V_MISC_IRQSTA | V_FR_IRQSTA))) { @@ -2657,6 +2658,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (status & V_MISC_IRQSTA) { /* misc IRQ */ r_irq_misc = HFC_inb_nodebug(hc, R_IRQ_MISC); + r_irq_misc &= hc->hw.r_irqmsk_misc; /* ignore disabled irqs */ if (r_irq_misc & V_STA_IRQ) { if (hc->type == 1) { /* state machine */ @@ -2691,23 +2693,20 @@ hfcmulti_interrupt(int intno, void *dev_id) plxsd_checksync(hc, 0); } } - if (r_irq_misc & V_TI_IRQ) + if (r_irq_misc & V_TI_IRQ) { + if (hc->iclock_on) + mISDN_clock_update(hc->iclock, poll, NULL); handle_timer_irq(hc); + } if (r_irq_misc & V_DTMF_IRQ) { - /* -> DTMF IRQ */ hfcmulti_dtmf(hc); } - /* TODO: REPLACE !!!! 125 us Interrupts are not acceptable */ if (r_irq_misc & V_IRQ_PROC) { - /* IRQ every 125us */ - count++; - /* generate 1kHz signal */ - if (count == 8) { - if (hfc_interrupt) - hfc_interrupt(); - count = 0; - } + static int irq_proc_cnt; + if (!irq_proc_cnt++) + printk(KERN_WARNING "%s: got V_IRQ_PROC -" + " this should not happen\n", __func__); } } @@ -2954,7 +2953,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); HFC_outb(hc, R_SLOT, (((ch / 4) * 8) + ((ch % 4) * 4)) << 1); HFC_outb(hc, A_SL_CFG, 0x80 | 0x20 | (ch << 1)); @@ -2969,7 +2968,7 @@ mode_hfcmulti(struct hfc_multi *hc, int ch, int protocol, int slot_tx, HFC_outb(hc, R_INC_RES_FIFO, V_RES_F); HFC_wait(hc); /* tx silence */ - HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, silence); + HFC_outb_nodebug(hc, A_FIFO_DATA0_NOINC, hc->silence); /* enable RX fifo */ HFC_outb(hc, R_FIFO, (ch<<1)|1); HFC_wait(hc); @@ -3461,7 +3460,7 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: cq->op = MISDN_CTRL_HFC_OP | MISDN_CTRL_HW_FEATURES_OP - | MISDN_CTRL_RX_OFF; + | MISDN_CTRL_RX_OFF | MISDN_CTRL_FILL_EMPTY; break; case MISDN_CTRL_RX_OFF: /* turn off / on rx stream */ hc->chan[bch->slot].rx_off = !!cq->p1; @@ -3476,6 +3475,12 @@ channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) printk(KERN_DEBUG "%s: RX_OFF request (nr=%d off=%d)\n", __func__, bch->nr, hc->chan[bch->slot].rx_off); break; + case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + if (debug & DEBUG_HFCMULTI_MSG) + printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " + "off=%d)\n", __func__, bch->nr, !!cq->p1); + break; case MISDN_CTRL_HW_FEATURES: /* fill features structure */ if (debug & DEBUG_HFCMULTI_MSG) printk(KERN_DEBUG "%s: HW_FEATURE request\n", @@ -3610,7 +3615,7 @@ hfcm_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) static void ph_state_change(struct dchannel *dch) { - struct hfc_multi *hc = dch->hw; + struct hfc_multi *hc; int ch, i; if (!dch) { @@ -3618,6 +3623,7 @@ ph_state_change(struct dchannel *dch) __func__); return; } + hc = dch->hw; ch = dch->slot; if (hc->type == 1) { @@ -3992,6 +3998,7 @@ open_bchannel(struct hfc_multi *hc, struct dchannel *dch, } if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; hc->chan[ch].rx_off = 0; rq->ch = &bch->ch; @@ -4081,6 +4088,15 @@ hfcm_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) return err; } +static int +clockctl(void *priv, int enable) +{ + struct hfc_multi *hc = priv; + + hc->iclock_on = enable; + return 0; +} + /* * initialize the card */ @@ -4495,10 +4511,14 @@ release_card(struct hfc_multi *hc) printk(KERN_WARNING "%s: release card (%d) entered\n", __func__, hc->id); + /* unregister clock source */ + if (hc->iclock) + mISDN_unregister_clock(hc->iclock); + + /* disable irq */ spin_lock_irqsave(&hc->lock, flags); disable_hwirq(hc); spin_unlock_irqrestore(&hc->lock, flags); - udelay(1000); /* dimm leds */ @@ -4699,7 +4719,7 @@ init_e1_port(struct hfc_multi *hc, struct hm_map *m) } else hc->chan[hc->dslot].jitter = 2; /* default */ snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-e1.%d", HFC_cnt + 1); - ret = mISDN_register_device(&dch->dev, name); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; hc->created[0] = 1; @@ -4807,9 +4827,9 @@ init_multi_port(struct hfc_multi *hc, int pt) test_and_set_bit(HFC_CFG_DIS_ECHANNEL, &hc->chan[i + 2].cfg); } - snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d/%d", + snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-%ds.%d-%d", hc->type, HFC_cnt + 1, pt + 1); - ret = mISDN_register_device(&dch->dev, name); + ret = mISDN_register_device(&dch->dev, &hc->pci_dev->dev, name); if (ret) goto free_chan; hc->created[pt] = 1; @@ -4828,6 +4848,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) struct hfc_multi *hc; u_long flags; u_char dips = 0, pmj = 0; /* dip settings, port mode Jumpers */ + int i; if (HFC_cnt >= MAX_CARDS) { printk(KERN_ERR "too many cards (max=%d).\n", @@ -4861,11 +4882,11 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->id = HFC_cnt; hc->pcm = pcm[HFC_cnt]; hc->io_mode = iomode[HFC_cnt]; - if (dslot[HFC_cnt] < 0) { + if (dslot[HFC_cnt] < 0 && hc->type == 1) { hc->dslot = 0; printk(KERN_INFO "HFC-E1 card has disabled D-channel, but " "31 B-channels\n"); - } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32) { + } if (dslot[HFC_cnt] > 0 && dslot[HFC_cnt] < 32 && hc->type == 1) { hc->dslot = dslot[HFC_cnt]; printk(KERN_INFO "HFC-E1 card has alternating D-channel on " "time slot %d\n", dslot[HFC_cnt]); @@ -4876,9 +4897,17 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) hc->masterclk = -1; if (type[HFC_cnt] & 0x100) { test_and_set_bit(HFC_CHIP_ULAW, &hc->chip); - silence = 0xff; /* ulaw silence */ + hc->silence = 0xff; /* ulaw silence */ } else - silence = 0x2a; /* alaw silence */ + hc->silence = 0x2a; /* alaw silence */ + if ((poll >> 1) > sizeof(hc->silence_data)) { + printk(KERN_ERR "HFCMULTI error: silence_data too small, " + "please fix\n"); + return -EINVAL; + } + for (i = 0; i < (poll >> 1); i++) + hc->silence_data[i] = hc->silence; + if (!(type[HFC_cnt] & 0x200)) test_and_set_bit(HFC_CHIP_DTMF, &hc->chip); @@ -4945,9 +4974,7 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) switch (m->dip_type) { case DIP_4S: /* - * get DIP Setting for beroNet 1S/2S/4S cards - * check if Port Jumper config matches - * module param 'protocol' + * Get DIP setting for beroNet 1S/2S/4S cards * DIP Setting: (collect GPIO 13/14/15 (R_GPIO_IN1) + * GPI 19/23 (R_GPI_IN2)) */ @@ -4966,9 +4993,8 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) break; case DIP_8S: /* - * get DIP Setting for beroNet 8S0+ cards - * - * enable PCI auxbridge function + * Get DIP Setting for beroNet 8S0+ cards + * Enable PCI auxbridge function */ HFC_outb(hc, R_BRG_PCM_CFG, 1 | V_PCM_CLK); /* prepare access to auxport */ @@ -5003,6 +5029,10 @@ hfcmulti_init(struct pci_dev *pdev, const struct pci_device_id *ent) list_add_tail(&hc->list, &HFClist); spin_unlock_irqrestore(&HFClock, flags); + /* use as clock source */ + if (clock == HFC_cnt + 1) + hc->iclock = mISDN_register_clock("HFCMulti", 0, clockctl, hc); + /* initialize hardware */ ret_err = init_card(hc); if (ret_err) { @@ -5137,8 +5167,7 @@ static struct pci_device_id hfmultipci_ids[] __devinitdata = { { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, 0, 0, H(14)}, /* old Eval */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, - PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, - /* IOB8ST Recording */ + PCI_SUBDEVICE_ID_CCD_IOB8STR, 0, 0, H(15)}, /* IOB8ST Recording */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, PCI_SUBDEVICE_ID_CCD_IOB8ST, 0, 0, H(16)}, /* IOB8ST */ { PCI_VENDOR_ID_CCD, PCI_DEVICE_ID_CCD_HFC8S, PCI_VENDOR_ID_CCD, @@ -5188,18 +5217,16 @@ hfcmulti_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct hm_map *m = (struct hm_map *)ent->driver_data; int ret; - if (m == NULL) { - if (ent->vendor == PCI_VENDOR_ID_CCD) - if (ent->device == PCI_DEVICE_ID_CCD_HFC4S || - ent->device == PCI_DEVICE_ID_CCD_HFC8S || - ent->device == PCI_DEVICE_ID_CCD_HFCE1) - printk(KERN_ERR - "unknown HFC multiport controller " - "(vendor:%x device:%x subvendor:%x " - "subdevice:%x) Please contact the " - "driver maintainer for support.\n", - ent->vendor, ent->device, - ent->subvendor, ent->subdevice); + if (m == NULL && ent->vendor == PCI_VENDOR_ID_CCD && ( + ent->device == PCI_DEVICE_ID_CCD_HFC4S || + ent->device == PCI_DEVICE_ID_CCD_HFC8S || + ent->device == PCI_DEVICE_ID_CCD_HFCE1)) { + printk(KERN_ERR + "Unknown HFC multiport controller (vendor:%x device:%x " + "subvendor:%x subdevice:%x)\n", ent->vendor, ent->device, + ent->subvendor, ent->subdevice); + printk(KERN_ERR + "Please contact the driver maintainer for support.\n"); return -ENODEV; } ret = hfcmulti_init(pdev, ent); @@ -5222,22 +5249,9 @@ HFCmulti_cleanup(void) { struct hfc_multi *card, *next; - /* unload interrupt function symbol */ - if (hfc_interrupt) - symbol_put(ztdummy_extern_interrupt); - if (register_interrupt) - symbol_put(ztdummy_register_interrupt); - if (unregister_interrupt) { - if (interrupt_registered) { - interrupt_registered = 0; - unregister_interrupt(); - } - symbol_put(ztdummy_unregister_interrupt); - } - + /* get rid of all devices of this driver */ list_for_each_entry_safe(card, next, &HFClist, list) release_card(card); - /* get rid of all devices of this driver */ pci_unregister_driver(&hfcmultipci_driver); } @@ -5246,8 +5260,10 @@ HFCmulti_init(void) { int err; + printk(KERN_INFO "mISDN: HFC-multi driver %s\n", HFC_MULTI_VERSION); + #ifdef IRQ_DEBUG - printk(KERN_ERR "%s: IRQ_DEBUG IS ENABLED!\n", __func__); + printk(KERN_DEBUG "%s: IRQ_DEBUG IS ENABLED!\n", __func__); #endif spin_lock_init(&HFClock); @@ -5256,22 +5272,11 @@ HFCmulti_init(void) if (debug & DEBUG_HFCMULTI_INIT) printk(KERN_DEBUG "%s: init entered\n", __func__); - hfc_interrupt = symbol_get(ztdummy_extern_interrupt); - register_interrupt = symbol_get(ztdummy_register_interrupt); - unregister_interrupt = symbol_get(ztdummy_unregister_interrupt); - printk(KERN_INFO "mISDN: HFC-multi driver %s\n", - hfcmulti_revision); - switch (poll) { case 0: poll_timer = 6; poll = 128; break; - /* - * wenn dieses break nochmal verschwindet, - * gibt es heisse ohren :-) - * "without the break you will get hot ears ???" - */ case 8: poll_timer = 2; break; @@ -5298,20 +5303,12 @@ HFCmulti_init(void) } + if (!clock) + clock = 1; + err = pci_register_driver(&hfcmultipci_driver); if (err < 0) { printk(KERN_ERR "error registering pci driver: %x\n", err); - if (hfc_interrupt) - symbol_put(ztdummy_extern_interrupt); - if (register_interrupt) - symbol_put(ztdummy_register_interrupt); - if (unregister_interrupt) { - if (interrupt_registered) { - interrupt_registered = 0; - unregister_interrupt(); - } - symbol_put(ztdummy_unregister_interrupt); - } return err; } return 0; diff --git a/drivers/isdn/hardware/mISDN/hfcpci.c b/drivers/isdn/hardware/mISDN/hfcpci.c index cd8302af40e..f0e14dfcf71 100644 --- a/drivers/isdn/hardware/mISDN/hfcpci.c +++ b/drivers/isdn/hardware/mISDN/hfcpci.c @@ -23,6 +23,25 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * Module options: + * + * debug: + * NOTE: only one poll value must be given for all cards + * See hfc_pci.h for debug flags. + * + * poll: + * NOTE: only one poll value must be given for all cards + * Give the number of samples for each fifo process. + * By default 128 is used. Decrease to reduce delay, increase to + * reduce cpu load. If unsure, don't mess with it! + * A value of 128 will use controller's interrupt. Other values will + * use kernel timer, because the controller will not allow lower values + * than 128. + * Also note that the value depends on the kernel timer frequency. + * If kernel uses a frequency of 1000 Hz, steps of 8 samples are possible. + * If the kernel uses 100 Hz, steps of 80 samples are possible. + * If the kernel uses 300 Hz, steps of about 26 samples are possible. + * */ #include <linux/module.h> @@ -34,16 +53,16 @@ static const char *hfcpci_revision = "2.0"; -#define MAX_CARDS 8 static int HFC_cnt; static uint debug; +static uint poll, tics; +struct timer_list hfc_tl; +u32 hfc_jiffies; MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); -module_param(debug, uint, 0); - -static LIST_HEAD(HFClist); -static DEFINE_RWLOCK(HFClock); +module_param(debug, uint, S_IRUGO | S_IWUSR); +module_param(poll, uint, S_IRUGO | S_IWUSR); enum { HFC_CCD_2BD0, @@ -114,7 +133,6 @@ struct hfcPCI_hw { struct hfc_pci { - struct list_head list; u_char subtype; u_char chanlimit; u_char initdone; @@ -520,9 +538,9 @@ receive_dmsg(struct hfc_pci *hc) } /* - * check for transparent receive data and read max one threshold size if avail + * check for transparent receive data and read max one 'poll' size if avail */ -static int +static void hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) { __le16 *z1r, *z2r; @@ -534,17 +552,19 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) fcnt = le16_to_cpu(*z1r) - le16_to_cpu(*z2r); if (!fcnt) - return 0; /* no data avail */ + return; /* no data avail */ if (fcnt <= 0) fcnt += B_FIFO_SIZE; /* bytes actually buffered */ - if (fcnt > HFCPCI_BTRANS_THRESHOLD) - fcnt = HFCPCI_BTRANS_THRESHOLD; /* limit size */ - new_z2 = le16_to_cpu(*z2r) + fcnt; /* new position in fifo */ if (new_z2 >= (B_FIFO_SIZE + B_SUB_VAL)) new_z2 -= B_FIFO_SIZE; /* buffer wrap */ + if (fcnt > MAX_DATA_SIZE) { /* flush, if oversized */ + *z2r = cpu_to_le16(new_z2); /* new position */ + return; + } + bch->rx_skb = mI_alloc_skb(fcnt, GFP_ATOMIC); if (bch->rx_skb) { ptr = skb_put(bch->rx_skb, fcnt); @@ -569,7 +589,6 @@ hfcpci_empty_fifo_trans(struct bchannel *bch, struct bzfifo *bz, u_char *bdata) printk(KERN_WARNING "HFCPCI: receive out of memory\n"); *z2r = cpu_to_le16(new_z2); /* new position */ - return 1; } /* @@ -580,12 +599,11 @@ main_rec_hfcpci(struct bchannel *bch) { struct hfc_pci *hc = bch->hw; int rcnt, real_fifo; - int receive, count = 5; + int receive = 0, count = 5; struct bzfifo *bz; u_char *bdata; struct zt *zp; - if ((bch->nr & 2) && (!hc->hw.bswapped)) { bz = &((union fifo_area *)(hc->hw.fifos))->b_chans.rxbz_b2; bdata = ((union fifo_area *)(hc->hw.fifos))->b_chans.rxdat_b2; @@ -625,9 +643,10 @@ Begin: receive = 1; else receive = 0; - } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) - receive = hfcpci_empty_fifo_trans(bch, bz, bdata); - else + } else if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + hfcpci_empty_fifo_trans(bch, bz, bdata); + return; + } else receive = 0; if (count && receive) goto Begin; @@ -751,11 +770,41 @@ hfcpci_fill_fifo(struct bchannel *bch) /* fcnt contains available bytes in fifo */ fcnt = B_FIFO_SIZE - fcnt; /* remaining bytes to send (bytes in fifo) */ + + /* "fill fifo if empty" feature */ + if (test_bit(FLG_FILLEMPTY, &bch->Flags) && !fcnt) { + /* printk(KERN_DEBUG "%s: buffer empty, so we have " + "underrun\n", __func__); */ + /* fill buffer, to prevent future underrun */ + count = HFCPCI_FILLEMPTY; + new_z1 = le16_to_cpu(*z1t) + count; + /* new buffer Position */ + if (new_z1 >= (B_FIFO_SIZE + B_SUB_VAL)) + new_z1 -= B_FIFO_SIZE; /* buffer wrap */ + dst = bdata + (le16_to_cpu(*z1t) - B_SUB_VAL); + maxlen = (B_FIFO_SIZE + B_SUB_VAL) - le16_to_cpu(*z1t); + /* end of fifo */ + if (bch->debug & DEBUG_HW_BFIFO) + printk(KERN_DEBUG "hfcpci_FFt fillempty " + "fcnt(%d) maxl(%d) nz1(%x) dst(%p)\n", + fcnt, maxlen, new_z1, dst); + fcnt += count; + if (maxlen > count) + maxlen = count; /* limit size */ + memset(dst, 0x2a, maxlen); /* first copy */ + count -= maxlen; /* remaining bytes */ + if (count) { + dst = bdata; /* start of buffer */ + memset(dst, 0x2a, count); + } + *z1t = cpu_to_le16(new_z1); /* now send data */ + } + next_t_frame: count = bch->tx_skb->len - bch->tx_idx; - /* maximum fill shall be HFCPCI_BTRANS_MAX */ - if (count > HFCPCI_BTRANS_MAX - fcnt) - count = HFCPCI_BTRANS_MAX - fcnt; + /* maximum fill shall be poll*2 */ + if (count > (poll << 1) - fcnt) + count = (poll << 1) - fcnt; if (count <= 0) return; /* data is suitable for fifo */ @@ -1135,37 +1184,37 @@ hfcpci_int(int intno, void *dev_id) val &= ~0x80; Write_hfc(hc, HFCPCI_CTMT, hc->hw.ctmt | HFCPCI_CLTIMER); } - if (val & 0x08) { + if (val & 0x08) { /* B1 rx */ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch) main_rec_hfcpci(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x08 IRQ\n"); } - if (val & 0x10) { + if (val & 0x10) { /* B2 rx */ bch = Sel_BCS(hc, 2); if (bch) main_rec_hfcpci(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x10 IRQ\n"); } - if (val & 0x01) { + if (val & 0x01) { /* B1 tx */ bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); if (bch) tx_birq(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x01 IRQ\n"); } - if (val & 0x02) { + if (val & 0x02) { /* B2 tx */ bch = Sel_BCS(hc, 2); if (bch) tx_birq(bch); else if (hc->dch.debug) printk(KERN_DEBUG "hfcpci spurious 0x02 IRQ\n"); } - if (val & 0x20) + if (val & 0x20) /* D rx */ receive_dmsg(hc); - if (val & 0x04) { /* dframe transmitted */ + if (val & 0x04) { /* D tx */ if (test_and_clear_bit(FLG_BUSY_TIMER, &hc->dch.Flags)) del_timer(&hc->dch.timer); tx_dirq(&hc->dch); @@ -1283,14 +1332,16 @@ mode_hfcpci(struct bchannel *bch, int bc, int protocol) } if (fifo2 & 2) { hc->hw.fifo_en |= HFCPCI_FIFOEN_B2; - hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + - HFCPCI_INTS_B2REC); + if (!tics) + hc->hw.int_m1 |= (HFCPCI_INTS_B2TRANS + + HFCPCI_INTS_B2REC); hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; } else { hc->hw.fifo_en |= HFCPCI_FIFOEN_B1; - hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + - HFCPCI_INTS_B1REC); + if (!tics) + hc->hw.int_m1 |= (HFCPCI_INTS_B1TRANS + + HFCPCI_INTS_B1REC); hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; } @@ -1398,7 +1449,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) if (chan & 2) { hc->hw.sctrl_r |= SCTRL_B2_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B2RX; - hc->hw.int_m1 |= HFCPCI_INTS_B2REC; + if (!tics) + hc->hw.int_m1 |= HFCPCI_INTS_B2REC; hc->hw.ctmt |= 2; hc->hw.conn &= ~0x18; #ifdef REVERSE_BITORDER @@ -1407,7 +1459,8 @@ set_hfcpci_rxtest(struct bchannel *bch, int protocol, int chan) } else { hc->hw.sctrl_r |= SCTRL_B1_ENA; hc->hw.fifo_en |= HFCPCI_FIFOEN_B1RX; - hc->hw.int_m1 |= HFCPCI_INTS_B1REC; + if (!tics) + hc->hw.int_m1 |= HFCPCI_INTS_B1REC; hc->hw.ctmt |= 1; hc->hw.conn &= ~0x03; #ifdef REVERSE_BITORDER @@ -1481,11 +1534,17 @@ deactivate_bchannel(struct bchannel *bch) static int channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) { - int ret = 0; + int ret = 0; switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = 0; + cq->op = MISDN_CTRL_FILL_EMPTY; + break; + case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + if (debug & DEBUG_HW_OPEN) + printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " + "off=%d)\n", __func__, bch->nr, !!cq->p1); break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -1859,6 +1918,10 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, hc->dch.dev.id, __builtin_return_address(0)); if (rq->protocol == ISDN_P_NONE) return -EINVAL; + if (rq->adr.channel == 1) { + /* TODO: E-Channel */ + return -EINVAL; + } if (!hc->initdone) { if (rq->protocol == ISDN_P_TE_S0) { err = create_l1(&hc->dch, hfc_l1callback); @@ -1874,6 +1937,11 @@ open_dchannel(struct hfc_pci *hc, struct mISDNchannel *ch, if (rq->protocol != ch->protocol) { if (hc->hw.protocol == ISDN_P_TE_S0) l1_event(hc->dch.l1, CLOSE_CHANNEL); + if (rq->protocol == ISDN_P_TE_S0) { + err = create_l1(&hc->dch, hfc_l1callback); + if (err) + return err; + } hc->hw.protocol = rq->protocol; ch->protocol = rq->protocol; hfcpci_setmode(hc); @@ -1903,6 +1971,7 @@ open_bchannel(struct hfc_pci *hc, struct channel_req *rq) bch = &hc->bch[rq->adr.channel - 1]; if (test_and_set_bit(FLG_OPEN, &bch->Flags)) return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); bch->ch.protocol = rq->protocol; rq->ch = &bch->ch; /* TODO: E-channel */ if (!try_module_get(THIS_MODULE)) @@ -1928,7 +1997,8 @@ hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) switch (cmd) { case OPEN_CHANNEL: rq = arg; - if (rq->adr.channel == 0) + if ((rq->protocol == ISDN_P_TE_S0) || + (rq->protocol == ISDN_P_NT_S0)) err = open_dchannel(hc, ch, rq); else err = open_bchannel(hc, rq); @@ -2027,7 +2097,6 @@ release_card(struct hfc_pci *hc) { mISDN_freebchannel(&hc->bch[1]); mISDN_freebchannel(&hc->bch[0]); mISDN_freedchannel(&hc->dch); - list_del(&hc->list); pci_set_drvdata(hc->pdev, NULL); kfree(hc); } @@ -2037,12 +2106,8 @@ setup_card(struct hfc_pci *card) { int err = -EINVAL; u_int i; - u_long flags; char name[MISDN_MAX_IDLEN]; - if (HFC_cnt >= MAX_CARDS) - return -EINVAL; /* maybe better value */ - card->dch.debug = debug; spin_lock_init(&card->lock); mISDN_initdchannel(&card->dch, MAX_DFRAME_LEN_L1, ph_state); @@ -2068,13 +2133,10 @@ setup_card(struct hfc_pci *card) if (err) goto error; snprintf(name, MISDN_MAX_IDLEN - 1, "hfc-pci.%d", HFC_cnt + 1); - err = mISDN_register_device(&card->dch.dev, name); + err = mISDN_register_device(&card->dch.dev, &card->pdev->dev, name); if (err) goto error; HFC_cnt++; - write_lock_irqsave(&HFClock, flags); - list_add_tail(&card->list, &HFClist); - write_unlock_irqrestore(&HFClock, flags); printk(KERN_INFO "HFC %d cards installed\n", HFC_cnt); return 0; error: @@ -2210,15 +2272,12 @@ static void __devexit hfc_remove_pci(struct pci_dev *pdev) { struct hfc_pci *card = pci_get_drvdata(pdev); - u_long flags; - if (card) { - write_lock_irqsave(&HFClock, flags); + if (card) release_card(card); - write_unlock_irqrestore(&HFClock, flags); - } else + else if (debug) - printk(KERN_WARNING "%s: drvdata allready removed\n", + printk(KERN_WARNING "%s: drvdata already removed\n", __func__); } @@ -2230,25 +2289,97 @@ static struct pci_driver hfc_driver = { .id_table = hfc_ids, }; +static int +_hfcpci_softirq(struct device *dev, void *arg) +{ + struct hfc_pci *hc = dev_get_drvdata(dev); + struct bchannel *bch; + if (hc == NULL) + return 0; + + if (hc->hw.int_m2 & HFCPCI_IRQ_ENABLE) { + spin_lock(&hc->lock); + bch = Sel_BCS(hc, hc->hw.bswapped ? 2 : 1); + if (bch && bch->state == ISDN_P_B_RAW) { /* B1 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + bch = Sel_BCS(hc, hc->hw.bswapped ? 1 : 2); + if (bch && bch->state == ISDN_P_B_RAW) { /* B2 rx&tx */ + main_rec_hfcpci(bch); + tx_birq(bch); + } + spin_unlock(&hc->lock); + } + return 0; +} + +static void +hfcpci_softirq(void *arg) +{ + (void) driver_for_each_device(&hfc_driver.driver, NULL, arg, + _hfcpci_softirq); + + /* if next event would be in the past ... */ + if ((s32)(hfc_jiffies + tics - jiffies) <= 0) + hfc_jiffies = jiffies + 1; + else + hfc_jiffies += tics; + hfc_tl.expires = hfc_jiffies; + add_timer(&hfc_tl); +} + static int __init HFC_init(void) { int err; + if (!poll) + poll = HFCPCI_BTRANS_THRESHOLD; + + if (poll != HFCPCI_BTRANS_THRESHOLD) { + tics = (poll * HZ) / 8000; + if (tics < 1) + tics = 1; + poll = (tics * 8000) / HZ; + if (poll > 256 || poll < 8) { + printk(KERN_ERR "%s: Wrong poll value %d not in range " + "of 8..256.\n", __func__, poll); + err = -EINVAL; + return err; + } + } + if (poll != HFCPCI_BTRANS_THRESHOLD) { + printk(KERN_INFO "%s: Using alternative poll value of %d\n", + __func__, poll); + hfc_tl.function = (void *)hfcpci_softirq; + hfc_tl.data = 0; + init_timer(&hfc_tl); + hfc_tl.expires = jiffies + tics; + hfc_jiffies = hfc_tl.expires; + add_timer(&hfc_tl); + } else + tics = 0; /* indicate the use of controller's timer */ + err = pci_register_driver(&hfc_driver); + if (err) { + if (timer_pending(&hfc_tl)) + del_timer(&hfc_tl); + } + return err; } static void __exit HFC_cleanup(void) { - struct hfc_pci *card, *next; + if (timer_pending(&hfc_tl)) + del_timer(&hfc_tl); - list_for_each_entry_safe(card, next, &HFClist, list) { - release_card(card); - } pci_unregister_driver(&hfc_driver); } module_init(HFC_init); module_exit(HFC_cleanup); + +MODULE_DEVICE_TABLE(pci, hfc_ids); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.c b/drivers/isdn/hardware/mISDN/hfcsusb.c new file mode 100644 index 00000000000..ba6925fbf38 --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcsusb.c @@ -0,0 +1,2196 @@ +/* hfcsusb.c + * mISDN driver for Colognechip HFC-S USB chip + * + * Copyright 2001 by Peter Sprenger (sprenger@moving-bytes.de) + * Copyright 2008 by Martin Bachem (info@bachem-it.com) + * + * 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * module params + * debug=<n>, default=0, with n=0xHHHHGGGG + * H - l1 driver flags described in hfcsusb.h + * G - common mISDN debug flags described at mISDNhw.h + * + * poll=<n>, default 128 + * n : burst size of PH_DATA_IND at transparent rx data + * + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/usb.h> +#include <linux/mISDNhw.h> +#include "hfcsusb.h" + +const char *hfcsusb_rev = "Revision: 0.3.3 (socket), 2008-11-05"; + +static unsigned int debug; +static int poll = DEFAULT_TRANSP_BURST_SZ; + +static LIST_HEAD(HFClist); +static DEFINE_RWLOCK(HFClock); + + +MODULE_AUTHOR("Martin Bachem"); +MODULE_LICENSE("GPL"); +module_param(debug, uint, S_IRUGO | S_IWUSR); +module_param(poll, int, 0); + +static int hfcsusb_cnt; + +/* some function prototypes */ +static void hfcsusb_ph_command(struct hfcsusb *hw, u_char command); +static void release_hw(struct hfcsusb *hw); +static void reset_hfcsusb(struct hfcsusb *hw); +static void setPortMode(struct hfcsusb *hw); +static void hfcsusb_start_endpoint(struct hfcsusb *hw, int channel); +static void hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel); +static int hfcsusb_setup_bch(struct bchannel *bch, int protocol); +static void deactivate_bchannel(struct bchannel *bch); +static void hfcsusb_ph_info(struct hfcsusb *hw); + +/* start next background transfer for control channel */ +static void +ctrl_start_transfer(struct hfcsusb *hw) +{ + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + if (hw->ctrl_cnt) { + hw->ctrl_urb->pipe = hw->ctrl_out_pipe; + hw->ctrl_urb->setup_packet = (u_char *)&hw->ctrl_write; + hw->ctrl_urb->transfer_buffer = NULL; + hw->ctrl_urb->transfer_buffer_length = 0; + hw->ctrl_write.wIndex = + cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].hfcs_reg); + hw->ctrl_write.wValue = + cpu_to_le16(hw->ctrl_buff[hw->ctrl_out_idx].reg_val); + + usb_submit_urb(hw->ctrl_urb, GFP_ATOMIC); + } +} + +/* + * queue a control transfer request to write HFC-S USB + * chip register using CTRL resuest queue + */ +static int write_reg(struct hfcsusb *hw, __u8 reg, __u8 val) +{ + struct ctrl_buf *buf; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s reg(0x%02x) val(0x%02x)\n", + hw->name, __func__, reg, val); + + spin_lock(&hw->ctrl_lock); + if (hw->ctrl_cnt >= HFC_CTRL_BUFSIZE) + return 1; + buf = &hw->ctrl_buff[hw->ctrl_in_idx]; + buf->hfcs_reg = reg; + buf->reg_val = val; + if (++hw->ctrl_in_idx >= HFC_CTRL_BUFSIZE) + hw->ctrl_in_idx = 0; + if (++hw->ctrl_cnt == 1) + ctrl_start_transfer(hw); + spin_unlock(&hw->ctrl_lock); + + return 0; +} + +/* control completion routine handling background control cmds */ +static void +ctrl_complete(struct urb *urb) +{ + struct hfcsusb *hw = (struct hfcsusb *) urb->context; + struct ctrl_buf *buf; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + urb->dev = hw->dev; + if (hw->ctrl_cnt) { + buf = &hw->ctrl_buff[hw->ctrl_out_idx]; + hw->ctrl_cnt--; /* decrement actual count */ + if (++hw->ctrl_out_idx >= HFC_CTRL_BUFSIZE) + hw->ctrl_out_idx = 0; /* pointer wrap */ + + ctrl_start_transfer(hw); /* start next transfer */ + } +} + +/* handle LED bits */ +static void +set_led_bit(struct hfcsusb *hw, signed short led_bits, int set_on) +{ + if (set_on) { + if (led_bits < 0) + hw->led_state &= ~abs(led_bits); + else + hw->led_state |= led_bits; + } else { + if (led_bits < 0) + hw->led_state |= abs(led_bits); + else + hw->led_state &= ~led_bits; + } +} + +/* handle LED requests */ +static void +handle_led(struct hfcsusb *hw, int event) +{ + struct hfcsusb_vdata *driver_info = (struct hfcsusb_vdata *) + hfcsusb_idtab[hw->vend_idx].driver_info; + __u8 tmpled; + + if (driver_info->led_scheme == LED_OFF) + return; + tmpled = hw->led_state; + + switch (event) { + case LED_POWER_ON: + set_led_bit(hw, driver_info->led_bits[0], 1); + set_led_bit(hw, driver_info->led_bits[1], 0); + set_led_bit(hw, driver_info->led_bits[2], 0); + set_led_bit(hw, driver_info->led_bits[3], 0); + break; + case LED_POWER_OFF: + set_led_bit(hw, driver_info->led_bits[0], 0); + set_led_bit(hw, driver_info->led_bits[1], 0); + set_led_bit(hw, driver_info->led_bits[2], 0); + set_led_bit(hw, driver_info->led_bits[3], 0); + break; + case LED_S0_ON: + set_led_bit(hw, driver_info->led_bits[1], 1); + break; + case LED_S0_OFF: + set_led_bit(hw, driver_info->led_bits[1], 0); + break; + case LED_B1_ON: + set_led_bit(hw, driver_info->led_bits[2], 1); + break; + case LED_B1_OFF: + set_led_bit(hw, driver_info->led_bits[2], 0); + break; + case LED_B2_ON: + set_led_bit(hw, driver_info->led_bits[3], 1); + break; + case LED_B2_OFF: + set_led_bit(hw, driver_info->led_bits[3], 0); + break; + } + + if (hw->led_state != tmpled) { + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s reg(0x%02x) val(x%02x)\n", + hw->name, __func__, + HFCUSB_P_DATA, hw->led_state); + + write_reg(hw, HFCUSB_P_DATA, hw->led_state); + } +} + +/* + * Layer2 -> Layer 1 Bchannel data + */ +static int +hfcusb_l2l1B(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + struct hfcsusb *hw = bch->hw; + int ret = -EINVAL; + struct mISDNhead *hh = mISDN_HEAD_P(skb); + u_long flags; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + switch (hh->prim) { + case PH_DATA_REQ: + spin_lock_irqsave(&hw->lock, flags); + ret = bchannel_senddata(bch, skb); + spin_unlock_irqrestore(&hw->lock, flags); + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s PH_DATA_REQ ret(%i)\n", + hw->name, __func__, ret); + if (ret > 0) { + /* + * other l1 drivers don't send early confirms on + * transp data, but hfcsusb does because tx_next + * skb is needed in tx_iso_complete() + */ + queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL); + ret = 0; + } + return ret; + case PH_ACTIVATE_REQ: + if (!test_and_set_bit(FLG_ACTIVE, &bch->Flags)) { + hfcsusb_start_endpoint(hw, bch->nr); + ret = hfcsusb_setup_bch(bch, ch->protocol); + } else + ret = 0; + if (!ret) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + break; + case PH_DEACTIVATE_REQ: + deactivate_bchannel(bch); + _queue_data(ch, PH_DEACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + ret = 0; + break; + } + if (!ret) + dev_kfree_skb(skb); + return ret; +} + +/* + * send full D/B channel status information + * as MPH_INFORMATION_IND + */ +static void +hfcsusb_ph_info(struct hfcsusb *hw) +{ + struct ph_info *phi; + struct dchannel *dch = &hw->dch; + int i; + + phi = kzalloc(sizeof(struct ph_info) + + dch->dev.nrbchan * sizeof(struct ph_info_ch), GFP_ATOMIC); + phi->dch.ch.protocol = hw->protocol; + phi->dch.ch.Flags = dch->Flags; + phi->dch.state = dch->state; + phi->dch.num_bch = dch->dev.nrbchan; + for (i = 0; i < dch->dev.nrbchan; i++) { + phi->bch[i].protocol = hw->bch[i].ch.protocol; + phi->bch[i].Flags = hw->bch[i].Flags; + } + _queue_data(&dch->dev.D, MPH_INFORMATION_IND, MISDN_ID_ANY, + sizeof(struct ph_info_dch) + dch->dev.nrbchan * + sizeof(struct ph_info_ch), phi, GFP_ATOMIC); +} + +/* + * Layer2 -> Layer 1 Dchannel data + */ +static int +hfcusb_l2l1D(struct mISDNchannel *ch, struct sk_buff *skb) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct mISDNhead *hh = mISDN_HEAD_P(skb); + struct hfcsusb *hw = dch->hw; + int ret = -EINVAL; + u_long flags; + + switch (hh->prim) { + case PH_DATA_REQ: + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s: PH_DATA_REQ\n", + hw->name, __func__); + + spin_lock_irqsave(&hw->lock, flags); + ret = dchannel_senddata(dch, skb); + spin_unlock_irqrestore(&hw->lock, flags); + if (ret > 0) { + ret = 0; + queue_ch_frame(ch, PH_DATA_CNF, hh->id, NULL); + } + break; + + case PH_ACTIVATE_REQ: + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s: PH_ACTIVATE_REQ %s\n", + hw->name, __func__, + (hw->protocol == ISDN_P_NT_S0) ? "NT" : "TE"); + + if (hw->protocol == ISDN_P_NT_S0) { + ret = 0; + if (test_bit(FLG_ACTIVE, &dch->Flags)) { + _queue_data(&dch->dev.D, + PH_ACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_ATOMIC); + } else { + hfcsusb_ph_command(hw, + HFC_L1_ACTIVATE_NT); + test_and_set_bit(FLG_L2_ACTIVATED, + &dch->Flags); + } + } else { + hfcsusb_ph_command(hw, HFC_L1_ACTIVATE_TE); + ret = l1_event(dch->l1, hh->prim); + } + break; + + case PH_DEACTIVATE_REQ: + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s: PH_DEACTIVATE_REQ\n", + hw->name, __func__); + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + + if (hw->protocol == ISDN_P_NT_S0) { + hfcsusb_ph_command(hw, HFC_L1_DEACTIVATE_NT); + spin_lock_irqsave(&hw->lock, flags); + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + spin_unlock_irqrestore(&hw->lock, flags); +#ifdef FIXME + if (test_and_clear_bit(FLG_L1_BUSY, &dch->Flags)) + dchannel_sched_event(&hc->dch, D_CLEARBUSY); +#endif + ret = 0; + } else + ret = l1_event(dch->l1, hh->prim); + break; + case MPH_INFORMATION_REQ: + hfcsusb_ph_info(hw); + ret = 0; + break; + } + + return ret; +} + +/* + * Layer 1 callback function + */ +static int +hfc_l1callback(struct dchannel *dch, u_int cmd) +{ + struct hfcsusb *hw = dch->hw; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s cmd 0x%x\n", + hw->name, __func__, cmd); + + switch (cmd) { + case INFO3_P8: + case INFO3_P10: + case HW_RESET_REQ: + case HW_POWERUP_REQ: + break; + + case HW_DEACT_REQ: + skb_queue_purge(&dch->squeue); + if (dch->tx_skb) { + dev_kfree_skb(dch->tx_skb); + dch->tx_skb = NULL; + } + dch->tx_idx = 0; + if (dch->rx_skb) { + dev_kfree_skb(dch->rx_skb); + dch->rx_skb = NULL; + } + test_and_clear_bit(FLG_TX_BUSY, &dch->Flags); + break; + case PH_ACTIVATE_IND: + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + case PH_DEACTIVATE_IND: + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, cmd, MISDN_ID_ANY, 0, NULL, + GFP_ATOMIC); + break; + default: + if (dch->debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: unknown cmd %x\n", + hw->name, __func__, cmd); + return -1; + } + hfcsusb_ph_info(hw); + return 0; +} + +static int +open_dchannel(struct hfcsusb *hw, struct mISDNchannel *ch, + struct channel_req *rq) +{ + int err = 0; + + if (debug & DEBUG_HW_OPEN) + printk(KERN_DEBUG "%s: %s: dev(%d) open addr(%i) from %p\n", + hw->name, __func__, hw->dch.dev.id, rq->adr.channel, + __builtin_return_address(0)); + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + + test_and_clear_bit(FLG_ACTIVE, &hw->dch.Flags); + test_and_clear_bit(FLG_ACTIVE, &hw->ech.Flags); + hfcsusb_start_endpoint(hw, HFC_CHAN_D); + + /* E-Channel logging */ + if (rq->adr.channel == 1) { + if (hw->fifos[HFCUSB_PCM_RX].pipe) { + hfcsusb_start_endpoint(hw, HFC_CHAN_E); + set_bit(FLG_ACTIVE, &hw->ech.Flags); + _queue_data(&hw->ech.dev.D, PH_ACTIVATE_IND, + MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); + } else + return -EINVAL; + } + + if (!hw->initdone) { + hw->protocol = rq->protocol; + if (rq->protocol == ISDN_P_TE_S0) { + err = create_l1(&hw->dch, hfc_l1callback); + if (err) + return err; + } + setPortMode(hw); + ch->protocol = rq->protocol; + hw->initdone = 1; + } else { + if (rq->protocol != ch->protocol) + return -EPROTONOSUPPORT; + } + + if (((ch->protocol == ISDN_P_NT_S0) && (hw->dch.state == 3)) || + ((ch->protocol == ISDN_P_TE_S0) && (hw->dch.state == 7))) + _queue_data(ch, PH_ACTIVATE_IND, MISDN_ID_ANY, + 0, NULL, GFP_KERNEL); + rq->ch = ch; + if (!try_module_get(THIS_MODULE)) + printk(KERN_WARNING "%s: %s: cannot get module\n", + hw->name, __func__); + return 0; +} + +static int +open_bchannel(struct hfcsusb *hw, struct channel_req *rq) +{ + struct bchannel *bch; + + if (rq->adr.channel > 2) + return -EINVAL; + if (rq->protocol == ISDN_P_NONE) + return -EINVAL; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s B%i\n", + hw->name, __func__, rq->adr.channel); + + bch = &hw->bch[rq->adr.channel - 1]; + if (test_and_set_bit(FLG_OPEN, &bch->Flags)) + return -EBUSY; /* b-channel can be only open once */ + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + bch->ch.protocol = rq->protocol; + rq->ch = &bch->ch; + + /* start USB endpoint for bchannel */ + if (rq->adr.channel == 1) + hfcsusb_start_endpoint(hw, HFC_CHAN_B1); + else + hfcsusb_start_endpoint(hw, HFC_CHAN_B2); + + if (!try_module_get(THIS_MODULE)) + printk(KERN_WARNING "%s: %s:cannot get module\n", + hw->name, __func__); + return 0; +} + +static int +channel_ctrl(struct hfcsusb *hw, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s op(0x%x) channel(0x%x)\n", + hw->name, __func__, (cq->op), (cq->channel)); + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_LOOP | MISDN_CTRL_CONNECT | + MISDN_CTRL_DISCONNECT; + break; + default: + printk(KERN_WARNING "%s: %s: unknown Op %x\n", + hw->name, __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +/* + * device control function + */ +static int +hfc_dctrl(struct mISDNchannel *ch, u_int cmd, void *arg) +{ + struct mISDNdevice *dev = container_of(ch, struct mISDNdevice, D); + struct dchannel *dch = container_of(dev, struct dchannel, dev); + struct hfcsusb *hw = dch->hw; + struct channel_req *rq; + int err = 0; + + if (dch->debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: cmd:%x %p\n", + hw->name, __func__, cmd, arg); + switch (cmd) { + case OPEN_CHANNEL: + rq = arg; + if ((rq->protocol == ISDN_P_TE_S0) || + (rq->protocol == ISDN_P_NT_S0)) + err = open_dchannel(hw, ch, rq); + else + err = open_bchannel(hw, rq); + if (!err) + hw->open++; + break; + case CLOSE_CHANNEL: + hw->open--; + if (debug & DEBUG_HW_OPEN) + printk(KERN_DEBUG + "%s: %s: dev(%d) close from %p (open %d)\n", + hw->name, __func__, hw->dch.dev.id, + __builtin_return_address(0), hw->open); + if (!hw->open) { + hfcsusb_stop_endpoint(hw, HFC_CHAN_D); + if (hw->fifos[HFCUSB_PCM_RX].pipe) + hfcsusb_stop_endpoint(hw, HFC_CHAN_E); + handle_led(hw, LED_POWER_ON); + } + module_put(THIS_MODULE); + break; + case CONTROL_CHANNEL: + err = channel_ctrl(hw, arg); + break; + default: + if (dch->debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: unknown command %x\n", + hw->name, __func__, cmd); + return -EINVAL; + } + return err; +} + +/* + * S0 TE state change event handler + */ +static void +ph_state_te(struct dchannel *dch) +{ + struct hfcsusb *hw = dch->hw; + + if (debug & DEBUG_HW) { + if (dch->state <= HFC_MAX_TE_LAYER1_STATE) + printk(KERN_DEBUG "%s: %s: %s\n", hw->name, __func__, + HFC_TE_LAYER1_STATES[dch->state]); + else + printk(KERN_DEBUG "%s: %s: TE F%d\n", + hw->name, __func__, dch->state); + } + + switch (dch->state) { + case 0: + l1_event(dch->l1, HW_RESET_IND); + break; + case 3: + l1_event(dch->l1, HW_DEACT_IND); + break; + case 5: + case 8: + l1_event(dch->l1, ANYSIGNAL); + break; + case 6: + l1_event(dch->l1, INFO2); + break; + case 7: + l1_event(dch->l1, INFO4_P8); + break; + } + if (dch->state == 7) + handle_led(hw, LED_S0_ON); + else + handle_led(hw, LED_S0_OFF); +} + +/* + * S0 NT state change event handler + */ +static void +ph_state_nt(struct dchannel *dch) +{ + struct hfcsusb *hw = dch->hw; + + if (debug & DEBUG_HW) { + if (dch->state <= HFC_MAX_NT_LAYER1_STATE) + printk(KERN_DEBUG "%s: %s: %s\n", + hw->name, __func__, + HFC_NT_LAYER1_STATES[dch->state]); + + else + printk(KERN_INFO DRIVER_NAME "%s: %s: NT G%d\n", + hw->name, __func__, dch->state); + } + + switch (dch->state) { + case (1): + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + test_and_clear_bit(FLG_L2_ACTIVATED, &dch->Flags); + hw->nt_timer = 0; + hw->timers &= ~NT_ACTIVATION_TIMER; + handle_led(hw, LED_S0_OFF); + break; + + case (2): + if (hw->nt_timer < 0) { + hw->nt_timer = 0; + hw->timers &= ~NT_ACTIVATION_TIMER; + hfcsusb_ph_command(dch->hw, HFC_L1_DEACTIVATE_NT); + } else { + hw->timers |= NT_ACTIVATION_TIMER; + hw->nt_timer = NT_T1_COUNT; + /* allow G2 -> G3 transition */ + write_reg(hw, HFCUSB_STATES, 2 | HFCUSB_NT_G2_G3); + } + break; + case (3): + hw->nt_timer = 0; + hw->timers &= ~NT_ACTIVATION_TIMER; + test_and_set_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, PH_ACTIVATE_IND, + MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); + handle_led(hw, LED_S0_ON); + break; + case (4): + hw->nt_timer = 0; + hw->timers &= ~NT_ACTIVATION_TIMER; + break; + default: + break; + } + hfcsusb_ph_info(hw); +} + +static void +ph_state(struct dchannel *dch) +{ + struct hfcsusb *hw = dch->hw; + + if (hw->protocol == ISDN_P_NT_S0) + ph_state_nt(dch); + else if (hw->protocol == ISDN_P_TE_S0) + ph_state_te(dch); +} + +/* + * disable/enable BChannel for desired protocoll + */ +static int +hfcsusb_setup_bch(struct bchannel *bch, int protocol) +{ + struct hfcsusb *hw = bch->hw; + __u8 conhdlc, sctrl, sctrl_r; + + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: protocol %x-->%x B%d\n", + hw->name, __func__, bch->state, protocol, + bch->nr); + + /* setup val for CON_HDLC */ + conhdlc = 0; + if (protocol > ISDN_P_NONE) + conhdlc = 8; /* enable FIFO */ + + switch (protocol) { + case (-1): /* used for init */ + bch->state = -1; + /* fall trough */ + case (ISDN_P_NONE): + if (bch->state == ISDN_P_NONE) + return 0; /* already in idle state */ + bch->state = ISDN_P_NONE; + clear_bit(FLG_HDLC, &bch->Flags); + clear_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case (ISDN_P_B_RAW): + conhdlc |= 2; + bch->state = protocol; + set_bit(FLG_TRANSPARENT, &bch->Flags); + break; + case (ISDN_P_B_HDLC): + bch->state = protocol; + set_bit(FLG_HDLC, &bch->Flags); + break; + default: + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: prot not known %x\n", + hw->name, __func__, protocol); + return -ENOPROTOOPT; + } + + if (protocol >= ISDN_P_NONE) { + write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 0 : 2); + write_reg(hw, HFCUSB_CON_HDLC, conhdlc); + write_reg(hw, HFCUSB_INC_RES_F, 2); + write_reg(hw, HFCUSB_FIFO, (bch->nr == 1) ? 1 : 3); + write_reg(hw, HFCUSB_CON_HDLC, conhdlc); + write_reg(hw, HFCUSB_INC_RES_F, 2); + + sctrl = 0x40 + ((hw->protocol == ISDN_P_TE_S0) ? 0x00 : 0x04); + sctrl_r = 0x0; + if (test_bit(FLG_ACTIVE, &hw->bch[0].Flags)) { + sctrl |= 1; + sctrl_r |= 1; + } + if (test_bit(FLG_ACTIVE, &hw->bch[1].Flags)) { + sctrl |= 2; + sctrl_r |= 2; + } + write_reg(hw, HFCUSB_SCTRL, sctrl); + write_reg(hw, HFCUSB_SCTRL_R, sctrl_r); + + if (protocol > ISDN_P_NONE) + handle_led(hw, (bch->nr == 1) ? LED_B1_ON : LED_B2_ON); + else + handle_led(hw, (bch->nr == 1) ? LED_B1_OFF : + LED_B2_OFF); + } + hfcsusb_ph_info(hw); + return 0; +} + +static void +hfcsusb_ph_command(struct hfcsusb *hw, u_char command) +{ + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: %x\n", + hw->name, __func__, command); + + switch (command) { + case HFC_L1_ACTIVATE_TE: + /* force sending sending INFO1 */ + write_reg(hw, HFCUSB_STATES, 0x14); + /* start l1 activation */ + write_reg(hw, HFCUSB_STATES, 0x04); + break; + + case HFC_L1_FORCE_DEACTIVATE_TE: + write_reg(hw, HFCUSB_STATES, 0x10); + write_reg(hw, HFCUSB_STATES, 0x03); + break; + + case HFC_L1_ACTIVATE_NT: + if (hw->dch.state == 3) + _queue_data(&hw->dch.dev.D, PH_ACTIVATE_IND, + MISDN_ID_ANY, 0, NULL, GFP_ATOMIC); + else + write_reg(hw, HFCUSB_STATES, HFCUSB_ACTIVATE | + HFCUSB_DO_ACTION | HFCUSB_NT_G2_G3); + break; + + case HFC_L1_DEACTIVATE_NT: + write_reg(hw, HFCUSB_STATES, + HFCUSB_DO_ACTION); + break; + } +} + +/* + * Layer 1 B-channel hardware access + */ +static int +channel_bctrl(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_FILL_EMPTY; + break; + case MISDN_CTRL_FILL_EMPTY: /* fill fifo, if empty */ + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + if (debug & DEBUG_HW_OPEN) + printk(KERN_DEBUG "%s: FILL_EMPTY request (nr=%d " + "off=%d)\n", __func__, bch->nr, !!cq->p1); + break; + default: + printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); + ret = -EINVAL; + break; + } + return ret; +} + +/* collect data from incoming interrupt or isochron USB data */ +static void +hfcsusb_rx_frame(struct usb_fifo *fifo, __u8 *data, unsigned int len, + int finish) +{ + struct hfcsusb *hw = fifo->hw; + struct sk_buff *rx_skb = NULL; + int maxlen = 0; + int fifon = fifo->fifonum; + int i; + int hdlc = 0; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s: fifo(%i) len(%i) " + "dch(%p) bch(%p) ech(%p)\n", + hw->name, __func__, fifon, len, + fifo->dch, fifo->bch, fifo->ech); + + if (!len) + return; + + if ((!!fifo->dch + !!fifo->bch + !!fifo->ech) != 1) { + printk(KERN_DEBUG "%s: %s: undefined channel\n", + hw->name, __func__); + return; + } + + spin_lock(&hw->lock); + if (fifo->dch) { + rx_skb = fifo->dch->rx_skb; + maxlen = fifo->dch->maxlen; + hdlc = 1; + } + if (fifo->bch) { + rx_skb = fifo->bch->rx_skb; + maxlen = fifo->bch->maxlen; + hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); + } + if (fifo->ech) { + rx_skb = fifo->ech->rx_skb; + maxlen = fifo->ech->maxlen; + hdlc = 1; + } + + if (!rx_skb) { + rx_skb = mI_alloc_skb(maxlen, GFP_ATOMIC); + if (rx_skb) { + if (fifo->dch) + fifo->dch->rx_skb = rx_skb; + if (fifo->bch) + fifo->bch->rx_skb = rx_skb; + if (fifo->ech) + fifo->ech->rx_skb = rx_skb; + skb_trim(rx_skb, 0); + } else { + printk(KERN_DEBUG "%s: %s: No mem for rx_skb\n", + hw->name, __func__); + spin_unlock(&hw->lock); + return; + } + } + + if (fifo->dch || fifo->ech) { + /* D/E-Channel SKB range check */ + if ((rx_skb->len + len) >= MAX_DFRAME_LEN_L1) { + printk(KERN_DEBUG "%s: %s: sbk mem exceeded " + "for fifo(%d) HFCUSB_D_RX\n", + hw->name, __func__, fifon); + skb_trim(rx_skb, 0); + spin_unlock(&hw->lock); + return; + } + } else if (fifo->bch) { + /* B-Channel SKB range check */ + if ((rx_skb->len + len) >= (MAX_BCH_SIZE + 3)) { + printk(KERN_DEBUG "%s: %s: sbk mem exceeded " + "for fifo(%d) HFCUSB_B_RX\n", + hw->name, __func__, fifon); + skb_trim(rx_skb, 0); + spin_unlock(&hw->lock); + return; + } + } + + memcpy(skb_put(rx_skb, len), data, len); + + if (hdlc) { + /* we have a complete hdlc packet */ + if (finish) { + if ((rx_skb->len > 3) && + (!(rx_skb->data[rx_skb->len - 1]))) { + if (debug & DBG_HFC_FIFO_VERBOSE) { + printk(KERN_DEBUG "%s: %s: fifon(%i)" + " new RX len(%i): ", + hw->name, __func__, fifon, + rx_skb->len); + i = 0; + while (i < rx_skb->len) + printk("%02x ", + rx_skb->data[i++]); + printk("\n"); + } + + /* remove CRC & status */ + skb_trim(rx_skb, rx_skb->len - 3); + + if (fifo->dch) + recv_Dchannel(fifo->dch); + if (fifo->bch) + recv_Bchannel(fifo->bch); + if (fifo->ech) + recv_Echannel(fifo->ech, + &hw->dch); + } else { + if (debug & DBG_HFC_FIFO_VERBOSE) { + printk(KERN_DEBUG + "%s: CRC or minlen ERROR fifon(%i) " + "RX len(%i): ", + hw->name, fifon, rx_skb->len); + i = 0; + while (i < rx_skb->len) + printk("%02x ", + rx_skb->data[i++]); + printk("\n"); + } + skb_trim(rx_skb, 0); + } + } + } else { + /* deliver transparent data to layer2 */ + if (rx_skb->len >= poll) + recv_Bchannel(fifo->bch); + } + spin_unlock(&hw->lock); +} + +void +fill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, + void *buf, int num_packets, int packet_size, int interval, + usb_complete_t complete, void *context) +{ + int k; + + usb_fill_bulk_urb(urb, dev, pipe, buf, packet_size * num_packets, + complete, context); + + urb->number_of_packets = num_packets; + urb->transfer_flags = URB_ISO_ASAP; + urb->actual_length = 0; + urb->interval = interval; + + for (k = 0; k < num_packets; k++) { + urb->iso_frame_desc[k].offset = packet_size * k; + urb->iso_frame_desc[k].length = packet_size; + urb->iso_frame_desc[k].actual_length = 0; + } +} + +/* receive completion routine for all ISO tx fifos */ +static void +rx_iso_complete(struct urb *urb) +{ + struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; + struct usb_fifo *fifo = context_iso_urb->owner_fifo; + struct hfcsusb *hw = fifo->hw; + int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, + status, iso_status, i; + __u8 *buf; + static __u8 eof[8]; + __u8 s0_state; + + fifon = fifo->fifonum; + status = urb->status; + + spin_lock(&hw->lock); + if (fifo->stop_gracefull) { + fifo->stop_gracefull = 0; + fifo->active = 0; + spin_unlock(&hw->lock); + return; + } + spin_unlock(&hw->lock); + + /* + * ISO transfer only partially completed, + * look at individual frame status for details + */ + if (status == -EXDEV) { + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: with -EXDEV " + "urb->status %d, fifonum %d\n", + hw->name, __func__, status, fifon); + + /* clear status, so go on with ISO transfers */ + status = 0; + } + + s0_state = 0; + if (fifo->active && !status) { + num_isoc_packets = iso_packets[fifon]; + maxlen = fifo->usb_packet_maxlen; + + for (k = 0; k < num_isoc_packets; ++k) { + len = urb->iso_frame_desc[k].actual_length; + offset = urb->iso_frame_desc[k].offset; + buf = context_iso_urb->buffer + offset; + iso_status = urb->iso_frame_desc[k].status; + + if (iso_status && (debug & DBG_HFC_FIFO_VERBOSE)) { + printk(KERN_DEBUG "%s: %s: " + "ISO packet %i, status: %i\n", + hw->name, __func__, k, iso_status); + } + + /* USB data log for every D ISO in */ + if ((fifon == HFCUSB_D_RX) && + (debug & DBG_HFC_USB_VERBOSE)) { + printk(KERN_DEBUG + "%s: %s: %d (%d/%d) len(%d) ", + hw->name, __func__, urb->start_frame, + k, num_isoc_packets-1, + len); + for (i = 0; i < len; i++) + printk("%x ", buf[i]); + printk("\n"); + } + + if (!iso_status) { + if (fifo->last_urblen != maxlen) { + /* + * save fifo fill-level threshold bits + * to use them later in TX ISO URB + * completions + */ + hw->threshold_mask = buf[1]; + + if (fifon == HFCUSB_D_RX) + s0_state = (buf[0] >> 4); + + eof[fifon] = buf[0] & 1; + if (len > 2) + hfcsusb_rx_frame(fifo, buf + 2, + len - 2, (len < maxlen) + ? eof[fifon] : 0); + } else + hfcsusb_rx_frame(fifo, buf, len, + (len < maxlen) ? + eof[fifon] : 0); + fifo->last_urblen = len; + } + } + + /* signal S0 layer1 state change */ + if ((s0_state) && (hw->initdone) && + (s0_state != hw->dch.state)) { + hw->dch.state = s0_state; + schedule_event(&hw->dch, FLG_PHCHANGE); + } + + fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, + context_iso_urb->buffer, num_isoc_packets, + fifo->usb_packet_maxlen, fifo->intervall, + (usb_complete_t)rx_iso_complete, urb->context); + errcode = usb_submit_urb(urb, GFP_ATOMIC); + if (errcode < 0) { + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: error submitting " + "ISO URB: %d\n", + hw->name, __func__, errcode); + } + } else { + if (status && (debug & DBG_HFC_URB_INFO)) + printk(KERN_DEBUG "%s: %s: rx_iso_complete : " + "urb->status %d, fifonum %d\n", + hw->name, __func__, status, fifon); + } +} + +/* receive completion routine for all interrupt rx fifos */ +static void +rx_int_complete(struct urb *urb) +{ + int len, status, i; + __u8 *buf, maxlen, fifon; + struct usb_fifo *fifo = (struct usb_fifo *) urb->context; + struct hfcsusb *hw = fifo->hw; + static __u8 eof[8]; + + spin_lock(&hw->lock); + if (fifo->stop_gracefull) { + fifo->stop_gracefull = 0; + fifo->active = 0; + spin_unlock(&hw->lock); + return; + } + spin_unlock(&hw->lock); + + fifon = fifo->fifonum; + if ((!fifo->active) || (urb->status)) { + if (debug & DBG_HFC_URB_ERROR) + printk(KERN_DEBUG + "%s: %s: RX-Fifo %i is going down (%i)\n", + hw->name, __func__, fifon, urb->status); + + fifo->urb->interval = 0; /* cancel automatic rescheduling */ + return; + } + len = urb->actual_length; + buf = fifo->buffer; + maxlen = fifo->usb_packet_maxlen; + + /* USB data log for every D INT in */ + if ((fifon == HFCUSB_D_RX) && (debug & DBG_HFC_USB_VERBOSE)) { + printk(KERN_DEBUG "%s: %s: D RX INT len(%d) ", + hw->name, __func__, len); + for (i = 0; i < len; i++) + printk("%02x ", buf[i]); + printk("\n"); + } + + if (fifo->last_urblen != fifo->usb_packet_maxlen) { + /* the threshold mask is in the 2nd status byte */ + hw->threshold_mask = buf[1]; + + /* signal S0 layer1 state change */ + if (hw->initdone && ((buf[0] >> 4) != hw->dch.state)) { + hw->dch.state = (buf[0] >> 4); + schedule_event(&hw->dch, FLG_PHCHANGE); + } + + eof[fifon] = buf[0] & 1; + /* if we have more than the 2 status bytes -> collect data */ + if (len > 2) + hfcsusb_rx_frame(fifo, buf + 2, + urb->actual_length - 2, + (len < maxlen) ? eof[fifon] : 0); + } else { + hfcsusb_rx_frame(fifo, buf, urb->actual_length, + (len < maxlen) ? eof[fifon] : 0); + } + fifo->last_urblen = urb->actual_length; + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status) { + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: error resubmitting USB\n", + hw->name, __func__); + } +} + +/* transmit completion routine for all ISO tx fifos */ +static void +tx_iso_complete(struct urb *urb) +{ + struct iso_urb *context_iso_urb = (struct iso_urb *) urb->context; + struct usb_fifo *fifo = context_iso_urb->owner_fifo; + struct hfcsusb *hw = fifo->hw; + struct sk_buff *tx_skb; + int k, tx_offset, num_isoc_packets, sink, remain, current_len, + errcode, hdlc, i; + int *tx_idx; + int frame_complete, fifon, status; + __u8 threshbit; + + spin_lock(&hw->lock); + if (fifo->stop_gracefull) { + fifo->stop_gracefull = 0; + fifo->active = 0; + spin_unlock(&hw->lock); + return; + } + + if (fifo->dch) { + tx_skb = fifo->dch->tx_skb; + tx_idx = &fifo->dch->tx_idx; + hdlc = 1; + } else if (fifo->bch) { + tx_skb = fifo->bch->tx_skb; + tx_idx = &fifo->bch->tx_idx; + hdlc = test_bit(FLG_HDLC, &fifo->bch->Flags); + } else { + printk(KERN_DEBUG "%s: %s: neither BCH nor DCH\n", + hw->name, __func__); + spin_unlock(&hw->lock); + return; + } + + fifon = fifo->fifonum; + status = urb->status; + + tx_offset = 0; + + /* + * ISO transfer only partially completed, + * look at individual frame status for details + */ + if (status == -EXDEV) { + if (debug & DBG_HFC_URB_ERROR) + printk(KERN_DEBUG "%s: %s: " + "-EXDEV (%i) fifon (%d)\n", + hw->name, __func__, status, fifon); + + /* clear status, so go on with ISO transfers */ + status = 0; + } + + if (fifo->active && !status) { + /* is FifoFull-threshold set for our channel? */ + threshbit = (hw->threshold_mask & (1 << fifon)); + num_isoc_packets = iso_packets[fifon]; + + /* predict dataflow to avoid fifo overflow */ + if (fifon >= HFCUSB_D_TX) + sink = (threshbit) ? SINK_DMIN : SINK_DMAX; + else + sink = (threshbit) ? SINK_MIN : SINK_MAX; + fill_isoc_urb(urb, fifo->hw->dev, fifo->pipe, + context_iso_urb->buffer, num_isoc_packets, + fifo->usb_packet_maxlen, fifo->intervall, + (usb_complete_t)tx_iso_complete, urb->context); + memset(context_iso_urb->buffer, 0, + sizeof(context_iso_urb->buffer)); + frame_complete = 0; + + for (k = 0; k < num_isoc_packets; ++k) { + /* analyze tx success of previous ISO packets */ + if (debug & DBG_HFC_URB_ERROR) { + errcode = urb->iso_frame_desc[k].status; + if (errcode) { + printk(KERN_DEBUG "%s: %s: " + "ISO packet %i, status: %i\n", + hw->name, __func__, k, errcode); + } + } + + /* Generate next ISO Packets */ + if (tx_skb) + remain = tx_skb->len - *tx_idx; + else + remain = 0; + + if (remain > 0) { + fifo->bit_line -= sink; + current_len = (0 - fifo->bit_line) / 8; + if (current_len > 14) + current_len = 14; + if (current_len < 0) + current_len = 0; + if (remain < current_len) + current_len = remain; + + /* how much bit do we put on the line? */ + fifo->bit_line += current_len * 8; + + context_iso_urb->buffer[tx_offset] = 0; + if (current_len == remain) { + if (hdlc) { + /* signal frame completion */ + context_iso_urb-> + buffer[tx_offset] = 1; + /* add 2 byte flags and 16bit + * CRC at end of ISDN frame */ + fifo->bit_line += 32; + } + frame_complete = 1; + } + + /* copy tx data to iso-urb buffer */ + memcpy(context_iso_urb->buffer + tx_offset + 1, + (tx_skb->data + *tx_idx), current_len); + *tx_idx += current_len; + + urb->iso_frame_desc[k].offset = tx_offset; + urb->iso_frame_desc[k].length = current_len + 1; + + /* USB data log for every D ISO out */ + if ((fifon == HFCUSB_D_RX) && + (debug & DBG_HFC_USB_VERBOSE)) { + printk(KERN_DEBUG + "%s: %s (%d/%d) offs(%d) len(%d) ", + hw->name, __func__, + k, num_isoc_packets-1, + urb->iso_frame_desc[k].offset, + urb->iso_frame_desc[k].length); + + for (i = urb->iso_frame_desc[k].offset; + i < (urb->iso_frame_desc[k].offset + + urb->iso_frame_desc[k].length); + i++) + printk("%x ", + context_iso_urb->buffer[i]); + + printk(" skb->len(%i) tx-idx(%d)\n", + tx_skb->len, *tx_idx); + } + + tx_offset += (current_len + 1); + } else { + urb->iso_frame_desc[k].offset = tx_offset++; + urb->iso_frame_desc[k].length = 1; + /* we lower data margin every msec */ + fifo->bit_line -= sink; + if (fifo->bit_line < BITLINE_INF) + fifo->bit_line = BITLINE_INF; + } + + if (frame_complete) { + frame_complete = 0; + + if (debug & DBG_HFC_FIFO_VERBOSE) { + printk(KERN_DEBUG "%s: %s: " + "fifon(%i) new TX len(%i): ", + hw->name, __func__, + fifon, tx_skb->len); + i = 0; + while (i < tx_skb->len) + printk("%02x ", + tx_skb->data[i++]); + printk("\n"); + } + + dev_kfree_skb(tx_skb); + tx_skb = NULL; + if (fifo->dch && get_next_dframe(fifo->dch)) + tx_skb = fifo->dch->tx_skb; + else if (fifo->bch && + get_next_bframe(fifo->bch)) { + if (test_bit(FLG_TRANSPARENT, + &fifo->bch->Flags)) + confirm_Bsend(fifo->bch); + tx_skb = fifo->bch->tx_skb; + } + } + } + errcode = usb_submit_urb(urb, GFP_ATOMIC); + if (errcode < 0) { + if (debug & DEBUG_HW) + printk(KERN_DEBUG + "%s: %s: error submitting ISO URB: %d \n", + hw->name, __func__, errcode); + } + + /* + * abuse DChannel tx iso completion to trigger NT mode state + * changes tx_iso_complete is assumed to be called every + * fifo->intervall (ms) + */ + if ((fifon == HFCUSB_D_TX) && (hw->protocol == ISDN_P_NT_S0) + && (hw->timers & NT_ACTIVATION_TIMER)) { + if ((--hw->nt_timer) < 0) + schedule_event(&hw->dch, FLG_PHCHANGE); + } + + } else { + if (status && (debug & DBG_HFC_URB_ERROR)) + printk(KERN_DEBUG "%s: %s: urb->status %s (%i)" + "fifonum=%d\n", + hw->name, __func__, + symbolic(urb_errlist, status), status, fifon); + } + spin_unlock(&hw->lock); +} + +/* + * allocs urbs and start isoc transfer with two pending urbs to avoid + * gaps in the transfer chain + */ +static int +start_isoc_chain(struct usb_fifo *fifo, int num_packets_per_urb, + usb_complete_t complete, int packet_size) +{ + struct hfcsusb *hw = fifo->hw; + int i, k, errcode; + + if (debug) + printk(KERN_DEBUG "%s: %s: fifo %i\n", + hw->name, __func__, fifo->fifonum); + + /* allocate Memory for Iso out Urbs */ + for (i = 0; i < 2; i++) { + if (!(fifo->iso[i].urb)) { + fifo->iso[i].urb = + usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); + if (!(fifo->iso[i].urb)) { + printk(KERN_DEBUG + "%s: %s: alloc urb for fifo %i failed", + hw->name, __func__, fifo->fifonum); + } + fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; + fifo->iso[i].indx = i; + + /* Init the first iso */ + if (ISO_BUFFER_SIZE >= + (fifo->usb_packet_maxlen * + num_packets_per_urb)) { + fill_isoc_urb(fifo->iso[i].urb, + fifo->hw->dev, fifo->pipe, + fifo->iso[i].buffer, + num_packets_per_urb, + fifo->usb_packet_maxlen, + fifo->intervall, complete, + &fifo->iso[i]); + memset(fifo->iso[i].buffer, 0, + sizeof(fifo->iso[i].buffer)); + + for (k = 0; k < num_packets_per_urb; k++) { + fifo->iso[i].urb-> + iso_frame_desc[k].offset = + k * packet_size; + fifo->iso[i].urb-> + iso_frame_desc[k].length = + packet_size; + } + } else { + printk(KERN_DEBUG + "%s: %s: ISO Buffer size to small!\n", + hw->name, __func__); + } + } + fifo->bit_line = BITLINE_INF; + + errcode = usb_submit_urb(fifo->iso[i].urb, GFP_KERNEL); + fifo->active = (errcode >= 0) ? 1 : 0; + fifo->stop_gracefull = 0; + if (errcode < 0) { + printk(KERN_DEBUG "%s: %s: %s URB nr:%d\n", + hw->name, __func__, + symbolic(urb_errlist, errcode), i); + } + } + return fifo->active; +} + +static void +stop_iso_gracefull(struct usb_fifo *fifo) +{ + struct hfcsusb *hw = fifo->hw; + int i, timeout; + u_long flags; + + for (i = 0; i < 2; i++) { + spin_lock_irqsave(&hw->lock, flags); + if (debug) + printk(KERN_DEBUG "%s: %s for fifo %i.%i\n", + hw->name, __func__, fifo->fifonum, i); + fifo->stop_gracefull = 1; + spin_unlock_irqrestore(&hw->lock, flags); + } + + for (i = 0; i < 2; i++) { + timeout = 3; + while (fifo->stop_gracefull && timeout--) + schedule_timeout_interruptible((HZ/1000)*16); + if (debug && fifo->stop_gracefull) + printk(KERN_DEBUG "%s: ERROR %s for fifo %i.%i\n", + hw->name, __func__, fifo->fifonum, i); + } +} + +static void +stop_int_gracefull(struct usb_fifo *fifo) +{ + struct hfcsusb *hw = fifo->hw; + int timeout; + u_long flags; + + spin_lock_irqsave(&hw->lock, flags); + if (debug) + printk(KERN_DEBUG "%s: %s for fifo %i\n", + hw->name, __func__, fifo->fifonum); + fifo->stop_gracefull = 1; + spin_unlock_irqrestore(&hw->lock, flags); + + timeout = 3; + while (fifo->stop_gracefull && timeout--) + schedule_timeout_interruptible((HZ/1000)*3); + if (debug && fifo->stop_gracefull) + printk(KERN_DEBUG "%s: ERROR %s for fifo %i\n", + hw->name, __func__, fifo->fifonum); +} + +/* start the interrupt transfer for the given fifo */ +static void +start_int_fifo(struct usb_fifo *fifo) +{ + struct hfcsusb *hw = fifo->hw; + int errcode; + + if (debug) + printk(KERN_DEBUG "%s: %s: INT IN fifo:%d\n", + hw->name, __func__, fifo->fifonum); + + if (!fifo->urb) { + fifo->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!fifo->urb) + return; + } + usb_fill_int_urb(fifo->urb, fifo->hw->dev, fifo->pipe, + fifo->buffer, fifo->usb_packet_maxlen, + (usb_complete_t)rx_int_complete, fifo, fifo->intervall); + fifo->active = 1; + fifo->stop_gracefull = 0; + errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); + if (errcode) { + printk(KERN_DEBUG "%s: %s: submit URB: status:%i\n", + hw->name, __func__, errcode); + fifo->active = 0; + } +} + +static void +setPortMode(struct hfcsusb *hw) +{ + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s %s\n", hw->name, __func__, + (hw->protocol == ISDN_P_TE_S0) ? "TE" : "NT"); + + if (hw->protocol == ISDN_P_TE_S0) { + write_reg(hw, HFCUSB_SCTRL, 0x40); + write_reg(hw, HFCUSB_SCTRL_E, 0x00); + write_reg(hw, HFCUSB_CLKDEL, CLKDEL_TE); + write_reg(hw, HFCUSB_STATES, 3 | 0x10); + write_reg(hw, HFCUSB_STATES, 3); + } else { + write_reg(hw, HFCUSB_SCTRL, 0x44); + write_reg(hw, HFCUSB_SCTRL_E, 0x09); + write_reg(hw, HFCUSB_CLKDEL, CLKDEL_NT); + write_reg(hw, HFCUSB_STATES, 1 | 0x10); + write_reg(hw, HFCUSB_STATES, 1); + } +} + +static void +reset_hfcsusb(struct hfcsusb *hw) +{ + struct usb_fifo *fifo; + int i; + + if (debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + /* do Chip reset */ + write_reg(hw, HFCUSB_CIRM, 8); + + /* aux = output, reset off */ + write_reg(hw, HFCUSB_CIRM, 0x10); + + /* set USB_SIZE to match the wMaxPacketSize for INT or BULK transfers */ + write_reg(hw, HFCUSB_USB_SIZE, (hw->packet_size / 8) | + ((hw->packet_size / 8) << 4)); + + /* set USB_SIZE_I to match the the wMaxPacketSize for ISO transfers */ + write_reg(hw, HFCUSB_USB_SIZE_I, hw->iso_packet_size); + + /* enable PCM/GCI master mode */ + write_reg(hw, HFCUSB_MST_MODE1, 0); /* set default values */ + write_reg(hw, HFCUSB_MST_MODE0, 1); /* enable master mode */ + + /* init the fifos */ + write_reg(hw, HFCUSB_F_THRES, + (HFCUSB_TX_THRESHOLD / 8) | ((HFCUSB_RX_THRESHOLD / 8) << 4)); + + fifo = hw->fifos; + for (i = 0; i < HFCUSB_NUM_FIFOS; i++) { + write_reg(hw, HFCUSB_FIFO, i); /* select the desired fifo */ + fifo[i].max_size = + (i <= HFCUSB_B2_RX) ? MAX_BCH_SIZE : MAX_DFRAME_LEN; + fifo[i].last_urblen = 0; + + /* set 2 bit for D- & E-channel */ + write_reg(hw, HFCUSB_HDLC_PAR, ((i <= HFCUSB_B2_RX) ? 0 : 2)); + + /* enable all fifos */ + if (i == HFCUSB_D_TX) + write_reg(hw, HFCUSB_CON_HDLC, + (hw->protocol == ISDN_P_NT_S0) ? 0x08 : 0x09); + else + write_reg(hw, HFCUSB_CON_HDLC, 0x08); + write_reg(hw, HFCUSB_INC_RES_F, 2); /* reset the fifo */ + } + + write_reg(hw, HFCUSB_SCTRL_R, 0); /* disable both B receivers */ + handle_led(hw, LED_POWER_ON); +} + +/* start USB data pipes dependand on device's endpoint configuration */ +static void +hfcsusb_start_endpoint(struct hfcsusb *hw, int channel) +{ + /* quick check if endpoint already running */ + if ((channel == HFC_CHAN_D) && (hw->fifos[HFCUSB_D_RX].active)) + return; + if ((channel == HFC_CHAN_B1) && (hw->fifos[HFCUSB_B1_RX].active)) + return; + if ((channel == HFC_CHAN_B2) && (hw->fifos[HFCUSB_B2_RX].active)) + return; + if ((channel == HFC_CHAN_E) && (hw->fifos[HFCUSB_PCM_RX].active)) + return; + + /* start rx endpoints using USB INT IN method */ + if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) + start_int_fifo(hw->fifos + channel*2 + 1); + + /* start rx endpoints using USB ISO IN method */ + if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) { + switch (channel) { + case HFC_CHAN_D: + start_isoc_chain(hw->fifos + HFCUSB_D_RX, + ISOC_PACKETS_D, + (usb_complete_t)rx_iso_complete, + 16); + break; + case HFC_CHAN_E: + start_isoc_chain(hw->fifos + HFCUSB_PCM_RX, + ISOC_PACKETS_D, + (usb_complete_t)rx_iso_complete, + 16); + break; + case HFC_CHAN_B1: + start_isoc_chain(hw->fifos + HFCUSB_B1_RX, + ISOC_PACKETS_B, + (usb_complete_t)rx_iso_complete, + 16); + break; + case HFC_CHAN_B2: + start_isoc_chain(hw->fifos + HFCUSB_B2_RX, + ISOC_PACKETS_B, + (usb_complete_t)rx_iso_complete, + 16); + break; + } + } + + /* start tx endpoints using USB ISO OUT method */ + switch (channel) { + case HFC_CHAN_D: + start_isoc_chain(hw->fifos + HFCUSB_D_TX, + ISOC_PACKETS_B, + (usb_complete_t)tx_iso_complete, 1); + break; + case HFC_CHAN_B1: + start_isoc_chain(hw->fifos + HFCUSB_B1_TX, + ISOC_PACKETS_D, + (usb_complete_t)tx_iso_complete, 1); + break; + case HFC_CHAN_B2: + start_isoc_chain(hw->fifos + HFCUSB_B2_TX, + ISOC_PACKETS_B, + (usb_complete_t)tx_iso_complete, 1); + break; + } +} + +/* stop USB data pipes dependand on device's endpoint configuration */ +static void +hfcsusb_stop_endpoint(struct hfcsusb *hw, int channel) +{ + /* quick check if endpoint currently running */ + if ((channel == HFC_CHAN_D) && (!hw->fifos[HFCUSB_D_RX].active)) + return; + if ((channel == HFC_CHAN_B1) && (!hw->fifos[HFCUSB_B1_RX].active)) + return; + if ((channel == HFC_CHAN_B2) && (!hw->fifos[HFCUSB_B2_RX].active)) + return; + if ((channel == HFC_CHAN_E) && (!hw->fifos[HFCUSB_PCM_RX].active)) + return; + + /* rx endpoints using USB INT IN method */ + if (hw->cfg_used == CNF_3INT3ISO || hw->cfg_used == CNF_4INT3ISO) + stop_int_gracefull(hw->fifos + channel*2 + 1); + + /* rx endpoints using USB ISO IN method */ + if (hw->cfg_used == CNF_3ISO3ISO || hw->cfg_used == CNF_4ISO3ISO) + stop_iso_gracefull(hw->fifos + channel*2 + 1); + + /* tx endpoints using USB ISO OUT method */ + if (channel != HFC_CHAN_E) + stop_iso_gracefull(hw->fifos + channel*2); +} + + +/* Hardware Initialization */ +int +setup_hfcsusb(struct hfcsusb *hw) +{ + int err; + u_char b; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + /* check the chip id */ + if (read_reg_atomic(hw, HFCUSB_CHIP_ID, &b) != 1) { + printk(KERN_DEBUG "%s: %s: cannot read chip id\n", + hw->name, __func__); + return 1; + } + if (b != HFCUSB_CHIPID) { + printk(KERN_DEBUG "%s: %s: Invalid chip id 0x%02x\n", + hw->name, __func__, b); + return 1; + } + + /* first set the needed config, interface and alternate */ + err = usb_set_interface(hw->dev, hw->if_used, hw->alt_used); + + hw->led_state = 0; + + /* init the background machinery for control requests */ + hw->ctrl_read.bRequestType = 0xc0; + hw->ctrl_read.bRequest = 1; + hw->ctrl_read.wLength = cpu_to_le16(1); + hw->ctrl_write.bRequestType = 0x40; + hw->ctrl_write.bRequest = 0; + hw->ctrl_write.wLength = 0; + usb_fill_control_urb(hw->ctrl_urb, hw->dev, hw->ctrl_out_pipe, + (u_char *)&hw->ctrl_write, NULL, 0, + (usb_complete_t)ctrl_complete, hw); + + reset_hfcsusb(hw); + return 0; +} + +static void +release_hw(struct hfcsusb *hw) +{ + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + /* + * stop all endpoints gracefully + * TODO: mISDN_core should generate CLOSE_CHANNEL + * signals after calling mISDN_unregister_device() + */ + hfcsusb_stop_endpoint(hw, HFC_CHAN_D); + hfcsusb_stop_endpoint(hw, HFC_CHAN_B1); + hfcsusb_stop_endpoint(hw, HFC_CHAN_B2); + if (hw->fifos[HFCUSB_PCM_RX].pipe) + hfcsusb_stop_endpoint(hw, HFC_CHAN_E); + if (hw->protocol == ISDN_P_TE_S0) + l1_event(hw->dch.l1, CLOSE_CHANNEL); + + mISDN_unregister_device(&hw->dch.dev); + mISDN_freebchannel(&hw->bch[1]); + mISDN_freebchannel(&hw->bch[0]); + mISDN_freedchannel(&hw->dch); + + if (hw->ctrl_urb) { + usb_kill_urb(hw->ctrl_urb); + usb_free_urb(hw->ctrl_urb); + hw->ctrl_urb = NULL; + } + + if (hw->intf) + usb_set_intfdata(hw->intf, NULL); + list_del(&hw->list); + kfree(hw); + hw = NULL; +} + +static void +deactivate_bchannel(struct bchannel *bch) +{ + struct hfcsusb *hw = bch->hw; + u_long flags; + + if (bch->debug & DEBUG_HW) + printk(KERN_DEBUG "%s: %s: bch->nr(%i)\n", + hw->name, __func__, bch->nr); + + spin_lock_irqsave(&hw->lock, flags); + if (test_and_clear_bit(FLG_TX_NEXT, &bch->Flags)) { + dev_kfree_skb(bch->next_skb); + bch->next_skb = NULL; + } + if (bch->tx_skb) { + dev_kfree_skb(bch->tx_skb); + bch->tx_skb = NULL; + } + bch->tx_idx = 0; + if (bch->rx_skb) { + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } + clear_bit(FLG_ACTIVE, &bch->Flags); + clear_bit(FLG_TX_BUSY, &bch->Flags); + spin_unlock_irqrestore(&hw->lock, flags); + hfcsusb_setup_bch(bch, ISDN_P_NONE); + hfcsusb_stop_endpoint(hw, bch->nr); +} + +/* + * Layer 1 B-channel hardware access + */ +static int +hfc_bctrl(struct mISDNchannel *ch, u_int cmd, void *arg) +{ + struct bchannel *bch = container_of(ch, struct bchannel, ch); + int ret = -EINVAL; + + if (bch->debug & DEBUG_HW) + printk(KERN_DEBUG "%s: cmd:%x %p\n", __func__, cmd, arg); + + switch (cmd) { + case HW_TESTRX_RAW: + case HW_TESTRX_HDLC: + case HW_TESTRX_OFF: + ret = -EINVAL; + break; + + case CLOSE_CHANNEL: + test_and_clear_bit(FLG_OPEN, &bch->Flags); + if (test_bit(FLG_ACTIVE, &bch->Flags)) + deactivate_bchannel(bch); + ch->protocol = ISDN_P_NONE; + ch->peer = NULL; + module_put(THIS_MODULE); + ret = 0; + break; + case CONTROL_CHANNEL: + ret = channel_bctrl(bch, arg); + break; + default: + printk(KERN_WARNING "%s: unknown prim(%x)\n", + __func__, cmd); + } + return ret; +} + +static int +setup_instance(struct hfcsusb *hw, struct device *parent) +{ + u_long flags; + int err, i; + + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_DEBUG "%s: %s\n", hw->name, __func__); + + spin_lock_init(&hw->ctrl_lock); + spin_lock_init(&hw->lock); + + mISDN_initdchannel(&hw->dch, MAX_DFRAME_LEN_L1, ph_state); + hw->dch.debug = debug & 0xFFFF; + hw->dch.hw = hw; + hw->dch.dev.Dprotocols = (1 << ISDN_P_TE_S0) | (1 << ISDN_P_NT_S0); + hw->dch.dev.D.send = hfcusb_l2l1D; + hw->dch.dev.D.ctrl = hfc_dctrl; + + /* enable E-Channel logging */ + if (hw->fifos[HFCUSB_PCM_RX].pipe) + mISDN_initdchannel(&hw->ech, MAX_DFRAME_LEN_L1, NULL); + + hw->dch.dev.Bprotocols = (1 << (ISDN_P_B_RAW & ISDN_P_B_MASK)) | + (1 << (ISDN_P_B_HDLC & ISDN_P_B_MASK)); + hw->dch.dev.nrbchan = 2; + for (i = 0; i < 2; i++) { + hw->bch[i].nr = i + 1; + set_channelmap(i + 1, hw->dch.dev.channelmap); + hw->bch[i].debug = debug; + mISDN_initbchannel(&hw->bch[i], MAX_DATA_MEM); + hw->bch[i].hw = hw; + hw->bch[i].ch.send = hfcusb_l2l1B; + hw->bch[i].ch.ctrl = hfc_bctrl; + hw->bch[i].ch.nr = i + 1; + list_add(&hw->bch[i].ch.list, &hw->dch.dev.bchannels); + } + + hw->fifos[HFCUSB_B1_TX].bch = &hw->bch[0]; + hw->fifos[HFCUSB_B1_RX].bch = &hw->bch[0]; + hw->fifos[HFCUSB_B2_TX].bch = &hw->bch[1]; + hw->fifos[HFCUSB_B2_RX].bch = &hw->bch[1]; + hw->fifos[HFCUSB_D_TX].dch = &hw->dch; + hw->fifos[HFCUSB_D_RX].dch = &hw->dch; + hw->fifos[HFCUSB_PCM_RX].ech = &hw->ech; + hw->fifos[HFCUSB_PCM_TX].ech = &hw->ech; + + err = setup_hfcsusb(hw); + if (err) + goto out; + + snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s.%d", DRIVER_NAME, + hfcsusb_cnt + 1); + printk(KERN_INFO "%s: registered as '%s'\n", + DRIVER_NAME, hw->name); + + err = mISDN_register_device(&hw->dch.dev, parent, hw->name); + if (err) + goto out; + + hfcsusb_cnt++; + write_lock_irqsave(&HFClock, flags); + list_add_tail(&hw->list, &HFClist); + write_unlock_irqrestore(&HFClock, flags); + return 0; + +out: + mISDN_freebchannel(&hw->bch[1]); + mISDN_freebchannel(&hw->bch[0]); + mISDN_freedchannel(&hw->dch); + kfree(hw); + return err; +} + +static int +hfcsusb_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct hfcsusb *hw; + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *iface = intf->cur_altsetting; + struct usb_host_interface *iface_used = NULL; + struct usb_host_endpoint *ep; + struct hfcsusb_vdata *driver_info; + int ifnum = iface->desc.bInterfaceNumber, i, idx, alt_idx, + probe_alt_setting, vend_idx, cfg_used, *vcf, attr, cfg_found, + ep_addr, cmptbl[16], small_match, iso_packet_size, packet_size, + alt_used = 0; + + vend_idx = 0xffff; + for (i = 0; hfcsusb_idtab[i].idVendor; i++) { + if ((le16_to_cpu(dev->descriptor.idVendor) + == hfcsusb_idtab[i].idVendor) && + (le16_to_cpu(dev->descriptor.idProduct) + == hfcsusb_idtab[i].idProduct)) { + vend_idx = i; + continue; + } + } + + printk(KERN_DEBUG + "%s: interface(%d) actalt(%d) minor(%d) vend_idx(%d)\n", + __func__, ifnum, iface->desc.bAlternateSetting, + intf->minor, vend_idx); + + if (vend_idx == 0xffff) { + printk(KERN_WARNING + "%s: no valid vendor found in USB descriptor\n", + __func__); + return -EIO; + } + /* if vendor and product ID is OK, start probing alternate settings */ + alt_idx = 0; + small_match = -1; + + /* default settings */ + iso_packet_size = 16; + packet_size = 64; + + while (alt_idx < intf->num_altsetting) { + iface = intf->altsetting + alt_idx; + probe_alt_setting = iface->desc.bAlternateSetting; + cfg_used = 0; + + while (validconf[cfg_used][0]) { + cfg_found = 1; + vcf = validconf[cfg_used]; + ep = iface->endpoint; + memcpy(cmptbl, vcf, 16 * sizeof(int)); + + /* check for all endpoints in this alternate setting */ + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + ep_addr = ep->desc.bEndpointAddress; + + /* get endpoint base */ + idx = ((ep_addr & 0x7f) - 1) * 2; + if (ep_addr & 0x80) + idx++; + attr = ep->desc.bmAttributes; + + if (cmptbl[idx] != EP_NOP) { + if (cmptbl[idx] == EP_NUL) + cfg_found = 0; + if (attr == USB_ENDPOINT_XFER_INT + && cmptbl[idx] == EP_INT) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_BULK + && cmptbl[idx] == EP_BLK) + cmptbl[idx] = EP_NUL; + if (attr == USB_ENDPOINT_XFER_ISOC + && cmptbl[idx] == EP_ISO) + cmptbl[idx] = EP_NUL; + + if (attr == USB_ENDPOINT_XFER_INT && + ep->desc.bInterval < vcf[17]) { + cfg_found = 0; + } + } + ep++; + } + + for (i = 0; i < 16; i++) + if (cmptbl[i] != EP_NOP && cmptbl[i] != EP_NUL) + cfg_found = 0; + + if (cfg_found) { + if (small_match < cfg_used) { + small_match = cfg_used; + alt_used = probe_alt_setting; + iface_used = iface; + } + } + cfg_used++; + } + alt_idx++; + } /* (alt_idx < intf->num_altsetting) */ + + /* not found a valid USB Ta Endpoint config */ + if (small_match == -1) + return -EIO; + + iface = iface_used; + hw = kzalloc(sizeof(struct hfcsusb), GFP_KERNEL); + if (!hw) + return -ENOMEM; /* got no mem */ + snprintf(hw->name, MISDN_MAX_IDLEN - 1, "%s", DRIVER_NAME); + + ep = iface->endpoint; + vcf = validconf[small_match]; + + for (i = 0; i < iface->desc.bNumEndpoints; i++) { + struct usb_fifo *f; + + ep_addr = ep->desc.bEndpointAddress; + /* get endpoint base */ + idx = ((ep_addr & 0x7f) - 1) * 2; + if (ep_addr & 0x80) + idx++; + f = &hw->fifos[idx & 7]; + + /* init Endpoints */ + if (vcf[idx] == EP_NOP || vcf[idx] == EP_NUL) { + ep++; + continue; + } + switch (ep->desc.bmAttributes) { + case USB_ENDPOINT_XFER_INT: + f->pipe = usb_rcvintpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_INT; + packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + case USB_ENDPOINT_XFER_BULK: + if (ep_addr & 0x80) + f->pipe = usb_rcvbulkpipe(dev, + ep->desc.bEndpointAddress); + else + f->pipe = usb_sndbulkpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_BULK; + packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + case USB_ENDPOINT_XFER_ISOC: + if (ep_addr & 0x80) + f->pipe = usb_rcvisocpipe(dev, + ep->desc.bEndpointAddress); + else + f->pipe = usb_sndisocpipe(dev, + ep->desc.bEndpointAddress); + f->usb_transfer_mode = USB_ISOC; + iso_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize); + break; + default: + f->pipe = 0; + } + + if (f->pipe) { + f->fifonum = idx & 7; + f->hw = hw; + f->usb_packet_maxlen = + le16_to_cpu(ep->desc.wMaxPacketSize); + f->intervall = ep->desc.bInterval; + } + ep++; + } + hw->dev = dev; /* save device */ + hw->if_used = ifnum; /* save used interface */ + hw->alt_used = alt_used; /* and alternate config */ + hw->ctrl_paksize = dev->descriptor.bMaxPacketSize0; /* control size */ + hw->cfg_used = vcf[16]; /* store used config */ + hw->vend_idx = vend_idx; /* store found vendor */ + hw->packet_size = packet_size; + hw->iso_packet_size = iso_packet_size; + + /* create the control pipes needed for register access */ + hw->ctrl_in_pipe = usb_rcvctrlpipe(hw->dev, 0); + hw->ctrl_out_pipe = usb_sndctrlpipe(hw->dev, 0); + hw->ctrl_urb = usb_alloc_urb(0, GFP_KERNEL); + + driver_info = + (struct hfcsusb_vdata *)hfcsusb_idtab[vend_idx].driver_info; + printk(KERN_DEBUG "%s: %s: detected \"%s\" (%s, if=%d alt=%d)\n", + hw->name, __func__, driver_info->vend_name, + conf_str[small_match], ifnum, alt_used); + + if (setup_instance(hw, dev->dev.parent)) + return -EIO; + + hw->intf = intf; + usb_set_intfdata(hw->intf, hw); + return 0; +} + +/* function called when an active device is removed */ +static void +hfcsusb_disconnect(struct usb_interface *intf) +{ + struct hfcsusb *hw = usb_get_intfdata(intf); + struct hfcsusb *next; + int cnt = 0; + + printk(KERN_INFO "%s: device disconnected\n", hw->name); + + handle_led(hw, LED_POWER_OFF); + release_hw(hw); + + list_for_each_entry_safe(hw, next, &HFClist, list) + cnt++; + if (!cnt) + hfcsusb_cnt = 0; + + usb_set_intfdata(intf, NULL); +} + +static struct usb_driver hfcsusb_drv = { + .name = DRIVER_NAME, + .id_table = hfcsusb_idtab, + .probe = hfcsusb_probe, + .disconnect = hfcsusb_disconnect, +}; + +static int __init +hfcsusb_init(void) +{ + printk(KERN_INFO DRIVER_NAME " driver Rev. %s debug(0x%x) poll(%i)\n", + hfcsusb_rev, debug, poll); + + if (usb_register(&hfcsusb_drv)) { + printk(KERN_INFO DRIVER_NAME + ": Unable to register hfcsusb module at usb stack\n"); + return -ENODEV; + } + + return 0; +} + +static void __exit +hfcsusb_cleanup(void) +{ + if (debug & DBG_HFC_CALL_TRACE) + printk(KERN_INFO DRIVER_NAME ": %s\n", __func__); + + /* unregister Hardware */ + usb_deregister(&hfcsusb_drv); /* release our driver */ +} + +module_init(hfcsusb_init); +module_exit(hfcsusb_cleanup); diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h new file mode 100644 index 00000000000..098486b8e8d --- /dev/null +++ b/drivers/isdn/hardware/mISDN/hfcsusb.h @@ -0,0 +1,418 @@ +/* + * hfcsusb.h, HFC-S USB mISDN driver + */ + +#ifndef __HFCSUSB_H__ +#define __HFCSUSB_H__ + + +#define DRIVER_NAME "HFC-S_USB" + +#define DBG_HFC_CALL_TRACE 0x00010000 +#define DBG_HFC_FIFO_VERBOSE 0x00020000 +#define DBG_HFC_USB_VERBOSE 0x00100000 +#define DBG_HFC_URB_INFO 0x00200000 +#define DBG_HFC_URB_ERROR 0x00400000 + +#define DEFAULT_TRANSP_BURST_SZ 128 + +#define HFC_CTRL_TIMEOUT 20 /* 5ms timeout writing/reading regs */ +#define CLKDEL_TE 0x0f /* CLKDEL in TE mode */ +#define CLKDEL_NT 0x6c /* CLKDEL in NT mode */ + +/* hfcsusb Layer1 commands */ +#define HFC_L1_ACTIVATE_TE 1 +#define HFC_L1_ACTIVATE_NT 2 +#define HFC_L1_DEACTIVATE_NT 3 +#define HFC_L1_FORCE_DEACTIVATE_TE 4 + +/* cmd FLAGS in HFCUSB_STATES register */ +#define HFCUSB_LOAD_STATE 0x10 +#define HFCUSB_ACTIVATE 0x20 +#define HFCUSB_DO_ACTION 0x40 +#define HFCUSB_NT_G2_G3 0x80 + +/* timers */ +#define NT_ACTIVATION_TIMER 0x01 /* enables NT mode activation Timer */ +#define NT_T1_COUNT 10 + +#define MAX_BCH_SIZE 2048 /* allowed B-channel packet size */ + +#define HFCUSB_RX_THRESHOLD 64 /* threshold for fifo report bit rx */ +#define HFCUSB_TX_THRESHOLD 96 /* threshold for fifo report bit tx */ + +#define HFCUSB_CHIP_ID 0x16 /* Chip ID register index */ +#define HFCUSB_CIRM 0x00 /* cirm register index */ +#define HFCUSB_USB_SIZE 0x07 /* int length register */ +#define HFCUSB_USB_SIZE_I 0x06 /* iso length register */ +#define HFCUSB_F_CROSS 0x0b /* bit order register */ +#define HFCUSB_CLKDEL 0x37 /* bit delay register */ +#define HFCUSB_CON_HDLC 0xfa /* channel connect register */ +#define HFCUSB_HDLC_PAR 0xfb +#define HFCUSB_SCTRL 0x31 /* S-bus control register (tx) */ +#define HFCUSB_SCTRL_E 0x32 /* same for E and special funcs */ +#define HFCUSB_SCTRL_R 0x33 /* S-bus control register (rx) */ +#define HFCUSB_F_THRES 0x0c /* threshold register */ +#define HFCUSB_FIFO 0x0f /* fifo select register */ +#define HFCUSB_F_USAGE 0x1a /* fifo usage register */ +#define HFCUSB_MST_MODE0 0x14 +#define HFCUSB_MST_MODE1 0x15 +#define HFCUSB_P_DATA 0x1f +#define HFCUSB_INC_RES_F 0x0e +#define HFCUSB_B1_SSL 0x20 +#define HFCUSB_B2_SSL 0x21 +#define HFCUSB_B1_RSL 0x24 +#define HFCUSB_B2_RSL 0x25 +#define HFCUSB_STATES 0x30 + + +#define HFCUSB_CHIPID 0x40 /* ID value of HFC-S USB */ + +/* fifo registers */ +#define HFCUSB_NUM_FIFOS 8 /* maximum number of fifos */ +#define HFCUSB_B1_TX 0 /* index for B1 transmit bulk/int */ +#define HFCUSB_B1_RX 1 /* index for B1 receive bulk/int */ +#define HFCUSB_B2_TX 2 +#define HFCUSB_B2_RX 3 +#define HFCUSB_D_TX 4 +#define HFCUSB_D_RX 5 +#define HFCUSB_PCM_TX 6 +#define HFCUSB_PCM_RX 7 + + +#define USB_INT 0 +#define USB_BULK 1 +#define USB_ISOC 2 + +#define ISOC_PACKETS_D 8 +#define ISOC_PACKETS_B 8 +#define ISO_BUFFER_SIZE 128 + +/* defines how much ISO packets are handled in one URB */ +static int iso_packets[8] = + { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, + ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D +}; + + +/* Fifo flow Control for TX ISO */ +#define SINK_MAX 68 +#define SINK_MIN 48 +#define SINK_DMIN 12 +#define SINK_DMAX 18 +#define BITLINE_INF (-96*8) + +/* HFC-S USB register access by Control-URSs */ +#define write_reg_atomic(a, b, c) \ + usb_control_msg((a)->dev, (a)->ctrl_out_pipe, 0, 0x40, (c), (b), \ + 0, 0, HFC_CTRL_TIMEOUT) +#define read_reg_atomic(a, b, c) \ + usb_control_msg((a)->dev, (a)->ctrl_in_pipe, 1, 0xC0, 0, (b), (c), \ + 1, HFC_CTRL_TIMEOUT) +#define HFC_CTRL_BUFSIZE 64 + +struct ctrl_buf { + __u8 hfcs_reg; /* register number */ + __u8 reg_val; /* value to be written (or read) */ +}; + +/* + * URB error codes + * Used to represent a list of values and their respective symbolic names + */ +struct hfcusb_symbolic_list { + const int num; + const char *name; +}; + +static struct hfcusb_symbolic_list urb_errlist[] = { + {-ENOMEM, "No memory for allocation of internal structures"}, + {-ENOSPC, "The host controller's bandwidth is already consumed"}, + {-ENOENT, "URB was canceled by unlink_urb"}, + {-EXDEV, "ISO transfer only partially completed"}, + {-EAGAIN, "Too match scheduled for the future"}, + {-ENXIO, "URB already queued"}, + {-EFBIG, "Too much ISO frames requested"}, + {-ENOSR, "Buffer error (overrun)"}, + {-EPIPE, "Specified endpoint is stalled (device not responding)"}, + {-EOVERFLOW, "Babble (bad cable?)"}, + {-EPROTO, "Bit-stuff error (bad cable?)"}, + {-EILSEQ, "CRC/Timeout"}, + {-ETIMEDOUT, "NAK (device does not respond)"}, + {-ESHUTDOWN, "Device unplugged"}, + {-1, NULL} +}; + +static inline const char * +symbolic(struct hfcusb_symbolic_list list[], const int num) +{ + int i; + for (i = 0; list[i].name != NULL; i++) + if (list[i].num == num) + return list[i].name; + return "<unkown USB Error>"; +} + +/* USB descriptor need to contain one of the following EndPoint combination: */ +#define CNF_4INT3ISO 1 /* 4 INT IN, 3 ISO OUT */ +#define CNF_3INT3ISO 2 /* 3 INT IN, 3 ISO OUT */ +#define CNF_4ISO3ISO 3 /* 4 ISO IN, 3 ISO OUT */ +#define CNF_3ISO3ISO 4 /* 3 ISO IN, 3 ISO OUT */ + +#define EP_NUL 1 /* Endpoint at this position not allowed */ +#define EP_NOP 2 /* all type of endpoints allowed at this position */ +#define EP_ISO 3 /* Isochron endpoint mandatory at this position */ +#define EP_BLK 4 /* Bulk endpoint mandatory at this position */ +#define EP_INT 5 /* Interrupt endpoint mandatory at this position */ + +#define HFC_CHAN_B1 0 +#define HFC_CHAN_B2 1 +#define HFC_CHAN_D 2 +#define HFC_CHAN_E 3 + + +/* + * List of all supported enpoints configiration sets, used to find the + * best matching endpoint configuration within a devices' USB descriptor. + * We need at least 3 RX endpoints, and 3 TX endpoints, either + * INT-in and ISO-out, or ISO-in and ISO-out) + * with 4 RX endpoints even E-Channel logging is possible + */ +static int +validconf[][19] = { + /* INT in, ISO out config */ + {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT, + EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, + CNF_4INT3ISO, 2, 1}, + {EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_NUL, + EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL, + CNF_3INT3ISO, 2, 0}, + /* ISO in, ISO out config */ + {EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, EP_NOP, + EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NOP, EP_ISO, + CNF_4ISO3ISO, 2, 1}, + {EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, EP_NUL, + EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_ISO, EP_NUL, EP_NUL, + CNF_3ISO3ISO, 2, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} /* EOL element */ +}; + +/* string description of chosen config */ +char *conf_str[] = { + "4 Interrupt IN + 3 Isochron OUT", + "3 Interrupt IN + 3 Isochron OUT", + "4 Isochron IN + 3 Isochron OUT", + "3 Isochron IN + 3 Isochron OUT" +}; + + +#define LED_OFF 0 /* no LED support */ +#define LED_SCHEME1 1 /* LED standard scheme */ +#define LED_SCHEME2 2 /* not used yet... */ + +#define LED_POWER_ON 1 +#define LED_POWER_OFF 2 +#define LED_S0_ON 3 +#define LED_S0_OFF 4 +#define LED_B1_ON 5 +#define LED_B1_OFF 6 +#define LED_B1_DATA 7 +#define LED_B2_ON 8 +#define LED_B2_OFF 9 +#define LED_B2_DATA 10 + +#define LED_NORMAL 0 /* LEDs are normal */ +#define LED_INVERTED 1 /* LEDs are inverted */ + +/* time in ms to perform a Flashing LED when B-Channel has traffic */ +#define LED_TIME 250 + + + +struct hfcsusb; +struct usb_fifo; + +/* structure defining input+output fifos (interrupt/bulk mode) */ +struct iso_urb { + struct urb *urb; + __u8 buffer[ISO_BUFFER_SIZE]; /* buffer rx/tx USB URB data */ + struct usb_fifo *owner_fifo; /* pointer to owner fifo */ + __u8 indx; /* Fifos's ISO double buffer 0 or 1 ? */ +#ifdef ISO_FRAME_START_DEBUG + int start_frames[ISO_FRAME_START_RING_COUNT]; + __u8 iso_frm_strt_pos; /* index in start_frame[] */ +#endif +}; + +struct usb_fifo { + int fifonum; /* fifo index attached to this structure */ + int active; /* fifo is currently active */ + struct hfcsusb *hw; /* pointer to main structure */ + int pipe; /* address of endpoint */ + __u8 usb_packet_maxlen; /* maximum length for usb transfer */ + unsigned int max_size; /* maximum size of receive/send packet */ + __u8 intervall; /* interrupt interval */ + struct urb *urb; /* transfer structure for usb routines */ + __u8 buffer[128]; /* buffer USB INT OUT URB data */ + int bit_line; /* how much bits are in the fifo? */ + + __u8 usb_transfer_mode; /* switched between ISO and INT */ + struct iso_urb iso[2]; /* two urbs to have one always + one pending */ + + struct dchannel *dch; /* link to hfcsusb_t->dch */ + struct bchannel *bch; /* link to hfcsusb_t->bch */ + struct dchannel *ech; /* link to hfcsusb_t->ech, TODO: E-CHANNEL */ + int last_urblen; /* remember length of last packet */ + __u8 stop_gracefull; /* stops URB retransmission */ +}; + +struct hfcsusb { + struct list_head list; + struct dchannel dch; + struct bchannel bch[2]; + struct dchannel ech; /* TODO : wait for struct echannel ;) */ + + struct usb_device *dev; /* our device */ + struct usb_interface *intf; /* used interface */ + int if_used; /* used interface number */ + int alt_used; /* used alternate config */ + int cfg_used; /* configuration index used */ + int vend_idx; /* index in hfcsusb_idtab */ + int packet_size; + int iso_packet_size; + struct usb_fifo fifos[HFCUSB_NUM_FIFOS]; + + /* control pipe background handling */ + struct ctrl_buf ctrl_buff[HFC_CTRL_BUFSIZE]; + int ctrl_in_idx, ctrl_out_idx, ctrl_cnt; + struct urb *ctrl_urb; + struct usb_ctrlrequest ctrl_write; + struct usb_ctrlrequest ctrl_read; + int ctrl_paksize; + int ctrl_in_pipe, ctrl_out_pipe; + spinlock_t ctrl_lock; /* lock for ctrl */ + spinlock_t lock; + + __u8 threshold_mask; + __u8 led_state; + + __u8 protocol; + int nt_timer; + int open; + __u8 timers; + __u8 initdone; + char name[MISDN_MAX_IDLEN]; +}; + +/* private vendor specific data */ +struct hfcsusb_vdata { + __u8 led_scheme; /* led display scheme */ + signed short led_bits[8]; /* array of 8 possible LED bitmask */ + char *vend_name; /* device name */ +}; + + +#define HFC_MAX_TE_LAYER1_STATE 8 +#define HFC_MAX_NT_LAYER1_STATE 4 + +const char *HFC_TE_LAYER1_STATES[HFC_MAX_TE_LAYER1_STATE + 1] = { + "TE F0 - Reset", + "TE F1 - Reset", + "TE F2 - Sensing", + "TE F3 - Deactivated", + "TE F4 - Awaiting signal", + "TE F5 - Identifying input", + "TE F6 - Synchronized", + "TE F7 - Activated", + "TE F8 - Lost framing", +}; + +const char *HFC_NT_LAYER1_STATES[HFC_MAX_NT_LAYER1_STATE + 1] = { + "NT G0 - Reset", + "NT G1 - Deactive", + "NT G2 - Pending activation", + "NT G3 - Active", + "NT G4 - Pending deactivation", +}; + +/* supported devices */ +static struct usb_device_id hfcsusb_idtab[] = { + { + USB_DEVICE(0x0959, 0x2bd0), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_OFF, {4, 0, 2, 1}, + "ISDN USB TA (Cologne Chip HFC-S USB based)"}), + }, + { + USB_DEVICE(0x0675, 0x1688), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {1, 2, 0, 0}, + "DrayTek miniVigor 128 USB ISDN TA"}), + }, + { + USB_DEVICE(0x07b0, 0x0007), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Billion tiny USB ISDN TA 128"}), + }, + { + USB_DEVICE(0x0742, 0x2008), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "Stollmann USB TA"}), + }, + { + USB_DEVICE(0x0742, 0x2009), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "Aceex USB ISDN TA"}), + }, + { + USB_DEVICE(0x0742, 0x200A), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {4, 0, 2, 1}, + "OEM USB ISDN TA"}), + }, + { + USB_DEVICE(0x08e3, 0x0301), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {2, 0, 1, 4}, + "Olitec USB RNIS"}), + }, + { + USB_DEVICE(0x07fa, 0x0846), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Bewan Modem RNIS USB"}), + }, + { + USB_DEVICE(0x07fa, 0x0847), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Djinn Numeris USB"}), + }, + { + USB_DEVICE(0x07b0, 0x0006), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x80, -64, -32, -16}, + "Twister ISDN TA"}), + }, + { + USB_DEVICE(0x071d, 0x1005), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x02, 0, 0x01, 0x04}, + "Eicon DIVA USB 4.0"}), + }, + { + USB_DEVICE(0x0586, 0x0102), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x88, -64, -32, -16}, + "ZyXEL OMNI.NET USB II"}), + }, + { } +}; + +MODULE_DEVICE_TABLE(usb, hfcsusb_idtab); + +#endif /* __HFCSUSB_H__ */ diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 7ee5bd9f2bb..579974cf4c9 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -38,16 +38,12 @@ char *hysdn_net_revision = "$Revision: 1.8.6.4 $"; /* inside the definition. */ /****************************************************************************/ struct net_local { - struct net_device netdev; /* the network device */ - struct net_device_stats stats; - /* additional vars may be added here */ - char dev_name[9]; /* our own device name */ - /* Tx control lock. This protects the transmit buffer ring * state along with the "tx full" state of the driver. This * means all netif_queue flow control actions are protected * by this lock as well. */ + struct net_device *dev; spinlock_t lock; struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */ int in_idx, out_idx; /* indexes to buffer ring */ @@ -55,15 +51,6 @@ struct net_local { }; /* net_local */ -/*****************************************************/ -/* Get the current statistics for this card. */ -/* This may be called with the card open or closed ! */ -/*****************************************************/ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - return (&((struct net_local *) dev)->stats); -} /* net_device_stats */ /*********************************************************************/ /* Open/initialize the board. This is called (in the current kernel) */ @@ -182,8 +169,8 @@ hysdn_tx_netack(hysdn_card * card) if (!lp->sk_count) return; /* error condition */ - lp->stats.tx_packets++; - lp->stats.tx_bytes += lp->skbs[lp->out_idx]->len; + lp->dev->stats.tx_packets++; + lp->dev->stats.tx_bytes += lp->skbs[lp->out_idx]->len; dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */ if (lp->out_idx >= MAX_SKB_BUFFERS) @@ -200,29 +187,30 @@ void hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len) { struct net_local *lp = card->netif; + struct net_device *dev = lp->dev; struct sk_buff *skb; if (!lp) return; /* non existing device */ - lp->stats.rx_bytes += len; + dev->stats.rx_bytes += len; skb = dev_alloc_skb(len); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - lp->netdev.name); - lp->stats.rx_dropped++; + dev->name); + dev->stats.rx_dropped++; return; } /* copy the data */ memcpy(skb_put(skb, len), buf, len); /* determine the used protocol */ - skb->protocol = eth_type_trans(skb, &lp->netdev); + skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - lp->stats.rx_packets++; /* adjust packet count */ + dev->stats.rx_packets++; /* adjust packet count */ + netif_rx(skb); } /* hysdn_rx_netpkt */ /*****************************************************/ @@ -242,24 +230,15 @@ hysdn_tx_netget(hysdn_card * card) return (lp->skbs[lp->out_idx]); /* next packet to send */ } /* hysdn_tx_netget */ +static const struct net_device_ops hysdn_netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = net_send_packet, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; -/*******************************************/ -/* init function called by register device */ -/*******************************************/ -static int -net_init(struct net_device *dev) -{ - /* setup the function table */ - dev->open = net_open; - dev->stop = net_close; - dev->hard_start_xmit = net_send_packet; - dev->get_stats = net_get_stats; - - /* Fill in the fields of the device structure with ethernet values. */ - ether_setup(dev); - - return (0); /* success */ -} /* net_init */ /*****************************************************************************/ /* hysdn_net_create creates a new net device for the given card. If a device */ @@ -271,28 +250,34 @@ hysdn_net_create(hysdn_card * card) { struct net_device *dev; int i; + struct net_local *lp; + if(!card) { printk(KERN_WARNING "No card-pt in hysdn_net_create!\n"); return (-ENOMEM); } hysdn_net_release(card); /* release an existing net device */ - if ((dev = kzalloc(sizeof(struct net_local), GFP_KERNEL)) == NULL) { + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) { printk(KERN_WARNING "HYSDN: unable to allocate mem\n"); return (-ENOMEM); } + lp = netdev_priv(dev); + lp->dev = dev; + + dev->netdev_ops = &hysdn_netdev_ops; spin_lock_init(&((struct net_local *) dev)->lock); /* initialise necessary or informing fields */ dev->base_addr = card->iobase; /* IO address */ dev->irq = card->irq; /* irq */ - dev->init = net_init; /* the init function of the device */ - if(dev->name) { - strcpy(dev->name, ((struct net_local *) dev)->dev_name); - } + + dev->netdev_ops = &hysdn_netdev_ops; if ((i = register_netdev(dev))) { printk(KERN_WARNING "HYSDN: unable to create network device\n"); - kfree(dev); + free_netdev(dev); return (i); } dev->ml_priv = card; /* remember pointer to own data structure */ @@ -316,7 +301,7 @@ hysdn_net_release(hysdn_card * card) return (0); /* non existing */ card->netif = NULL; /* clear out pointer */ - dev->stop(dev); /* close the device */ + net_close(dev); flush_tx_buffers((struct net_local *) dev); /* empty buffers */ diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 023ea11d2f9..7c5f97033b9 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1485,6 +1485,24 @@ isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return (rc); } + +static int isdn_net_ioctl(struct net_device *dev, + struct ifreq *ifr, int cmd) +{ + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); + + switch (lp->p_encap) { +#ifdef CONFIG_ISDN_PPP + case ISDN_NET_ENCAP_SYNCPPP: + return isdn_ppp_dev_ioctl(dev, ifr, cmd); +#endif + case ISDN_NET_ENCAP_CISCOHDLCK: + return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd); + default: + return -EINVAL; + } +} + /* called via cisco_timer.function */ static void isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) @@ -1998,23 +2016,6 @@ isdn_net_init(struct net_device *ndev) ushort max_hlhdr_len = 0; int drvidx; - ether_setup(ndev); - ndev->header_ops = NULL; - - /* Setup the generic properties */ - ndev->mtu = 1500; - ndev->flags = IFF_NOARP|IFF_POINTOPOINT; - ndev->type = ARPHRD_ETHER; - ndev->addr_len = ETH_ALEN; - ndev->validate_addr = NULL; - - /* for clients with MPPP maybe higher values better */ - ndev->tx_queue_len = 30; - - /* The ISDN-specific entries in the device structure. */ - ndev->open = &isdn_net_open; - ndev->hard_start_xmit = &isdn_net_start_xmit; - /* * up till binding we ask the protocol layer to reserve as much * as we might need for HL layer @@ -2026,9 +2027,6 @@ isdn_net_init(struct net_device *ndev) max_hlhdr_len = dev->drv[drvidx]->interface->hl_hdrlen; ndev->hard_header_len = ETH_HLEN + max_hlhdr_len; - ndev->stop = &isdn_net_close; - ndev->get_stats = &isdn_net_get_stats; - ndev->do_ioctl = NULL; return 0; } @@ -2508,6 +2506,19 @@ isdn_net_force_dial(char *name) return (isdn_net_force_dial_lp(p->local)); } +/* The ISDN-specific entries in the device structure. */ +static const struct net_device_ops isdn_netdev_ops = { + .ndo_init = isdn_net_init, + .ndo_open = isdn_net_open, + .ndo_stop = isdn_net_close, + .ndo_do_ioctl = isdn_net_ioctl, + + .ndo_validate_addr = NULL, + .ndo_start_xmit = isdn_net_start_xmit, + .ndo_get_stats = isdn_net_get_stats, + .ndo_tx_timeout = isdn_net_tx_timeout, +}; + /* * Helper for alloc_netdev() */ @@ -2515,7 +2526,20 @@ static void _isdn_setup(struct net_device *dev) { isdn_net_local *lp = netdev_priv(dev); + ether_setup(dev); + dev->flags = IFF_NOARP | IFF_POINTOPOINT; + /* Setup the generic properties */ + dev->mtu = 1500; + dev->flags = IFF_NOARP|IFF_POINTOPOINT; + dev->type = ARPHRD_ETHER; + dev->addr_len = ETH_ALEN; + dev->header_ops = NULL; + dev->netdev_ops = &isdn_netdev_ops; + + /* for clients with MPPP maybe higher values better */ + dev->tx_queue_len = 30; + lp->p_encap = ISDN_NET_ENCAP_RAWIP; lp->magic = ISDN_NET_MAGIC; lp->last = lp; @@ -2570,7 +2594,7 @@ isdn_net_new(char *name, struct net_device *master) return NULL; } netdev->local = netdev_priv(netdev->dev); - netdev->dev->init = isdn_net_init; + if (master) { /* Device shall be a slave */ struct net_device *p = MASTER_TO_SLAVE(master); @@ -2588,7 +2612,6 @@ isdn_net_new(char *name, struct net_device *master) /* * Watchdog timer (currently) for master only. */ - netdev->dev->tx_timeout = isdn_net_tx_timeout; netdev->dev->watchdog_timeo = ISDN_NET_TX_TIMEOUT; if (register_netdev(netdev->dev) != 0) { printk(KERN_WARNING "isdn_net: Could not register net-device\n"); @@ -2704,7 +2727,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) #else p->dev->type = ARPHRD_PPP; /* change ARP type */ p->dev->addr_len = 0; - p->dev->do_ioctl = isdn_ppp_dev_ioctl; #endif break; case ISDN_NET_ENCAP_X25IFACE: @@ -2718,7 +2740,6 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) #endif break; case ISDN_NET_ENCAP_CISCOHDLCK: - p->dev->do_ioctl = isdn_ciscohdlck_dev_ioctl; break; default: if( cfg->p_encap >= 0 && diff --git a/drivers/isdn/mISDN/Makefile b/drivers/isdn/mISDN/Makefile index 1cb5e633cf7..0a6bd2a9e73 100644 --- a/drivers/isdn/mISDN/Makefile +++ b/drivers/isdn/mISDN/Makefile @@ -8,6 +8,6 @@ obj-$(CONFIG_MISDN_L1OIP) += l1oip.o # multi objects -mISDN_core-objs := core.o fsm.o socket.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o +mISDN_core-objs := core.o fsm.o socket.o clock.o hwchannel.o stack.o layer1.o layer2.o tei.o timerdev.o mISDN_dsp-objs := dsp_core.o dsp_cmx.o dsp_tones.o dsp_dtmf.o dsp_audio.o dsp_blowfish.o dsp_pipeline.o dsp_hwec.o l1oip-objs := l1oip_core.o l1oip_codec.o diff --git a/drivers/isdn/mISDN/clock.c b/drivers/isdn/mISDN/clock.c new file mode 100644 index 00000000000..44d9c3d5d33 --- /dev/null +++ b/drivers/isdn/mISDN/clock.c @@ -0,0 +1,216 @@ +/* + * Copyright 2008 by Andreas Eversberg <andreas@eversberg.eu> + * + * 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. + * + * 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. + * + * Quick API description: + * + * A clock source registers using mISDN_register_clock: + * name = text string to name clock source + * priority = value to priorize clock sources (0 = default) + * ctl = callback function to enable/disable clock source + * priv = private pointer of clock source + * return = pointer to clock source structure; + * + * Note: Callback 'ctl' can be called before mISDN_register_clock returns! + * Also it can be called during mISDN_unregister_clock. + * + * A clock source calls mISDN_clock_update with given samples elapsed, if + * enabled. If function call is delayed, tv must be set with the timestamp + * of the actual event. + * + * A clock source unregisters using mISDN_unregister_clock. + * + * To get current clock, call mISDN_clock_get. The signed short value + * counts the number of samples since. Time since last clock event is added. + * + */ + +#include <linux/types.h> +#include <linux/stddef.h> +#include <linux/spinlock.h> +#include <linux/mISDNif.h> +#include "core.h" + +static u_int *debug; +static LIST_HEAD(iclock_list); +DEFINE_RWLOCK(iclock_lock); +u16 iclock_count; /* counter of last clock */ +struct timeval iclock_tv; /* time stamp of last clock */ +int iclock_tv_valid; /* already received one timestamp */ +struct mISDNclock *iclock_current; + +void +mISDN_init_clock(u_int *dp) +{ + debug = dp; + do_gettimeofday(&iclock_tv); +} + +static void +select_iclock(void) +{ + struct mISDNclock *iclock, *bestclock = NULL, *lastclock = NULL; + int pri = -128; + + list_for_each_entry(iclock, &iclock_list, list) { + if (iclock->pri > pri) { + pri = iclock->pri; + bestclock = iclock; + } + if (iclock_current == iclock) + lastclock = iclock; + } + if (lastclock && bestclock != lastclock) { + /* last used clock source still exists but changes, disable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "Old clock source '%s' disable.\n", + lastclock->name); + lastclock->ctl(lastclock->priv, 0); + } + if (bestclock && bestclock != iclock_current) { + /* new clock source selected, enable */ + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG "New clock source '%s' enable.\n", + bestclock->name); + bestclock->ctl(bestclock->priv, 1); + } + if (bestclock != iclock_current) { + /* no clock received yet */ + iclock_tv_valid = 0; + } + iclock_current = bestclock; +} + +struct mISDNclock +*mISDN_register_clock(char *name, int pri, clockctl_func_t *ctl, void *priv) +{ + u_long flags; + struct mISDNclock *iclock; + + if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) + printk(KERN_DEBUG "%s: %s %d\n", __func__, name, pri); + iclock = kzalloc(sizeof(struct mISDNclock), GFP_ATOMIC); + if (!iclock) { + printk(KERN_ERR "%s: No memory for clock entry.\n", __func__); + return NULL; + } + strncpy(iclock->name, name, sizeof(iclock->name)-1); + iclock->pri = pri; + iclock->priv = priv; + iclock->ctl = ctl; + write_lock_irqsave(&iclock_lock, flags); + list_add_tail(&iclock->list, &iclock_list); + select_iclock(); + write_unlock_irqrestore(&iclock_lock, flags); + return iclock; +} +EXPORT_SYMBOL(mISDN_register_clock); + +void +mISDN_unregister_clock(struct mISDNclock *iclock) +{ + u_long flags; + + if (*debug & (DEBUG_CORE | DEBUG_CLOCK)) + printk(KERN_DEBUG "%s: %s %d\n", __func__, iclock->name, + iclock->pri); + write_lock_irqsave(&iclock_lock, flags); + if (iclock_current == iclock) { + if (*debug & DEBUG_CLOCK) + printk(KERN_DEBUG + "Current clock source '%s' unregisters.\n", + iclock->name); + iclock->ctl(iclock->priv, 0); + } + list_del(&iclock->list); + select_iclock(); + write_unlock_irqrestore(&iclock_lock, flags); +} +EXPORT_SYMBOL(mISDN_unregister_clock); + +void +mISDN_clock_update(struct mISDNclock *iclock, int samples, struct timeval *tv) +{ + u_long flags; + struct timeval tv_now; + time_t elapsed_sec; + int elapsed_8000th; + + write_lock_irqsave(&iclock_lock, flags); + if (iclock_current != iclock) { + printk(KERN_ERR "%s: '%s' sends us clock updates, but we do " + "listen to '%s'. This is a bug!\n", __func__, + iclock->name, + iclock_current ? iclock_current->name : "nothing"); + iclock->ctl(iclock->priv, 0); + write_unlock_irqrestore(&iclock_lock, flags); + return; + } + if (iclock_tv_valid) { + /* increment sample counter by given samples */ + iclock_count += samples; + if (tv) { /* tv must be set, if function call is delayed */ + iclock_tv.tv_sec = tv->tv_sec; + iclock_tv.tv_usec = tv->tv_usec; + } else + do_gettimeofday(&iclock_tv); + } else { + /* calc elapsed time by system clock */ + if (tv) { /* tv must be set, if function call is delayed */ + tv_now.tv_sec = tv->tv_sec; + tv_now.tv_usec = tv->tv_usec; + } else + do_gettimeofday(&tv_now); + elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; + elapsed_8000th = (tv_now.tv_usec / 125) + - (iclock_tv.tv_usec / 125); + if (elapsed_8000th < 0) { + elapsed_sec -= 1; + elapsed_8000th += 8000; + } + /* add elapsed time to counter and set new timestamp */ + iclock_count += elapsed_sec * 8000 + elapsed_8000th; + iclock_tv.tv_sec = tv_now.tv_sec; + iclock_tv.tv_usec = tv_now.tv_usec; + iclock_tv_valid = 1; + if (*debug & DEBUG_CLOCK) + printk("Received first clock from source '%s'.\n", + iclock_current ? iclock_current->name : "nothing"); + } + write_unlock_irqrestore(&iclock_lock, flags); +} +EXPORT_SYMBOL(mISDN_clock_update); + +unsigned short +mISDN_clock_get(void) +{ + u_long flags; + struct timeval tv_now; + time_t elapsed_sec; + int elapsed_8000th; + u16 count; + + read_lock_irqsave(&iclock_lock, flags); + /* calc elapsed time by system clock */ + do_gettimeofday(&tv_now); + elapsed_sec = tv_now.tv_sec - iclock_tv.tv_sec; + elapsed_8000th = (tv_now.tv_usec / 125) - (iclock_tv.tv_usec / 125); + if (elapsed_8000th < 0) { + elapsed_sec -= 1; + elapsed_8000th += 8000; + } + /* add elapsed time to counter */ + count = iclock_count + elapsed_sec * 8000 + elapsed_8000th; + read_unlock_irqrestore(&iclock_lock, flags); + return count; +} +EXPORT_SYMBOL(mISDN_clock_get); + diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 751665c448d..9426c9827e4 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -25,39 +25,183 @@ MODULE_AUTHOR("Karsten Keil"); MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); -static LIST_HEAD(devices); -static DEFINE_RWLOCK(device_lock); static u64 device_ids; #define MAX_DEVICE_ID 63 static LIST_HEAD(Bprotocols); static DEFINE_RWLOCK(bp_lock); +static void mISDN_dev_release(struct device *dev) +{ + /* nothing to do: the device is part of its parent's data structure */ +} + +static ssize_t _show_id(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->id); +} + +static ssize_t _show_nrbchan(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->nrbchan); +} + +static ssize_t _show_d_protocols(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->Dprotocols); +} + +static ssize_t _show_b_protocols(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->Bprotocols | get_all_Bprotocols()); +} + +static ssize_t _show_protocol(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return -ENODEV; + return sprintf(buf, "%d\n", mdev->D.protocol); +} + +static ssize_t _show_name(struct device *dev, + struct device_attribute *attr, char *buf) +{ + strcpy(buf, dev_name(dev)); + return strlen(buf); +} + +#if 0 /* hangs */ +static ssize_t _set_name(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int err = 0; + char *out = kmalloc(count + 1, GFP_KERNEL); + + if (!out) + return -ENOMEM; + + memcpy(out, buf, count); + if (count && out[count - 1] == '\n') + out[--count] = 0; + if (count) + err = device_rename(dev, out); + kfree(out); + + return (err < 0) ? err : count; +} +#endif + +static ssize_t _show_channelmap(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + char *bp = buf; + int i; + + for (i = 0; i <= mdev->nrbchan; i++) + *bp++ = test_channelmap(i, mdev->channelmap) ? '1' : '0'; + + return bp - buf; +} + +static struct device_attribute mISDN_dev_attrs[] = { + __ATTR(id, S_IRUGO, _show_id, NULL), + __ATTR(d_protocols, S_IRUGO, _show_d_protocols, NULL), + __ATTR(b_protocols, S_IRUGO, _show_b_protocols, NULL), + __ATTR(protocol, S_IRUGO, _show_protocol, NULL), + __ATTR(channelmap, S_IRUGO, _show_channelmap, NULL), + __ATTR(nrbchan, S_IRUGO, _show_nrbchan, NULL), + __ATTR(name, S_IRUGO, _show_name, NULL), +/* __ATTR(name, S_IRUGO|S_IWUSR, _show_name, _set_name), */ + {} +}; + +#ifdef CONFIG_HOTPLUG +static int mISDN_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return 0; + + if (add_uevent_var(env, "nchans=%d", mdev->nrbchan)) + return -ENOMEM; + + return 0; +} +#endif + +static void mISDN_class_release(struct class *cls) +{ + /* do nothing, it's static */ +} + +static struct class mISDN_class = { + .name = "mISDN", + .owner = THIS_MODULE, +#ifdef CONFIG_HOTPLUG + .dev_uevent = mISDN_uevent, +#endif + .dev_attrs = mISDN_dev_attrs, + .dev_release = mISDN_dev_release, + .class_release = mISDN_class_release, +}; + +static int +_get_mdevice(struct device *dev, void *id) +{ + struct mISDNdevice *mdev = dev_to_mISDN(dev); + + if (!mdev) + return 0; + if (mdev->id != *(u_int *)id) + return 0; + return 1; +} + struct mISDNdevice *get_mdevice(u_int id) { - struct mISDNdevice *dev; + return dev_to_mISDN(class_find_device(&mISDN_class, NULL, &id, + _get_mdevice)); +} - read_lock(&device_lock); - list_for_each_entry(dev, &devices, D.list) - if (dev->id == id) { - read_unlock(&device_lock); - return dev; - } - read_unlock(&device_lock); - return NULL; +static int +_get_mdevice_count(struct device *dev, void *cnt) +{ + *(int *)cnt += 1; + return 0; } int get_mdevice_count(void) { - struct mISDNdevice *dev; - int cnt = 0; + int cnt = 0; - read_lock(&device_lock); - list_for_each_entry(dev, &devices, D.list) - cnt++; - read_unlock(&device_lock); + class_for_each_device(&mISDN_class, NULL, &cnt, _get_mdevice_count); return cnt; } @@ -68,48 +212,66 @@ get_free_devid(void) for (i = 0; i <= MAX_DEVICE_ID; i++) if (!test_and_set_bit(i, (u_long *)&device_ids)) - return i; - return -1; + break; + if (i > MAX_DEVICE_ID) + return -1; + return i; } int -mISDN_register_device(struct mISDNdevice *dev, char *name) +mISDN_register_device(struct mISDNdevice *dev, + struct device *parent, char *name) { - u_long flags; int err; dev->id = get_free_devid(); + err = -EBUSY; if (dev->id < 0) - return -EBUSY; + goto error1; + + device_initialize(&dev->dev); if (name && name[0]) - strcpy(dev->name, name); + dev_set_name(&dev->dev, "%s", name); else - sprintf(dev->name, "mISDN%d", dev->id); + dev_set_name(&dev->dev, "mISDN%d", dev->id); if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_register %s %d\n", - dev->name, dev->id); + dev_name(&dev->dev), dev->id); err = create_stack(dev); if (err) - return err; - write_lock_irqsave(&device_lock, flags); - list_add_tail(&dev->D.list, &devices); - write_unlock_irqrestore(&device_lock, flags); + goto error1; + + dev->dev.class = &mISDN_class; + dev->dev.platform_data = dev; + dev->dev.parent = parent; + dev_set_drvdata(&dev->dev, dev); + + err = device_add(&dev->dev); + if (err) + goto error3; return 0; + +error3: + delete_stack(dev); + return err; +error1: + return err; + } EXPORT_SYMBOL(mISDN_register_device); void mISDN_unregister_device(struct mISDNdevice *dev) { - u_long flags; - if (debug & DEBUG_CORE) printk(KERN_DEBUG "mISDN_unregister %s %d\n", - dev->name, dev->id); - write_lock_irqsave(&device_lock, flags); - list_del(&dev->D.list); - write_unlock_irqrestore(&device_lock, flags); + dev_name(&dev->dev), dev->id); + /* sysfs_remove_link(&dev->dev.kobj, "device"); */ + device_del(&dev->dev); + dev_set_drvdata(&dev->dev, NULL); + test_and_clear_bit(dev->id, (u_long *)&device_ids); delete_stack(dev); + put_device(&dev->dev); } EXPORT_SYMBOL(mISDN_unregister_device); @@ -199,43 +361,45 @@ mISDNInit(void) printk(KERN_INFO "Modular ISDN core version %d.%d.%d\n", MISDN_MAJOR_VERSION, MISDN_MINOR_VERSION, MISDN_RELEASE); + mISDN_init_clock(&debug); mISDN_initstack(&debug); + err = class_register(&mISDN_class); + if (err) + goto error1; err = mISDN_inittimer(&debug); if (err) - goto error; + goto error2; err = l1_init(&debug); - if (err) { - mISDN_timer_cleanup(); - goto error; - } + if (err) + goto error3; err = Isdnl2_Init(&debug); - if (err) { - mISDN_timer_cleanup(); - l1_cleanup(); - goto error; - } + if (err) + goto error4; err = misdn_sock_init(&debug); - if (err) { - mISDN_timer_cleanup(); - l1_cleanup(); - Isdnl2_cleanup(); - } -error: + if (err) + goto error5; + return 0; + +error5: + Isdnl2_cleanup(); +error4: + l1_cleanup(); +error3: + mISDN_timer_cleanup(); +error2: + class_unregister(&mISDN_class); +error1: return err; } static void mISDN_cleanup(void) { misdn_sock_cleanup(); - mISDN_timer_cleanup(); - l1_cleanup(); Isdnl2_cleanup(); + l1_cleanup(); + mISDN_timer_cleanup(); + class_unregister(&mISDN_class); - if (!list_empty(&devices)) - printk(KERN_ERR "%s devices still registered\n", __func__); - - if (!list_empty(&Bprotocols)) - printk(KERN_ERR "%s Bprotocols still registered\n", __func__); printk(KERN_DEBUG "mISDNcore unloaded\n"); } diff --git a/drivers/isdn/mISDN/core.h b/drivers/isdn/mISDN/core.h index 7da7233b4c1..7ac2f81a812 100644 --- a/drivers/isdn/mISDN/core.h +++ b/drivers/isdn/mISDN/core.h @@ -74,4 +74,6 @@ extern void l1_cleanup(void); extern int Isdnl2_Init(u_int *); extern void Isdnl2_cleanup(void); +extern void mISDN_init_clock(u_int *); + #endif diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index 6c3fed6b8d4..98a33c58f09 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -15,6 +15,7 @@ #define DEBUG_DSP_TONE 0x0020 #define DEBUG_DSP_BLOWFISH 0x0040 #define DEBUG_DSP_DELAY 0x0100 +#define DEBUG_DSP_CLOCK 0x0200 #define DEBUG_DSP_DTMFCOEFF 0x8000 /* heavy output */ /* options may be: @@ -198,6 +199,7 @@ struct dsp { /* hardware stuff */ struct dsp_features features; int features_rx_off; /* set if rx_off is featured */ + int features_fill_empty; /* set if fill_empty is featured */ int pcm_slot_rx; /* current PCM slot (or -1) */ int pcm_bank_rx; int pcm_slot_tx; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index c884511e2d4..58c43e429f7 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -137,6 +137,7 @@ /* #define CMX_CONF_DEBUG */ /*#define CMX_DEBUG * massive read/write pointer output */ +/*#define CMX_DELAY_DEBUG * gives rx-buffer delay overview */ /*#define CMX_TX_DEBUG * massive read/write on tx-buffer with content */ static inline int @@ -744,11 +745,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i = 0; @@ -836,11 +837,11 @@ conf_software: if (dsp->pcm_slot_rx >= 0 && dsp->pcm_slot_rx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_tx] = 0; + freeslots[dsp->pcm_slot_rx] = 0; if (dsp->pcm_slot_tx >= 0 && dsp->pcm_slot_tx < sizeof(freeslots)) - freeslots[dsp->pcm_slot_rx] = 0; + freeslots[dsp->pcm_slot_tx] = 0; } } i1 = 0; @@ -926,10 +927,6 @@ conf_software: /* for more than two members.. */ - /* in case of hdlc, we change to software */ - if (dsp->hdlc) - goto conf_software; - /* if all members already have the same conference */ if (all_conf) return; @@ -940,6 +937,9 @@ conf_software: if (current_conf >= 0) { join_members: list_for_each_entry(member, &conf->mlist, list) { + /* in case of hdlc, change to software */ + if (member->dsp->hdlc) + goto conf_software; /* join to current conference */ if (member->dsp->hfc_conf == current_conf) continue; @@ -1135,6 +1135,25 @@ dsp_cmx_conf(struct dsp *dsp, u32 conf_id) return 0; } +#ifdef CMX_DELAY_DEBUG +int delaycount; +static void +showdelay(struct dsp *dsp, int samples, int delay) +{ + char bar[] = "--------------------------------------------------|"; + int sdelay; + + delaycount += samples; + if (delaycount < 8000) + return; + delaycount = 0; + + sdelay = delay * 50 / (dsp_poll << 2); + + printk(KERN_DEBUG "DELAY (%s) %3d >%s\n", dsp->name, delay, + sdelay > 50 ? "..." : bar + 50 - sdelay); +} +#endif /* * audio data is received from card @@ -1168,11 +1187,18 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) dsp->rx_init = 0; if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + else + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } } /* if frame contains time code, write directly */ @@ -1185,19 +1211,25 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) * we set our new read pointer, and write silence to buffer */ if (((dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK) >= CMX_BUFF_HALF) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "cmx_receive(dsp=%lx): UNDERRUN (or overrun the " "maximum delay), adjusting read pointer! " "(inst %s)\n", (u_long)dsp, dsp->name); - /* flush buffer */ + /* flush rx buffer and set delay to dsp_poll / 2 */ if (dsp->features.unordered) { dsp->rx_R = (hh->id & CMX_BUFF_MASK); - dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) - & CMX_BUFF_MASK; + if (dsp->cmx_delay) + dsp->rx_W = (dsp->rx_R + dsp->cmx_delay) + & CMX_BUFF_MASK; + dsp->rx_W = (dsp->rx_R + (dsp_poll >> 1)) + & CMX_BUFF_MASK; } else { dsp->rx_R = 0; - dsp->rx_W = dsp->cmx_delay; + if (dsp->cmx_delay) + dsp->rx_W = dsp->cmx_delay; + else + dsp->rx_W = dsp_poll >> 1; } memset(dsp->rx_buff, dsp_silence, sizeof(dsp->rx_buff)); } @@ -1205,7 +1237,7 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) if (dsp->cmx_delay) if (((dsp->rx_W - dsp->rx_R) & CMX_BUFF_MASK) >= (dsp->cmx_delay << 1)) { - if (dsp_debug & DEBUG_DSP_CMX) + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "cmx_receive(dsp=%lx): OVERRUN (because " "twice the delay is reached), adjusting " @@ -1243,6 +1275,9 @@ dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb) /* increase write-pointer */ dsp->rx_W = ((dsp->rx_W+len) & CMX_BUFF_MASK); +#ifdef CMX_DELAY_DEBUG + showdelay(dsp, len, (dsp->rx_W-dsp->rx_R) & CMX_BUFF_MASK); +#endif } @@ -1360,8 +1395,12 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) t = (t+1) & CMX_BUFF_MASK; r = (r+1) & CMX_BUFF_MASK; } - if (r != rr) + if (r != rr) { + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: RX empty\n", + __func__); memset(d, dsp_silence, (rr-r)&CMX_BUFF_MASK); + } /* -> if echo is enabled */ } else { /* @@ -1540,13 +1579,11 @@ send_packet: schedule_work(&dsp->workq); } -static u32 samplecount; +static u32 jittercount; /* counter for jitter check */ struct timer_list dsp_spl_tl; u32 dsp_spl_jiffies; /* calculate the next time to fire */ -#ifdef UNUSED -static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ -#endif /* UNUSED */ -static struct timeval dsp_start_tv; /* time at start of calculation */ +static u16 dsp_count; /* last sample count */ +static int dsp_count_valid ; /* if we have last sample count */ void dsp_cmx_send(void *arg) @@ -1560,38 +1597,32 @@ dsp_cmx_send(void *arg) int r, rr; int jittercheck = 0, delay, i; u_long flags; - struct timeval tv; - u32 elapsed; - s16 length; + u16 length, count; /* lock */ spin_lock_irqsave(&dsp_lock, flags); - if (!dsp_start_tv.tv_sec) { - do_gettimeofday(&dsp_start_tv); + if (!dsp_count_valid) { + dsp_count = mISDN_clock_get(); length = dsp_poll; + dsp_count_valid = 1; } else { - do_gettimeofday(&tv); - elapsed = ((tv.tv_sec - dsp_start_tv.tv_sec) * 8000) - + ((s32)(tv.tv_usec / 125) - (dsp_start_tv.tv_usec / 125)); - dsp_start_tv.tv_sec = tv.tv_sec; - dsp_start_tv.tv_usec = tv.tv_usec; - length = elapsed; + count = mISDN_clock_get(); + length = count - dsp_count; + dsp_count = count; } if (length > MAX_POLL + 100) length = MAX_POLL + 100; -/* printk(KERN_DEBUG "len=%d dsp_count=0x%x.%04x dsp_poll_diff=0x%x.%04x\n", - length, dsp_count >> 16, dsp_count & 0xffff, dsp_poll_diff >> 16, - dsp_poll_diff & 0xffff); - */ + /* printk(KERN_DEBUG "len=%d dsp_count=0x%x\n", length, dsp_count); */ /* - * check if jitter needs to be checked - * (this is about every second = 8192 samples) + * check if jitter needs to be checked (this is every second) */ - samplecount += length; - if ((samplecount & 8191) < length) + jittercount += length; + if (jittercount >= 8000) { + jittercount -= 8000; jittercheck = 1; + } /* loop all members that do not require conference mixing */ list_for_each_entry(dsp, &dsp_ilist, list) { @@ -1704,17 +1735,19 @@ dsp_cmx_send(void *arg) } /* * remove rx_delay only if we have delay AND we - * have not preset cmx_delay + * have not preset cmx_delay AND + * the delay is greater dsp_poll */ - if (delay && !dsp->cmx_delay) { - if (dsp_debug & DEBUG_DSP_CMX) + if (delay > dsp_poll && !dsp->cmx_delay) { + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "%s lowest rx_delay of %d bytes for" " dsp %s are now removed.\n", __func__, delay, dsp->name); r = dsp->rx_R; - rr = (r + delay) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete rx-data */ while (r != rr) { p[r] = dsp_silence; @@ -1736,15 +1769,16 @@ dsp_cmx_send(void *arg) * remove delay only if we have delay AND we * have enabled tx_dejitter */ - if (delay && dsp->tx_dejitter) { - if (dsp_debug & DEBUG_DSP_CMX) + if (delay > dsp_poll && dsp->tx_dejitter) { + if (dsp_debug & DEBUG_DSP_CLOCK) printk(KERN_DEBUG "%s lowest tx_delay of %d bytes for" " dsp %s are now removed.\n", __func__, delay, dsp->name); r = dsp->tx_R; - rr = (r + delay) & CMX_BUFF_MASK; + rr = (r + delay - (dsp_poll >> 1)) + & CMX_BUFF_MASK; /* delete tx-data */ while (r != rr) { q[r] = dsp_silence; @@ -1797,14 +1831,16 @@ dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb) ww = dsp->tx_R; p = dsp->tx_buff; d = skb->data; - space = ww-w; - if (space <= 0) - space += CMX_BUFF_SIZE; + space = (ww - w - 1) & CMX_BUFF_MASK; /* write-pointer should not overrun nor reach read pointer */ - if (space-1 < skb->len) + if (space < skb->len) { /* write to the space we have left */ - ww = (ww - 1) & CMX_BUFF_MASK; - else + ww = (ww - 1) & CMX_BUFF_MASK; /* end one byte prior tx_R */ + if (dsp_debug & DEBUG_DSP_CLOCK) + printk(KERN_DEBUG "%s: TX overflow space=%d skb->len=" + "%d, w=0x%04x, ww=0x%04x\n", __func__, space, + skb->len, w, ww); + } else /* write until all byte are copied */ ww = (w + skb->len) & CMX_BUFF_MASK; dsp->tx_W = ww; @@ -1857,7 +1893,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) /* in case of hardware (echo) */ if (dsp->pcm_slot_tx >= 0) return; - if (dsp->echo) + if (dsp->echo) { nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { hh = mISDN_HEAD_P(nskb); @@ -1866,6 +1902,7 @@ dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb) skb_queue_tail(&dsp->sendq, nskb); schedule_work(&dsp->workq); } + } return; } /* in case of hardware conference */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 1dc21d80341..3083338716b 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -191,6 +191,8 @@ dsp_rx_off_member(struct dsp *dsp) struct mISDN_ctrl_req cq; int rx_off = 1; + memset(&cq, 0, sizeof(cq)); + if (!dsp->features_rx_off) return; @@ -249,6 +251,32 @@ dsp_rx_off(struct dsp *dsp) } } +/* enable "fill empty" feature */ +static void +dsp_fill_empty(struct dsp *dsp) +{ + struct mISDN_ctrl_req cq; + + memset(&cq, 0, sizeof(cq)); + + if (!dsp->ch.peer) { + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: no peer, no fill_empty\n", + __func__); + return; + } + cq.op = MISDN_CTRL_FILL_EMPTY; + cq.p1 = 1; + if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { + printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", + __func__); + return; + } + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_DEBUG "%s: %s set fill_empty = 1\n", + __func__, dsp->name); +} + static int dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) { @@ -273,8 +301,9 @@ dsp_control_req(struct dsp *dsp, struct mISDNhead *hh, struct sk_buff *skb) if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: start dtmf\n", __func__); if (len == sizeof(int)) { - printk(KERN_NOTICE "changing DTMF Threshold " - "to %d\n", *((int *)data)); + if (dsp_debug & DEBUG_DSP_CORE) + printk(KERN_NOTICE "changing DTMF Threshold " + "to %d\n", *((int *)data)); dsp->dtmf.treshold = (*(int *)data) * 10000; } /* init goertzel */ @@ -593,8 +622,6 @@ get_features(struct mISDNchannel *ch) struct dsp *dsp = container_of(ch, struct dsp, ch); struct mISDN_ctrl_req cq; - if (dsp_options & DSP_OPT_NOHARDWARE) - return; if (!ch->peer) { if (dsp_debug & DEBUG_DSP_CORE) printk(KERN_DEBUG "%s: no peer, no features\n", @@ -610,6 +637,10 @@ get_features(struct mISDNchannel *ch) } if (cq.op & MISDN_CTRL_RX_OFF) dsp->features_rx_off = 1; + if (cq.op & MISDN_CTRL_FILL_EMPTY) + dsp->features_fill_empty = 1; + if (dsp_options & DSP_OPT_NOHARDWARE) + return; if ((cq.op & MISDN_CTRL_HW_FEATURES_OP)) { cq.op = MISDN_CTRL_HW_FEATURES; *((u_long *)&cq.p1) = (u_long)&dsp->features; @@ -837,11 +868,14 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) } if (dsp->hdlc) { /* hdlc */ - spin_lock_irqsave(&dsp_lock, flags); - if (dsp->b_active) { - skb_queue_tail(&dsp->sendq, skb); - schedule_work(&dsp->workq); + if (!dsp->b_active) { + ret = -EIO; + break; } + hh->prim = PH_DATA_REQ; + spin_lock_irqsave(&dsp_lock, flags); + skb_queue_tail(&dsp->sendq, skb); + schedule_work(&dsp->workq); spin_unlock_irqrestore(&dsp_lock, flags); return 0; } @@ -865,6 +899,9 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) if (dsp->dtmf.hardware || dsp->dtmf.software) dsp_dtmf_goertzel_init(dsp); get_features(ch); + /* enable fill_empty feature */ + if (dsp->features_fill_empty) + dsp_fill_empty(dsp); /* send ph_activate */ hh->prim = PH_ACTIVATE_REQ; if (ch->peer) @@ -1105,7 +1142,7 @@ static int dsp_init(void) } else { poll = 8; while (poll <= MAX_POLL) { - tics = poll * HZ / 8000; + tics = (poll * HZ) / 8000; if (tics * 8000 == poll * HZ) { dsp_tics = tics; dsp_poll = poll; diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 83639be7f7a..18cf87c113e 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -75,6 +75,15 @@ static struct device_attribute element_attributes[] = { __ATTR(args, 0444, attr_show_args, NULL), }; +static void +mISDN_dsp_dev_release(struct device *dev) +{ + struct dsp_element_entry *entry = + container_of(dev, struct dsp_element_entry, dev); + list_del(&entry->list); + kfree(entry); +} + int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) { struct dsp_element_entry *entry; @@ -83,13 +92,14 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) if (!elem) return -EINVAL; - entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL); + entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC); if (!entry) return -ENOMEM; entry->elem = elem; entry->dev.class = elements_class; + entry->dev.release = mISDN_dsp_dev_release; dev_set_drvdata(&entry->dev, elem); dev_set_name(&entry->dev, elem->name); ret = device_register(&entry->dev); @@ -98,9 +108,9 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) __func__, elem->name); goto err1; } + list_add_tail(&entry->list, &dsp_elements); - for (i = 0; i < (sizeof(element_attributes) - / sizeof(struct device_attribute)); ++i) + for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) { ret = device_create_file(&entry->dev, &element_attributes[i]); if (ret) { @@ -108,15 +118,17 @@ int mISDN_dsp_element_register(struct mISDN_dsp_element *elem) __func__); goto err2; } + } - list_add_tail(&entry->list, &dsp_elements); - +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name); +#endif return 0; err2: device_unregister(&entry->dev); + return ret; err1: kfree(entry); return ret; @@ -132,11 +144,11 @@ void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem) list_for_each_entry_safe(entry, n, &dsp_elements, list) if (entry->elem == elem) { - list_del(&entry->list); device_unregister(&entry->dev); - kfree(entry); +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: %s unregistered\n", __func__, elem->name); +#endif return; } printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name); @@ -173,7 +185,9 @@ void dsp_pipeline_module_exit(void) kfree(entry); } +#ifdef PIPELINE_DEBUG printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__); +#endif } int dsp_pipeline_init(struct dsp_pipeline *pipeline) @@ -239,7 +253,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) if (!len) return 0; - dup = kmalloc(len + 1, GFP_KERNEL); + dup = kmalloc(len + 1, GFP_ATOMIC); if (!dup) return 0; strcpy(dup, cfg); @@ -256,9 +270,9 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) elem = entry->elem; pipeline_entry = kmalloc(sizeof(struct - dsp_pipeline_entry), GFP_KERNEL); + dsp_pipeline_entry), GFP_ATOMIC); if (!pipeline_entry) { - printk(KERN_DEBUG "%s: failed to add " + printk(KERN_ERR "%s: failed to add " "entry to pipeline: %s (out of " "memory)\n", __func__, elem->name); incomplete = 1; @@ -286,7 +300,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) args : ""); #endif } else { - printk(KERN_DEBUG "%s: failed " + printk(KERN_ERR "%s: failed " "to add entry to pipeline: " "%s (new() returned NULL)\n", __func__, elem->name); @@ -301,7 +315,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) if (found) found = 0; else { - printk(KERN_DEBUG "%s: element not found, skipping: " + printk(KERN_ERR "%s: element not found, skipping: " "%s\n", __func__, name); incomplete = 1; } diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 2596fba4e61..ab1168a110a 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -50,9 +50,6 @@ bchannel_bh(struct work_struct *ws) if (test_and_clear_bit(FLG_RECVQUEUE, &bch->Flags)) { while ((skb = skb_dequeue(&bch->rqueue))) { - if (bch->rcount >= 64) - printk(KERN_WARNING "B-channel %p receive " - "queue if full, but empties...\n", bch); bch->rcount--; if (likely(bch->ch.peer)) { err = bch->ch.recv(bch->ch.peer, skb); @@ -169,6 +166,25 @@ recv_Dchannel(struct dchannel *dch) EXPORT_SYMBOL(recv_Dchannel); void +recv_Echannel(struct dchannel *ech, struct dchannel *dch) +{ + struct mISDNhead *hh; + + if (ech->rx_skb->len < 2) { /* at least 2 for sapi / tei */ + dev_kfree_skb(ech->rx_skb); + ech->rx_skb = NULL; + return; + } + hh = mISDN_HEAD_P(ech->rx_skb); + hh->prim = PH_DATA_E_IND; + hh->id = get_sapi_tei(ech->rx_skb->data); + skb_queue_tail(&dch->rqueue, ech->rx_skb); + ech->rx_skb = NULL; + schedule_event(dch, FLG_RECVQUEUE); +} +EXPORT_SYMBOL(recv_Echannel); + +void recv_Bchannel(struct bchannel *bch) { struct mISDNhead *hh; @@ -177,8 +193,10 @@ recv_Bchannel(struct bchannel *bch) hh->prim = PH_DATA_IND; hh->id = MISDN_ID_ANY; if (bch->rcount >= 64) { - dev_kfree_skb(bch->rx_skb); - bch->rx_skb = NULL; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; return; } bch->rcount++; @@ -200,8 +218,10 @@ void recv_Bchannel_skb(struct bchannel *bch, struct sk_buff *skb) { if (bch->rcount >= 64) { - dev_kfree_skb(skb); - return; + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; } bch->rcount++; skb_queue_tail(&bch->rqueue, skb); @@ -245,8 +265,12 @@ confirm_Bsend(struct bchannel *bch) { struct sk_buff *skb; - if (bch->rcount >= 64) - return; + if (bch->rcount >= 64) { + printk(KERN_WARNING "B-channel %p receive queue overflow, " + "fushing!\n", bch); + skb_queue_purge(&bch->rqueue); + bch->rcount = 0; + } skb = _alloc_mISDN_skb(PH_DATA_CNF, mISDN_HEAD_ID(bch->tx_skb), 0, NULL, GFP_ATOMIC); if (!skb) { diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 0884dd6892f..abe57498957 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -777,6 +777,8 @@ fail: static void l1oip_socket_close(struct l1oip *hc) { + struct dchannel *dch = hc->chan[hc->d_idx].dch; + /* kill thread */ if (hc->socket_thread) { if (debug & DEBUG_L1OIP_SOCKET) @@ -785,6 +787,16 @@ l1oip_socket_close(struct l1oip *hc) send_sig(SIGTERM, hc->socket_thread, 0); wait_for_completion(&hc->socket_complete); } + + /* if active, we send up a PH_DEACTIVATE and deactivate */ + if (test_bit(FLG_ACTIVE, &dch->Flags)) { + if (debug & (DEBUG_L1OIP_MSG|DEBUG_L1OIP_SOCKET)) + printk(KERN_DEBUG "%s: interface become deactivated " + "due to timeout\n", __func__); + test_and_clear_bit(FLG_ACTIVE, &dch->Flags); + _queue_data(&dch->dev.D, PH_DEACTIVATE_IND, MISDN_ID_ANY, 0, + NULL, GFP_ATOMIC); + } } static int @@ -944,7 +956,8 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) switch (cq->op) { case MISDN_CTRL_GETOP: - cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER; + cq->op = MISDN_CTRL_SETPEER | MISDN_CTRL_UNSETPEER + | MISDN_CTRL_GETPEER; break; case MISDN_CTRL_SETPEER: hc->remoteip = (u32)cq->p1; @@ -964,6 +977,13 @@ channel_dctrl(struct dchannel *dch, struct mISDN_ctrl_req *cq) hc->remoteip = 0; l1oip_socket_open(hc); break; + case MISDN_CTRL_GETPEER: + if (debug & DEBUG_L1OIP_SOCKET) + printk(KERN_DEBUG "%s: getting ip address.\n", + __func__); + cq->p1 = hc->remoteip; + cq->p2 = hc->remoteport | (hc->localport << 16); + break; default: printk(KERN_WARNING "%s: unknown Op %x\n", __func__, cq->op); @@ -1413,7 +1433,8 @@ init_card(struct l1oip *hc, int pri, int bundle) hc->chan[i + ch].bch = bch; set_channelmap(bch->nr, dch->dev.channelmap); } - ret = mISDN_register_device(&dch->dev, hc->name); + /* TODO: create a parent device for this driver */ + ret = mISDN_register_device(&dch->dev, NULL, hc->name); if (ret) return ret; hc->registered = 1; diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index b73e952d12c..e826eeb1ece 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -101,7 +101,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...) va_list va; va_start(va, fmt); - printk(KERN_DEBUG "%s: ", l1->dch->dev.name); + printk(KERN_DEBUG "%s: ", dev_name(&l1->dch->dev.dev)); vprintk(fmt, va); printk("\n"); va_end(va); diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index 37a2de18cfd..508945d1b9c 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -381,7 +381,7 @@ data_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else @@ -460,6 +460,8 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sockaddr_mISDN *maddr = (struct sockaddr_mISDN *) addr; struct sock *sk = sock->sk; + struct hlist_node *node; + struct sock *csk; int err = 0; if (*debug & DEBUG_SOCKET) @@ -480,6 +482,26 @@ data_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) err = -ENODEV; goto done; } + + if (sk->sk_protocol < ISDN_P_B_START) { + read_lock_bh(&data_sockets.lock); + sk_for_each(csk, node, &data_sockets.head) { + if (sk == csk) + continue; + if (_pms(csk)->dev != _pms(sk)->dev) + continue; + if (csk->sk_protocol >= ISDN_P_B_START) + continue; + if (IS_ISDN_P_TE(csk->sk_protocol) + == IS_ISDN_P_TE(sk->sk_protocol)) + continue; + read_unlock_bh(&data_sockets.lock); + err = -EBUSY; + goto done; + } + read_unlock_bh(&data_sockets.lock); + } + _pms(sk)->ch.send = mISDN_send; _pms(sk)->ch.ctrl = mISDN_ctrl; @@ -639,12 +661,27 @@ base_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) memcpy(di.channelmap, dev->channelmap, sizeof(di.channelmap)); di.nrbchan = dev->nrbchan; - strcpy(di.name, dev->name); + strcpy(di.name, dev_name(&dev->dev)); if (copy_to_user((void __user *)arg, &di, sizeof(di))) err = -EFAULT; } else err = -ENODEV; break; + case IMSETDEVNAME: + { + struct mISDN_devrename dn; + if (copy_from_user(&dn, (void __user *)arg, + sizeof(dn))) { + err = -EFAULT; + break; + } + dev = get_mdevice(dn.id); + if (dev) + err = device_rename(&dev->dev, dn.name); + else + err = -ENODEV; + } + break; default: err = -EINVAL; } diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index d55b14ae4e9..e2f45019ebf 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -172,7 +172,8 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else if (lm == 0x8) { WARN_ON(lm == 0x8); ch = get_channel4id(st, hh->id); @@ -181,11 +182,12 @@ send_msg_to_layer(struct mISDNstack *st, struct sk_buff *skb) else printk(KERN_WARNING "%s: dev(%s) prim(%x) id(%x) no channel\n", - __func__, st->dev->name, hh->prim, hh->id); + __func__, dev_name(&st->dev->dev), hh->prim, + hh->id); } else { /* broadcast not handled yet */ printk(KERN_WARNING "%s: dev(%s) prim %x not delivered\n", - __func__, st->dev->name, hh->prim); + __func__, dev_name(&st->dev->dev), hh->prim); } return -ESRCH; } @@ -209,7 +211,8 @@ mISDNStackd(void *data) unlock_kernel(); #endif if (*debug & DEBUG_MSG_THREAD) - printk(KERN_DEBUG "mISDNStackd %s started\n", st->dev->name); + printk(KERN_DEBUG "mISDNStackd %s started\n", + dev_name(&st->dev->dev)); if (st->notify != NULL) { complete(st->notify); @@ -245,7 +248,7 @@ mISDNStackd(void *data) printk(KERN_DEBUG "%s: %s prim(%x) id(%x) " "send call(%d)\n", - __func__, st->dev->name, + __func__, dev_name(&st->dev->dev), mISDN_HEAD_PRIM(skb), mISDN_HEAD_ID(skb), err); dev_kfree_skb(skb); @@ -288,7 +291,7 @@ mISDNStackd(void *data) mISDN_STACK_ACTION_MASK)); if (*debug & DEBUG_MSG_THREAD) printk(KERN_DEBUG "%s: %s wake status %08lx\n", - __func__, st->dev->name, st->status); + __func__, dev_name(&st->dev->dev), st->status); test_and_set_bit(mISDN_STACK_ACTIVE, &st->status); test_and_clear_bit(mISDN_STACK_WAKEUP, &st->status); @@ -303,15 +306,16 @@ mISDNStackd(void *data) #ifdef MISDN_MSG_STATS printk(KERN_DEBUG "mISDNStackd daemon for %s proceed %d " "msg %d sleep %d stopped\n", - st->dev->name, st->msg_cnt, st->sleep_cnt, st->stopped_cnt); + dev_name(&st->dev->dev), st->msg_cnt, st->sleep_cnt, + st->stopped_cnt); printk(KERN_DEBUG "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", - st->dev->name, st->thread->utime, st->thread->stime); + dev_name(&st->dev->dev), st->thread->utime, st->thread->stime); printk(KERN_DEBUG "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", - st->dev->name, st->thread->nvcsw, st->thread->nivcsw); + dev_name(&st->dev->dev), st->thread->nvcsw, st->thread->nivcsw); printk(KERN_DEBUG "mISDNStackd daemon for %s killed now\n", - st->dev->name); + dev_name(&st->dev->dev)); #endif test_and_set_bit(mISDN_STACK_KILLED, &st->status); test_and_clear_bit(mISDN_STACK_RUNNING, &st->status); @@ -401,15 +405,16 @@ create_stack(struct mISDNdevice *dev) newst->own.send = mISDN_queue_message; newst->own.recv = mISDN_queue_message; if (*debug & DEBUG_CORE_FUNC) - printk(KERN_DEBUG "%s: st(%s)\n", __func__, newst->dev->name); + printk(KERN_DEBUG "%s: st(%s)\n", __func__, + dev_name(&newst->dev->dev)); newst->notify = &done; newst->thread = kthread_run(mISDNStackd, (void *)newst, "mISDN_%s", - newst->dev->name); + dev_name(&newst->dev->dev)); if (IS_ERR(newst->thread)) { err = PTR_ERR(newst->thread); printk(KERN_ERR "mISDN:cannot create kernel thread for %s (%d)\n", - newst->dev->name, err); + dev_name(&newst->dev->dev), err); delete_teimanager(dev->teimgr); kfree(newst); } else @@ -428,29 +433,21 @@ connect_layer1(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, adr->dev, adr->channel, - adr->sapi, adr->tei); + __func__, dev_name(&dev->dev), protocol, adr->dev, + adr->channel, adr->sapi, adr->tei); switch (protocol) { case ISDN_P_NT_S0: case ISDN_P_NT_E1: case ISDN_P_TE_S0: case ISDN_P_TE_E1: -#ifdef PROTOCOL_CHECK - /* this should be enhanced */ - if (!list_empty(&dev->D.st->layer2) - && dev->D.protocol != protocol) - return -EBUSY; - if (!hlist_empty(&dev->D.st->l1sock.head) - && dev->D.protocol != protocol) - return -EBUSY; -#endif ch->recv = mISDN_queue_message; ch->peer = &dev->D.st->own; ch->st = dev->D.st; rq.protocol = protocol; - rq.adr.channel = 0; + rq.adr.channel = adr->channel; err = dev->D.ctrl(&dev->D, OPEN_CHANNEL, &rq); - printk(KERN_DEBUG "%s: ret 1 %d\n", __func__, err); + printk(KERN_DEBUG "%s: ret %d (dev %d)\n", __func__, err, + dev->id); if (err) return err; write_lock_bh(&dev->D.st->l1sock.lock); @@ -473,7 +470,7 @@ connect_Bstack(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); ch->st = dev->D.st; @@ -529,7 +526,7 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, dev->name, protocol, + __func__, dev_name(&dev->dev), protocol, adr->dev, adr->channel, adr->sapi, adr->tei); rq.protocol = ISDN_P_TE_S0; @@ -541,15 +538,6 @@ create_l2entity(struct mISDNdevice *dev, struct mISDNchannel *ch, if (dev->Dprotocols & (1 << ISDN_P_NT_E1)) rq.protocol = ISDN_P_NT_E1; case ISDN_P_LAPD_TE: -#ifdef PROTOCOL_CHECK - /* this should be enhanced */ - if (!list_empty(&dev->D.st->layer2) - && dev->D.protocol != protocol) - return -EBUSY; - if (!hlist_empty(&dev->D.st->l1sock.head) - && dev->D.protocol != protocol) - return -EBUSY; -#endif ch->recv = mISDN_queue_message; ch->peer = &dev->D.st->own; ch->st = dev->D.st; @@ -590,7 +578,7 @@ delete_channel(struct mISDNchannel *ch) } if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s) protocol(%x)\n", __func__, - ch->st->dev->name, ch->protocol); + dev_name(&ch->st->dev->dev), ch->protocol); if (ch->protocol >= ISDN_P_B_START) { if (ch->peer) { ch->peer->ctrl(ch->peer, CLOSE_CHANNEL, NULL); @@ -643,7 +631,7 @@ delete_stack(struct mISDNdevice *dev) if (*debug & DEBUG_CORE_FUNC) printk(KERN_DEBUG "%s: st(%s)\n", __func__, - st->dev->name); + dev_name(&st->dev->dev)); if (dev->teimgr) delete_teimanager(dev->teimgr); if (st->thread) { diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 5c43d19e7c1..b452dead8fd 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -968,9 +968,9 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", - __func__, mgr->ch.st->dev->name, crq->protocol, - crq->adr.dev, crq->adr.channel, crq->adr.sapi, - crq->adr.tei); + __func__, dev_name(&mgr->ch.st->dev->dev), + crq->protocol, crq->adr.dev, crq->adr.channel, + crq->adr.sapi, crq->adr.tei); if (crq->adr.sapi != 0) /* not supported yet */ return -EINVAL; if (crq->adr.tei > GROUP_TEI) diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index e7fb7d2fcbf..a4a1ae21463 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -63,6 +63,12 @@ config LEDS_WRAP help This option enables support for the PCEngines WRAP programmable LEDs. +config LEDS_ALIX2 + tristate "LED Support for ALIX.2 and ALIX.3 series" + depends on LEDS_CLASS && X86 && EXPERIMENTAL + help + This option enables support for the PCEngines ALIX.2 and ALIX.3 LEDs. + config LEDS_H1940 tristate "LED Support for iPAQ H1940 device" depends on LEDS_CLASS && ARCH_H1940 @@ -77,7 +83,7 @@ config LEDS_COBALT_QUBE config LEDS_COBALT_RAQ bool "LED Support for the Cobalt Raq series" - depends on LEDS_CLASS && MIPS_COBALT + depends on LEDS_CLASS=y && MIPS_COBALT select LEDS_TRIGGERS help This option enables support for the Cobalt Raq series LEDs. @@ -158,6 +164,13 @@ config LEDS_PCA955X LED driver chips accessed via the I2C bus. Supported devices include PCA9550, PCA9551, PCA9552, and PCA9553. +config LEDS_WM8350 + tristate "LED Support for WM8350 AudioPlus PMIC" + depends on LEDS_CLASS && MFD_WM8350 + help + This option enables support for LEDs driven by the Wolfson + Microelectronics WM8350 AudioPlus PMIC. + config LEDS_DA903X tristate "LED Support for DA9030/DA9034 PMIC" depends on LEDS_CLASS && PMIC_DA903X diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index e1967a29850..bc247cb02e8 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o +obj-$(CONFIG_LEDS_ALIX2) += leds-alix2.o obj-$(CONFIG_LEDS_H1940) += leds-h1940.o obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o @@ -23,6 +24,7 @@ obj-$(CONFIG_LEDS_FSG) += leds-fsg.o obj-$(CONFIG_LEDS_PCA955X) += leds-pca955x.o obj-$(CONFIG_LEDS_DA903X) += leds-da903x.o obj-$(CONFIG_LEDS_HP_DISK) += leds-hp-disk.o +obj-$(CONFIG_LEDS_WM8350) += leds-wm8350.o # LED Triggers obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 6c4a326176d..52f82e3ea13 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -91,9 +91,29 @@ void led_classdev_resume(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_classdev_resume); +static int led_suspend(struct device *dev, pm_message_t state) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (led_cdev->flags & LED_CORE_SUSPENDRESUME) + led_classdev_suspend(led_cdev); + + return 0; +} + +static int led_resume(struct device *dev) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (led_cdev->flags & LED_CORE_SUSPENDRESUME) + led_classdev_resume(led_cdev); + + return 0; +} + /** * led_classdev_register - register a new object of led_classdev class. - * @dev: The device to register. + * @parent: The device to register. * @led_cdev: the led_classdev structure for this device. */ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) @@ -174,6 +194,8 @@ static int __init leds_init(void) leds_class = class_create(THIS_MODULE, "leds"); if (IS_ERR(leds_class)) return PTR_ERR(leds_class); + leds_class->suspend = led_suspend; + leds_class->resume = led_resume; return 0; } diff --git a/drivers/leds/leds-alix2.c b/drivers/leds/leds-alix2.c new file mode 100644 index 00000000000..ddbd7730dfc --- /dev/null +++ b/drivers/leds/leds-alix2.c @@ -0,0 +1,181 @@ +/* + * LEDs driver for PCEngines ALIX.2 and ALIX.3 + * + * Copyright (C) 2008 Constantin Baranov <const@mimas.ru> + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/string.h> + +static int force = 0; +module_param(force, bool, 0444); +MODULE_PARM_DESC(force, "Assume system has ALIX.2 style LEDs"); + +struct alix_led { + struct led_classdev cdev; + unsigned short port; + unsigned int on_value; + unsigned int off_value; +}; + +static void alix_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct alix_led *led_dev = + container_of(led_cdev, struct alix_led, cdev); + + if (brightness) + outl(led_dev->on_value, led_dev->port); + else + outl(led_dev->off_value, led_dev->port); +} + +static struct alix_led alix_leds[] = { + { + .cdev = { + .name = "alix:1", + .brightness_set = alix_led_set, + }, + .port = 0x6100, + .on_value = 1 << 22, + .off_value = 1 << 6, + }, + { + .cdev = { + .name = "alix:2", + .brightness_set = alix_led_set, + }, + .port = 0x6180, + .on_value = 1 << 25, + .off_value = 1 << 9, + }, + { + .cdev = { + .name = "alix:3", + .brightness_set = alix_led_set, + }, + .port = 0x6180, + .on_value = 1 << 27, + .off_value = 1 << 11, + }, +}; + +static int __init alix_led_probe(struct platform_device *pdev) +{ + int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(alix_leds); i++) { + alix_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME; + ret = led_classdev_register(&pdev->dev, &alix_leds[i].cdev); + if (ret < 0) + goto fail; + } + return 0; + +fail: + while (--i >= 0) + led_classdev_unregister(&alix_leds[i].cdev); + return ret; +} + +static int alix_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(alix_leds); i++) + led_classdev_unregister(&alix_leds[i].cdev); + return 0; +} + +static struct platform_driver alix_led_driver = { + .remove = alix_led_remove, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init alix_present(void) +{ + const unsigned long bios_phys = 0x000f0000; + const size_t bios_len = 0x00010000; + const char alix_sig[] = "PC Engines ALIX."; + const size_t alix_sig_len = sizeof(alix_sig) - 1; + + const char *bios_virt; + const char *scan_end; + const char *p; + int ret = 0; + + if (force) { + printk(KERN_NOTICE "%s: forced to skip BIOS test, " + "assume system has ALIX.2 style LEDs\n", + KBUILD_MODNAME); + ret = 1; + goto out; + } + + bios_virt = phys_to_virt(bios_phys); + scan_end = bios_virt + bios_len - (alix_sig_len + 2); + for (p = bios_virt; p < scan_end; p++) { + const char *tail; + + if (memcmp(p, alix_sig, alix_sig_len) != 0) { + continue; + } + + tail = p + alix_sig_len; + if ((tail[0] == '2' || tail[0] == '3') && tail[1] == '\0') { + printk(KERN_INFO + "%s: system is recognized as \"%s\"\n", + KBUILD_MODNAME, p); + ret = 1; + break; + } + } + +out: + return ret; +} + +static struct platform_device *pdev; + +static int __init alix_led_init(void) +{ + int ret; + + if (!alix_present()) { + ret = -ENODEV; + goto out; + } + + pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0); + if (!IS_ERR(pdev)) { + ret = platform_driver_probe(&alix_led_driver, alix_led_probe); + if (ret) + platform_device_unregister(pdev); + } else + ret = PTR_ERR(pdev); + +out: + return ret; +} + +static void __exit alix_led_exit(void) +{ + platform_device_unregister(pdev); + platform_driver_unregister(&alix_led_driver); +} + +module_init(alix_led_init); +module_exit(alix_led_exit); + +MODULE_AUTHOR("Constantin Baranov <const@mimas.ru>"); +MODULE_DESCRIPTION("PCEngines ALIX.2 and ALIX.3 LED driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c index 1bd590bb3a6..446050759b4 100644 --- a/drivers/leds/leds-ams-delta.c +++ b/drivers/leds/leds-ams-delta.c @@ -79,37 +79,12 @@ static struct ams_delta_led ams_delta_leds[] = { }, }; -#ifdef CONFIG_PM -static int ams_delta_led_suspend(struct platform_device *dev, - pm_message_t state) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) - led_classdev_suspend(&ams_delta_leds[i].cdev); - - return 0; -} - -static int ams_delta_led_resume(struct platform_device *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) - led_classdev_resume(&ams_delta_leds[i].cdev); - - return 0; -} -#else -#define ams_delta_led_suspend NULL -#define ams_delta_led_resume NULL -#endif - static int ams_delta_led_probe(struct platform_device *pdev) { int i, ret; for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) { + ams_delta_leds[i].cdev.flags |= LED_CORE_SUSPENDRESUME; ret = led_classdev_register(&pdev->dev, &ams_delta_leds[i].cdev); if (ret < 0) @@ -127,7 +102,7 @@ static int ams_delta_led_remove(struct platform_device *pdev) { int i; - for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i--) + for (i = 0; i < ARRAY_SIZE(ams_delta_leds); i++) led_classdev_unregister(&ams_delta_leds[i].cdev); return 0; @@ -136,8 +111,6 @@ static int ams_delta_led_remove(struct platform_device *pdev) static struct platform_driver ams_delta_led_driver = { .probe = ams_delta_led_probe, .remove = ams_delta_led_remove, - .suspend = ams_delta_led_suspend, - .resume = ams_delta_led_resume, .driver = { .name = "ams-delta-led", .owner = THIS_MODULE, @@ -151,7 +124,7 @@ static int __init ams_delta_led_init(void) static void __exit ams_delta_led_exit(void) { - return platform_driver_unregister(&ams_delta_led_driver); + platform_driver_unregister(&ams_delta_led_driver); } module_init(ams_delta_led_init); diff --git a/drivers/leds/leds-clevo-mail.c b/drivers/leds/leds-clevo-mail.c index eb3415e88f4..1813c84ea5f 100644 --- a/drivers/leds/leds-clevo-mail.c +++ b/drivers/leds/leds-clevo-mail.c @@ -142,6 +142,7 @@ static struct led_classdev clevo_mail_led = { .name = "clevo::mail", .brightness_set = clevo_mail_led_set, .blink_set = clevo_mail_led_blink, + .flags = LED_CORE_SUSPENDRESUME, }; static int __init clevo_mail_led_probe(struct platform_device *pdev) @@ -155,29 +156,9 @@ static int clevo_mail_led_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int clevo_mail_led_suspend(struct platform_device *dev, - pm_message_t state) -{ - led_classdev_suspend(&clevo_mail_led); - return 0; -} - -static int clevo_mail_led_resume(struct platform_device *dev) -{ - led_classdev_resume(&clevo_mail_led); - return 0; -} -#else -#define clevo_mail_led_suspend NULL -#define clevo_mail_led_resume NULL -#endif - static struct platform_driver clevo_mail_led_driver = { .probe = clevo_mail_led_probe, .remove = clevo_mail_led_remove, - .suspend = clevo_mail_led_suspend, - .resume = clevo_mail_led_resume, .driver = { .name = KBUILD_MODNAME, .owner = THIS_MODULE, diff --git a/drivers/leds/leds-fsg.c b/drivers/leds/leds-fsg.c index 34935155c1c..5f7c9c5c09b 100644 --- a/drivers/leds/leds-fsg.c +++ b/drivers/leds/leds-fsg.c @@ -99,64 +99,43 @@ static void fsg_led_ring_set(struct led_classdev *led_cdev, } - static struct led_classdev fsg_wlan_led = { .name = "fsg:blue:wlan", .brightness_set = fsg_led_wlan_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev fsg_wan_led = { .name = "fsg:blue:wan", .brightness_set = fsg_led_wan_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev fsg_sata_led = { .name = "fsg:blue:sata", .brightness_set = fsg_led_sata_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev fsg_usb_led = { .name = "fsg:blue:usb", .brightness_set = fsg_led_usb_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev fsg_sync_led = { .name = "fsg:blue:sync", .brightness_set = fsg_led_sync_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev fsg_ring_led = { .name = "fsg:blue:ring", .brightness_set = fsg_led_ring_set, + .flags = LED_CORE_SUSPENDRESUME, }; - -#ifdef CONFIG_PM -static int fsg_led_suspend(struct platform_device *dev, pm_message_t state) -{ - led_classdev_suspend(&fsg_wlan_led); - led_classdev_suspend(&fsg_wan_led); - led_classdev_suspend(&fsg_sata_led); - led_classdev_suspend(&fsg_usb_led); - led_classdev_suspend(&fsg_sync_led); - led_classdev_suspend(&fsg_ring_led); - return 0; -} - -static int fsg_led_resume(struct platform_device *dev) -{ - led_classdev_resume(&fsg_wlan_led); - led_classdev_resume(&fsg_wan_led); - led_classdev_resume(&fsg_sata_led); - led_classdev_resume(&fsg_usb_led); - led_classdev_resume(&fsg_sync_led); - led_classdev_resume(&fsg_ring_led); - return 0; -} -#endif - - static int fsg_led_probe(struct platform_device *pdev) { int ret; @@ -232,10 +211,6 @@ static int fsg_led_remove(struct platform_device *pdev) static struct platform_driver fsg_led_driver = { .probe = fsg_led_probe, .remove = fsg_led_remove, -#ifdef CONFIG_PM - .suspend = fsg_led_suspend, - .resume = fsg_led_resume, -#endif .driver = { .name = "fsg-led", }, diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c index b13bd2950e9..2e3df08b649 100644 --- a/drivers/leds/leds-gpio.c +++ b/drivers/leds/leds-gpio.c @@ -105,6 +105,7 @@ static int gpio_led_probe(struct platform_device *pdev) } led_dat->cdev.brightness_set = gpio_led_set; led_dat->cdev.brightness = LED_OFF; + led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME; gpio_direction_output(led_dat->gpio, led_dat->active_low); @@ -154,44 +155,9 @@ static int __devexit gpio_led_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int gpio_led_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct gpio_led_platform_data *pdata = pdev->dev.platform_data; - struct gpio_led_data *leds_data; - int i; - - leds_data = platform_get_drvdata(pdev); - - for (i = 0; i < pdata->num_leds; i++) - led_classdev_suspend(&leds_data[i].cdev); - - return 0; -} - -static int gpio_led_resume(struct platform_device *pdev) -{ - struct gpio_led_platform_data *pdata = pdev->dev.platform_data; - struct gpio_led_data *leds_data; - int i; - - leds_data = platform_get_drvdata(pdev); - - for (i = 0; i < pdata->num_leds; i++) - led_classdev_resume(&leds_data[i].cdev); - - return 0; -} -#else -#define gpio_led_suspend NULL -#define gpio_led_resume NULL -#endif - static struct platform_driver gpio_led_driver = { .probe = gpio_led_probe, .remove = __devexit_p(gpio_led_remove), - .suspend = gpio_led_suspend, - .resume = gpio_led_resume, .driver = { .name = "leds-gpio", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-hp-disk.c b/drivers/leds/leds-hp-disk.c index 44fa757d825..d786adc8c5e 100644 --- a/drivers/leds/leds-hp-disk.c +++ b/drivers/leds/leds-hp-disk.c @@ -68,25 +68,9 @@ static struct led_classdev hpled_led = { .name = "hp:red:hddprotection", .default_trigger = "heartbeat", .brightness_set = hpled_set, + .flags = LED_CORE_SUSPENDRESUME, }; -#ifdef CONFIG_PM -static int hpled_suspend(struct acpi_device *dev, pm_message_t state) -{ - led_classdev_suspend(&hpled_led); - return 0; -} - -static int hpled_resume(struct acpi_device *dev) -{ - led_classdev_resume(&hpled_led); - return 0; -} -#else -#define hpled_suspend NULL -#define hpled_resume NULL -#endif - static int hpled_add(struct acpi_device *device) { int ret; @@ -121,8 +105,6 @@ static struct acpi_driver leds_hp_driver = { .ops = { .add = hpled_add, .remove = hpled_remove, - .suspend = hpled_suspend, - .resume = hpled_resume, } }; diff --git a/drivers/leds/leds-hp6xx.c b/drivers/leds/leds-hp6xx.c index e8fb1baf8a5..e4ce1fd4633 100644 --- a/drivers/leds/leds-hp6xx.c +++ b/drivers/leds/leds-hp6xx.c @@ -45,30 +45,16 @@ static struct led_classdev hp6xx_red_led = { .name = "hp6xx:red", .default_trigger = "hp6xx-charge", .brightness_set = hp6xxled_red_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev hp6xx_green_led = { .name = "hp6xx:green", .default_trigger = "ide-disk", .brightness_set = hp6xxled_green_set, + .flags = LED_CORE_SUSPENDRESUME, }; -#ifdef CONFIG_PM -static int hp6xxled_suspend(struct platform_device *dev, pm_message_t state) -{ - led_classdev_suspend(&hp6xx_red_led); - led_classdev_suspend(&hp6xx_green_led); - return 0; -} - -static int hp6xxled_resume(struct platform_device *dev) -{ - led_classdev_resume(&hp6xx_red_led); - led_classdev_resume(&hp6xx_green_led); - return 0; -} -#endif - static int hp6xxled_probe(struct platform_device *pdev) { int ret; @@ -98,10 +84,6 @@ MODULE_ALIAS("platform:hp6xx-led"); static struct platform_driver hp6xxled_driver = { .probe = hp6xxled_probe, .remove = hp6xxled_remove, -#ifdef CONFIG_PM - .suspend = hp6xxled_suspend, - .resume = hp6xxled_resume, -#endif .driver = { .name = "hp6xx-led", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c index 054360473c9..93987a12da4 100644 --- a/drivers/leds/leds-net48xx.c +++ b/drivers/leds/leds-net48xx.c @@ -33,26 +33,9 @@ static void net48xx_error_led_set(struct led_classdev *led_cdev, static struct led_classdev net48xx_error_led = { .name = "net48xx::error", .brightness_set = net48xx_error_led_set, + .flags = LED_CORE_SUSPENDRESUME, }; -#ifdef CONFIG_PM -static int net48xx_led_suspend(struct platform_device *dev, - pm_message_t state) -{ - led_classdev_suspend(&net48xx_error_led); - return 0; -} - -static int net48xx_led_resume(struct platform_device *dev) -{ - led_classdev_resume(&net48xx_error_led); - return 0; -} -#else -#define net48xx_led_suspend NULL -#define net48xx_led_resume NULL -#endif - static int net48xx_led_probe(struct platform_device *pdev) { return led_classdev_register(&pdev->dev, &net48xx_error_led); @@ -67,8 +50,6 @@ static int net48xx_led_remove(struct platform_device *pdev) static struct platform_driver net48xx_led_driver = { .probe = net48xx_led_probe, .remove = net48xx_led_remove, - .suspend = net48xx_led_suspend, - .resume = net48xx_led_resume, .driver = { .name = DRVNAME, .owner = THIS_MODULE, diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c index 4064d4f6b33..76ec7498e2d 100644 --- a/drivers/leds/leds-pca9532.c +++ b/drivers/leds/leds-pca9532.c @@ -16,6 +16,7 @@ #include <linux/leds.h> #include <linux/input.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <linux/leds-pca9532.h> static const unsigned short normal_i2c[] = { /*0x60,*/ I2C_CLIENT_END}; @@ -34,6 +35,7 @@ struct pca9532_data { struct pca9532_led leds[16]; struct mutex update_lock; struct input_dev *idev; + struct work_struct work; u8 pwm[2]; u8 psc[2]; }; @@ -63,7 +65,7 @@ static struct i2c_driver pca9532_driver = { * as a compromise we average one pwm to the values requested by all * leds that are not ON/OFF. * */ -static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink, +static int pca9532_calcpwm(struct i2c_client *client, int pwm, int blink, enum led_brightness value) { int a = 0, b = 0, i = 0; @@ -84,11 +86,17 @@ static int pca9532_setpwm(struct i2c_client *client, int pwm, int blink, b = b/a; if (b > 0xFF) return -EINVAL; - mutex_lock(&data->update_lock); data->pwm[pwm] = b; + data->psc[pwm] = blink; + return 0; +} + +static int pca9532_setpwm(struct i2c_client *client, int pwm) +{ + struct pca9532_data *data = i2c_get_clientdata(client); + mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(client, PCA9532_REG_PWM(pwm), data->pwm[pwm]); - data->psc[pwm] = blink; i2c_smbus_write_byte_data(client, PCA9532_REG_PSC(pwm), data->psc[pwm]); mutex_unlock(&data->update_lock); @@ -124,11 +132,11 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev, led->state = PCA9532_ON; else { led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */ - err = pca9532_setpwm(led->client, 0, 0, value); + err = pca9532_calcpwm(led->client, 0, 0, value); if (err) return; /* XXX: led api doesn't allow error code? */ } - pca9532_setled(led); + schedule_work(&led->work); } static int pca9532_set_blink(struct led_classdev *led_cdev, @@ -137,6 +145,7 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, struct pca9532_led *led = ldev_to_led(led_cdev); struct i2c_client *client = led->client; int psc; + int err = 0; if (*delay_on == 0 && *delay_off == 0) { /* led subsystem ask us for a blink rate */ @@ -148,11 +157,15 @@ static int pca9532_set_blink(struct led_classdev *led_cdev, /* Thecus specific: only use PSC/PWM 0 */ psc = (*delay_on * 152-1)/1000; - return pca9532_setpwm(client, 0, psc, led_cdev->brightness); + err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness); + if (err) + return err; + schedule_work(&led->work); + return 0; } -int pca9532_event(struct input_dev *dev, unsigned int type, unsigned int code, - int value) +static int pca9532_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) { struct pca9532_data *data = input_get_drvdata(dev); @@ -165,13 +178,28 @@ int pca9532_event(struct input_dev *dev, unsigned int type, unsigned int code, else data->pwm[1] = 0; - dev_info(&dev->dev, "setting beep to %d \n", data->pwm[1]); + schedule_work(&data->work); + + return 0; +} + +static void pca9532_input_work(struct work_struct *work) +{ + struct pca9532_data *data; + data = container_of(work, struct pca9532_data, work); mutex_lock(&data->update_lock); i2c_smbus_write_byte_data(data->client, PCA9532_REG_PWM(1), data->pwm[1]); mutex_unlock(&data->update_lock); +} - return 0; +static void pca9532_led_work(struct work_struct *work) +{ + struct pca9532_led *led; + led = container_of(work, struct pca9532_led, work); + if (led->state == PCA9532_PWM0) + pca9532_setpwm(led->client, 0); + pca9532_setled(led); } static int pca9532_configure(struct i2c_client *client, @@ -204,8 +232,9 @@ static int pca9532_configure(struct i2c_client *client, led->ldev.brightness = LED_OFF; led->ldev.brightness_set = pca9532_set_brightness; led->ldev.blink_set = pca9532_set_blink; - if (led_classdev_register(&client->dev, - &led->ldev) < 0) { + INIT_WORK(&led->work, pca9532_led_work); + err = led_classdev_register(&client->dev, &led->ldev); + if (err < 0) { dev_err(&client->dev, "couldn't register LED %s\n", led->name); @@ -233,9 +262,11 @@ static int pca9532_configure(struct i2c_client *client, BIT_MASK(SND_TONE); data->idev->event = pca9532_event; input_set_drvdata(data->idev, data); + INIT_WORK(&data->work, pca9532_input_work); err = input_register_device(data->idev); if (err) { input_free_device(data->idev); + cancel_work_sync(&data->work); data->idev = NULL; goto exit; } @@ -252,18 +283,19 @@ exit: break; case PCA9532_TYPE_LED: led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); break; case PCA9532_TYPE_N2100_BEEP: if (data->idev != NULL) { input_unregister_device(data->idev); input_free_device(data->idev); + cancel_work_sync(&data->work); data->idev = NULL; } break; } return err; - } static int pca9532_probe(struct i2c_client *client, @@ -271,12 +303,16 @@ static int pca9532_probe(struct i2c_client *client, { struct pca9532_data *data = i2c_get_clientdata(client); struct pca9532_platform_data *pca9532_pdata = client->dev.platform_data; + int err; + + if (!pca9532_pdata) + return -EIO; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - data = kzalloc(sizeof(struct pca9532_data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -285,12 +321,13 @@ static int pca9532_probe(struct i2c_client *client, data->client = client; mutex_init(&data->update_lock); - if (pca9532_pdata == NULL) - return -EIO; - - pca9532_configure(client, data, pca9532_pdata); - return 0; + err = pca9532_configure(client, data, pca9532_pdata); + if (err) { + kfree(data); + i2c_set_clientdata(client, NULL); + } + return err; } static int pca9532_remove(struct i2c_client *client) @@ -303,11 +340,13 @@ static int pca9532_remove(struct i2c_client *client) break; case PCA9532_TYPE_LED: led_classdev_unregister(&data->leds[i].ldev); + cancel_work_sync(&data->leds[i].work); break; case PCA9532_TYPE_N2100_BEEP: if (data->idev != NULL) { input_unregister_device(data->idev); input_free_device(data->idev); + cancel_work_sync(&data->work); data->idev = NULL; } break; diff --git a/drivers/leds/leds-s3c24xx.c b/drivers/leds/leds-s3c24xx.c index 25a07f2643a..4d81131542a 100644 --- a/drivers/leds/leds-s3c24xx.c +++ b/drivers/leds/leds-s3c24xx.c @@ -82,6 +82,7 @@ static int s3c24xx_led_probe(struct platform_device *dev) led->cdev.brightness_set = s3c24xx_led_set; led->cdev.default_trigger = pdata->def_trigger; led->cdev.name = pdata->name; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; led->pdata = pdata; @@ -111,33 +112,9 @@ static int s3c24xx_led_probe(struct platform_device *dev) return ret; } - -#ifdef CONFIG_PM -static int s3c24xx_led_suspend(struct platform_device *dev, pm_message_t state) -{ - struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); - - led_classdev_suspend(&led->cdev); - return 0; -} - -static int s3c24xx_led_resume(struct platform_device *dev) -{ - struct s3c24xx_gpio_led *led = pdev_to_gpio(dev); - - led_classdev_resume(&led->cdev); - return 0; -} -#else -#define s3c24xx_led_suspend NULL -#define s3c24xx_led_resume NULL -#endif - static struct platform_driver s3c24xx_led_driver = { .probe = s3c24xx_led_probe, .remove = s3c24xx_led_remove, - .suspend = s3c24xx_led_suspend, - .resume = s3c24xx_led_resume, .driver = { .name = "s3c24xx_led", .owner = THIS_MODULE, diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c new file mode 100644 index 00000000000..38c6bcb07e6 --- /dev/null +++ b/drivers/leds/leds-wm8350.c @@ -0,0 +1,311 @@ +/* + * LED driver for WM8350 driven LEDS. + * + * Copyright(C) 2007, 2008 Wolfson Microelectronics PLC. + * + * 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 <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/leds.h> +#include <linux/err.h> +#include <linux/mfd/wm8350/pmic.h> +#include <linux/regulator/consumer.h> + +/* Microamps */ +static const int isink_cur[] = { + 4, + 5, + 6, + 7, + 8, + 10, + 11, + 14, + 16, + 19, + 23, + 27, + 32, + 39, + 46, + 54, + 65, + 77, + 92, + 109, + 130, + 154, + 183, + 218, + 259, + 308, + 367, + 436, + 518, + 616, + 733, + 872, + 1037, + 1233, + 1466, + 1744, + 2073, + 2466, + 2933, + 3487, + 4147, + 4932, + 5865, + 6975, + 8294, + 9864, + 11730, + 13949, + 16589, + 19728, + 23460, + 27899, + 33178, + 39455, + 46920, + 55798, + 66355, + 78910, + 93840, + 111596, + 132710, + 157820, + 187681, + 223191 +}; + +#define to_wm8350_led(led_cdev) \ + container_of(led_cdev, struct wm8350_led, cdev) + +static void wm8350_led_enable(struct wm8350_led *led) +{ + int ret; + + if (led->enabled) + return; + + ret = regulator_enable(led->isink); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret); + return; + } + + ret = regulator_enable(led->dcdc); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret); + regulator_disable(led->isink); + return; + } + + led->enabled = 1; +} + +static void wm8350_led_disable(struct wm8350_led *led) +{ + int ret; + + if (!led->enabled) + return; + + ret = regulator_disable(led->dcdc); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret); + return; + } + + ret = regulator_disable(led->isink); + if (ret != 0) { + dev_err(led->cdev.dev, "Failed to disable ISINK: %d\n", ret); + regulator_enable(led->dcdc); + return; + } + + led->enabled = 0; +} + +static void led_work(struct work_struct *work) +{ + struct wm8350_led *led = container_of(work, struct wm8350_led, work); + int ret; + int uA; + unsigned long flags; + + mutex_lock(&led->mutex); + + spin_lock_irqsave(&led->value_lock, flags); + + if (led->value == LED_OFF) { + spin_unlock_irqrestore(&led->value_lock, flags); + wm8350_led_disable(led); + goto out; + } + + /* This scales linearly into the index of valid current + * settings which results in a linear scaling of perceived + * brightness due to the non-linear current settings provided + * by the hardware. + */ + uA = (led->max_uA_index * led->value) / LED_FULL; + spin_unlock_irqrestore(&led->value_lock, flags); + BUG_ON(uA >= ARRAY_SIZE(isink_cur)); + + ret = regulator_set_current_limit(led->isink, isink_cur[uA], + isink_cur[uA]); + if (ret != 0) + dev_err(led->cdev.dev, "Failed to set %duA: %d\n", + isink_cur[uA], ret); + + wm8350_led_enable(led); + +out: + mutex_unlock(&led->mutex); +} + +static void wm8350_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct wm8350_led *led = to_wm8350_led(led_cdev); + unsigned long flags; + + spin_lock_irqsave(&led->value_lock, flags); + led->value = value; + schedule_work(&led->work); + spin_unlock_irqrestore(&led->value_lock, flags); +} + +static void wm8350_led_shutdown(struct platform_device *pdev) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + mutex_lock(&led->mutex); + led->value = LED_OFF; + wm8350_led_disable(led); + mutex_unlock(&led->mutex); +} + +static int wm8350_led_probe(struct platform_device *pdev) +{ + struct regulator *isink, *dcdc; + struct wm8350_led *led; + struct wm8350_led_platform_data *pdata = pdev->dev.platform_data; + int ret, i; + + if (pdata == NULL) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; + } + + if (pdata->max_uA < isink_cur[0]) { + dev_err(&pdev->dev, "Invalid maximum current %duA\n", + pdata->max_uA); + return -EINVAL; + } + + isink = regulator_get(&pdev->dev, "led_isink"); + if (IS_ERR(isink)) { + printk(KERN_ERR "%s: cant get ISINK\n", __func__); + return PTR_ERR(isink); + } + + dcdc = regulator_get(&pdev->dev, "led_vcc"); + if (IS_ERR(dcdc)) { + printk(KERN_ERR "%s: cant get DCDC\n", __func__); + ret = PTR_ERR(dcdc); + goto err_isink; + } + + led = kzalloc(sizeof(*led), GFP_KERNEL); + if (led == NULL) { + ret = -ENOMEM; + goto err_dcdc; + } + + led->cdev.brightness_set = wm8350_led_set; + led->cdev.default_trigger = pdata->default_trigger; + led->cdev.name = pdata->name; + led->cdev.flags |= LED_CORE_SUSPENDRESUME; + led->enabled = regulator_is_enabled(isink); + led->isink = isink; + led->dcdc = dcdc; + + for (i = 0; i < ARRAY_SIZE(isink_cur) - 1; i++) + if (isink_cur[i] >= pdata->max_uA) + break; + led->max_uA_index = i; + if (pdata->max_uA != isink_cur[i]) + dev_warn(&pdev->dev, + "Maximum current %duA is not directly supported," + " check platform data\n", + pdata->max_uA); + + spin_lock_init(&led->value_lock); + mutex_init(&led->mutex); + INIT_WORK(&led->work, led_work); + led->value = LED_OFF; + platform_set_drvdata(pdev, led); + + ret = led_classdev_register(&pdev->dev, &led->cdev); + if (ret < 0) + goto err_led; + + return 0; + + err_led: + kfree(led); + err_dcdc: + regulator_put(dcdc); + err_isink: + regulator_put(isink); + return ret; +} + +static int wm8350_led_remove(struct platform_device *pdev) +{ + struct wm8350_led *led = platform_get_drvdata(pdev); + + led_classdev_unregister(&led->cdev); + flush_scheduled_work(); + wm8350_led_disable(led); + regulator_put(led->dcdc); + regulator_put(led->isink); + kfree(led); + return 0; +} + +static struct platform_driver wm8350_led_driver = { + .driver = { + .name = "wm8350-led", + .owner = THIS_MODULE, + }, + .probe = wm8350_led_probe, + .remove = wm8350_led_remove, + .shutdown = wm8350_led_shutdown, +}; + +static int __devinit wm8350_led_init(void) +{ + return platform_driver_register(&wm8350_led_driver); +} +module_init(wm8350_led_init); + +static void wm8350_led_exit(void) +{ + platform_driver_unregister(&wm8350_led_driver); +} +module_exit(wm8350_led_exit); + +MODULE_AUTHOR("Mark Brown"); +MODULE_DESCRIPTION("WM8350 LED driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:wm8350-led"); diff --git a/drivers/leds/leds-wrap.c b/drivers/leds/leds-wrap.c index 2f3aa87f2a1..2982c86ac4c 100644 --- a/drivers/leds/leds-wrap.c +++ b/drivers/leds/leds-wrap.c @@ -56,40 +56,21 @@ static struct led_classdev wrap_power_led = { .name = "wrap::power", .brightness_set = wrap_power_led_set, .default_trigger = "default-on", + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev wrap_error_led = { .name = "wrap::error", .brightness_set = wrap_error_led_set, + .flags = LED_CORE_SUSPENDRESUME, }; static struct led_classdev wrap_extra_led = { .name = "wrap::extra", .brightness_set = wrap_extra_led_set, + .flags = LED_CORE_SUSPENDRESUME, }; -#ifdef CONFIG_PM -static int wrap_led_suspend(struct platform_device *dev, - pm_message_t state) -{ - led_classdev_suspend(&wrap_power_led); - led_classdev_suspend(&wrap_error_led); - led_classdev_suspend(&wrap_extra_led); - return 0; -} - -static int wrap_led_resume(struct platform_device *dev) -{ - led_classdev_resume(&wrap_power_led); - led_classdev_resume(&wrap_error_led); - led_classdev_resume(&wrap_extra_led); - return 0; -} -#else -#define wrap_led_suspend NULL -#define wrap_led_resume NULL -#endif - static int wrap_led_probe(struct platform_device *pdev) { int ret; @@ -127,8 +108,6 @@ static int wrap_led_remove(struct platform_device *pdev) static struct platform_driver wrap_led_driver = { .probe = wrap_led_probe, .remove = wrap_led_remove, - .suspend = wrap_led_suspend, - .resume = wrap_led_resume, .driver = { .name = DRVNAME, .owner = THIS_MODULE, diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c index db681962d7b..3d6531396dd 100644 --- a/drivers/leds/ledtrig-timer.c +++ b/drivers/leds/ledtrig-timer.c @@ -199,6 +199,7 @@ err_out: static void timer_trig_deactivate(struct led_classdev *led_cdev) { struct timer_trig_data *timer_data = led_cdev->trigger_data; + unsigned long on = 0, off = 0; if (timer_data) { device_remove_file(led_cdev->dev, &dev_attr_delay_on); @@ -206,6 +207,10 @@ static void timer_trig_deactivate(struct led_classdev *led_cdev) del_timer_sync(&timer_data->timer); kfree(timer_data); } + + /* If there is hardware support for blinking, stop it */ + if (led_cdev->blink_set) + led_cdev->blink_set(led_cdev, &on, &off); } static struct led_trigger timer_led_trigger = { diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index ab7c8e4a61f..71994376339 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -215,7 +215,6 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, /* choose a good rdev and read the page from there */ mdk_rdev_t *rdev; - struct list_head *tmp; sector_t target; if (!page) @@ -223,7 +222,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, if (!page) return ERR_PTR(-ENOMEM); - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { if (! test_bit(In_sync, &rdev->flags) || test_bit(Faulty, &rdev->flags)) continue; @@ -964,9 +963,11 @@ static int bitmap_init_from_disk(struct bitmap *bitmap, sector_t start) */ page = bitmap->sb_page; offset = sizeof(bitmap_super_t); - read_sb_page(bitmap->mddev, bitmap->offset, - page, - index, count); + if (!file) + read_sb_page(bitmap->mddev, + bitmap->offset, + page, + index, count); } else if (file) { page = read_page(file, index, bitmap, count); offset = 0; diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index f26c1f9a475..86d9adf90e7 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -283,7 +283,6 @@ static int reconfig(mddev_t *mddev, int layout, int chunk_size) static int run(mddev_t *mddev) { mdk_rdev_t *rdev; - struct list_head *tmp; int i; conf_t *conf = kmalloc(sizeof(*conf), GFP_KERNEL); @@ -296,7 +295,7 @@ static int run(mddev_t *mddev) } conf->nfaults = 0; - rdev_for_each(rdev, tmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) conf->rdev = rdev; mddev->array_sectors = mddev->size * 2; diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 3b90c5c924e..1e3aea9eecf 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -105,7 +105,6 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) int i, nb_zone, cnt; sector_t min_sectors; sector_t curr_sector; - struct list_head *tmp; conf = kzalloc (sizeof (*conf) + raid_disks*sizeof(dev_info_t), GFP_KERNEL); @@ -115,7 +114,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) cnt = 0; conf->array_sectors = 0; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { int j = rdev->raid_disk; dev_info_t *disk = conf->disks + j; diff --git a/drivers/md/md.c b/drivers/md/md.c index 1b1d32694f6..41e2509bf89 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -214,20 +214,33 @@ static inline mddev_t *mddev_get(mddev_t *mddev) return mddev; } +static void mddev_delayed_delete(struct work_struct *ws) +{ + mddev_t *mddev = container_of(ws, mddev_t, del_work); + kobject_del(&mddev->kobj); + kobject_put(&mddev->kobj); +} + static void mddev_put(mddev_t *mddev) { if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) return; - if (!mddev->raid_disks && list_empty(&mddev->disks)) { + if (!mddev->raid_disks && list_empty(&mddev->disks) && + !mddev->hold_active) { list_del(&mddev->all_mddevs); - spin_unlock(&all_mddevs_lock); - blk_cleanup_queue(mddev->queue); - if (mddev->sysfs_state) - sysfs_put(mddev->sysfs_state); - mddev->sysfs_state = NULL; - kobject_put(&mddev->kobj); - } else - spin_unlock(&all_mddevs_lock); + if (mddev->gendisk) { + /* we did a probe so need to clean up. + * Call schedule_work inside the spinlock + * so that flush_scheduled_work() after + * mddev_find will succeed in waiting for the + * work to be done. + */ + INIT_WORK(&mddev->del_work, mddev_delayed_delete); + schedule_work(&mddev->del_work); + } else + kfree(mddev); + } + spin_unlock(&all_mddevs_lock); } static mddev_t * mddev_find(dev_t unit) @@ -236,15 +249,50 @@ static mddev_t * mddev_find(dev_t unit) retry: spin_lock(&all_mddevs_lock); - list_for_each_entry(mddev, &all_mddevs, all_mddevs) - if (mddev->unit == unit) { - mddev_get(mddev); + + if (unit) { + list_for_each_entry(mddev, &all_mddevs, all_mddevs) + if (mddev->unit == unit) { + mddev_get(mddev); + spin_unlock(&all_mddevs_lock); + kfree(new); + return mddev; + } + + if (new) { + list_add(&new->all_mddevs, &all_mddevs); spin_unlock(&all_mddevs_lock); - kfree(new); - return mddev; + new->hold_active = UNTIL_IOCTL; + return new; } - - if (new) { + } else if (new) { + /* find an unused unit number */ + static int next_minor = 512; + int start = next_minor; + int is_free = 0; + int dev = 0; + while (!is_free) { + dev = MKDEV(MD_MAJOR, next_minor); + next_minor++; + if (next_minor > MINORMASK) + next_minor = 0; + if (next_minor == start) { + /* Oh dear, all in use. */ + spin_unlock(&all_mddevs_lock); + kfree(new); + return NULL; + } + + is_free = 1; + list_for_each_entry(mddev, &all_mddevs, all_mddevs) + if (mddev->unit == dev) { + is_free = 0; + break; + } + } + new->unit = dev; + new->md_minor = MINOR(dev); + new->hold_active = UNTIL_STOP; list_add(&new->all_mddevs, &all_mddevs); spin_unlock(&all_mddevs_lock); return new; @@ -275,16 +323,6 @@ static mddev_t * mddev_find(dev_t unit) new->resync_max = MaxSector; new->level = LEVEL_NONE; - new->queue = blk_alloc_queue(GFP_KERNEL); - if (!new->queue) { - kfree(new); - return NULL; - } - /* Can be unlocked because the queue is new: no concurrency */ - queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue); - - blk_queue_make_request(new->queue, md_fail_request); - goto retry; } @@ -307,25 +345,23 @@ static inline void mddev_unlock(mddev_t * mddev) static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) { - mdk_rdev_t * rdev; - struct list_head *tmp; + mdk_rdev_t *rdev; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->desc_nr == nr) return rdev; - } + return NULL; } static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev) { - struct list_head *tmp; mdk_rdev_t *rdev; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->bdev->bd_dev == dev) return rdev; - } + return NULL; } @@ -861,7 +897,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) { mdp_super_t *sb; - struct list_head *tmp; mdk_rdev_t *rdev2; int next_spare = mddev->raid_disks; @@ -933,7 +968,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->state |= (1<<MD_SB_BITMAP_PRESENT); sb->disks[0].state = (1<<MD_DISK_REMOVED); - rdev_for_each(rdev2, tmp, mddev) { + list_for_each_entry(rdev2, &mddev->disks, same_set) { mdp_disk_t *d; int desc_nr; if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags) @@ -1259,7 +1294,6 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) { struct mdp_superblock_1 *sb; - struct list_head *tmp; mdk_rdev_t *rdev2; int max_dev, i; /* make rdev->sb match mddev and rdev data. */ @@ -1307,7 +1341,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) } max_dev = 0; - rdev_for_each(rdev2, tmp, mddev) + list_for_each_entry(rdev2, &mddev->disks, same_set) if (rdev2->desc_nr+1 > max_dev) max_dev = rdev2->desc_nr+1; @@ -1316,7 +1350,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) for (i=0; i<max_dev;i++) sb->dev_roles[i] = cpu_to_le16(0xfffe); - rdev_for_each(rdev2, tmp, mddev) { + list_for_each_entry(rdev2, &mddev->disks, same_set) { i = rdev2->desc_nr; if (test_bit(Faulty, &rdev2->flags)) sb->dev_roles[i] = cpu_to_le16(0xfffe); @@ -1466,6 +1500,9 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) list_add_rcu(&rdev->same_set, &mddev->disks); bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); + + /* May as well allow recovery to be retried once */ + mddev->recovery_disabled = 0; return 0; fail: @@ -1571,8 +1608,7 @@ static void kick_rdev_from_array(mdk_rdev_t * rdev) static void export_array(mddev_t *mddev) { - struct list_head *tmp; - mdk_rdev_t *rdev; + mdk_rdev_t *rdev, *tmp; rdev_for_each(rdev, tmp, mddev) { if (!rdev->mddev) { @@ -1593,7 +1629,7 @@ static void print_desc(mdp_disk_t *desc) desc->major,desc->minor,desc->raid_disk,desc->state); } -static void print_sb(mdp_super_t *sb) +static void print_sb_90(mdp_super_t *sb) { int i; @@ -1624,10 +1660,57 @@ static void print_sb(mdp_super_t *sb) } printk(KERN_INFO "md: THIS: "); print_desc(&sb->this_disk); - } -static void print_rdev(mdk_rdev_t *rdev) +static void print_sb_1(struct mdp_superblock_1 *sb) +{ + __u8 *uuid; + + uuid = sb->set_uuid; + printk(KERN_INFO "md: SB: (V:%u) (F:0x%08x) Array-ID:<%02x%02x%02x%02x" + ":%02x%02x:%02x%02x:%02x%02x:%02x%02x%02x%02x%02x%02x>\n" + KERN_INFO "md: Name: \"%s\" CT:%llu\n", + le32_to_cpu(sb->major_version), + le32_to_cpu(sb->feature_map), + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15], + sb->set_name, + (unsigned long long)le64_to_cpu(sb->ctime) + & MD_SUPERBLOCK_1_TIME_SEC_MASK); + + uuid = sb->device_uuid; + printk(KERN_INFO "md: L%u SZ%llu RD:%u LO:%u CS:%u DO:%llu DS:%llu SO:%llu" + " RO:%llu\n" + KERN_INFO "md: Dev:%08x UUID: %02x%02x%02x%02x:%02x%02x:%02x%02x:%02x%02x" + ":%02x%02x%02x%02x%02x%02x\n" + KERN_INFO "md: (F:0x%08x) UT:%llu Events:%llu ResyncOffset:%llu CSUM:0x%08x\n" + KERN_INFO "md: (MaxDev:%u) \n", + le32_to_cpu(sb->level), + (unsigned long long)le64_to_cpu(sb->size), + le32_to_cpu(sb->raid_disks), + le32_to_cpu(sb->layout), + le32_to_cpu(sb->chunksize), + (unsigned long long)le64_to_cpu(sb->data_offset), + (unsigned long long)le64_to_cpu(sb->data_size), + (unsigned long long)le64_to_cpu(sb->super_offset), + (unsigned long long)le64_to_cpu(sb->recovery_offset), + le32_to_cpu(sb->dev_number), + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15], + sb->devflags, + (unsigned long long)le64_to_cpu(sb->utime) & MD_SUPERBLOCK_1_TIME_SEC_MASK, + (unsigned long long)le64_to_cpu(sb->events), + (unsigned long long)le64_to_cpu(sb->resync_offset), + le32_to_cpu(sb->sb_csum), + le32_to_cpu(sb->max_dev) + ); +} + +static void print_rdev(mdk_rdev_t *rdev, int major_version) { char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n", @@ -1635,15 +1718,22 @@ static void print_rdev(mdk_rdev_t *rdev) test_bit(Faulty, &rdev->flags), test_bit(In_sync, &rdev->flags), rdev->desc_nr); if (rdev->sb_loaded) { - printk(KERN_INFO "md: rdev superblock:\n"); - print_sb((mdp_super_t*)page_address(rdev->sb_page)); + printk(KERN_INFO "md: rdev superblock (MJ:%d):\n", major_version); + switch (major_version) { + case 0: + print_sb_90((mdp_super_t*)page_address(rdev->sb_page)); + break; + case 1: + print_sb_1((struct mdp_superblock_1 *)page_address(rdev->sb_page)); + break; + } } else printk(KERN_INFO "md: no rdev superblock!\n"); } static void md_print_devices(void) { - struct list_head *tmp, *tmp2; + struct list_head *tmp; mdk_rdev_t *rdev; mddev_t *mddev; char b[BDEVNAME_SIZE]; @@ -1658,12 +1748,12 @@ static void md_print_devices(void) bitmap_print_sb(mddev->bitmap); else printk("%s: ", mdname(mddev)); - rdev_for_each(rdev, tmp2, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) printk("<%s>", bdevname(rdev->bdev,b)); printk("\n"); - rdev_for_each(rdev, tmp2, mddev) - print_rdev(rdev); + list_for_each_entry(rdev, &mddev->disks, same_set) + print_rdev(rdev, mddev->major_version); } printk("md: **********************************\n"); printk("\n"); @@ -1679,9 +1769,8 @@ static void sync_sbs(mddev_t * mddev, int nospares) * with the rest of the array) */ mdk_rdev_t *rdev; - struct list_head *tmp; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->sb_events == mddev->events || (nospares && rdev->raid_disk < 0 && @@ -1699,7 +1788,6 @@ static void sync_sbs(mddev_t * mddev, int nospares) static void md_update_sb(mddev_t * mddev, int force_change) { - struct list_head *tmp; mdk_rdev_t *rdev; int sync_req; int nospares = 0; @@ -1790,7 +1878,7 @@ repeat: mdname(mddev),mddev->in_sync); bitmap_update_sb(mddev->bitmap); - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { char b[BDEVNAME_SIZE]; dprintk(KERN_INFO "md: "); if (rdev->sb_loaded != 1) @@ -1999,7 +2087,6 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) md_wakeup_thread(rdev->mddev->thread); } else if (rdev->mddev->pers) { mdk_rdev_t *rdev2; - struct list_head *tmp; /* Activating a spare .. or possibly reactivating * if we every get bitmaps working here. */ @@ -2010,7 +2097,7 @@ slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) if (rdev->mddev->pers->hot_add_disk == NULL) return -EINVAL; - rdev_for_each(rdev2, tmp, rdev->mddev) + list_for_each_entry(rdev2, &rdev->mddev->disks, same_set) if (rdev2->raid_disk == slot) return -EEXIST; @@ -2125,14 +2212,14 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) */ mddev_t *mddev; int overlap = 0; - struct list_head *tmp, *tmp2; + struct list_head *tmp; mddev_unlock(my_mddev); for_each_mddev(mddev, tmp) { mdk_rdev_t *rdev2; mddev_lock(mddev); - rdev_for_each(rdev2, tmp2, mddev) + list_for_each_entry(rdev2, &mddev->disks, same_set) if (test_bit(AllReserved, &rdev2->flags) || (rdev->bdev == rdev2->bdev && rdev != rdev2 && @@ -2328,8 +2415,7 @@ abort_free: static void analyze_sbs(mddev_t * mddev) { int i; - struct list_head *tmp; - mdk_rdev_t *rdev, *freshest; + mdk_rdev_t *rdev, *freshest, *tmp; char b[BDEVNAME_SIZE]; freshest = NULL; @@ -3046,7 +3132,7 @@ action_store(mddev_t *mddev, const char *page, size_t len) } set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); - sysfs_notify(&mddev->kobj, NULL, "sync_action"); + sysfs_notify_dirent(mddev->sysfs_action); return len; } @@ -3404,6 +3490,8 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, if (!capable(CAP_SYS_ADMIN)) return -EACCES; rv = mddev_lock(mddev); + if (mddev->hold_active == UNTIL_IOCTL) + mddev->hold_active = 0; if (!rv) { rv = entry->store(mddev, page, length); mddev_unlock(mddev); @@ -3414,6 +3502,17 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, static void md_free(struct kobject *ko) { mddev_t *mddev = container_of(ko, mddev_t, kobj); + + if (mddev->sysfs_state) + sysfs_put(mddev->sysfs_state); + + if (mddev->gendisk) { + del_gendisk(mddev->gendisk); + put_disk(mddev->gendisk); + } + if (mddev->queue) + blk_cleanup_queue(mddev->queue); + kfree(mddev); } @@ -3429,34 +3528,74 @@ static struct kobj_type md_ktype = { int mdp_major = 0; -static struct kobject *md_probe(dev_t dev, int *part, void *data) +static int md_alloc(dev_t dev, char *name) { static DEFINE_MUTEX(disks_mutex); mddev_t *mddev = mddev_find(dev); struct gendisk *disk; - int partitioned = (MAJOR(dev) != MD_MAJOR); - int shift = partitioned ? MdpMinorShift : 0; - int unit = MINOR(dev) >> shift; + int partitioned; + int shift; + int unit; int error; if (!mddev) - return NULL; + return -ENODEV; + + partitioned = (MAJOR(mddev->unit) != MD_MAJOR); + shift = partitioned ? MdpMinorShift : 0; + unit = MINOR(mddev->unit) >> shift; + + /* wait for any previous instance if this device + * to be completed removed (mddev_delayed_delete). + */ + flush_scheduled_work(); mutex_lock(&disks_mutex); if (mddev->gendisk) { mutex_unlock(&disks_mutex); mddev_put(mddev); - return NULL; + return -EEXIST; + } + + if (name) { + /* Need to ensure that 'name' is not a duplicate. + */ + mddev_t *mddev2; + spin_lock(&all_mddevs_lock); + + list_for_each_entry(mddev2, &all_mddevs, all_mddevs) + if (mddev2->gendisk && + strcmp(mddev2->gendisk->disk_name, name) == 0) { + spin_unlock(&all_mddevs_lock); + return -EEXIST; + } + spin_unlock(&all_mddevs_lock); + } + + mddev->queue = blk_alloc_queue(GFP_KERNEL); + if (!mddev->queue) { + mutex_unlock(&disks_mutex); + mddev_put(mddev); + return -ENOMEM; } + /* Can be unlocked because the queue is new: no concurrency */ + queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue); + + blk_queue_make_request(mddev->queue, md_fail_request); + disk = alloc_disk(1 << shift); if (!disk) { mutex_unlock(&disks_mutex); + blk_cleanup_queue(mddev->queue); + mddev->queue = NULL; mddev_put(mddev); - return NULL; + return -ENOMEM; } - disk->major = MAJOR(dev); + disk->major = MAJOR(mddev->unit); disk->first_minor = unit << shift; - if (partitioned) + if (name) + strcpy(disk->disk_name, name); + else if (partitioned) sprintf(disk->disk_name, "md_d%d", unit); else sprintf(disk->disk_name, "md%d", unit); @@ -3464,7 +3603,7 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) disk->private_data = mddev; disk->queue = mddev->queue; /* Allow extended partitions. This makes the - * 'mdp' device redundant, but we can really + * 'mdp' device redundant, but we can't really * remove it now. */ disk->flags |= GENHD_FL_EXT_DEVT; @@ -3480,9 +3619,35 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data) kobject_uevent(&mddev->kobj, KOBJ_ADD); mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state"); } + mddev_put(mddev); + return 0; +} + +static struct kobject *md_probe(dev_t dev, int *part, void *data) +{ + md_alloc(dev, NULL); return NULL; } +static int add_named_array(const char *val, struct kernel_param *kp) +{ + /* val must be "md_*" where * is not all digits. + * We allocate an array with a large free minor number, and + * set the name to val. val must not already be an active name. + */ + int len = strlen(val); + char buf[DISK_NAME_LEN]; + + while (len && val[len-1] == '\n') + len--; + if (len >= DISK_NAME_LEN) + return -E2BIG; + strlcpy(buf, val, len+1); + if (strncmp(buf, "md_", 3) != 0) + return -EINVAL; + return md_alloc(0, buf); +} + static void md_safemode_timeout(unsigned long data) { mddev_t *mddev = (mddev_t *) data; @@ -3501,7 +3666,6 @@ static int do_md_run(mddev_t * mddev) { int err; int chunk_size; - struct list_head *tmp; mdk_rdev_t *rdev; struct gendisk *disk; struct mdk_personality *pers; @@ -3540,7 +3704,7 @@ static int do_md_run(mddev_t * mddev) } /* devices must have minimum size of one chunk */ - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { if (test_bit(Faulty, &rdev->flags)) continue; if (rdev->size < chunk_size / 1024) { @@ -3565,7 +3729,7 @@ static int do_md_run(mddev_t * mddev) * the only valid external interface is through the md * device. */ - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { if (test_bit(Faulty, &rdev->flags)) continue; sync_blockdev(rdev->bdev); @@ -3630,10 +3794,10 @@ static int do_md_run(mddev_t * mddev) */ char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; mdk_rdev_t *rdev2; - struct list_head *tmp2; int warned = 0; - rdev_for_each(rdev, tmp, mddev) { - rdev_for_each(rdev2, tmp2, mddev) { + + list_for_each_entry(rdev, &mddev->disks, same_set) + list_for_each_entry(rdev2, &mddev->disks, same_set) { if (rdev < rdev2 && rdev->bdev->bd_contains == rdev2->bdev->bd_contains) { @@ -3647,7 +3811,7 @@ static int do_md_run(mddev_t * mddev) warned = 1; } } - } + if (warned) printk(KERN_WARNING "True protection against single-disk" @@ -3684,6 +3848,7 @@ static int do_md_run(mddev_t * mddev) printk(KERN_WARNING "md: cannot register extra attributes for %s\n", mdname(mddev)); + mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); } else if (mddev->ro == 2) /* auto-readonly not meaningful */ mddev->ro = 0; @@ -3694,7 +3859,7 @@ static int do_md_run(mddev_t * mddev) mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->in_sync = 1; - rdev_for_each(rdev, tmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0) { char nm[20]; sprintf(nm, "rd%d", rdev->raid_disk); @@ -3725,9 +3890,8 @@ static int do_md_run(mddev_t * mddev) * it will remove the drives and not do the right thing */ if (mddev->degraded && !mddev->sync_thread) { - struct list_head *rtmp; int spares = 0; - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) @@ -3754,7 +3918,8 @@ static int do_md_run(mddev_t * mddev) mddev->changed = 1; md_new_event(mddev); sysfs_notify_dirent(mddev->sysfs_state); - sysfs_notify(&mddev->kobj, NULL, "sync_action"); + if (mddev->sysfs_action) + sysfs_notify_dirent(mddev->sysfs_action); sysfs_notify(&mddev->kobj, NULL, "degraded"); kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE); return 0; @@ -3854,9 +4019,12 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) mddev->queue->merge_bvec_fn = NULL; mddev->queue->unplug_fn = NULL; mddev->queue->backing_dev_info.congested_fn = NULL; - if (mddev->pers->sync_request) + if (mddev->pers->sync_request) { sysfs_remove_group(&mddev->kobj, &md_redundancy_group); - + if (mddev->sysfs_action) + sysfs_put(mddev->sysfs_action); + mddev->sysfs_action = NULL; + } module_put(mddev->pers->owner); mddev->pers = NULL; /* tell userspace to handle 'inactive' */ @@ -3883,7 +4051,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) */ if (mode == 0) { mdk_rdev_t *rdev; - struct list_head *tmp; printk(KERN_INFO "md: %s stopped.\n", mdname(mddev)); @@ -3895,7 +4062,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) } mddev->bitmap_offset = 0; - rdev_for_each(rdev, tmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0) { char nm[20]; sprintf(nm, "rd%d", rdev->raid_disk); @@ -3941,6 +4108,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) mddev->barriers_work = 0; mddev->safemode = 0; kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE); + if (mddev->hold_active == UNTIL_STOP) + mddev->hold_active = 0; } else if (mddev->pers) printk(KERN_INFO "md: %s switched to read-only mode.\n", @@ -3956,7 +4125,6 @@ out: static void autorun_array(mddev_t *mddev) { mdk_rdev_t *rdev; - struct list_head *tmp; int err; if (list_empty(&mddev->disks)) @@ -3964,7 +4132,7 @@ static void autorun_array(mddev_t *mddev) printk(KERN_INFO "md: running: "); - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { char b[BDEVNAME_SIZE]; printk("<%s>", bdevname(rdev->bdev,b)); } @@ -3991,8 +4159,7 @@ static void autorun_array(mddev_t *mddev) */ static void autorun_devices(int part) { - struct list_head *tmp; - mdk_rdev_t *rdev0, *rdev; + mdk_rdev_t *rdev0, *rdev, *tmp; mddev_t *mddev; char b[BDEVNAME_SIZE]; @@ -4007,7 +4174,7 @@ static void autorun_devices(int part) printk(KERN_INFO "md: considering %s ...\n", bdevname(rdev0->bdev,b)); INIT_LIST_HEAD(&candidates); - rdev_for_each_list(rdev, tmp, pending_raid_disks) + rdev_for_each_list(rdev, tmp, &pending_raid_disks) if (super_90_load(rdev, rdev0, 0) >= 0) { printk(KERN_INFO "md: adding %s ...\n", bdevname(rdev->bdev,b)); @@ -4053,7 +4220,7 @@ static void autorun_devices(int part) } else { printk(KERN_INFO "md: created %s\n", mdname(mddev)); mddev->persistent = 1; - rdev_for_each_list(rdev, tmp, candidates) { + rdev_for_each_list(rdev, tmp, &candidates) { list_del_init(&rdev->same_set); if (bind_rdev_to_array(rdev, mddev)) export_rdev(rdev); @@ -4064,7 +4231,7 @@ static void autorun_devices(int part) /* on success, candidates will be empty, on error * it won't... */ - rdev_for_each_list(rdev, tmp, candidates) { + rdev_for_each_list(rdev, tmp, &candidates) { list_del_init(&rdev->same_set); export_rdev(rdev); } @@ -4093,10 +4260,9 @@ static int get_array_info(mddev_t * mddev, void __user * arg) mdu_array_info_t info; int nr,working,active,failed,spare; mdk_rdev_t *rdev; - struct list_head *tmp; nr=working=active=failed=spare=0; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { nr++; if (test_bit(Faulty, &rdev->flags)) failed++; @@ -4614,9 +4780,8 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) static int update_size(mddev_t *mddev, sector_t num_sectors) { - mdk_rdev_t * rdev; + mdk_rdev_t *rdev; int rv; - struct list_head *tmp; int fit = (num_sectors == 0); if (mddev->pers->resize == NULL) @@ -4638,7 +4803,7 @@ static int update_size(mddev_t *mddev, sector_t num_sectors) * grow, and re-add. */ return -EBUSY; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { sector_t avail; avail = rdev->size * 2; @@ -5000,6 +5165,9 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode, done_unlock: abort_unlock: + if (mddev->hold_active == UNTIL_IOCTL && + err != -EINVAL) + mddev->hold_active = 0; mddev_unlock(mddev); return err; @@ -5016,14 +5184,25 @@ static int md_open(struct block_device *bdev, fmode_t mode) * Succeed if we can lock the mddev, which confirms that * it isn't being stopped right now. */ - mddev_t *mddev = bdev->bd_disk->private_data; + mddev_t *mddev = mddev_find(bdev->bd_dev); int err; + if (mddev->gendisk != bdev->bd_disk) { + /* we are racing with mddev_put which is discarding this + * bd_disk. + */ + mddev_put(mddev); + /* Wait until bdev->bd_disk is definitely gone */ + flush_scheduled_work(); + /* Then retry the open from the top */ + return -ERESTARTSYS; + } + BUG_ON(mddev != bdev->bd_disk->private_data); + if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1))) goto out; err = 0; - mddev_get(mddev); atomic_inc(&mddev->openers); mddev_unlock(mddev); @@ -5187,11 +5366,10 @@ static void status_unused(struct seq_file *seq) { int i = 0; mdk_rdev_t *rdev; - struct list_head *tmp; seq_printf(seq, "unused devices: "); - rdev_for_each_list(rdev, tmp, pending_raid_disks) { + list_for_each_entry(rdev, &pending_raid_disks, same_set) { char b[BDEVNAME_SIZE]; i++; seq_printf(seq, "%s ", @@ -5350,7 +5528,6 @@ static int md_seq_show(struct seq_file *seq, void *v) { mddev_t *mddev = v; sector_t size; - struct list_head *tmp2; mdk_rdev_t *rdev; struct mdstat_info *mi = seq->private; struct bitmap *bitmap; @@ -5387,7 +5564,7 @@ static int md_seq_show(struct seq_file *seq, void *v) } size = 0; - rdev_for_each(rdev, tmp2, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", bdevname(rdev->bdev,b), rdev->desc_nr); @@ -5694,7 +5871,6 @@ void md_do_sync(mddev_t *mddev) struct list_head *tmp; sector_t last_check; int skipped = 0; - struct list_head *rtmp; mdk_rdev_t *rdev; char *desc; @@ -5799,7 +5975,7 @@ void md_do_sync(mddev_t *mddev) /* recovery follows the physical size of devices */ max_sectors = mddev->size << 1; j = MaxSector; - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && @@ -5949,7 +6125,7 @@ void md_do_sync(mddev_t *mddev) } else { if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) mddev->curr_resync = MaxSector; - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && @@ -5985,10 +6161,9 @@ EXPORT_SYMBOL_GPL(md_do_sync); static int remove_and_add_spares(mddev_t *mddev) { mdk_rdev_t *rdev; - struct list_head *rtmp; int spares = 0; - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk >= 0 && !test_bit(Blocked, &rdev->flags) && (test_bit(Faulty, &rdev->flags) || @@ -6003,8 +6178,8 @@ static int remove_and_add_spares(mddev_t *mddev) } } - if (mddev->degraded && ! mddev->ro) { - rdev_for_each(rdev, rtmp, mddev) { + if (mddev->degraded && ! mddev->ro && !mddev->recovery_disabled) { + list_for_each_entry(rdev, &mddev->disks, same_set) { if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && !test_bit(Blocked, &rdev->flags)) @@ -6056,7 +6231,6 @@ static int remove_and_add_spares(mddev_t *mddev) void md_check_recovery(mddev_t *mddev) { mdk_rdev_t *rdev; - struct list_head *rtmp; if (mddev->bitmap) @@ -6120,7 +6294,7 @@ void md_check_recovery(mddev_t *mddev) if (mddev->flags) md_update_sb(mddev, 0); - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (test_and_clear_bit(StateChanged, &rdev->flags)) sysfs_notify_dirent(rdev->sysfs_state); @@ -6149,13 +6323,13 @@ void md_check_recovery(mddev_t *mddev) * information must be scrapped */ if (!mddev->degraded) - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) rdev->saved_raid_disk = -1; mddev->recovery = 0; /* flag recovery needed just to double check */ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); - sysfs_notify(&mddev->kobj, NULL, "sync_action"); + sysfs_notify_dirent(mddev->sysfs_action); md_new_event(mddev); goto unlock; } @@ -6216,7 +6390,7 @@ void md_check_recovery(mddev_t *mddev) mddev->recovery = 0; } else md_wakeup_thread(mddev->sync_thread); - sysfs_notify(&mddev->kobj, NULL, "sync_action"); + sysfs_notify_dirent(mddev->sysfs_action); md_new_event(mddev); } unlock: @@ -6224,7 +6398,8 @@ void md_check_recovery(mddev_t *mddev) clear_bit(MD_RECOVERY_RUNNING, &mddev->recovery); if (test_and_clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery)) - sysfs_notify(&mddev->kobj, NULL, "sync_action"); + if (mddev->sysfs_action) + sysfs_notify_dirent(mddev->sysfs_action); } mddev_unlock(mddev); } @@ -6386,14 +6561,8 @@ static __exit void md_exit(void) unregister_sysctl_table(raid_table_header); remove_proc_entry("mdstat", NULL); for_each_mddev(mddev, tmp) { - struct gendisk *disk = mddev->gendisk; - if (!disk) - continue; export_array(mddev); - del_gendisk(disk); - put_disk(disk); - mddev->gendisk = NULL; - mddev_put(mddev); + mddev->hold_active = 0; } } @@ -6418,6 +6587,7 @@ static int set_ro(const char *val, struct kernel_param *kp) module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR); module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR); +module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR); EXPORT_SYMBOL(register_md_personality); EXPORT_SYMBOL(unregister_md_personality); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index d4ac47d1127..f6d08f24167 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -408,7 +408,6 @@ static int multipath_run (mddev_t *mddev) int disk_idx; struct multipath_info *disk; mdk_rdev_t *rdev; - struct list_head *tmp; if (mddev->level != LEVEL_MULTIPATH) { printk("multipath: %s: raid level not set to multipath IO (%d)\n", @@ -441,7 +440,7 @@ static int multipath_run (mddev_t *mddev) } conf->working_disks = 0; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { disk_idx = rdev->raid_disk; if (disk_idx < 0 || disk_idx >= mddev->raid_disks) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 8ac6488ad0d..c605ba80558 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -53,11 +53,10 @@ static int raid0_congested(void *data, int bits) static int create_strip_zones (mddev_t *mddev) { int i, c, j; - sector_t current_offset, curr_zone_offset; + sector_t current_start, curr_zone_start; sector_t min_spacing; raid0_conf_t *conf = mddev_to_conf(mddev); mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; - struct list_head *tmp1, *tmp2; struct strip_zone *zone; int cnt; char b[BDEVNAME_SIZE]; @@ -67,19 +66,19 @@ static int create_strip_zones (mddev_t *mddev) */ conf->nr_strip_zones = 0; - rdev_for_each(rdev1, tmp1, mddev) { - printk("raid0: looking at %s\n", + list_for_each_entry(rdev1, &mddev->disks, same_set) { + printk(KERN_INFO "raid0: looking at %s\n", bdevname(rdev1->bdev,b)); c = 0; - rdev_for_each(rdev2, tmp2, mddev) { - printk("raid0: comparing %s(%llu)", + list_for_each_entry(rdev2, &mddev->disks, same_set) { + printk(KERN_INFO "raid0: comparing %s(%llu)", bdevname(rdev1->bdev,b), (unsigned long long)rdev1->size); - printk(" with %s(%llu)\n", + printk(KERN_INFO " with %s(%llu)\n", bdevname(rdev2->bdev,b), (unsigned long long)rdev2->size); if (rdev2 == rdev1) { - printk("raid0: END\n"); + printk(KERN_INFO "raid0: END\n"); break; } if (rdev2->size == rdev1->size) @@ -88,19 +87,20 @@ static int create_strip_zones (mddev_t *mddev) * Not unique, don't count it as a new * group */ - printk("raid0: EQUAL\n"); + printk(KERN_INFO "raid0: EQUAL\n"); c = 1; break; } - printk("raid0: NOT EQUAL\n"); + printk(KERN_INFO "raid0: NOT EQUAL\n"); } if (!c) { - printk("raid0: ==> UNIQUE\n"); + printk(KERN_INFO "raid0: ==> UNIQUE\n"); conf->nr_strip_zones++; - printk("raid0: %d zones\n", conf->nr_strip_zones); + printk(KERN_INFO "raid0: %d zones\n", + conf->nr_strip_zones); } } - printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); + printk(KERN_INFO "raid0: FINAL %d zones\n", conf->nr_strip_zones); conf->strip_zone = kzalloc(sizeof(struct strip_zone)* conf->nr_strip_zones, GFP_KERNEL); @@ -119,16 +119,17 @@ static int create_strip_zones (mddev_t *mddev) cnt = 0; smallest = NULL; zone->dev = conf->devlist; - rdev_for_each(rdev1, tmp1, mddev) { + list_for_each_entry(rdev1, &mddev->disks, same_set) { int j = rdev1->raid_disk; if (j < 0 || j >= mddev->raid_disks) { - printk("raid0: bad disk number %d - aborting!\n", j); + printk(KERN_ERR "raid0: bad disk number %d - " + "aborting!\n", j); goto abort; } if (zone->dev[j]) { - printk("raid0: multiple devices for %d - aborting!\n", - j); + printk(KERN_ERR "raid0: multiple devices for %d - " + "aborting!\n", j); goto abort; } zone->dev[j] = rdev1; @@ -149,16 +150,16 @@ static int create_strip_zones (mddev_t *mddev) cnt++; } if (cnt != mddev->raid_disks) { - printk("raid0: too few disks (%d of %d) - aborting!\n", - cnt, mddev->raid_disks); + printk(KERN_ERR "raid0: too few disks (%d of %d) - " + "aborting!\n", cnt, mddev->raid_disks); goto abort; } zone->nb_dev = cnt; - zone->size = smallest->size * cnt; - zone->zone_offset = 0; + zone->sectors = smallest->size * cnt * 2; + zone->zone_start = 0; - current_offset = smallest->size; - curr_zone_offset = zone->size; + current_start = smallest->size * 2; + curr_zone_start = zone->sectors; /* now do the other zones */ for (i = 1; i < conf->nr_strip_zones; i++) @@ -166,40 +167,41 @@ static int create_strip_zones (mddev_t *mddev) zone = conf->strip_zone + i; zone->dev = conf->strip_zone[i-1].dev + mddev->raid_disks; - printk("raid0: zone %d\n", i); - zone->dev_offset = current_offset; + printk(KERN_INFO "raid0: zone %d\n", i); + zone->dev_start = current_start; smallest = NULL; c = 0; for (j=0; j<cnt; j++) { char b[BDEVNAME_SIZE]; rdev = conf->strip_zone[0].dev[j]; - printk("raid0: checking %s ...", bdevname(rdev->bdev,b)); - if (rdev->size > current_offset) - { - printk(" contained as device %d\n", c); + printk(KERN_INFO "raid0: checking %s ...", + bdevname(rdev->bdev, b)); + if (rdev->size > current_start / 2) { + printk(KERN_INFO " contained as device %d\n", + c); zone->dev[c] = rdev; c++; if (!smallest || (rdev->size <smallest->size)) { smallest = rdev; - printk(" (%llu) is smallest!.\n", + printk(KERN_INFO " (%llu) is smallest!.\n", (unsigned long long)rdev->size); } } else - printk(" nope.\n"); + printk(KERN_INFO " nope.\n"); } zone->nb_dev = c; - zone->size = (smallest->size - current_offset) * c; - printk("raid0: zone->nb_dev: %d, size: %llu\n", - zone->nb_dev, (unsigned long long)zone->size); + zone->sectors = (smallest->size * 2 - current_start) * c; + printk(KERN_INFO "raid0: zone->nb_dev: %d, sectors: %llu\n", + zone->nb_dev, (unsigned long long)zone->sectors); - zone->zone_offset = curr_zone_offset; - curr_zone_offset += zone->size; + zone->zone_start = curr_zone_start; + curr_zone_start += zone->sectors; - current_offset = smallest->size; - printk("raid0: current zone offset: %llu\n", - (unsigned long long)current_offset); + current_start = smallest->size * 2; + printk(KERN_INFO "raid0: current zone start: %llu\n", + (unsigned long long)current_start); } /* Now find appropriate hash spacing. @@ -210,16 +212,16 @@ static int create_strip_zones (mddev_t *mddev) * strip though as it's size has no bearing on the efficacy of the hash * table. */ - conf->hash_spacing = curr_zone_offset; - min_spacing = curr_zone_offset; + conf->spacing = curr_zone_start; + min_spacing = curr_zone_start; sector_div(min_spacing, PAGE_SIZE/sizeof(struct strip_zone*)); for (i=0; i < conf->nr_strip_zones-1; i++) { - sector_t sz = 0; - for (j=i; j<conf->nr_strip_zones-1 && - sz < min_spacing ; j++) - sz += conf->strip_zone[j].size; - if (sz >= min_spacing && sz < conf->hash_spacing) - conf->hash_spacing = sz; + sector_t s = 0; + for (j = i; j < conf->nr_strip_zones - 1 && + s < min_spacing; j++) + s += conf->strip_zone[j].sectors; + if (s >= min_spacing && s < conf->spacing) + conf->spacing = s; } mddev->queue->unplug_fn = raid0_unplug; @@ -227,7 +229,7 @@ static int create_strip_zones (mddev_t *mddev) mddev->queue->backing_dev_info.congested_fn = raid0_congested; mddev->queue->backing_dev_info.congested_data = mddev; - printk("raid0: done.\n"); + printk(KERN_INFO "raid0: done.\n"); return 0; abort: return 1; @@ -262,10 +264,9 @@ static int raid0_mergeable_bvec(struct request_queue *q, static int raid0_run (mddev_t *mddev) { unsigned cur=0, i=0, nb_zone; - s64 size; + s64 sectors; raid0_conf_t *conf; mdk_rdev_t *rdev; - struct list_head *tmp; if (mddev->chunk_size == 0) { printk(KERN_ERR "md/raid0: non-zero chunk size required.\n"); @@ -291,54 +292,54 @@ static int raid0_run (mddev_t *mddev) /* calculate array device size */ mddev->array_sectors = 0; - rdev_for_each(rdev, tmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) mddev->array_sectors += rdev->size * 2; - printk("raid0 : md_size is %llu blocks.\n", - (unsigned long long)mddev->array_sectors / 2); - printk("raid0 : conf->hash_spacing is %llu blocks.\n", - (unsigned long long)conf->hash_spacing); + printk(KERN_INFO "raid0 : md_size is %llu sectors.\n", + (unsigned long long)mddev->array_sectors); + printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n", + (unsigned long long)conf->spacing); { - sector_t s = mddev->array_sectors / 2; - sector_t space = conf->hash_spacing; + sector_t s = mddev->array_sectors; + sector_t space = conf->spacing; int round; - conf->preshift = 0; + conf->sector_shift = 0; if (sizeof(sector_t) > sizeof(u32)) { /*shift down space and s so that sector_div will work */ while (space > (sector_t) (~(u32)0)) { s >>= 1; space >>= 1; s += 1; /* force round-up */ - conf->preshift++; + conf->sector_shift++; } } round = sector_div(s, (u32)space) ? 1 : 0; nb_zone = s + round; } - printk("raid0 : nb_zone is %d.\n", nb_zone); + printk(KERN_INFO "raid0 : nb_zone is %d.\n", nb_zone); - printk("raid0 : Allocating %Zd bytes for hash.\n", + printk(KERN_INFO "raid0 : Allocating %zu bytes for hash.\n", nb_zone*sizeof(struct strip_zone*)); conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL); if (!conf->hash_table) goto out_free_conf; - size = conf->strip_zone[cur].size; + sectors = conf->strip_zone[cur].sectors; conf->hash_table[0] = conf->strip_zone + cur; for (i=1; i< nb_zone; i++) { - while (size <= conf->hash_spacing) { + while (sectors <= conf->spacing) { cur++; - size += conf->strip_zone[cur].size; + sectors += conf->strip_zone[cur].sectors; } - size -= conf->hash_spacing; + sectors -= conf->spacing; conf->hash_table[i] = conf->strip_zone + cur; } - if (conf->preshift) { - conf->hash_spacing >>= conf->preshift; - /* round hash_spacing up so when we divide by it, we + if (conf->sector_shift) { + conf->spacing >>= conf->sector_shift; + /* round spacing up so when we divide by it, we * err on the side of too-low, which is safest */ - conf->hash_spacing++; + conf->spacing++; } /* calculate the max read-ahead size. @@ -387,12 +388,12 @@ static int raid0_stop (mddev_t *mddev) static int raid0_make_request (struct request_queue *q, struct bio *bio) { mddev_t *mddev = q->queuedata; - unsigned int sect_in_chunk, chunksize_bits, chunk_size, chunk_sects; + unsigned int sect_in_chunk, chunksect_bits, chunk_sects; raid0_conf_t *conf = mddev_to_conf(mddev); struct strip_zone *zone; mdk_rdev_t *tmp_dev; sector_t chunk; - sector_t block, rsect; + sector_t sector, rsect; const int rw = bio_data_dir(bio); int cpu; @@ -407,11 +408,9 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) bio_sectors(bio)); part_stat_unlock(); - chunk_size = mddev->chunk_size >> 10; chunk_sects = mddev->chunk_size >> 9; - chunksize_bits = ffz(~chunk_size); - block = bio->bi_sector >> 1; - + chunksect_bits = ffz(~chunk_sects); + sector = bio->bi_sector; if (unlikely(chunk_sects < (bio->bi_sector & (chunk_sects - 1)) + (bio->bi_size >> 9))) { struct bio_pair *bp; @@ -434,28 +433,27 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) { - sector_t x = block >> conf->preshift; - sector_div(x, (u32)conf->hash_spacing); + sector_t x = sector >> conf->sector_shift; + sector_div(x, (u32)conf->spacing); zone = conf->hash_table[x]; } - - while (block >= (zone->zone_offset + zone->size)) + + while (sector >= zone->zone_start + zone->sectors) zone++; - - sect_in_chunk = bio->bi_sector & ((chunk_size<<1) -1); + + sect_in_chunk = bio->bi_sector & (chunk_sects - 1); { - sector_t x = (block - zone->zone_offset) >> chunksize_bits; + sector_t x = (sector - zone->zone_start) >> chunksect_bits; sector_div(x, zone->nb_dev); chunk = x; - x = block >> chunksize_bits; + x = sector >> chunksect_bits; tmp_dev = zone->dev[sector_div(x, zone->nb_dev)]; } - rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1) - + sect_in_chunk; + rsect = (chunk << chunksect_bits) + zone->dev_start + sect_in_chunk; bio->bi_bdev = tmp_dev->bdev; bio->bi_sector = rsect + tmp_dev->data_offset; @@ -467,7 +465,7 @@ static int raid0_make_request (struct request_queue *q, struct bio *bio) bad_map: printk("raid0_make_request bug: can't convert block across chunks" - " or bigger than %dk %llu %d\n", chunk_size, + " or bigger than %dk %llu %d\n", chunk_sects / 2, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); bio_io_error(bio); @@ -492,10 +490,10 @@ static void raid0_status (struct seq_file *seq, mddev_t *mddev) seq_printf(seq, "%s/", bdevname( conf->strip_zone[j].dev[k]->bdev,b)); - seq_printf(seq, "] zo=%d do=%d s=%d\n", - conf->strip_zone[j].zone_offset, - conf->strip_zone[j].dev_offset, - conf->strip_zone[j].size); + seq_printf(seq, "] zs=%d ds=%d s=%d\n", + conf->strip_zone[j].zone_start, + conf->strip_zone[j].dev_start, + conf->strip_zone[j].sectors); } #endif seq_printf(seq, " %dk chunks", mddev->chunk_size/1024); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 9c788e2489b..7b4f5f7155d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1016,12 +1016,16 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) * else mark the drive as failed */ if (test_bit(In_sync, &rdev->flags) - && (conf->raid_disks - mddev->degraded) == 1) + && (conf->raid_disks - mddev->degraded) == 1) { /* * Don't fail the drive, act as though we were just a - * normal single drive + * normal single drive. + * However don't try a recovery from this drive as + * it is very likely to fail. */ + mddev->recovery_disabled = 1; return; + } if (test_and_clear_bit(In_sync, &rdev->flags)) { unsigned long flags; spin_lock_irqsave(&conf->device_lock, flags); @@ -1919,7 +1923,6 @@ static int run(mddev_t *mddev) int i, j, disk_idx; mirror_info_t *disk; mdk_rdev_t *rdev; - struct list_head *tmp; if (mddev->level != 1) { printk("raid1: %s: raid level not set to mirroring (%d)\n", @@ -1964,7 +1967,7 @@ static int run(mddev_t *mddev) spin_lock_init(&conf->device_lock); mddev->queue->queue_lock = &conf->device_lock; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 970a96ef9b1..6736d6dff98 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2025,7 +2025,6 @@ static int run(mddev_t *mddev) int i, disk_idx; mirror_info_t *disk; mdk_rdev_t *rdev; - struct list_head *tmp; int nc, fc, fo; sector_t stride, size; @@ -2108,7 +2107,7 @@ static int run(mddev_t *mddev) spin_lock_init(&conf->device_lock); mddev->queue->queue_lock = &conf->device_lock; - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a36a7435edf..a5ba080d303 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3998,7 +3998,6 @@ static int run(mddev_t *mddev) int raid_disk, memory; mdk_rdev_t *rdev; struct disk_info *disk; - struct list_head *tmp; int working_disks = 0; if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) { @@ -4108,7 +4107,7 @@ static int run(mddev_t *mddev) pr_debug("raid5: run(%s) called.\n", mdname(mddev)); - rdev_for_each(rdev, tmp, mddev) { + list_for_each_entry(rdev, &mddev->disks, same_set) { raid_disk = rdev->raid_disk; if (raid_disk >= conf->raid_disks || raid_disk < 0) @@ -4533,7 +4532,6 @@ static int raid5_start_reshape(mddev_t *mddev) { raid5_conf_t *conf = mddev_to_conf(mddev); mdk_rdev_t *rdev; - struct list_head *rtmp; int spares = 0; int added_devices = 0; unsigned long flags; @@ -4541,7 +4539,7 @@ static int raid5_start_reshape(mddev_t *mddev) if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return -EBUSY; - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) spares++; @@ -4563,7 +4561,7 @@ static int raid5_start_reshape(mddev_t *mddev) /* Add some new drives, as many as will fit. * We know there are enough to make the newly sized array work. */ - rdev_for_each(rdev, rtmp, mddev) + list_for_each_entry(rdev, &mddev->disks, same_set) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) { if (raid5_add_disk(mddev, rdev) == 0) { diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 03fd9dd5c68..f6ba8468858 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -125,7 +125,6 @@ static void hexdump( const unsigned char *buf, unsigned short len ) struct dvb_net_priv { int in_use; - struct net_device_stats stats; u16 pid; struct net_device *net; struct dvb_net *host; @@ -384,8 +383,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ - priv->stats.rx_errors++; - priv->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -438,8 +437,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ // reset_ule(priv); moved to below. - priv->stats.rx_errors++; - priv->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); /* skip to next PUSI. */ @@ -460,8 +459,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); - priv->stats.rx_errors++; - priv->stats.rx_frame_errors++; + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -477,8 +476,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); @@ -520,8 +519,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_len < 5) { printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); - priv->stats.rx_errors++; - priv->stats.rx_length_errors++; + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; priv->ule_sndu_len = 0; priv->need_pusi = 1; new_ts = 1; @@ -573,7 +572,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - priv->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -637,8 +636,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) ule_dump = 1; #endif - priv->stats.rx_errors++; - priv->stats.rx_crc_errors++; + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; dev_kfree_skb(priv->ule_skb); } else { /* CRC32 verified OK. */ @@ -744,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * receive the packet anyhow. */ /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) priv->ule_skb->pkt_type = PACKET_HOST; */ - priv->stats.rx_packets++; - priv->stats.rx_bytes += priv->ule_skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->ule_skb->len; netif_rx(priv->ule_skb); } sndu_done: @@ -800,8 +799,7 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; - struct net_device_stats *stats = - &((struct dvb_net_priv *) netdev_priv(dev))->stats; + struct net_device_stats *stats = &dev->stats; int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -1216,28 +1214,29 @@ static int dvb_net_stop(struct net_device *dev) return dvb_net_feed_stop(dev); } -static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) -{ - return &((struct dvb_net_priv *) netdev_priv(dev))->stats; -} - static const struct header_ops dvb_header_ops = { .create = eth_header, .parse = eth_header_parse, .rebuild = eth_rebuild_header, }; + +static const struct net_device_ops dvb_netdev_ops = { + .ndo_open = dvb_net_open, + .ndo_stop = dvb_net_stop, + .ndo_start_xmit = dvb_net_tx, + .ndo_set_multicast_list = dvb_net_set_multicast_list, + .ndo_set_mac_address = dvb_net_set_mac, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); dev->header_ops = &dvb_header_ops; - dev->open = dvb_net_open; - dev->stop = dvb_net_stop; - dev->hard_start_xmit = dvb_net_tx; - dev->get_stats = dvb_net_get_stats; - dev->set_multicast_list = dvb_net_set_multicast_list; - dev->set_mac_address = dvb_net_set_mac; + dev->netdev_ops = &dvb_netdev_ops; dev->mtu = 4096; dev->mc_count = 0; diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index 1f1e3982b1a..de143deb06f 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -52,14 +52,14 @@ struct mspro_sys_attr { }; struct mspro_attr_entry { - unsigned int address; - unsigned int size; + __be32 address; + __be32 size; unsigned char id; unsigned char reserved[3]; } __attribute__((packed)); struct mspro_attribute { - unsigned short signature; + __be16 signature; unsigned short version; unsigned char count; unsigned char reserved[11]; @@ -69,28 +69,28 @@ struct mspro_attribute { struct mspro_sys_info { unsigned char class; unsigned char reserved0; - unsigned short block_size; - unsigned short block_count; - unsigned short user_block_count; - unsigned short page_size; + __be16 block_size; + __be16 block_count; + __be16 user_block_count; + __be16 page_size; unsigned char reserved1[2]; unsigned char assembly_date[8]; - unsigned int serial_number; + __be32 serial_number; unsigned char assembly_maker_code; unsigned char assembly_model_code[3]; - unsigned short memory_maker_code; - unsigned short memory_model_code; + __be16 memory_maker_code; + __be16 memory_model_code; unsigned char reserved2[4]; unsigned char vcc; unsigned char vpp; - unsigned short controller_number; - unsigned short controller_function; - unsigned short start_sector; - unsigned short unit_size; + __be16 controller_number; + __be16 controller_function; + __be16 start_sector; + __be16 unit_size; unsigned char ms_sub_class; unsigned char reserved3[4]; unsigned char interface_type; - unsigned short controller_code; + __be16 controller_code; unsigned char format_type; unsigned char reserved4; unsigned char device_type; @@ -124,11 +124,11 @@ struct mspro_specfile { } __attribute__((packed)); struct mspro_devinfo { - unsigned short cylinders; - unsigned short heads; - unsigned short bytes_per_track; - unsigned short bytes_per_sector; - unsigned short sectors_per_track; + __be16 cylinders; + __be16 heads; + __be16 bytes_per_track; + __be16 bytes_per_sector; + __be16 sectors_per_track; unsigned char reserved[6]; } __attribute__((packed)); @@ -338,8 +338,7 @@ static ssize_t mspro_block_attr_show_sysinfo(struct device *dev, rc += scnprintf(buffer + rc, PAGE_SIZE - rc, "assembly date: " "GMT%+d:%d %04u-%02u-%02u %02u:%02u:%02u\n", date_tz, date_tz_f, - be16_to_cpu(*(unsigned short *) - &x_sys->assembly_date[1]), + be16_to_cpup((__be16 *)&x_sys->assembly_date[1]), x_sys->assembly_date[3], x_sys->assembly_date[4], x_sys->assembly_date[5], x_sys->assembly_date[6], x_sys->assembly_date[7]); diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index b89f476cd0a..c63817117c0 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -308,10 +308,11 @@ static void mptctl_timeout_expired (MPT_IOCTL *ioctl) { int rc = 1; - dctlprintk(ioctl->ioc, printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n", - ioctl->ioc->name, ioctl->ioc->id)); if (ioctl == NULL) return; + dctlprintk(ioctl->ioc, + printk(MYIOC_s_DEBUG_FMT ": Timeout Expired! Host %d\n", + ioctl->ioc->name, ioctl->ioc->id)); ioctl->wait_done = 0; if (ioctl->reset & MPTCTL_RESET_OK) diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index a13f6eecd25..c2804f26cb4 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -106,7 +106,6 @@ struct mpt_lan_priv { u32 total_posted; u32 total_received; - struct net_device_stats stats; /* Per device statistics */ struct delayed_work post_buckets_task; struct net_device *dev; @@ -548,15 +547,6 @@ mpt_lan_close(struct net_device *dev) } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static struct net_device_stats * -mpt_lan_get_stats(struct net_device *dev) -{ - struct mpt_lan_priv *priv = netdev_priv(dev); - - return (struct net_device_stats *) &priv->stats; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static int mpt_lan_change_mtu(struct net_device *dev, int new_mtu) { @@ -594,8 +584,8 @@ mpt_lan_send_turbo(struct net_device *dev, u32 tmsg) ctx = GET_LAN_BUFFER_CONTEXT(tmsg); sent = priv->SendCtl[ctx].skb; - priv->stats.tx_packets++; - priv->stats.tx_bytes += sent->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += sent->len; dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", IOC_AND_NETDEV_NAMES_s_s(dev), @@ -636,7 +626,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) switch (le16_to_cpu(pSendRep->IOCStatus) & MPI_IOCSTATUS_MASK) { case MPI_IOCSTATUS_SUCCESS: - priv->stats.tx_packets += count; + dev->stats.tx_packets += count; break; case MPI_IOCSTATUS_LAN_CANCELED: @@ -644,13 +634,13 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) break; case MPI_IOCSTATUS_INVALID_SGL: - priv->stats.tx_errors += count; + dev->stats.tx_errors += count; printk (KERN_ERR MYNAM ": %s/%s: ERROR - Invalid SGL sent to IOC!\n", IOC_AND_NETDEV_NAMES_s_s(dev)); goto out; default: - priv->stats.tx_errors += count; + dev->stats.tx_errors += count; break; } @@ -661,7 +651,7 @@ mpt_lan_send_reply(struct net_device *dev, LANSendReply_t *pSendRep) ctx = GET_LAN_BUFFER_CONTEXT(le32_to_cpu(*pContext)); sent = priv->SendCtl[ctx].skb; - priv->stats.tx_bytes += sent->len; + dev->stats.tx_bytes += sent->len; dioprintk((KERN_INFO MYNAM ": %s/%s: @%s, skb %p sent.\n", IOC_AND_NETDEV_NAMES_s_s(dev), @@ -842,8 +832,8 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) "delivered to upper level.\n", IOC_AND_NETDEV_NAMES_s_s(dev), skb->len)); - priv->stats.rx_bytes += skb->len; - priv->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + dev->stats.rx_packets++; skb->dev = dev; netif_rx(skb); @@ -1308,6 +1298,14 @@ mpt_lan_post_receive_buckets_work(struct work_struct *work) post_buckets_task.work)); } +static const struct net_device_ops mpt_netdev_ops = { + .ndo_open = mpt_lan_open, + .ndo_stop = mpt_lan_close, + .ndo_start_xmit = mpt_lan_sdu_send, + .ndo_change_mtu = mpt_lan_change_mtu, + .ndo_tx_timeout = mpt_lan_tx_timeout, +}; + /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) @@ -1372,15 +1370,7 @@ mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) priv->tx_max_out = (tx_max_out_p <= MPT_TX_MAX_OUT_LIM) ? tx_max_out_p : MPT_TX_MAX_OUT_LIM; - dev->open = mpt_lan_open; - dev->stop = mpt_lan_close; - dev->get_stats = mpt_lan_get_stats; - dev->set_multicast_list = NULL; - dev->change_mtu = mpt_lan_change_mtu; - dev->hard_start_xmit = mpt_lan_sdu_send; - -/* Not in 2.3.42. Need 2.3.45+ */ - dev->tx_timeout = mpt_lan_tx_timeout; + dev->netdev_ops = &mpt_netdev_ops; dev->watchdog_timeo = MPT_LAN_TX_TIMEOUT; dlprintk((KERN_INFO MYNAM ": Finished registering dev " diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 416f9e7286b..06a2b0f7737 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -217,6 +217,29 @@ config MFD_WM8350_I2C I2C as the control interface. Additional options must be selected to enable support for the functionality of the chip. +config MFD_PCF50633 + tristate "Support for NXP PCF50633" + depends on I2C + help + Say yes here if you have NXP PCF50633 chip on your board. + This core driver provides register access and IRQ handling + facilities, and registers devices for the various functions + so that function-specific drivers can bind to them. + +config PCF50633_ADC + tristate "Support for NXP PCF50633 ADC" + depends on MFD_PCF50633 + help + Say yes here if you want to include support for ADC in the + NXP PCF50633 chip. + +config PCF50633_GPIO + tristate "Support for NXP PCF50633 GPIO" + depends on MFD_PCF50633 + help + Say yes here if you want to include support GPIO for pins on + the PCF50633 chip. + endmenu menu "Multimedia Capabilities Port drivers" diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0c9418b36c2..3afb5192e4d 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -37,3 +37,7 @@ endif obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o + +obj-$(CONFIG_MFD_PCF50633) += pcf50633-core.o +obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o +obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
\ No newline at end of file diff --git a/drivers/mfd/dm355evm_msp.c b/drivers/mfd/dm355evm_msp.c index 4214b3f7242..7ac12cb0be4 100644 --- a/drivers/mfd/dm355evm_msp.c +++ b/drivers/mfd/dm355evm_msp.c @@ -107,6 +107,9 @@ static const u8 msp_gpios[] = { MSP_GPIO(0, SWITCH1), MSP_GPIO(1, SWITCH1), MSP_GPIO(2, SWITCH1), MSP_GPIO(3, SWITCH1), MSP_GPIO(4, SWITCH1), + /* switches on MMC/SD sockets */ + MSP_GPIO(1, SDMMC), MSP_GPIO(2, SDMMC), /* mmc0 WP, nCD */ + MSP_GPIO(3, SDMMC), MSP_GPIO(4, SDMMC), /* mmc1 WP, nCD */ }; #define MSP_GPIO_REG(offset) (msp_gpios[(offset)] >> 3) @@ -304,6 +307,13 @@ static int add_children(struct i2c_client *client) gpio_export(gpio, false); } + /* MMC/SD inputs -- right after the last config input */ + if (client->dev.platform_data) { + void (*mmcsd_setup)(unsigned) = client->dev.platform_data; + + mmcsd_setup(dm355evm_msp_gpio.base + 8 + 5); + } + /* RTC is a 32 bit counter, no alarm */ if (msp_has_rtc()) { child = add_child(client, "rtc-dm355evm", diff --git a/drivers/mfd/pcf50633-adc.c b/drivers/mfd/pcf50633-adc.c new file mode 100644 index 00000000000..c2d05becfa9 --- /dev/null +++ b/drivers/mfd/pcf50633-adc.c @@ -0,0 +1,277 @@ +/* NXP PCF50633 ADC Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte, Andy Green and Werner Almesberger + * + * 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. + * + * NOTE: This driver does not yet support subtractive ADC mode, which means + * you can do only one measurement per read request. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/completion.h> + +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/adc.h> + +struct pcf50633_adc_request { + int mux; + int avg; + int result; + void (*callback)(struct pcf50633 *, void *, int); + void *callback_param; + + /* Used in case of sync requests */ + struct completion completion; + +}; + +#define PCF50633_MAX_ADC_FIFO_DEPTH 8 + +struct pcf50633_adc { + struct pcf50633 *pcf; + + /* Private stuff */ + struct pcf50633_adc_request *queue[PCF50633_MAX_ADC_FIFO_DEPTH]; + int queue_head; + int queue_tail; + struct mutex queue_mutex; +}; + +static inline struct pcf50633_adc *__to_adc(struct pcf50633 *pcf) +{ + return platform_get_drvdata(pcf->adc_pdev); +} + +static void adc_setup(struct pcf50633 *pcf, int channel, int avg) +{ + channel &= PCF50633_ADCC1_ADCMUX_MASK; + + /* kill ratiometric, but enable ACCSW biasing */ + pcf50633_reg_write(pcf, PCF50633_REG_ADCC2, 0x00); + pcf50633_reg_write(pcf, PCF50633_REG_ADCC3, 0x01); + + /* start ADC conversion on selected channel */ + pcf50633_reg_write(pcf, PCF50633_REG_ADCC1, channel | avg | + PCF50633_ADCC1_ADCSTART | PCF50633_ADCC1_RES_10BIT); +} + +static void trigger_next_adc_job_if_any(struct pcf50633 *pcf) +{ + struct pcf50633_adc *adc = __to_adc(pcf); + int head; + + mutex_lock(&adc->queue_mutex); + + head = adc->queue_head; + + if (!adc->queue[head]) { + mutex_unlock(&adc->queue_mutex); + return; + } + mutex_unlock(&adc->queue_mutex); + + adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg); +} + +static int +adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req) +{ + struct pcf50633_adc *adc = __to_adc(pcf); + int head, tail; + + mutex_lock(&adc->queue_mutex); + + head = adc->queue_head; + tail = adc->queue_tail; + + if (adc->queue[tail]) { + mutex_unlock(&adc->queue_mutex); + return -EBUSY; + } + + adc->queue[tail] = req; + adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1); + + mutex_unlock(&adc->queue_mutex); + + trigger_next_adc_job_if_any(pcf); + + return 0; +} + +static void +pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result) +{ + struct pcf50633_adc_request *req = param; + + req->result = result; + complete(&req->completion); +} + +int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg) +{ + struct pcf50633_adc_request *req; + + /* req is freed when the result is ready, in interrupt handler */ + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->mux = mux; + req->avg = avg; + req->callback = pcf50633_adc_sync_read_callback; + req->callback_param = req; + + init_completion(&req->completion); + adc_enqueue_request(pcf, req); + wait_for_completion(&req->completion); + + return req->result; +} +EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read); + +int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg, + void (*callback)(struct pcf50633 *, void *, int), + void *callback_param) +{ + struct pcf50633_adc_request *req; + + /* req is freed when the result is ready, in interrupt handler */ + req = kmalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->mux = mux; + req->avg = avg; + req->callback = callback; + req->callback_param = callback_param; + + adc_enqueue_request(pcf, req); + + return 0; +} +EXPORT_SYMBOL_GPL(pcf50633_adc_async_read); + +static int adc_result(struct pcf50633 *pcf) +{ + u8 adcs1, adcs3; + u16 result; + + adcs1 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS1); + adcs3 = pcf50633_reg_read(pcf, PCF50633_REG_ADCS3); + result = (adcs1 << 2) | (adcs3 & PCF50633_ADCS3_ADCDAT1L_MASK); + + dev_dbg(pcf->dev, "adc result = %d\n", result); + + return result; +} + +static void pcf50633_adc_irq(int irq, void *data) +{ + struct pcf50633_adc *adc = data; + struct pcf50633 *pcf = adc->pcf; + struct pcf50633_adc_request *req; + int head; + + mutex_lock(&adc->queue_mutex); + head = adc->queue_head; + + req = adc->queue[head]; + if (WARN_ON(!req)) { + dev_err(pcf->dev, "pcf50633-adc irq: ADC queue empty!\n"); + mutex_unlock(&adc->queue_mutex); + return; + } + adc->queue[head] = NULL; + adc->queue_head = (head + 1) & + (PCF50633_MAX_ADC_FIFO_DEPTH - 1); + + mutex_unlock(&adc->queue_mutex); + + req->callback(pcf, req->callback_param, adc_result(pcf)); + kfree(req); + + trigger_next_adc_job_if_any(pcf); +} + +static int __devinit pcf50633_adc_probe(struct platform_device *pdev) +{ + struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; + struct pcf50633_adc *adc; + + adc = kzalloc(sizeof(*adc), GFP_KERNEL); + if (!adc) + return -ENOMEM; + + adc->pcf = pdata->pcf; + platform_set_drvdata(pdev, adc); + + pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY, + pcf50633_adc_irq, adc); + + mutex_init(&adc->queue_mutex); + + return 0; +} + +static int __devexit pcf50633_adc_remove(struct platform_device *pdev) +{ + struct pcf50633_adc *adc = platform_get_drvdata(pdev); + int i, head; + + pcf50633_free_irq(adc->pcf, PCF50633_IRQ_ADCRDY); + + mutex_lock(&adc->queue_mutex); + head = adc->queue_head; + + if (WARN_ON(adc->queue[head])) + dev_err(adc->pcf->dev, + "adc driver removed with request pending\n"); + + for (i = 0; i < PCF50633_MAX_ADC_FIFO_DEPTH; i++) + kfree(adc->queue[i]); + + mutex_unlock(&adc->queue_mutex); + kfree(adc); + + return 0; +} + +static struct platform_driver pcf50633_adc_driver = { + .driver = { + .name = "pcf50633-adc", + }, + .probe = pcf50633_adc_probe, + .remove = __devexit_p(pcf50633_adc_remove), +}; + +static int __init pcf50633_adc_init(void) +{ + return platform_driver_register(&pcf50633_adc_driver); +} +module_init(pcf50633_adc_init); + +static void __exit pcf50633_adc_exit(void) +{ + platform_driver_unregister(&pcf50633_adc_driver); +} +module_exit(pcf50633_adc_exit); + +MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); +MODULE_DESCRIPTION("PCF50633 adc driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-adc"); + diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c new file mode 100644 index 00000000000..24508e28e3f --- /dev/null +++ b/drivers/mfd/pcf50633-core.c @@ -0,0 +1,710 @@ +/* NXP PCF50633 Power Management Unit (PMU) driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * Balaji Rao <balajirrao@openmoko.org> + * 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; either version 2 of the License, or (at your + * option) any later version. + * + */ + +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/sysfs.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <linux/irq.h> + +#include <linux/mfd/pcf50633/core.h> + +/* Two MBCS registers used during cold start */ +#define PCF50633_REG_MBCS1 0x4b +#define PCF50633_REG_MBCS2 0x4c +#define PCF50633_MBCS1_USBPRES 0x01 +#define PCF50633_MBCS1_ADAPTPRES 0x01 + +static int __pcf50633_read(struct pcf50633 *pcf, u8 reg, int num, u8 *data) +{ + int ret; + + ret = i2c_smbus_read_i2c_block_data(pcf->i2c_client, reg, + num, data); + if (ret < 0) + dev_err(pcf->dev, "Error reading %d regs at %d\n", num, reg); + + return ret; +} + +static int __pcf50633_write(struct pcf50633 *pcf, u8 reg, int num, u8 *data) +{ + int ret; + + ret = i2c_smbus_write_i2c_block_data(pcf->i2c_client, reg, + num, data); + if (ret < 0) + dev_err(pcf->dev, "Error writing %d regs at %d\n", num, reg); + + return ret; + +} + +/* Read a block of upto 32 regs */ +int pcf50633_read_block(struct pcf50633 *pcf, u8 reg, + int nr_regs, u8 *data) +{ + int ret; + + mutex_lock(&pcf->lock); + ret = __pcf50633_read(pcf, reg, nr_regs, data); + mutex_unlock(&pcf->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_read_block); + +/* Write a block of upto 32 regs */ +int pcf50633_write_block(struct pcf50633 *pcf , u8 reg, + int nr_regs, u8 *data) +{ + int ret; + + mutex_lock(&pcf->lock); + ret = __pcf50633_write(pcf, reg, nr_regs, data); + mutex_unlock(&pcf->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_write_block); + +u8 pcf50633_reg_read(struct pcf50633 *pcf, u8 reg) +{ + u8 val; + + mutex_lock(&pcf->lock); + __pcf50633_read(pcf, reg, 1, &val); + mutex_unlock(&pcf->lock); + + return val; +} +EXPORT_SYMBOL_GPL(pcf50633_reg_read); + +int pcf50633_reg_write(struct pcf50633 *pcf, u8 reg, u8 val) +{ + int ret; + + mutex_lock(&pcf->lock); + ret = __pcf50633_write(pcf, reg, 1, &val); + mutex_unlock(&pcf->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_reg_write); + +int pcf50633_reg_set_bit_mask(struct pcf50633 *pcf, u8 reg, u8 mask, u8 val) +{ + int ret; + u8 tmp; + + val &= mask; + + mutex_lock(&pcf->lock); + ret = __pcf50633_read(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + tmp &= ~mask; + tmp |= val; + ret = __pcf50633_write(pcf, reg, 1, &tmp); + +out: + mutex_unlock(&pcf->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_reg_set_bit_mask); + +int pcf50633_reg_clear_bits(struct pcf50633 *pcf, u8 reg, u8 val) +{ + int ret; + u8 tmp; + + mutex_lock(&pcf->lock); + ret = __pcf50633_read(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + tmp &= ~val; + ret = __pcf50633_write(pcf, reg, 1, &tmp); + +out: + mutex_unlock(&pcf->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_reg_clear_bits); + +/* sysfs attributes */ +static ssize_t show_dump_regs(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct pcf50633 *pcf = dev_get_drvdata(dev); + u8 dump[16]; + int n, n1, idx = 0; + char *buf1 = buf; + static u8 address_no_read[] = { /* must be ascending */ + PCF50633_REG_INT1, + PCF50633_REG_INT2, + PCF50633_REG_INT3, + PCF50633_REG_INT4, + PCF50633_REG_INT5, + 0 /* terminator */ + }; + + for (n = 0; n < 256; n += sizeof(dump)) { + for (n1 = 0; n1 < sizeof(dump); n1++) + if (n == address_no_read[idx]) { + idx++; + dump[n1] = 0x00; + } else + dump[n1] = pcf50633_reg_read(pcf, n + n1); + + hex_dump_to_buffer(dump, sizeof(dump), 16, 1, buf1, 128, 0); + buf1 += strlen(buf1); + *buf1++ = '\n'; + *buf1 = '\0'; + } + + return buf1 - buf; +} +static DEVICE_ATTR(dump_regs, 0400, show_dump_regs, NULL); + +static ssize_t show_resume_reason(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct pcf50633 *pcf = dev_get_drvdata(dev); + int n; + + n = sprintf(buf, "%02x%02x%02x%02x%02x\n", + pcf->resume_reason[0], + pcf->resume_reason[1], + pcf->resume_reason[2], + pcf->resume_reason[3], + pcf->resume_reason[4]); + + return n; +} +static DEVICE_ATTR(resume_reason, 0400, show_resume_reason, NULL); + +static struct attribute *pcf_sysfs_entries[] = { + &dev_attr_dump_regs.attr, + &dev_attr_resume_reason.attr, + NULL, +}; + +static struct attribute_group pcf_attr_group = { + .name = NULL, /* put in device directory */ + .attrs = pcf_sysfs_entries, +}; + +int pcf50633_register_irq(struct pcf50633 *pcf, int irq, + void (*handler) (int, void *), void *data) +{ + if (irq < 0 || irq > PCF50633_NUM_IRQ || !handler) + return -EINVAL; + + if (WARN_ON(pcf->irq_handler[irq].handler)) + return -EBUSY; + + mutex_lock(&pcf->lock); + pcf->irq_handler[irq].handler = handler; + pcf->irq_handler[irq].data = data; + mutex_unlock(&pcf->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(pcf50633_register_irq); + +int pcf50633_free_irq(struct pcf50633 *pcf, int irq) +{ + if (irq < 0 || irq > PCF50633_NUM_IRQ) + return -EINVAL; + + mutex_lock(&pcf->lock); + pcf->irq_handler[irq].handler = NULL; + mutex_unlock(&pcf->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(pcf50633_free_irq); + +static int __pcf50633_irq_mask_set(struct pcf50633 *pcf, int irq, u8 mask) +{ + u8 reg, bits, tmp; + int ret = 0, idx; + + idx = irq >> 3; + reg = PCF50633_REG_INT1M + idx; + bits = 1 << (irq & 0x07); + + mutex_lock(&pcf->lock); + + if (mask) { + ret = __pcf50633_read(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + tmp |= bits; + + ret = __pcf50633_write(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + pcf->mask_regs[idx] &= ~bits; + pcf->mask_regs[idx] |= bits; + } else { + ret = __pcf50633_read(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + tmp &= ~bits; + + ret = __pcf50633_write(pcf, reg, 1, &tmp); + if (ret < 0) + goto out; + + pcf->mask_regs[idx] &= ~bits; + } +out: + mutex_unlock(&pcf->lock); + + return ret; +} + +int pcf50633_irq_mask(struct pcf50633 *pcf, int irq) +{ + dev_info(pcf->dev, "Masking IRQ %d\n", irq); + + return __pcf50633_irq_mask_set(pcf, irq, 1); +} +EXPORT_SYMBOL_GPL(pcf50633_irq_mask); + +int pcf50633_irq_unmask(struct pcf50633 *pcf, int irq) +{ + dev_info(pcf->dev, "Unmasking IRQ %d\n", irq); + + return __pcf50633_irq_mask_set(pcf, irq, 0); +} +EXPORT_SYMBOL_GPL(pcf50633_irq_unmask); + +int pcf50633_irq_mask_get(struct pcf50633 *pcf, int irq) +{ + u8 reg, bits; + + reg = irq >> 3; + bits = 1 << (irq & 0x07); + + return pcf->mask_regs[reg] & bits; +} +EXPORT_SYMBOL_GPL(pcf50633_irq_mask_get); + +static void pcf50633_irq_call_handler(struct pcf50633 *pcf, int irq) +{ + if (pcf->irq_handler[irq].handler) + pcf->irq_handler[irq].handler(irq, pcf->irq_handler[irq].data); +} + +/* Maximum amount of time ONKEY is held before emergency action is taken */ +#define PCF50633_ONKEY1S_TIMEOUT 8 + +static void pcf50633_irq_worker(struct work_struct *work) +{ + struct pcf50633 *pcf; + int ret, i, j; + u8 pcf_int[5], chgstat; + + pcf = container_of(work, struct pcf50633, irq_work); + + /* Read the 5 INT regs in one transaction */ + ret = pcf50633_read_block(pcf, PCF50633_REG_INT1, + ARRAY_SIZE(pcf_int), pcf_int); + if (ret != ARRAY_SIZE(pcf_int)) { + dev_err(pcf->dev, "Error reading INT registers\n"); + + /* + * If this doesn't ACK the interrupt to the chip, we'll be + * called once again as we're level triggered. + */ + goto out; + } + + /* We immediately read the usb and adapter status. We thus make sure + * only of USBINS/USBREM IRQ handlers are called */ + if (pcf_int[0] & (PCF50633_INT1_USBINS | PCF50633_INT1_USBREM)) { + chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2); + if (chgstat & (0x3 << 4)) + pcf_int[0] &= ~(1 << PCF50633_INT1_USBREM); + else + pcf_int[0] &= ~(1 << PCF50633_INT1_USBINS); + } + + /* Make sure only one of ADPINS or ADPREM is set */ + if (pcf_int[0] & (PCF50633_INT1_ADPINS | PCF50633_INT1_ADPREM)) { + chgstat = pcf50633_reg_read(pcf, PCF50633_REG_MBCS2); + if (chgstat & (0x3 << 4)) + pcf_int[0] &= ~(1 << PCF50633_INT1_ADPREM); + else + pcf_int[0] &= ~(1 << PCF50633_INT1_ADPINS); + } + + dev_dbg(pcf->dev, "INT1=0x%02x INT2=0x%02x INT3=0x%02x " + "INT4=0x%02x INT5=0x%02x\n", pcf_int[0], + pcf_int[1], pcf_int[2], pcf_int[3], pcf_int[4]); + + /* Some revisions of the chip don't have a 8s standby mode on + * ONKEY1S press. We try to manually do it in such cases. */ + if ((pcf_int[0] & PCF50633_INT1_SECOND) && pcf->onkey1s_held) { + dev_info(pcf->dev, "ONKEY1S held for %d secs\n", + pcf->onkey1s_held); + if (pcf->onkey1s_held++ == PCF50633_ONKEY1S_TIMEOUT) + if (pcf->pdata->force_shutdown) + pcf->pdata->force_shutdown(pcf); + } + + if (pcf_int[2] & PCF50633_INT3_ONKEY1S) { + dev_info(pcf->dev, "ONKEY1S held\n"); + pcf->onkey1s_held = 1 ; + + /* Unmask IRQ_SECOND */ + pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT1M, + PCF50633_INT1_SECOND); + + /* Unmask IRQ_ONKEYR */ + pcf50633_reg_clear_bits(pcf, PCF50633_REG_INT2M, + PCF50633_INT2_ONKEYR); + } + + if ((pcf_int[1] & PCF50633_INT2_ONKEYR) && pcf->onkey1s_held) { + pcf->onkey1s_held = 0; + + /* Mask SECOND and ONKEYR interrupts */ + if (pcf->mask_regs[0] & PCF50633_INT1_SECOND) + pcf50633_reg_set_bit_mask(pcf, + PCF50633_REG_INT1M, + PCF50633_INT1_SECOND, + PCF50633_INT1_SECOND); + + if (pcf->mask_regs[1] & PCF50633_INT2_ONKEYR) + pcf50633_reg_set_bit_mask(pcf, + PCF50633_REG_INT2M, + PCF50633_INT2_ONKEYR, + PCF50633_INT2_ONKEYR); + } + + /* Have we just resumed ? */ + if (pcf->is_suspended) { + pcf->is_suspended = 0; + + /* Set the resume reason filtering out non resumers */ + for (i = 0; i < ARRAY_SIZE(pcf_int); i++) + pcf->resume_reason[i] = pcf_int[i] & + pcf->pdata->resumers[i]; + + /* Make sure we don't pass on any ONKEY events to + * userspace now */ + pcf_int[1] &= ~(PCF50633_INT2_ONKEYR | PCF50633_INT2_ONKEYF); + } + + for (i = 0; i < ARRAY_SIZE(pcf_int); i++) { + /* Unset masked interrupts */ + pcf_int[i] &= ~pcf->mask_regs[i]; + + for (j = 0; j < 8 ; j++) + if (pcf_int[i] & (1 << j)) + pcf50633_irq_call_handler(pcf, (i * 8) + j); + } + +out: + put_device(pcf->dev); + enable_irq(pcf->irq); +} + +static irqreturn_t pcf50633_irq(int irq, void *data) +{ + struct pcf50633 *pcf = data; + + dev_dbg(pcf->dev, "pcf50633_irq\n"); + + get_device(pcf->dev); + disable_irq(pcf->irq); + schedule_work(&pcf->irq_work); + + return IRQ_HANDLED; +} + +static void +pcf50633_client_dev_register(struct pcf50633 *pcf, const char *name, + struct platform_device **pdev) +{ + struct pcf50633_subdev_pdata *subdev_pdata; + int ret; + + *pdev = platform_device_alloc(name, -1); + if (!*pdev) { + dev_err(pcf->dev, "Falied to allocate %s\n", name); + return; + } + + subdev_pdata = kmalloc(sizeof(*subdev_pdata), GFP_KERNEL); + if (!subdev_pdata) { + dev_err(pcf->dev, "Error allocating subdev pdata\n"); + platform_device_put(*pdev); + } + + subdev_pdata->pcf = pcf; + platform_device_add_data(*pdev, subdev_pdata, sizeof(*subdev_pdata)); + + (*pdev)->dev.parent = pcf->dev; + + ret = platform_device_add(*pdev); + if (ret) { + dev_err(pcf->dev, "Failed to register %s: %d\n", name, ret); + platform_device_put(*pdev); + *pdev = NULL; + } +} + +#ifdef CONFIG_PM +static int pcf50633_suspend(struct device *dev, pm_message_t state) +{ + struct pcf50633 *pcf; + int ret = 0, i; + u8 res[5]; + + pcf = dev_get_drvdata(dev); + + /* Make sure our interrupt handlers are not called + * henceforth */ + disable_irq(pcf->irq); + + /* Make sure that any running IRQ worker has quit */ + cancel_work_sync(&pcf->irq_work); + + /* Save the masks */ + ret = pcf50633_read_block(pcf, PCF50633_REG_INT1M, + ARRAY_SIZE(pcf->suspend_irq_masks), + pcf->suspend_irq_masks); + if (ret < 0) { + dev_err(pcf->dev, "error saving irq masks\n"); + goto out; + } + + /* Write wakeup irq masks */ + for (i = 0; i < ARRAY_SIZE(res); i++) + res[i] = ~pcf->pdata->resumers[i]; + + ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, + ARRAY_SIZE(res), &res[0]); + if (ret < 0) { + dev_err(pcf->dev, "error writing wakeup irq masks\n"); + goto out; + } + + pcf->is_suspended = 1; + +out: + return ret; +} + +static int pcf50633_resume(struct device *dev) +{ + struct pcf50633 *pcf; + int ret; + + pcf = dev_get_drvdata(dev); + + /* Write the saved mask registers */ + ret = pcf50633_write_block(pcf, PCF50633_REG_INT1M, + ARRAY_SIZE(pcf->suspend_irq_masks), + pcf->suspend_irq_masks); + if (ret < 0) + dev_err(pcf->dev, "Error restoring saved suspend masks\n"); + + /* Restore regulators' state */ + + + get_device(pcf->dev); + + /* + * Clear any pending interrupts and set resume reason if any. + * This will leave with enable_irq() + */ + pcf50633_irq_worker(&pcf->irq_work); + + return 0; +} +#else +#define pcf50633_suspend NULL +#define pcf50633_resume NULL +#endif + +static int __devinit pcf50633_probe(struct i2c_client *client, + const struct i2c_device_id *ids) +{ + struct pcf50633 *pcf; + struct pcf50633_platform_data *pdata = client->dev.platform_data; + int i, ret = 0; + int version, variant; + + pcf = kzalloc(sizeof(*pcf), GFP_KERNEL); + if (!pcf) + return -ENOMEM; + + pcf->pdata = pdata; + + mutex_init(&pcf->lock); + + i2c_set_clientdata(client, pcf); + pcf->dev = &client->dev; + pcf->i2c_client = client; + pcf->irq = client->irq; + + INIT_WORK(&pcf->irq_work, pcf50633_irq_worker); + + version = pcf50633_reg_read(pcf, 0); + variant = pcf50633_reg_read(pcf, 1); + if (version < 0 || variant < 0) { + dev_err(pcf->dev, "Unable to probe pcf50633\n"); + ret = -ENODEV; + goto err; + } + + dev_info(pcf->dev, "Probed device version %d variant %d\n", + version, variant); + + /* Enable all interrupts except RTC SECOND */ + pcf->mask_regs[0] = 0x80; + pcf50633_reg_write(pcf, PCF50633_REG_INT1M, pcf->mask_regs[0]); + pcf50633_reg_write(pcf, PCF50633_REG_INT2M, 0x00); + pcf50633_reg_write(pcf, PCF50633_REG_INT3M, 0x00); + pcf50633_reg_write(pcf, PCF50633_REG_INT4M, 0x00); + pcf50633_reg_write(pcf, PCF50633_REG_INT5M, 0x00); + + /* Create sub devices */ + pcf50633_client_dev_register(pcf, "pcf50633-input", + &pcf->input_pdev); + pcf50633_client_dev_register(pcf, "pcf50633-rtc", + &pcf->rtc_pdev); + pcf50633_client_dev_register(pcf, "pcf50633-mbc", + &pcf->mbc_pdev); + pcf50633_client_dev_register(pcf, "pcf50633-adc", + &pcf->adc_pdev); + + for (i = 0; i < PCF50633_NUM_REGULATORS; i++) { + struct platform_device *pdev; + + pdev = platform_device_alloc("pcf50633-regltr", i); + if (!pdev) { + dev_err(pcf->dev, "Cannot create regulator\n"); + continue; + } + + pdev->dev.parent = pcf->dev; + pdev->dev.platform_data = &pdata->reg_init_data[i]; + pdev->dev.driver_data = pcf; + pcf->regulator_pdev[i] = pdev; + + platform_device_add(pdev); + } + + if (client->irq) { + set_irq_handler(client->irq, handle_level_irq); + ret = request_irq(client->irq, pcf50633_irq, + IRQF_TRIGGER_LOW, "pcf50633", pcf); + + if (ret) { + dev_err(pcf->dev, "Failed to request IRQ %d\n", ret); + goto err; + } + } else { + dev_err(pcf->dev, "No IRQ configured\n"); + goto err; + } + + if (enable_irq_wake(client->irq) < 0) + dev_err(pcf->dev, "IRQ %u cannot be enabled as wake-up source" + "in this hardware revision", client->irq); + + ret = sysfs_create_group(&client->dev.kobj, &pcf_attr_group); + if (ret) + dev_err(pcf->dev, "error creating sysfs entries\n"); + + if (pdata->probe_done) + pdata->probe_done(pcf); + + return 0; + +err: + kfree(pcf); + return ret; +} + +static int __devexit pcf50633_remove(struct i2c_client *client) +{ + struct pcf50633 *pcf = i2c_get_clientdata(client); + int i; + + free_irq(pcf->irq, pcf); + + platform_device_unregister(pcf->input_pdev); + platform_device_unregister(pcf->rtc_pdev); + platform_device_unregister(pcf->mbc_pdev); + platform_device_unregister(pcf->adc_pdev); + + for (i = 0; i < PCF50633_NUM_REGULATORS; i++) + platform_device_unregister(pcf->regulator_pdev[i]); + + kfree(pcf); + + return 0; +} + +static struct i2c_device_id pcf50633_id_table[] = { + {"pcf50633", 0x73}, +}; + +static struct i2c_driver pcf50633_driver = { + .driver = { + .name = "pcf50633", + .suspend = pcf50633_suspend, + .resume = pcf50633_resume, + }, + .id_table = pcf50633_id_table, + .probe = pcf50633_probe, + .remove = __devexit_p(pcf50633_remove), +}; + +static int __init pcf50633_init(void) +{ + return i2c_add_driver(&pcf50633_driver); +} + +static void __exit pcf50633_exit(void) +{ + i2c_del_driver(&pcf50633_driver); +} + +MODULE_DESCRIPTION("I2C chip driver for NXP PCF50633 PMU"); +MODULE_AUTHOR("Harald Welte <laforge@openmoko.org>"); +MODULE_LICENSE("GPL"); + +module_init(pcf50633_init); +module_exit(pcf50633_exit); diff --git a/drivers/mfd/pcf50633-gpio.c b/drivers/mfd/pcf50633-gpio.c new file mode 100644 index 00000000000..2fa2eca5c9c --- /dev/null +++ b/drivers/mfd/pcf50633-gpio.c @@ -0,0 +1,118 @@ +/* NXP PCF50633 GPIO Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte, Andy Green and Werner Almesberger + * + * 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 <linux/kernel.h> + +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/gpio.h> + +enum pcf50633_regulator_id { + PCF50633_REGULATOR_AUTO, + PCF50633_REGULATOR_DOWN1, + PCF50633_REGULATOR_DOWN2, + PCF50633_REGULATOR_LDO1, + PCF50633_REGULATOR_LDO2, + PCF50633_REGULATOR_LDO3, + PCF50633_REGULATOR_LDO4, + PCF50633_REGULATOR_LDO5, + PCF50633_REGULATOR_LDO6, + PCF50633_REGULATOR_HCLDO, + PCF50633_REGULATOR_MEMLDO, +}; + +#define PCF50633_REG_AUTOOUT 0x1a +#define PCF50633_REG_DOWN1OUT 0x1e +#define PCF50633_REG_DOWN2OUT 0x22 +#define PCF50633_REG_MEMLDOOUT 0x26 +#define PCF50633_REG_LDO1OUT 0x2d +#define PCF50633_REG_LDO2OUT 0x2f +#define PCF50633_REG_LDO3OUT 0x31 +#define PCF50633_REG_LDO4OUT 0x33 +#define PCF50633_REG_LDO5OUT 0x35 +#define PCF50633_REG_LDO6OUT 0x37 +#define PCF50633_REG_HCLDOOUT 0x39 + +static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = { + [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT, + [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT, + [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT, + [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT, + [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT, + [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT, + [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT, + [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT, + [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT, + [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT, + [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT, +}; + +int pcf50633_gpio_set(struct pcf50633 *pcf, int gpio, u8 val) +{ + u8 reg; + + reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; + + return pcf50633_reg_set_bit_mask(pcf, reg, 0x07, val); +} +EXPORT_SYMBOL_GPL(pcf50633_gpio_set); + +u8 pcf50633_gpio_get(struct pcf50633 *pcf, int gpio) +{ + u8 reg, val; + + reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; + val = pcf50633_reg_read(pcf, reg) & 0x07; + + return val; +} +EXPORT_SYMBOL_GPL(pcf50633_gpio_get); + +int pcf50633_gpio_invert_set(struct pcf50633 *pcf, int gpio, int invert) +{ + u8 val, reg; + + reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; + val = !!invert << 3; + + return pcf50633_reg_set_bit_mask(pcf, reg, 1 << 3, val); +} +EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_set); + +int pcf50633_gpio_invert_get(struct pcf50633 *pcf, int gpio) +{ + u8 reg, val; + + reg = gpio - PCF50633_GPIO1 + PCF50633_REG_GPIO1CFG; + val = pcf50633_reg_read(pcf, reg); + + return val & (1 << 3); +} +EXPORT_SYMBOL_GPL(pcf50633_gpio_invert_get); + +int pcf50633_gpio_power_supply_set(struct pcf50633 *pcf, + int gpio, int regulator, int on) +{ + u8 reg, val, mask; + + /* the *ENA register is always one after the *OUT register */ + reg = pcf50633_regulator_registers[regulator] + 1; + + val = !!on << (gpio - PCF50633_GPIO1); + mask = 1 << (gpio - PCF50633_GPIO1); + + return pcf50633_reg_set_bit_mask(pcf, reg, mask, val); +} +EXPORT_SYMBOL_GPL(pcf50633_gpio_power_supply_set); diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c index 170f9d47c2f..0e5761f1263 100644 --- a/drivers/mfd/sm501.c +++ b/drivers/mfd/sm501.c @@ -41,6 +41,7 @@ struct sm501_gpio_chip { struct gpio_chip gpio; struct sm501_gpio *ourgpio; /* to get back to parent. */ void __iomem *regbase; + void __iomem *control; /* address of control reg. */ }; struct sm501_gpio { @@ -908,6 +909,25 @@ static int sm501_gpio_get(struct gpio_chip *chip, unsigned offset) return result & 1UL; } +static void sm501_gpio_ensure_gpio(struct sm501_gpio_chip *smchip, + unsigned long bit) +{ + unsigned long ctrl; + + /* check and modify if this pin is not set as gpio. */ + + if (readl(smchip->control) & bit) { + dev_info(sm501_gpio_to_dev(smchip->ourgpio)->dev, + "changing mode of gpio, bit %08lx\n", bit); + + ctrl = readl(smchip->control); + ctrl &= ~bit; + writel(ctrl, smchip->control); + + sm501_sync_regs(sm501_gpio_to_dev(smchip->ourgpio)); + } +} + static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { @@ -929,6 +949,8 @@ static void sm501_gpio_set(struct gpio_chip *chip, unsigned offset, int value) writel(val, regs); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); + sm501_gpio_ensure_gpio(smchip, bit); + spin_unlock_irqrestore(&smgpio->lock, save); } @@ -941,8 +963,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) unsigned long save; unsigned long ddr; - dev_info(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n", - __func__, chip, offset); + dev_dbg(sm501_gpio_to_dev(smgpio)->dev, "%s(%p,%d)\n", + __func__, chip, offset); spin_lock_irqsave(&smgpio->lock, save); @@ -950,6 +972,8 @@ static int sm501_gpio_input(struct gpio_chip *chip, unsigned offset) writel(ddr & ~bit, regs + SM501_GPIO_DDR_LOW); sm501_sync_regs(sm501_gpio_to_dev(smgpio)); + sm501_gpio_ensure_gpio(smchip, bit); + spin_unlock_irqrestore(&smgpio->lock, save); return 0; @@ -1012,9 +1036,11 @@ static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm, if (base > 0) base += 32; chip->regbase = gpio->regs + SM501_GPIO_DATA_HIGH; + chip->control = sm->regs + SM501_GPIO63_32_CONTROL; gchip->label = "SM501-HIGH"; } else { chip->regbase = gpio->regs + SM501_GPIO_DATA_LOW; + chip->control = sm->regs + SM501_GPIO31_0_CONTROL; gchip->label = "SM501-LOW"; } diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c index b59c385cbc1..e7ab0035d30 100644 --- a/drivers/mfd/twl4030-core.c +++ b/drivers/mfd/twl4030-core.c @@ -38,6 +38,9 @@ #include <linux/i2c.h> #include <linux/i2c/twl4030.h> +#ifdef CONFIG_ARM +#include <mach/cpu.h> +#endif /* * The TWL4030 "Triton 2" is one of a family of a multi-function "Power @@ -646,7 +649,7 @@ static inline int __init unprotect_pm_master(void) return e; } -static void __init clocks_init(void) +static void __init clocks_init(struct device *dev) { int e = 0; struct clk *osc; @@ -655,9 +658,9 @@ static void __init clocks_init(void) #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) if (cpu_is_omap2430()) - osc = clk_get(NULL, "osc_ck"); + osc = clk_get(dev, "osc_ck"); else - osc = clk_get(NULL, "osc_sys_ck"); + osc = clk_get(dev, "osc_sys_ck"); if (IS_ERR(osc)) { printk(KERN_WARNING "Skipping twl4030 internal clock init and " @@ -773,7 +776,7 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id) inuse = true; /* setup clock framework */ - clocks_init(); + clocks_init(&client->dev); /* Maybe init the T2 Interrupt subsystem */ if (client->irq diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c index 3a273ccef3f..f92595c8f16 100644 --- a/drivers/mfd/wm8350-core.c +++ b/drivers/mfd/wm8350-core.c @@ -1453,6 +1453,9 @@ void wm8350_device_exit(struct wm8350 *wm8350) { int i; + for (i = 0; i < ARRAY_SIZE(wm8350->pmic.led); i++) + platform_device_unregister(wm8350->pmic.led[i].pdev); + for (i = 0; i < ARRAY_SIZE(wm8350->pmic.pdev); i++) platform_device_unregister(wm8350->pmic.pdev[i]); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fee7304102a..419c378bd24 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -120,7 +120,7 @@ config TIFM_CORE cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD Interface support (MMC_TIFM_SD)'. - To compile this driver as a module, choose M here: the module will + To compile this driver as a module, choose M here: the module will be called tifm_core. config TIFM_7XX1 @@ -133,100 +133,9 @@ config TIFM_7XX1 To make actual use of the device, you will have to select some flash card format drivers, as outlined in the TIFM_CORE Help. - To compile this driver as a module, choose M here: the module will + To compile this driver as a module, choose M here: the module will be called tifm_7xx1. -config ACER_WMI - tristate "Acer WMI Laptop Extras (EXPERIMENTAL)" - depends on X86 - depends on EXPERIMENTAL - depends on ACPI - depends on LEDS_CLASS - depends on NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - depends on SERIO_I8042 - depends on RFKILL - select ACPI_WMI - ---help--- - This is a driver for newer Acer (and Wistron) laptops. It adds - wireless radio and bluetooth control, and on some laptops, - exposes the mail LED and LCD backlight. - - For more information about this driver see - <file:Documentation/laptops/acer-wmi.txt> - - If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M - here. - -config ASUS_LAPTOP - tristate "Asus Laptop Extras (EXPERIMENTAL)" - depends on X86 - depends on ACPI - depends on EXPERIMENTAL && !ACPI_ASUS - depends on LEDS_CLASS - depends on NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is the new Linux driver for Asus laptops. It may also support some - MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate - standard ACPI events that go through /proc/acpi/events. It also adds - support for video output switching, LCD backlight control, Bluetooth and - Wlan control, and most importantly, allows you to blink those fancy LEDs. - - For more information and a userspace daemon for handling the extra - buttons see <http://acpi4asus.sf.net/>. - - If you have an ACPI-compatible ASUS laptop, say Y or M here. - -config FUJITSU_LAPTOP - tristate "Fujitsu Laptop Extras" - depends on X86 - depends on ACPI - depends on INPUT - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by Fujitsu: - - * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks - * Possibly other Fujitsu laptop models - * Tested with S6410 and S7020 - - It adds support for LCD brightness control and some hotkeys. - - If you have a Fujitsu laptop, say Y or M here. - -config FUJITSU_LAPTOP_DEBUG - bool "Verbose debug mode for Fujitsu Laptop Extras" - depends on FUJITSU_LAPTOP - default n - ---help--- - Enables extra debug output from the fujitsu extras driver, at the - expense of a slight increase in driver size. - - If you are not sure, say N here. - -config TC1100_WMI - tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" - depends on X86 && !X86_64 - depends on EXPERIMENTAL - depends on ACPI - select ACPI_WMI - ---help--- - This is a driver for the WMI extensions (wireless and bluetooth power - control) of the HP Compaq TC1100 tablet. - -config HP_WMI - tristate "HP WMI extras" - depends on ACPI_WMI - depends on INPUT - depends on RFKILL - help - Say Y here if you want to support WMI-based hotkeys on HP laptops and - to read data from WMI such as docking or ambient light sensor state. - - To compile this driver as a module, choose M here: the module will - be called hp-wmi. - config ICS932S401 tristate "Integrated Circuits ICS932S401" depends on I2C && EXPERIMENTAL @@ -237,170 +146,6 @@ config ICS932S401 This driver can also be built as a module. If so, the module will be called ics932s401. -config MSI_LAPTOP - tristate "MSI Laptop Extras" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by MSI (MICRO-STAR - INTERNATIONAL): - - MSI MegaBook S270 (MS-1013) - Cytron/TCM/Medion/Tchibo MD96100/SAM2000 - - It adds support for Bluetooth, WLAN and LCD brightness control. - - More information about this driver is available at - <http://0pointer.de/lennart/tchibo.html>. - - If you have an MSI S270 laptop, say Y or M here. - -config PANASONIC_LAPTOP - tristate "Panasonic Laptop Extras" - depends on X86 && INPUT && ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This driver adds support for access to backlight control and hotkeys - on Panasonic Let's Note laptops. - - If you have a Panasonic Let's note laptop (such as the R1(N variant), - R2, R3, R5, T2, W2 and Y2 series), say Y. - -config COMPAL_LAPTOP - tristate "Compal Laptop Extras" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - ---help--- - This is a driver for laptops built by Compal: - - Compal FL90/IFL90 - Compal FL91/IFL91 - Compal FL92/JFL92 - Compal FT00/IFT00 - - It adds support for Bluetooth, WLAN and LCD brightness control. - - If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. - -config SONY_LAPTOP - tristate "Sony Laptop Extras" - depends on X86 && ACPI - select BACKLIGHT_CLASS_DEVICE - depends on INPUT - ---help--- - This mini-driver drives the SNC and SPIC devices present in the ACPI - BIOS of the Sony Vaio laptops. - - It gives access to some extra laptop functionalities like Bluetooth, - screen brightness control, Fn keys and allows powering on/off some - devices. - - Read <file:Documentation/laptops/sony-laptop.txt> for more information. - -config SONYPI_COMPAT - bool "Sonypi compatibility" - depends on SONY_LAPTOP - ---help--- - Build the sonypi driver compatibility code into the sony-laptop driver. - -config THINKPAD_ACPI - tristate "ThinkPad ACPI Laptop Extras" - depends on X86 && ACPI - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - select HWMON - select NVRAM - select INPUT - select NEW_LEDS - select LEDS_CLASS - select NET - select RFKILL - ---help--- - This is a driver for the IBM and Lenovo ThinkPad laptops. It adds - support for Fn-Fx key combinations, Bluetooth control, video - output switching, ThinkLight control, UltraBay eject and more. - For more information about this driver see - <file:Documentation/laptops/thinkpad-acpi.txt> and - <http://ibm-acpi.sf.net/> . - - This driver was formerly known as ibm-acpi. - - If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. - -config THINKPAD_ACPI_DEBUG - bool "Verbose debug mode" - depends on THINKPAD_ACPI - default n - ---help--- - Enables extra debugging information, at the expense of a slightly - increase in driver size. - - If you are not sure, say N here. - -config THINKPAD_ACPI_DOCK - bool "Legacy Docking Station Support" - depends on THINKPAD_ACPI - depends on ACPI_DOCK=n - default n - ---help--- - Allows the thinkpad_acpi driver to handle docking station events. - This support was made obsolete by the generic ACPI docking station - support (CONFIG_ACPI_DOCK). It will allow locking and removing the - laptop from the docking station, but will not properly connect PCI - devices. - - If you are not sure, say N here. - -config THINKPAD_ACPI_BAY - bool "Legacy Removable Bay Support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to handle removable bays. It will - electrically disable the device in the bay, and also generate - notifications when the bay lever is ejected or inserted. - - If you are not sure, say Y here. - -config THINKPAD_ACPI_VIDEO - bool "Video output control support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to provide an interface to control - the various video output ports. - - This feature often won't work well, depending on ThinkPad model, - display state, video output devices in use, whether there is a X - server running, phase of the moon, and the current mood of - Schroedinger's cat. If you can use X.org's RandR to control - your ThinkPad's video output ports instead of this feature, - don't think twice: do it and say N here to save some memory. - - If you are not sure, say Y here. - -config THINKPAD_ACPI_HOTKEY_POLL - bool "Support NVRAM polling for hot keys" - depends on THINKPAD_ACPI - default y - ---help--- - Some thinkpad models benefit from NVRAM polling to detect a few of - the hot key press events. If you know your ThinkPad model does not - need to do NVRAM polling to support any of the hot keys you use, - unselecting this option will save about 1kB of memory. - - ThinkPads T40 and newer, R52 and newer, and X31 and newer are - unlikely to need NVRAM polling in their latest BIOS versions. - - NVRAM polling can detect at most the following keys: ThinkPad/Access - IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, - Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). - - If you are not sure, say Y here. The driver enables polling only if - it is strictly necessary to do so. - config ATMEL_SSC tristate "Device driver for Atmel SSC peripheral" depends on AVR32 || ARCH_AT91 @@ -413,31 +158,6 @@ config ATMEL_SSC If unsure, say N. -config INTEL_MENLOW - tristate "Thermal Management driver for Intel menlow platform" - depends on ACPI_THERMAL - select THERMAL - depends on X86 - ---help--- - ACPI thermal management enhancement driver on - Intel Menlow platform. - - If unsure, say N. - -config EEEPC_LAPTOP - tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" - depends on X86 - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - depends on HWMON - depends on EXPERIMENTAL - depends on RFKILL - ---help--- - This driver supports the Fn-Fx keys on Eee PC laptops. - It also adds the ability to switch camera/wlan on/off. - - If you have an Eee PC laptop, say Y or M here. - config ENCLOSURE_SERVICES tristate "Enclosure Services" default n @@ -498,6 +218,18 @@ config SGI_GRU_DEBUG This option enables addition debugging code for the SGI GRU driver. If you are unsure, say N. +config DELL_LAPTOP + tristate "Dell Laptop Extras (EXPERIMENTAL)" + depends on X86 + depends on DCDBAS + depends on EXPERIMENTAL + depends on BACKLIGHT_CLASS_DEVICE + depends on RFKILL + default n + ---help--- + This driver adds support for rfkill and backlight control to Dell + laptops. + source "drivers/misc/c2port/Kconfig" endif # MISC_DEVICES diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 817f7f5ab3b..9cf8ae6e4b3 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -1,32 +1,20 @@ # # Makefile for misc devices that really don't fit anywhere else. # -obj- := misc.o # Dummy rule to force built-in.o to be made obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ -obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o -obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o -obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o -obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o -obj-$(CONFIG_ACER_WMI) += acer-wmi.o obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o -obj-$(CONFIG_HP_WMI) += hp-wmi.o obj-$(CONFIG_ICS932S401) += ics932s401.o -obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o +obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_PHANTOM) += phantom.o obj-$(CONFIG_SGI_IOC4) += ioc4.o -obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o -obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o -obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o -obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o -obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o obj-$(CONFIG_KGDB_TESTS) += kgdbts.o obj-$(CONFIG_SGI_XP) += sgi-xp/ diff --git a/drivers/misc/dell-laptop.c b/drivers/misc/dell-laptop.c new file mode 100644 index 00000000000..4d33a2068b7 --- /dev/null +++ b/drivers/misc/dell-laptop.c @@ -0,0 +1,436 @@ +/* + * Driver for Dell laptop extras + * + * Copyright (c) Red Hat <mjg@redhat.com> + * + * Based on documentation in the libsmbios package, Copyright (C) 2005 Dell + * Inc. + * + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/backlight.h> +#include <linux/err.h> +#include <linux/dmi.h> +#include <linux/io.h> +#include <linux/rfkill.h> +#include <linux/power_supply.h> +#include <linux/acpi.h> +#include "../firmware/dcdbas.h" + +#define BRIGHTNESS_TOKEN 0x7d + +/* This structure will be modified by the firmware when we enter + * system management mode, hence the volatiles */ + +struct calling_interface_buffer { + u16 class; + u16 select; + volatile u32 input[4]; + volatile u32 output[4]; +} __packed; + +struct calling_interface_token { + u16 tokenID; + u16 location; + union { + u16 value; + u16 stringlength; + }; +}; + +struct calling_interface_structure { + struct dmi_header header; + u16 cmdIOAddress; + u8 cmdIOCode; + u32 supportedCmds; + struct calling_interface_token tokens[]; +} __packed; + +static int da_command_address; +static int da_command_code; +static int da_num_tokens; +static struct calling_interface_token *da_tokens; + +static struct backlight_device *dell_backlight_device; +static struct rfkill *wifi_rfkill; +static struct rfkill *bluetooth_rfkill; +static struct rfkill *wwan_rfkill; + +static const struct dmi_system_id __initdata dell_device_table[] = { + { + .ident = "Dell laptop", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_CHASSIS_TYPE, "8"), + }, + }, + { } +}; + +static void parse_da_table(const struct dmi_header *dm) +{ + /* Final token is a terminator, so we don't want to copy it */ + int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; + struct calling_interface_structure *table = + container_of(dm, struct calling_interface_structure, header); + + /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least + 6 bytes of entry */ + + if (dm->length < 17) + return; + + da_command_address = table->cmdIOAddress; + da_command_code = table->cmdIOCode; + + da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * + sizeof(struct calling_interface_token), + GFP_KERNEL); + + if (!da_tokens) + return; + + memcpy(da_tokens+da_num_tokens, table->tokens, + sizeof(struct calling_interface_token) * tokens); + + da_num_tokens += tokens; +} + +static void find_tokens(const struct dmi_header *dm) +{ + switch (dm->type) { + case 0xd4: /* Indexed IO */ + break; + case 0xd5: /* Protected Area Type 1 */ + break; + case 0xd6: /* Protected Area Type 2 */ + break; + case 0xda: /* Calling interface */ + parse_da_table(dm); + break; + } +} + +static int find_token_location(int tokenid) +{ + int i; + for (i = 0; i < da_num_tokens; i++) { + if (da_tokens[i].tokenID == tokenid) + return da_tokens[i].location; + } + + return -1; +} + +static struct calling_interface_buffer * +dell_send_request(struct calling_interface_buffer *buffer, int class, + int select) +{ + struct smi_cmd command; + + command.magic = SMI_CMD_MAGIC; + command.command_address = da_command_address; + command.command_code = da_command_code; + command.ebx = virt_to_phys(buffer); + command.ecx = 0x42534931; + + buffer->class = class; + buffer->select = select; + + dcdbas_smi_request(&command); + + return buffer; +} + +/* Derived from information in DellWirelessCtl.cpp: + Class 17, select 11 is radio control. It returns an array of 32-bit values. + + result[0]: return code + result[1]: + Bit 0: Hardware switch supported + Bit 1: Wifi locator supported + Bit 2: Wifi is supported + Bit 3: Bluetooth is supported + Bit 4: WWAN is supported + Bit 5: Wireless keyboard supported + Bits 6-7: Reserved + Bit 8: Wifi is installed + Bit 9: Bluetooth is installed + Bit 10: WWAN is installed + Bits 11-15: Reserved + Bit 16: Hardware switch is on + Bit 17: Wifi is blocked + Bit 18: Bluetooth is blocked + Bit 19: WWAN is blocked + Bits 20-31: Reserved + result[2]: NVRAM size in bytes + result[3]: NVRAM format version number +*/ + +static int dell_rfkill_set(int radio, enum rfkill_state state) +{ + struct calling_interface_buffer buffer; + int disable = (state == RFKILL_STATE_UNBLOCKED) ? 0 : 1; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = (1 | (radio<<8) | (disable << 16)); + dell_send_request(&buffer, 17, 11); + + return 0; +} + +static int dell_wifi_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(1, state); +} + +static int dell_bluetooth_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(2, state); +} + +static int dell_wwan_set(void *data, enum rfkill_state state) +{ + return dell_rfkill_set(3, state); +} + +static int dell_rfkill_get(int bit, enum rfkill_state *state) +{ + struct calling_interface_buffer buffer; + int status; + int new_state = RFKILL_STATE_HARD_BLOCKED; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + dell_send_request(&buffer, 17, 11); + status = buffer.output[1]; + + if (status & (1<<16)) + new_state = RFKILL_STATE_SOFT_BLOCKED; + + if (status & (1<<bit)) + *state = new_state; + else + *state = RFKILL_STATE_UNBLOCKED; + + return 0; +} + +static int dell_wifi_get(void *data, enum rfkill_state *state) +{ + return dell_rfkill_get(17, state); +} + +static int dell_bluetooth_get(void *data, enum rfkill_state *state) +{ + return dell_rfkill_get(18, state); +} + +static int dell_wwan_get(void *data, enum rfkill_state *state) +{ + return dell_rfkill_get(19, state); +} + +static int dell_setup_rfkill(void) +{ + struct calling_interface_buffer buffer; + int status; + int ret; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + dell_send_request(&buffer, 17, 11); + status = buffer.output[1]; + + if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { + wifi_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WLAN); + if (!wifi_rfkill) + goto err_wifi; + wifi_rfkill->name = "dell-wifi"; + wifi_rfkill->toggle_radio = dell_wifi_set; + wifi_rfkill->get_state = dell_wifi_get; + ret = rfkill_register(wifi_rfkill); + if (ret) + goto err_wifi; + } + + if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { + bluetooth_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_BLUETOOTH); + if (!bluetooth_rfkill) + goto err_bluetooth; + bluetooth_rfkill->name = "dell-bluetooth"; + bluetooth_rfkill->toggle_radio = dell_bluetooth_set; + bluetooth_rfkill->get_state = dell_bluetooth_get; + ret = rfkill_register(bluetooth_rfkill); + if (ret) + goto err_bluetooth; + } + + if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { + wwan_rfkill = rfkill_allocate(NULL, RFKILL_TYPE_WWAN); + if (!wwan_rfkill) + goto err_wwan; + wwan_rfkill->name = "dell-wwan"; + wwan_rfkill->toggle_radio = dell_wwan_set; + wwan_rfkill->get_state = dell_wwan_get; + ret = rfkill_register(wwan_rfkill); + if (ret) + goto err_wwan; + } + + return 0; +err_wwan: + if (wwan_rfkill) + rfkill_free(wwan_rfkill); + if (bluetooth_rfkill) { + rfkill_unregister(bluetooth_rfkill); + bluetooth_rfkill = NULL; + } +err_bluetooth: + if (bluetooth_rfkill) + rfkill_free(bluetooth_rfkill); + if (wifi_rfkill) { + rfkill_unregister(wifi_rfkill); + wifi_rfkill = NULL; + } +err_wifi: + if (wifi_rfkill) + rfkill_free(wifi_rfkill); + + return ret; +} + +static int dell_send_intensity(struct backlight_device *bd) +{ + struct calling_interface_buffer buffer; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + buffer.input[1] = bd->props.brightness; + + if (buffer.input[0] == -1) + return -ENODEV; + + if (power_supply_is_system_supplied() > 0) + dell_send_request(&buffer, 1, 2); + else + dell_send_request(&buffer, 1, 1); + + return 0; +} + +static int dell_get_intensity(struct backlight_device *bd) +{ + struct calling_interface_buffer buffer; + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + + if (buffer.input[0] == -1) + return -ENODEV; + + if (power_supply_is_system_supplied() > 0) + dell_send_request(&buffer, 0, 2); + else + dell_send_request(&buffer, 0, 1); + + return buffer.output[1]; +} + +static struct backlight_ops dell_ops = { + .get_brightness = dell_get_intensity, + .update_status = dell_send_intensity, +}; + +static int __init dell_init(void) +{ + struct calling_interface_buffer buffer; + int max_intensity = 0; + int ret; + + if (!dmi_check_system(dell_device_table)) + return -ENODEV; + + dmi_walk(find_tokens); + + if (!da_tokens) { + printk(KERN_INFO "dell-laptop: Unable to find dmi tokens\n"); + return -ENODEV; + } + + ret = dell_setup_rfkill(); + + if (ret) { + printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); + goto out; + } + +#ifdef CONFIG_ACPI + /* In the event of an ACPI backlight being available, don't + * register the platform controller. + */ + if (acpi_video_backlight_support()) + return 0; +#endif + + memset(&buffer, 0, sizeof(struct calling_interface_buffer)); + buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); + + if (buffer.input[0] != -1) { + dell_send_request(&buffer, 0, 2); + max_intensity = buffer.output[3]; + } + + if (max_intensity) { + dell_backlight_device = backlight_device_register( + "dell_backlight", + NULL, NULL, + &dell_ops); + + if (IS_ERR(dell_backlight_device)) { + ret = PTR_ERR(dell_backlight_device); + dell_backlight_device = NULL; + goto out; + } + + dell_backlight_device->props.max_brightness = max_intensity; + dell_backlight_device->props.brightness = + dell_get_intensity(dell_backlight_device); + backlight_update_status(dell_backlight_device); + } + + return 0; +out: + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); + kfree(da_tokens); + return ret; +} + +static void __exit dell_exit(void) +{ + backlight_device_unregister(dell_backlight_device); + if (wifi_rfkill) + rfkill_unregister(wifi_rfkill); + if (bluetooth_rfkill) + rfkill_unregister(bluetooth_rfkill); + if (wwan_rfkill) + rfkill_unregister(wwan_rfkill); +} + +module_init(dell_init); +module_exit(dell_exit); + +MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); +MODULE_DESCRIPTION("Dell laptop driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 0736cff9d97..3cf61ece71d 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c @@ -119,7 +119,7 @@ enclosure_register(struct device *dev, const char *name, int components, edev->edev.class = &enclosure_class; edev->edev.parent = get_device(dev); edev->cb = cb; - snprintf(edev->edev.bus_id, BUS_ID_SIZE, "%s", name); + dev_set_name(&edev->edev, name); err = device_register(&edev->edev); if (err) goto err; @@ -170,7 +170,7 @@ EXPORT_SYMBOL_GPL(enclosure_unregister); static void enclosure_link_name(struct enclosure_component *cdev, char *name) { strcpy(name, "enclosure_device:"); - strcat(name, cdev->cdev.bus_id); + strcat(name, dev_name(&cdev->cdev)); } static void enclosure_remove_links(struct enclosure_component *cdev) @@ -256,9 +256,9 @@ enclosure_component_register(struct enclosure_device *edev, cdev = &ecomp->cdev; cdev->parent = get_device(&edev->edev); if (name) - snprintf(cdev->bus_id, BUS_ID_SIZE, "%s", name); + dev_set_name(cdev, name); else - snprintf(cdev->bus_id, BUS_ID_SIZE, "%u", number); + dev_set_name(cdev, "%u", number); cdev->release = enclosure_component_release; cdev->groups = enclosure_groups; diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 81152b3e360..7957f525b2f 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -95,11 +95,6 @@ struct xpnet_pending_msg { atomic_t use_count; }; -/* driver specific structure pointed to by the device structure */ -struct xpnet_dev_private { - struct net_device_stats stats; -}; - struct net_device *xpnet_device; /* @@ -153,7 +148,6 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) struct sk_buff *skb; void *dst; enum xp_retval ret; - struct xpnet_dev_private *priv = netdev_priv(xpnet_device); if (!XPNET_VALID_MSG(msg)) { /* @@ -161,7 +155,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) */ xpc_received(partid, channel, (void *)msg); - priv->stats.rx_errors++; + xpnet_device->stats.rx_errors++; return; } @@ -176,7 +170,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) xpc_received(partid, channel, (void *)msg); - priv->stats.rx_errors++; + xpnet_device->stats.rx_errors++; return; } @@ -226,7 +220,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) xpc_received(partid, channel, (void *)msg); - priv->stats.rx_errors++; + xpnet_device->stats.rx_errors++; return; } @@ -247,8 +241,8 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) skb_end_pointer(skb), skb->len); xpnet_device->last_rx = jiffies; - priv->stats.rx_packets++; - priv->stats.rx_bytes += skb->len + ETH_HLEN; + xpnet_device->stats.rx_packets++; + xpnet_device->stats.rx_bytes += skb->len + ETH_HLEN; netif_rx_ni(skb); xpc_received(partid, channel, (void *)msg); @@ -353,26 +347,6 @@ xpnet_dev_change_mtu(struct net_device *dev, int new_mtu) } /* - * Required for the net_device structure. - */ -static int -xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map) -{ - return 0; -} - -/* - * Return statistics to the caller. - */ -static struct net_device_stats * -xpnet_dev_get_stats(struct net_device *dev) -{ - struct xpnet_dev_private *priv = netdev_priv(dev); - - return &priv->stats; -} - -/* * Notification that the other end has received the message and * DMA'd the skb information. At this point, they are done with * our side. When all recipients are done processing, we @@ -453,7 +427,6 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct xpnet_pending_msg *queued_msg; u64 start_addr, end_addr; short dest_partid; - struct xpnet_dev_private *priv = netdev_priv(dev); u16 embedded_bytes = 0; dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " @@ -476,7 +449,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) dev_warn(xpnet, "failed to kmalloc %ld bytes; dropping " "packet\n", sizeof(struct xpnet_pending_msg)); - priv->stats.tx_errors++; + dev->stats.tx_errors++; return -ENOMEM; } @@ -526,8 +499,8 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) kfree(queued_msg); } - priv->stats.tx_packets++; - priv->stats.tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; return 0; } @@ -538,12 +511,19 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void xpnet_dev_tx_timeout(struct net_device *dev) { - struct xpnet_dev_private *priv = netdev_priv(dev); - - priv->stats.tx_errors++; - return; + dev->stats.tx_errors++; } +static const struct net_device_ops xpnet_netdev_ops = { + .ndo_open = xpnet_dev_open, + .ndo_stop = xpnet_dev_stop, + .ndo_start_xmit = xpnet_dev_hard_start_xmit, + .ndo_change_mtu = xpnet_dev_change_mtu, + .ndo_tx_timeout = xpnet_dev_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init xpnet_init(void) { @@ -563,8 +543,7 @@ xpnet_init(void) * use ether_setup() to init the majority of our device * structure and then override the necessary pieces. */ - xpnet_device = alloc_netdev(sizeof(struct xpnet_dev_private), - XPNET_DEVICE_NAME, ether_setup); + xpnet_device = alloc_netdev(0, XPNET_DEVICE_NAME, ether_setup); if (xpnet_device == NULL) { kfree(xpnet_broadcast_partitions); return -ENOMEM; @@ -573,13 +552,6 @@ xpnet_init(void) netif_carrier_off(xpnet_device); xpnet_device->mtu = XPNET_DEF_MTU; - xpnet_device->change_mtu = xpnet_dev_change_mtu; - xpnet_device->open = xpnet_dev_open; - xpnet_device->get_stats = xpnet_dev_get_stats; - xpnet_device->stop = xpnet_dev_stop; - xpnet_device->hard_start_xmit = xpnet_dev_hard_start_xmit; - xpnet_device->tx_timeout = xpnet_dev_tx_timeout; - xpnet_device->set_config = xpnet_dev_set_config; /* * Multicast assumes the LSB of the first octet is set for multicast diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 1e97916914a..76bfe16c09b 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -55,7 +55,6 @@ enum atmel_mci_state { struct atmel_mci_dma { #ifdef CONFIG_MMC_ATMELMCI_DMA - struct dma_client client; struct dma_chan *chan; struct dma_async_tx_descriptor *data_desc; #endif @@ -593,10 +592,8 @@ atmci_submit_data_dma(struct atmel_mci *host, struct mmc_data *data) /* If we don't have a channel, we can't do DMA */ chan = host->dma.chan; - if (chan) { - dma_chan_get(chan); + if (chan) host->data_chan = chan; - } if (!chan) return -ENODEV; @@ -1443,60 +1440,6 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -#ifdef CONFIG_MMC_ATMELMCI_DMA - -static inline struct atmel_mci * -dma_client_to_atmel_mci(struct dma_client *client) -{ - return container_of(client, struct atmel_mci, dma.client); -} - -static enum dma_state_client atmci_dma_event(struct dma_client *client, - struct dma_chan *chan, enum dma_state state) -{ - struct atmel_mci *host; - enum dma_state_client ret = DMA_NAK; - - host = dma_client_to_atmel_mci(client); - - switch (state) { - case DMA_RESOURCE_AVAILABLE: - spin_lock_bh(&host->lock); - if (!host->dma.chan) { - host->dma.chan = chan; - ret = DMA_ACK; - } - spin_unlock_bh(&host->lock); - - if (ret == DMA_ACK) - dev_info(&host->pdev->dev, - "Using %s for DMA transfers\n", - chan->dev.bus_id); - break; - - case DMA_RESOURCE_REMOVED: - spin_lock_bh(&host->lock); - if (host->dma.chan == chan) { - host->dma.chan = NULL; - ret = DMA_ACK; - } - spin_unlock_bh(&host->lock); - - if (ret == DMA_ACK) - dev_info(&host->pdev->dev, - "Lost %s, falling back to PIO\n", - chan->dev.bus_id); - break; - - default: - break; - } - - - return ret; -} -#endif /* CONFIG_MMC_ATMELMCI_DMA */ - static int __init atmci_init_slot(struct atmel_mci *host, struct mci_slot_pdata *slot_data, unsigned int id, u32 sdc_reg) @@ -1600,6 +1543,18 @@ static void __exit atmci_cleanup_slot(struct atmel_mci_slot *slot, mmc_free_host(slot->mmc); } +#ifdef CONFIG_MMC_ATMELMCI_DMA +static bool filter(struct dma_chan *chan, void *slave) +{ + struct dw_dma_slave *dws = slave; + + if (dws->dma_dev == chan->device->dev) + return true; + else + return false; +} +#endif + static int __init atmci_probe(struct platform_device *pdev) { struct mci_platform_data *pdata; @@ -1652,22 +1607,20 @@ static int __init atmci_probe(struct platform_device *pdev) goto err_request_irq; #ifdef CONFIG_MMC_ATMELMCI_DMA - if (pdata->dma_slave) { - struct dma_slave *slave = pdata->dma_slave; + if (pdata->dma_slave.dma_dev) { + struct dw_dma_slave *dws = &pdata->dma_slave; + dma_cap_mask_t mask; - slave->tx_reg = regs->start + MCI_TDR; - slave->rx_reg = regs->start + MCI_RDR; + dws->tx_reg = regs->start + MCI_TDR; + dws->rx_reg = regs->start + MCI_RDR; /* Try to grab a DMA channel */ - host->dma.client.event_callback = atmci_dma_event; - dma_cap_set(DMA_SLAVE, host->dma.client.cap_mask); - host->dma.client.slave = slave; - - dma_async_client_register(&host->dma.client); - dma_async_client_chan_request(&host->dma.client); - } else { - dev_notice(&pdev->dev, "DMA not available, using PIO\n"); + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + host->dma.chan = dma_request_channel(mask, filter, dws); } + if (!host->dma.chan) + dev_notice(&pdev->dev, "DMA not available, using PIO\n"); #endif /* CONFIG_MMC_ATMELMCI_DMA */ platform_set_drvdata(pdev, host); @@ -1699,8 +1652,8 @@ static int __init atmci_probe(struct platform_device *pdev) err_init_slot: #ifdef CONFIG_MMC_ATMELMCI_DMA - if (pdata->dma_slave) - dma_async_client_unregister(&host->dma.client); + if (host->dma.chan) + dma_release_channel(host->dma.chan); #endif free_irq(irq, host); err_request_irq: @@ -1731,8 +1684,8 @@ static int __exit atmci_remove(struct platform_device *pdev) clk_disable(host->mck); #ifdef CONFIG_MMC_ATMELMCI_DMA - if (host->dma.client.slave) - dma_async_client_unregister(&host->dma.client); + if (host->dma.chan) + dma_release_channel(host->dma.chan); #endif free_irq(platform_get_irq(pdev, 0), host); @@ -1761,7 +1714,7 @@ static void __exit atmci_exit(void) platform_driver_unregister(&atmci_driver); } -module_init(atmci_init); +late_initcall(atmci_init); /* try to load after dma driver when built-in */ module_exit(atmci_exit); MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver"); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index a90d50c2c3e..7d04fb9ddca 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -45,6 +45,14 @@ config MTD_PARTITIONS devices. Partitioning on NFTL 'devices' is a different - that's the 'normal' form of partitioning used on a block device. +config MTD_TESTS + tristate "MTD tests support" + depends on m + help + This option includes various MTD tests into compilation. The tests + should normally be compiled as kernel modules. The modules perform + various checks and verifications when loaded. + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" depends on MTD_PARTITIONS @@ -316,6 +324,8 @@ source "drivers/mtd/nand/Kconfig" source "drivers/mtd/onenand/Kconfig" +source "drivers/mtd/lpddr/Kconfig" + source "drivers/mtd/ubi/Kconfig" endif # MTD diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 4b77335715f..4521b1ecce4 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -29,6 +29,6 @@ obj-$(CONFIG_MTD_OOPS) += mtdoops.o nftl-objs := nftlcore.o nftlmount.o inftl-objs := inftlcore.o inftlmount.o -obj-y += chips/ maps/ devices/ nand/ onenand/ +obj-y += chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/ obj-$(CONFIG_MTD_UBI) += ubi/ diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c93a8be5d5f..f5ab6fa1057 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -58,8 +58,8 @@ static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); -static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); #ifdef CONFIG_MTD_OTP static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -558,8 +558,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) } for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "erase region %d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, + printk(KERN_DEBUG "erase region %d: offset=0x%llx,size=0x%x,blocks=%d\n", + i,(unsigned long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].numblocks); } @@ -2058,7 +2058,7 @@ out: put_chip(map, chip, adr); return ret; } -static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -2082,7 +2082,7 @@ static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return ret; } -static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index d74ec46aa03..94bb61e1904 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -71,8 +71,8 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); #include "fwh_lock.h" -static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); static struct mtd_chip_driver cfi_amdstd_chipdrv = { .probe = NULL, /* Not usable directly */ @@ -322,6 +322,14 @@ static struct cfi_fixup fixup_table[] = { }; +static void cfi_fixup_major_minor(struct cfi_private *cfi, + struct cfi_pri_amdstd *extp) +{ + if (cfi->mfr == CFI_MFR_SAMSUNG && cfi->id == 0x257e && + extp->MajorVersion == '0') + extp->MajorVersion = '1'; +} + struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -363,6 +371,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) return NULL; } + cfi_fixup_major_minor(cfi, extp); + if (extp->MajorVersion != '1' || (extp->MinorVersion < '0' || extp->MinorVersion > '4')) { printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query " @@ -1774,12 +1784,12 @@ out_unlock: return ret; } -static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_atmel_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { return cfi_varsize_frob(mtd, do_atmel_lock, ofs, len, NULL); } -static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_atmel_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { return cfi_varsize_frob(mtd, do_atmel_unlock, ofs, len, NULL); } diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index d4714dd9f7a..6c740f346f9 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -42,8 +42,8 @@ static int cfi_staa_writev(struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_staa_sync (struct mtd_info *); -static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len); -static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); static int cfi_staa_suspend (struct mtd_info *); static void cfi_staa_resume (struct mtd_info *); @@ -221,8 +221,8 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) } for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, + printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", + i, (unsigned long long)mtd->eraseregions[i].offset, mtd->eraseregions[i].erasesize, mtd->eraseregions[i].numblocks); } @@ -964,7 +964,7 @@ static int cfi_staa_erase_varsize(struct mtd_info *mtd, adr += regions[i].erasesize; len -= regions[i].erasesize; - if (adr % (1<< cfi->chipshift) == ((regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) + if (adr % (1<< cfi->chipshift) == (((unsigned long)regions[i].offset + (regions[i].erasesize * regions[i].numblocks)) %( 1<< cfi->chipshift))) i++; if (adr >> cfi->chipshift) { @@ -1135,7 +1135,7 @@ retry: spin_unlock_bh(chip->mutex); return 0; } -static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; @@ -1284,7 +1284,7 @@ retry: spin_unlock_bh(chip->mutex); return 0; } -static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index ab44f2b996f..57e0e4e921f 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -77,7 +77,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, } -static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -88,7 +88,7 @@ static int fwh_lock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) } -static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, size_t len) +static int fwh_unlock_varsize(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 6fde0a2e356..bc33200535f 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -120,6 +120,13 @@ config MTD_PHRAM doesn't have access to, memory beyond the mem=xxx limit, nvram, memory on the video card, etc... +config MTD_PS3VRAM + tristate "PS3 video RAM" + depends on FB_PS3 + help + This driver allows you to use excess PS3 video RAM as volatile + storage or system swap. + config MTD_LART tristate "28F160xx flash driver for LART" depends on SA1100_LART diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index 0993d5cf392..e51521df4e4 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o +obj-$(CONFIG_MTD_PS3VRAM) += ps3vram.o diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index f4bda4cee49..578de1c67bf 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -619,7 +619,7 @@ static struct mtd_partition lart_partitions[] = { }; #endif -int __init lart_flash_init (void) +static int __init lart_flash_init (void) { int result; memset (&mtd,0,sizeof (mtd)); @@ -690,7 +690,7 @@ int __init lart_flash_init (void) return (result); } -void __exit lart_flash_exit (void) +static void __exit lart_flash_exit (void) { #ifndef HAVE_PARTITIONS del_mtd_device (&mtd); @@ -705,5 +705,3 @@ module_exit (lart_flash_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Abraham vd Merwe <abraham@2d3d.co.za>"); MODULE_DESCRIPTION("MTD driver for Intel 28F160F3 on LART board"); - - diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 5733f064384..7c3fc766dcf 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -20,6 +20,7 @@ #include <linux/device.h> #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/math64.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -169,9 +170,9 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB\n", - dev_name(&flash->spi->dev), __func__, - flash->mtd.size / 1024); + DEBUG(MTD_DEBUG_LEVEL3, "%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)) @@ -232,18 +233,18 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) { struct m25p *flash = mtd_to_m25p(mtd); u32 addr,len; + uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %d\n", - dev_name(&flash->spi->dev), __func__, "at", - (u32)instr->addr, instr->len); + DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", + dev_name(&flash->spi->dev), __func__, "at", + (long long)instr->addr, (long long)instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) return -EINVAL; - if ((instr->addr % mtd->erasesize) != 0 - || (instr->len % mtd->erasesize) != 0) { + div_u64_rem(instr->len, mtd->erasesize, &rem); + if (rem) return -EINVAL; - } addr = instr->addr; len = instr->len; @@ -677,24 +678,24 @@ static int __devinit m25p_probe(struct spi_device *spi) flash->mtd.erasesize = info->sector_size; } - dev_info(&spi->dev, "%s (%d Kbytes)\n", info->name, - flash->mtd.size / 1024); + dev_info(&spi->dev, "%s (%lld Kbytes)\n", info->name, + (long long)flash->mtd.size >> 10); DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%.8x (%uMiB) " + "mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, - flash->mtd.size, flash->mtd.size / (1024*1024), + (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), flash->mtd.erasesize, flash->mtd.erasesize / 1024, flash->mtd.numeraseregions); if (flash->mtd.numeraseregions) for (i = 0; i < flash->mtd.numeraseregions; i++) DEBUG(MTD_DEBUG_LEVEL2, - "mtd.eraseregions[%d] = { .offset = 0x%.8x, " + "mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", - i, flash->mtd.eraseregions[i].offset, + i, (long long)flash->mtd.eraseregions[i].offset, flash->mtd.eraseregions[i].erasesize, flash->mtd.eraseregions[i].erasesize / 1024, flash->mtd.eraseregions[i].numblocks); @@ -722,12 +723,12 @@ static int __devinit m25p_probe(struct spi_device *spi) if (nr_parts > 0) { for (i = 0; i < nr_parts; i++) { DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%.8x, " - ".size = 0x%.8x (%uKiB) }\n", + "{.name = %s, .offset = 0x%llx, " + ".size = 0x%llx (%lldKiB) }\n", i, parts[i].name, - parts[i].offset, - parts[i].size, - parts[i].size / 1024); + (long long)parts[i].offset, + (long long)parts[i].size, + (long long)(parts[i].size >> 10)); } flash->partitioned = 1; return add_mtd_partitions(&flash->mtd, parts, nr_parts); diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 65126cd668f..d44f741ae22 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -16,6 +16,7 @@ #include <linux/device.h> #include <linux/mutex.h> #include <linux/err.h> +#include <linux/math64.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -152,15 +153,20 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) struct spi_message msg; unsigned blocksize = priv->page_size << 3; uint8_t *command; + uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n", - dev_name(&spi->dev), - instr->addr, instr->len); + DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", + dev_name(&spi->dev), (long long)instr->addr, + (long long)instr->len); /* Sanity checks */ - if ((instr->addr + instr->len) > mtd->size - || (instr->len % priv->page_size) != 0 - || (instr->addr % priv->page_size) != 0) + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + div_u64_rem(instr->len, priv->page_size, &rem); + if (rem) + return -EINVAL; + div_u64_rem(instr->addr, priv->page_size, &rem); + if (rem) return -EINVAL; spi_message_init(&msg); @@ -178,7 +184,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) /* Calculate flash page address; use block erase (for speed) if * we're at a block boundary and need to erase the whole block. */ - pageaddr = instr->addr / priv->page_size; + pageaddr = div_u64(instr->len, priv->page_size); do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize; pageaddr = pageaddr << priv->page_offset; @@ -667,8 +673,8 @@ add_dataflash_otp(struct spi_device *spi, char *name, if (revision >= 'c') otp_tag = otp_setup(device, revision); - dev_info(&spi->dev, "%s (%d KBytes) pagesize %d bytes%s\n", - name, DIV_ROUND_UP(device->size, 1024), + dev_info(&spi->dev, "%s (%lld KBytes) pagesize %d bytes%s\n", + name, (long long)((device->size + 1023) >> 10), pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); diff --git a/drivers/mtd/devices/ps3vram.c b/drivers/mtd/devices/ps3vram.c new file mode 100644 index 00000000000..d21e9beb7ed --- /dev/null +++ b/drivers/mtd/devices/ps3vram.c @@ -0,0 +1,768 @@ +/** + * ps3vram - Use extra PS3 video ram as MTD block device. + * + * Copyright (c) 2007-2008 Jim Paris <jim@jtan.com> + * Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr> + */ + +#include <linux/io.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/slab.h> +#include <linux/version.h> +#include <linux/gfp.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> + +#include <asm/lv1call.h> +#include <asm/ps3.h> + +#define DEVICE_NAME "ps3vram" + +#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */ +#define XDR_IOIF 0x0c000000 + +#define FIFO_BASE XDR_IOIF +#define FIFO_SIZE (64 * 1024) + +#define DMA_PAGE_SIZE (4 * 1024) + +#define CACHE_PAGE_SIZE (256 * 1024) +#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE) + +#define CACHE_OFFSET CACHE_PAGE_SIZE +#define FIFO_OFFSET 0 + +#define CTRL_PUT 0x10 +#define CTRL_GET 0x11 +#define CTRL_TOP 0x15 + +#define UPLOAD_SUBCH 1 +#define DOWNLOAD_SUBCH 2 + +#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c +#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 + +#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 + +struct mtd_info ps3vram_mtd; + +#define CACHE_PAGE_PRESENT 1 +#define CACHE_PAGE_DIRTY 2 + +struct ps3vram_tag { + unsigned int address; + unsigned int flags; +}; + +struct ps3vram_cache { + unsigned int page_count; + unsigned int page_size; + struct ps3vram_tag *tags; +}; + +struct ps3vram_priv { + u64 memory_handle; + u64 context_handle; + u32 *ctrl; + u32 *reports; + u8 __iomem *ddr_base; + u8 *xdr_buf; + + u32 *fifo_base; + u32 *fifo_ptr; + + struct device *dev; + struct ps3vram_cache cache; + + /* Used to serialize cache/DMA operations */ + struct mutex lock; +}; + +#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */ +#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */ +#define DMA_NOTIFIER_SIZE 0x40 +#define NOTIFIER 7 /* notifier used for completion report */ + +/* A trailing '-' means to subtract off ps3fb_videomemory.size */ +char *size = "256M-"; +module_param(size, charp, 0); +MODULE_PARM_DESC(size, "memory size"); + +static u32 *ps3vram_get_notifier(u32 *reports, int notifier) +{ + return (void *) reports + + DMA_NOTIFIER_OFFSET_BASE + + DMA_NOTIFIER_SIZE * notifier; +} + +static void ps3vram_notifier_reset(struct mtd_info *mtd) +{ + int i; + + struct ps3vram_priv *priv = mtd->priv; + u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); + for (i = 0; i < 4; i++) + notify[i] = 0xffffffff; +} + +static int ps3vram_notifier_wait(struct mtd_info *mtd, unsigned int timeout_ms) +{ + struct ps3vram_priv *priv = mtd->priv; + u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); + + do { + if (!notify[3]) + return 0; + msleep(1); + } while (time_before(jiffies, timeout)); + + return -ETIMEDOUT; +} + +static void ps3vram_init_ring(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; + priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; +} + +static int ps3vram_wait_ring(struct mtd_info *mtd, unsigned int timeout_ms) +{ + struct ps3vram_priv *priv = mtd->priv; + unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); + + do { + if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET]) + return 0; + msleep(1); + } while (time_before(jiffies, timeout)); + + dev_dbg(priv->dev, "%s:%d: FIFO timeout (%08x/%08x/%08x)\n", __func__, + __LINE__, priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET], + priv->ctrl[CTRL_TOP]); + + return -ETIMEDOUT; +} + +static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data) +{ + *(priv->fifo_ptr)++ = data; +} + +static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, + u32 tag, u32 size) +{ + ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag); +} + +static void ps3vram_rewind_ring(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + u64 status; + + ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); + + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; + + /* asking the HV for a blit will kick the fifo */ + status = lv1_gpu_context_attribute(priv->context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, + 0, 0, 0, 0); + if (status) + dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n", + __func__, __LINE__); + + priv->fifo_ptr = priv->fifo_base; +} + +static void ps3vram_fire_ring(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + u64 status; + + mutex_lock(&ps3_gpu_mutex); + + priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET + + (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); + + /* asking the HV for a blit will kick the fifo */ + status = lv1_gpu_context_attribute(priv->context_handle, + L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, + 0, 0, 0, 0); + if (status) + dev_err(priv->dev, "%s:%d: lv1_gpu_context_attribute failed\n", + __func__, __LINE__); + + if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > + FIFO_SIZE - 1024) { + dev_dbg(priv->dev, "%s:%d: fifo full, rewinding\n", __func__, + __LINE__); + ps3vram_wait_ring(mtd, 200); + ps3vram_rewind_ring(mtd); + } + + mutex_unlock(&ps3_gpu_mutex); +} + +static void ps3vram_bind(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); + ps3vram_out_ring(priv, 0x31337303); + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3); + ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); + ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ + ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ + + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1); + ps3vram_out_ring(priv, 0x3137c0de); + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3); + ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER); + ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */ + ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */ + + ps3vram_fire_ring(mtd); +} + +static int ps3vram_upload(struct mtd_info *mtd, unsigned int src_offset, + unsigned int dst_offset, int len, int count) +{ + struct ps3vram_priv *priv = mtd->priv; + + ps3vram_begin_ring(priv, UPLOAD_SUBCH, + NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); + ps3vram_out_ring(priv, XDR_IOIF + src_offset); + ps3vram_out_ring(priv, dst_offset); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, count); + ps3vram_out_ring(priv, (1 << 8) | 1); + ps3vram_out_ring(priv, 0); + + ps3vram_notifier_reset(mtd); + ps3vram_begin_ring(priv, UPLOAD_SUBCH, + NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); + ps3vram_out_ring(priv, 0); + ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1); + ps3vram_out_ring(priv, 0); + ps3vram_fire_ring(mtd); + if (ps3vram_notifier_wait(mtd, 200) < 0) { + dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__, + __LINE__); + return -1; + } + + return 0; +} + +static int ps3vram_download(struct mtd_info *mtd, unsigned int src_offset, + unsigned int dst_offset, int len, int count) +{ + struct ps3vram_priv *priv = mtd->priv; + + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, + NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); + ps3vram_out_ring(priv, src_offset); + ps3vram_out_ring(priv, XDR_IOIF + dst_offset); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, len); + ps3vram_out_ring(priv, count); + ps3vram_out_ring(priv, (1 << 8) | 1); + ps3vram_out_ring(priv, 0); + + ps3vram_notifier_reset(mtd); + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, + NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1); + ps3vram_out_ring(priv, 0); + ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1); + ps3vram_out_ring(priv, 0); + ps3vram_fire_ring(mtd); + if (ps3vram_notifier_wait(mtd, 200) < 0) { + dev_dbg(priv->dev, "%s:%d: notifier timeout\n", __func__, + __LINE__); + return -1; + } + + return 0; +} + +static void ps3vram_cache_evict(struct mtd_info *mtd, int entry) +{ + struct ps3vram_priv *priv = mtd->priv; + struct ps3vram_cache *cache = &priv->cache; + + if (cache->tags[entry].flags & CACHE_PAGE_DIRTY) { + dev_dbg(priv->dev, "%s:%d: flushing %d : 0x%08x\n", __func__, + __LINE__, entry, cache->tags[entry].address); + if (ps3vram_upload(mtd, + CACHE_OFFSET + entry * cache->page_size, + cache->tags[entry].address, + DMA_PAGE_SIZE, + cache->page_size / DMA_PAGE_SIZE) < 0) { + dev_dbg(priv->dev, "%s:%d: failed to upload from " + "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, + entry * cache->page_size, + cache->tags[entry].address, cache->page_size); + } + cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY; + } +} + +static void ps3vram_cache_load(struct mtd_info *mtd, int entry, + unsigned int address) +{ + struct ps3vram_priv *priv = mtd->priv; + struct ps3vram_cache *cache = &priv->cache; + + dev_dbg(priv->dev, "%s:%d: fetching %d : 0x%08x\n", __func__, __LINE__, + entry, address); + if (ps3vram_download(mtd, + address, + CACHE_OFFSET + entry * cache->page_size, + DMA_PAGE_SIZE, + cache->page_size / DMA_PAGE_SIZE) < 0) { + dev_err(priv->dev, "%s:%d: failed to download from " + "0x%x to 0x%x size 0x%x\n", __func__, __LINE__, address, + entry * cache->page_size, cache->page_size); + } + + cache->tags[entry].address = address; + cache->tags[entry].flags |= CACHE_PAGE_PRESENT; +} + + +static void ps3vram_cache_flush(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + struct ps3vram_cache *cache = &priv->cache; + int i; + + dev_dbg(priv->dev, "%s:%d: FLUSH\n", __func__, __LINE__); + for (i = 0; i < cache->page_count; i++) { + ps3vram_cache_evict(mtd, i); + cache->tags[i].flags = 0; + } +} + +static unsigned int ps3vram_cache_match(struct mtd_info *mtd, loff_t address) +{ + struct ps3vram_priv *priv = mtd->priv; + struct ps3vram_cache *cache = &priv->cache; + unsigned int base; + unsigned int offset; + int i; + static int counter; + + offset = (unsigned int) (address & (cache->page_size - 1)); + base = (unsigned int) (address - offset); + + /* fully associative check */ + for (i = 0; i < cache->page_count; i++) { + if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) && + cache->tags[i].address == base) { + dev_dbg(priv->dev, "%s:%d: found entry %d : 0x%08x\n", + __func__, __LINE__, i, cache->tags[i].address); + return i; + } + } + + /* choose a random entry */ + i = (jiffies + (counter++)) % cache->page_count; + dev_dbg(priv->dev, "%s:%d: using entry %d\n", __func__, __LINE__, i); + + ps3vram_cache_evict(mtd, i); + ps3vram_cache_load(mtd, i, base); + + return i; +} + +static int ps3vram_cache_init(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + + priv->cache.page_count = CACHE_PAGE_COUNT; + priv->cache.page_size = CACHE_PAGE_SIZE; + priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) * + CACHE_PAGE_COUNT, GFP_KERNEL); + if (priv->cache.tags == NULL) { + dev_err(priv->dev, "%s:%d: could not allocate cache tags\n", + __func__, __LINE__); + return -ENOMEM; + } + + dev_info(priv->dev, "created ram cache: %d entries, %d KiB each\n", + CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024); + + return 0; +} + +static void ps3vram_cache_cleanup(struct mtd_info *mtd) +{ + struct ps3vram_priv *priv = mtd->priv; + + ps3vram_cache_flush(mtd); + kfree(priv->cache.tags); +} + +static int ps3vram_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct ps3vram_priv *priv = mtd->priv; + + if (instr->addr + instr->len > mtd->size) + return -EINVAL; + + mutex_lock(&priv->lock); + + ps3vram_cache_flush(mtd); + + /* Set bytes to 0xFF */ + memset_io(priv->ddr_base + instr->addr, 0xFF, instr->len); + + mutex_unlock(&priv->lock); + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +static int ps3vram_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct ps3vram_priv *priv = mtd->priv; + unsigned int cached, count; + + dev_dbg(priv->dev, "%s:%d: from=0x%08x len=0x%zx\n", __func__, __LINE__, + (unsigned int)from, len); + + if (from >= mtd->size) + return -EINVAL; + + if (len > mtd->size - from) + len = mtd->size - from; + + /* Copy from vram to buf */ + count = len; + while (count) { + unsigned int offset, avail; + unsigned int entry; + + offset = (unsigned int) (from & (priv->cache.page_size - 1)); + avail = priv->cache.page_size - offset; + + mutex_lock(&priv->lock); + + entry = ps3vram_cache_match(mtd, from); + cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; + + dev_dbg(priv->dev, "%s:%d: from=%08x cached=%08x offset=%08x " + "avail=%08x count=%08x\n", __func__, __LINE__, + (unsigned int)from, cached, offset, avail, count); + + if (avail > count) + avail = count; + memcpy(buf, priv->xdr_buf + cached, avail); + + mutex_unlock(&priv->lock); + + buf += avail; + count -= avail; + from += avail; + } + + *retlen = len; + return 0; +} + +static int ps3vram_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct ps3vram_priv *priv = mtd->priv; + unsigned int cached, count; + + if (to >= mtd->size) + return -EINVAL; + + if (len > mtd->size - to) + len = mtd->size - to; + + /* Copy from buf to vram */ + count = len; + while (count) { + unsigned int offset, avail; + unsigned int entry; + + offset = (unsigned int) (to & (priv->cache.page_size - 1)); + avail = priv->cache.page_size - offset; + + mutex_lock(&priv->lock); + + entry = ps3vram_cache_match(mtd, to); + cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; + + dev_dbg(priv->dev, "%s:%d: to=%08x cached=%08x offset=%08x " + "avail=%08x count=%08x\n", __func__, __LINE__, + (unsigned int)to, cached, offset, avail, count); + + if (avail > count) + avail = count; + memcpy(priv->xdr_buf + cached, buf, avail); + + priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; + + mutex_unlock(&priv->lock); + + buf += avail; + count -= avail; + to += avail; + } + + *retlen = len; + return 0; +} + +static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) +{ + struct ps3vram_priv *priv; + int status; + u64 ddr_lpar; + u64 ctrl_lpar; + u64 info_lpar; + u64 reports_lpar; + u64 ddr_size; + u64 reports_size; + int ret = -ENOMEM; + char *rest; + + ret = -EIO; + ps3vram_mtd.priv = kzalloc(sizeof(struct ps3vram_priv), GFP_KERNEL); + if (!ps3vram_mtd.priv) + goto out; + priv = ps3vram_mtd.priv; + + mutex_init(&priv->lock); + priv->dev = &dev->core; + + /* Allocate XDR buffer (1MiB aligned) */ + priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, + get_order(XDR_BUF_SIZE)); + if (priv->xdr_buf == NULL) { + dev_dbg(&dev->core, "%s:%d: could not allocate XDR buffer\n", + __func__, __LINE__); + ret = -ENOMEM; + goto out_free_priv; + } + + /* Put FIFO at begginning of XDR buffer */ + priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET); + priv->fifo_ptr = priv->fifo_base; + + /* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */ + if (ps3_open_hv_device(dev)) { + dev_err(&dev->core, "%s:%d: ps3_open_hv_device failed\n", + __func__, __LINE__); + ret = -EAGAIN; + goto out_close_gpu; + } + + /* Request memory */ + status = -1; + ddr_size = memparse(size, &rest); + if (*rest == '-') + ddr_size -= ps3fb_videomemory.size; + ddr_size = ALIGN(ddr_size, 1024*1024); + if (ddr_size <= 0) { + dev_err(&dev->core, "%s:%d: specified size is too small\n", + __func__, __LINE__); + ret = -EINVAL; + goto out_close_gpu; + } + + while (ddr_size > 0) { + status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0, + &priv->memory_handle, + &ddr_lpar); + if (!status) + break; + ddr_size -= 1024*1024; + } + if (status || ddr_size <= 0) { + dev_err(&dev->core, "%s:%d: lv1_gpu_memory_allocate failed\n", + __func__, __LINE__); + ret = -ENOMEM; + goto out_free_xdr_buf; + } + + /* Request context */ + status = lv1_gpu_context_allocate(priv->memory_handle, + 0, + &priv->context_handle, + &ctrl_lpar, + &info_lpar, + &reports_lpar, + &reports_size); + if (status) { + dev_err(&dev->core, "%s:%d: lv1_gpu_context_allocate failed\n", + __func__, __LINE__); + ret = -ENOMEM; + goto out_free_memory; + } + + /* Map XDR buffer to RSX */ + status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, + ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), + XDR_BUF_SIZE, 0); + if (status) { + dev_err(&dev->core, "%s:%d: lv1_gpu_context_iomap failed\n", + __func__, __LINE__); + ret = -ENOMEM; + goto out_free_context; + } + + priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); + + if (!priv->ddr_base) { + dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + ret = -ENOMEM; + goto out_free_context; + } + + priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); + if (!priv->ctrl) { + dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + ret = -ENOMEM; + goto out_unmap_vram; + } + + priv->reports = ioremap(reports_lpar, reports_size); + if (!priv->reports) { + dev_err(&dev->core, "%s:%d: ioremap failed\n", __func__, + __LINE__); + ret = -ENOMEM; + goto out_unmap_ctrl; + } + + mutex_lock(&ps3_gpu_mutex); + ps3vram_init_ring(&ps3vram_mtd); + mutex_unlock(&ps3_gpu_mutex); + + ps3vram_mtd.name = "ps3vram"; + ps3vram_mtd.size = ddr_size; + ps3vram_mtd.flags = MTD_CAP_RAM; + ps3vram_mtd.erase = ps3vram_erase; + ps3vram_mtd.point = NULL; + ps3vram_mtd.unpoint = NULL; + ps3vram_mtd.read = ps3vram_read; + ps3vram_mtd.write = ps3vram_write; + ps3vram_mtd.owner = THIS_MODULE; + ps3vram_mtd.type = MTD_RAM; + ps3vram_mtd.erasesize = CACHE_PAGE_SIZE; + ps3vram_mtd.writesize = 1; + + ps3vram_bind(&ps3vram_mtd); + + mutex_lock(&ps3_gpu_mutex); + ret = ps3vram_wait_ring(&ps3vram_mtd, 100); + mutex_unlock(&ps3_gpu_mutex); + if (ret < 0) { + dev_err(&dev->core, "%s:%d: failed to initialize channels\n", + __func__, __LINE__); + ret = -ETIMEDOUT; + goto out_unmap_reports; + } + + ps3vram_cache_init(&ps3vram_mtd); + + if (add_mtd_device(&ps3vram_mtd)) { + dev_err(&dev->core, "%s:%d: add_mtd_device failed\n", + __func__, __LINE__); + ret = -EAGAIN; + goto out_cache_cleanup; + } + + dev_info(&dev->core, "reserved %u MiB of gpu memory\n", + (unsigned int)(ddr_size / 1024 / 1024)); + + return 0; + +out_cache_cleanup: + ps3vram_cache_cleanup(&ps3vram_mtd); +out_unmap_reports: + iounmap(priv->reports); +out_unmap_ctrl: + iounmap(priv->ctrl); +out_unmap_vram: + iounmap(priv->ddr_base); +out_free_context: + lv1_gpu_context_free(priv->context_handle); +out_free_memory: + lv1_gpu_memory_free(priv->memory_handle); +out_close_gpu: + ps3_close_hv_device(dev); +out_free_xdr_buf: + free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); +out_free_priv: + kfree(ps3vram_mtd.priv); + ps3vram_mtd.priv = NULL; +out: + return ret; +} + +static int ps3vram_shutdown(struct ps3_system_bus_device *dev) +{ + struct ps3vram_priv *priv; + + priv = ps3vram_mtd.priv; + + del_mtd_device(&ps3vram_mtd); + ps3vram_cache_cleanup(&ps3vram_mtd); + iounmap(priv->reports); + iounmap(priv->ctrl); + iounmap(priv->ddr_base); + lv1_gpu_context_free(priv->context_handle); + lv1_gpu_memory_free(priv->memory_handle); + ps3_close_hv_device(dev); + free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); + kfree(priv); + return 0; +} + +static struct ps3_system_bus_driver ps3vram_driver = { + .match_id = PS3_MATCH_ID_GPU, + .match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK, + .core.name = DEVICE_NAME, + .core.owner = THIS_MODULE, + .probe = ps3vram_probe, + .remove = ps3vram_shutdown, + .shutdown = ps3vram_shutdown, +}; + +static int __init ps3vram_init(void) +{ + return ps3_system_bus_driver_register(&ps3vram_driver); +} + +static void __exit ps3vram_exit(void) +{ + ps3_system_bus_driver_unregister(&ps3vram_driver); +} + +module_init(ps3vram_init); +module_exit(ps3vram_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jim Paris <jim@jtan.com>"); +MODULE_DESCRIPTION("MTD driver for PS3 video RAM"); +MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK); diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 9bf581c4f74..a790c062af1 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -109,25 +109,25 @@ module_param(shuffle_freq, int, 0); /* Each memory region corresponds to a minor device */ typedef struct partition_t { struct mtd_blktrans_dev mbd; - u_int32_t state; - u_int32_t *VirtualBlockMap; - u_int32_t *VirtualPageMap; - u_int32_t FreeTotal; + uint32_t state; + uint32_t *VirtualBlockMap; + uint32_t *VirtualPageMap; + uint32_t FreeTotal; struct eun_info_t { - u_int32_t Offset; - u_int32_t EraseCount; - u_int32_t Free; - u_int32_t Deleted; + uint32_t Offset; + uint32_t EraseCount; + uint32_t Free; + uint32_t Deleted; } *EUNInfo; struct xfer_info_t { - u_int32_t Offset; - u_int32_t EraseCount; - u_int16_t state; + uint32_t Offset; + uint32_t EraseCount; + uint16_t state; } *XferInfo; - u_int16_t bam_index; - u_int32_t *bam_cache; - u_int16_t DataUnits; - u_int32_t BlocksPerUnit; + uint16_t bam_index; + uint32_t *bam_cache; + uint16_t DataUnits; + uint32_t BlocksPerUnit; erase_unit_header_t header; } partition_t; @@ -199,8 +199,8 @@ static int scan_header(partition_t *part) static int build_maps(partition_t *part) { erase_unit_header_t header; - u_int16_t xvalid, xtrans, i; - u_int blocks, j; + uint16_t xvalid, xtrans, i; + unsigned blocks, j; int hdr_ok, ret = -1; ssize_t retval; loff_t offset; @@ -269,14 +269,14 @@ static int build_maps(partition_t *part) /* Set up virtual page map */ blocks = le32_to_cpu(header.FormattedSize) >> header.BlockSize; - part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int32_t)); + part->VirtualBlockMap = vmalloc(blocks * sizeof(uint32_t)); if (!part->VirtualBlockMap) goto out_XferInfo; - memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int32_t)); + memset(part->VirtualBlockMap, 0xff, blocks * sizeof(uint32_t)); part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize; - part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int32_t), + part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(uint32_t), GFP_KERNEL); if (!part->bam_cache) goto out_VirtualBlockMap; @@ -290,7 +290,7 @@ static int build_maps(partition_t *part) offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), &retval, + part->BlocksPerUnit * sizeof(uint32_t), &retval, (unsigned char *)part->bam_cache); if (ret) @@ -332,7 +332,7 @@ out: ======================================================================*/ static int erase_xfer(partition_t *part, - u_int16_t xfernum) + uint16_t xfernum) { int ret; struct xfer_info_t *xfer; @@ -408,7 +408,7 @@ static int prepare_xfer(partition_t *part, int i) erase_unit_header_t header; struct xfer_info_t *xfer; int nbam, ret; - u_int32_t ctl; + uint32_t ctl; ssize_t retlen; loff_t offset; @@ -430,15 +430,15 @@ static int prepare_xfer(partition_t *part, int i) } /* Write the BAM stub */ - nbam = (part->BlocksPerUnit * sizeof(u_int32_t) + + nbam = (part->BlocksPerUnit * sizeof(uint32_t) + le32_to_cpu(part->header.BAMOffset) + SECTOR_SIZE - 1) / SECTOR_SIZE; offset = xfer->Offset + le32_to_cpu(part->header.BAMOffset); ctl = cpu_to_le32(BLOCK_CONTROL); - for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { + for (i = 0; i < nbam; i++, offset += sizeof(uint32_t)) { - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&ctl); if (ret) @@ -461,18 +461,18 @@ static int prepare_xfer(partition_t *part, int i) ======================================================================*/ -static int copy_erase_unit(partition_t *part, u_int16_t srcunit, - u_int16_t xferunit) +static int copy_erase_unit(partition_t *part, uint16_t srcunit, + uint16_t xferunit) { u_char buf[SECTOR_SIZE]; struct eun_info_t *eun; struct xfer_info_t *xfer; - u_int32_t src, dest, free, i; - u_int16_t unit; + uint32_t src, dest, free, i; + uint16_t unit; int ret; ssize_t retlen; loff_t offset; - u_int16_t srcunitswap = cpu_to_le16(srcunit); + uint16_t srcunitswap = cpu_to_le16(srcunit); eun = &part->EUNInfo[srcunit]; xfer = &part->XferInfo[xferunit]; @@ -486,7 +486,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), + part->BlocksPerUnit * sizeof(uint32_t), &retlen, (u_char *) (part->bam_cache)); /* mark the cache bad, in case we get an error later */ @@ -503,7 +503,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, offset = xfer->Offset + 20; /* Bad! */ unit = cpu_to_le16(0x7fff); - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint16_t), &retlen, (u_char *) &unit); if (ret) { @@ -560,7 +560,7 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, /* All clear? Then update the LogicalEUN again */ - ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(uint16_t), &retlen, (u_char *)&srcunitswap); if (ret) { @@ -605,8 +605,8 @@ static int copy_erase_unit(partition_t *part, u_int16_t srcunit, static int reclaim_block(partition_t *part) { - u_int16_t i, eun, xfer; - u_int32_t best; + uint16_t i, eun, xfer; + uint32_t best; int queued, ret; DEBUG(0, "ftl_cs: reclaiming space...\n"); @@ -723,10 +723,10 @@ static void dump_lists(partition_t *part) } #endif -static u_int32_t find_free(partition_t *part) +static uint32_t find_free(partition_t *part) { - u_int16_t stop, eun; - u_int32_t blk; + uint16_t stop, eun; + uint32_t blk; size_t retlen; int ret; @@ -749,7 +749,7 @@ static u_int32_t find_free(partition_t *part) ret = part->mbd.mtd->read(part->mbd.mtd, part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), - part->BlocksPerUnit * sizeof(u_int32_t), + part->BlocksPerUnit * sizeof(uint32_t), &retlen, (u_char *) (part->bam_cache)); if (ret) { @@ -786,7 +786,7 @@ static u_int32_t find_free(partition_t *part) static int ftl_read(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks) { - u_int32_t log_addr, bsize; + uint32_t log_addr, bsize; u_long i; int ret; size_t offset, retlen; @@ -829,14 +829,14 @@ static int ftl_read(partition_t *part, caddr_t buffer, ======================================================================*/ -static int set_bam_entry(partition_t *part, u_int32_t log_addr, - u_int32_t virt_addr) +static int set_bam_entry(partition_t *part, uint32_t log_addr, + uint32_t virt_addr) { - u_int32_t bsize, blk, le_virt_addr; + uint32_t bsize, blk, le_virt_addr; #ifdef PSYCHO_DEBUG - u_int32_t old_addr; + uint32_t old_addr; #endif - u_int16_t eun; + uint16_t eun; int ret; size_t retlen, offset; @@ -845,11 +845,11 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, bsize = 1 << part->header.EraseUnitSize; eun = log_addr / bsize; blk = (log_addr % bsize) / SECTOR_SIZE; - offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int32_t) + + offset = (part->EUNInfo[eun].Offset + blk * sizeof(uint32_t) + le32_to_cpu(part->header.BAMOffset)); #ifdef PSYCHO_DEBUG - ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&old_addr); if (ret) { printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); @@ -886,7 +886,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, #endif part->bam_cache[blk] = le_virt_addr; } - ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(uint32_t), &retlen, (u_char *)&le_virt_addr); if (ret) { @@ -900,7 +900,7 @@ static int set_bam_entry(partition_t *part, u_int32_t log_addr, static int ftl_write(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks) { - u_int32_t bsize, log_addr, virt_addr, old_addr, blk; + uint32_t bsize, log_addr, virt_addr, old_addr, blk; u_long i; int ret; size_t retlen, offset; diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index 50ce13887f6..73f05227dc8 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -50,7 +50,7 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct INFTLrecord *inftl; unsigned long temp; - if (mtd->type != MTD_NANDFLASH) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 9113628ed1e..f751dd97c54 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -63,7 +63,7 @@ static int find_boot_record(struct INFTLrecord *inftl) * otherwise. */ inftl->EraseSize = inftl->mbd.mtd->erasesize; - inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; inftl->MediaUnit = BLOCK_NIL; @@ -187,7 +187,7 @@ static int find_boot_record(struct INFTLrecord *inftl) mh->BlockMultiplierBits); inftl->EraseSize = inftl->mbd.mtd->erasesize << mh->BlockMultiplierBits; - inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + inftl->nb_blocks = (u32)inftl->mbd.mtd->size / inftl->EraseSize; block >>= mh->BlockMultiplierBits; } diff --git a/drivers/mtd/lpddr/Kconfig b/drivers/mtd/lpddr/Kconfig new file mode 100644 index 00000000000..acd4ea9b227 --- /dev/null +++ b/drivers/mtd/lpddr/Kconfig @@ -0,0 +1,22 @@ +# drivers/mtd/chips/Kconfig + +menu "LPDDR flash memory drivers" + depends on MTD!=n + +config MTD_LPDDR + tristate "Support for LPDDR flash chips" + select MTD_QINFO_PROBE + help + This option enables support of LPDDR (Low power double data rate) + flash chips. Synonymous with Mobile-DDR. It is a new standard for + DDR memories, intended for battery-operated systems. + +config MTD_QINFO_PROBE + tristate "Detect flash chips by QINFO probe" + help + Device Information for LPDDR chips is offered through the Overlay + Window QINFO interface, permits software to be used for entire + families of devices. This serves similar purpose of CFI on legacy + Flash products +endmenu + diff --git a/drivers/mtd/lpddr/Makefile b/drivers/mtd/lpddr/Makefile new file mode 100644 index 00000000000..da48e46b581 --- /dev/null +++ b/drivers/mtd/lpddr/Makefile @@ -0,0 +1,6 @@ +# +# linux/drivers/mtd/lpddr/Makefile +# + +obj-$(CONFIG_MTD_QINFO_PROBE) += qinfo_probe.o +obj-$(CONFIG_MTD_LPDDR) += lpddr_cmds.o diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c new file mode 100644 index 00000000000..e22ca49583e --- /dev/null +++ b/drivers/mtd/lpddr/lpddr_cmds.c @@ -0,0 +1,796 @@ +/* + * LPDDR flash memory device operations. This module provides read, write, + * erase, lock/unlock support for LPDDR flash memories + * (C) 2008 Korolev Alexey <akorolev@infradead.org> + * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com> + * Many thanks to Roman Borisov for intial enabling + * + * 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. + * TODO: + * Implement VPP management + * Implement XIP support + * Implement OTP support + */ +#include <linux/mtd/pfow.h> +#include <linux/mtd/qinfo.h> + +static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, u_char *buf); +static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, const u_char *buf); +static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen); +static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr); +static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, void **mtdbuf, resource_size_t *phys); +static void lpddr_unpoint(struct mtd_info *mtd, loff_t adr, size_t len); +static int get_chip(struct map_info *map, struct flchip *chip, int mode); +static int chip_ready(struct map_info *map, struct flchip *chip, int mode); +static void put_chip(struct map_info *map, struct flchip *chip); + +struct mtd_info *lpddr_cmdset(struct map_info *map) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + struct flchip_shared *shared; + struct flchip *chip; + struct mtd_info *mtd; + int numchips; + int i, j; + + mtd = kzalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) { + printk(KERN_ERR "Failed to allocate memory for MTD device\n"); + return NULL; + } + mtd->priv = map; + mtd->type = MTD_NORFLASH; + + /* Fill in the default mtd operations */ + mtd->read = lpddr_read; + mtd->type = MTD_NORFLASH; + mtd->flags = MTD_CAP_NORFLASH; + mtd->flags &= ~MTD_BIT_WRITEABLE; + mtd->erase = lpddr_erase; + mtd->write = lpddr_write_buffers; + mtd->writev = lpddr_writev; + mtd->read_oob = NULL; + mtd->write_oob = NULL; + mtd->sync = NULL; + mtd->lock = lpddr_lock; + mtd->unlock = lpddr_unlock; + mtd->suspend = NULL; + mtd->resume = NULL; + if (map_is_linear(map)) { + mtd->point = lpddr_point; + mtd->unpoint = lpddr_unpoint; + } + mtd->block_isbad = NULL; + mtd->block_markbad = NULL; + mtd->size = 1 << lpddr->qinfo->DevSizeShift; + mtd->erasesize = 1 << lpddr->qinfo->UniformBlockSizeShift; + mtd->writesize = 1 << lpddr->qinfo->BufSizeShift; + + shared = kmalloc(sizeof(struct flchip_shared) * lpddr->numchips, + GFP_KERNEL); + if (!shared) { + kfree(lpddr); + kfree(mtd); + return NULL; + } + + chip = &lpddr->chips[0]; + numchips = lpddr->numchips / lpddr->qinfo->HWPartsNum; + for (i = 0; i < numchips; i++) { + shared[i].writing = shared[i].erasing = NULL; + spin_lock_init(&shared[i].lock); + for (j = 0; j < lpddr->qinfo->HWPartsNum; j++) { + *chip = lpddr->chips[i]; + chip->start += j << lpddr->chipshift; + chip->oldstate = chip->state = FL_READY; + chip->priv = &shared[i]; + /* those should be reset too since + they create memory references. */ + init_waitqueue_head(&chip->wq); + spin_lock_init(&chip->_spinlock); + chip->mutex = &chip->_spinlock; + chip++; + } + } + + return mtd; +} +EXPORT_SYMBOL(lpddr_cmdset); + +static int wait_for_ready(struct map_info *map, struct flchip *chip, + unsigned int chip_op_time) +{ + unsigned int timeo, reset_timeo, sleep_time; + unsigned int dsr; + flstate_t chip_state = chip->state; + int ret = 0; + + /* set our timeout to 8 times the expected delay */ + timeo = chip_op_time * 8; + if (!timeo) + timeo = 500000; + reset_timeo = timeo; + sleep_time = chip_op_time / 2; + + for (;;) { + dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); + if (dsr & DSR_READY_STATUS) + break; + if (!timeo) { + printk(KERN_ERR "%s: Flash timeout error state %d \n", + map->name, chip_state); + ret = -ETIME; + break; + } + + /* OK Still waiting. Drop the lock, wait a while and retry. */ + spin_unlock(chip->mutex); + if (sleep_time >= 1000000/HZ) { + /* + * Half of the normal delay still remaining + * can be performed with a sleeping delay instead + * of busy waiting. + */ + msleep(sleep_time/1000); + timeo -= sleep_time; + sleep_time = 1000000/HZ; + } else { + udelay(1); + cond_resched(); + timeo--; + } + spin_lock(chip->mutex); + + while (chip->state != chip_state) { + /* Someone's suspended the operation: sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + } + if (chip->erase_suspended || chip->write_suspended) { + /* Suspend has occured while sleep: reset timeout */ + timeo = reset_timeo; + chip->erase_suspended = chip->write_suspended = 0; + } + } + /* check status for errors */ + if (dsr & DSR_ERR) { + /* Clear DSR*/ + map_write(map, CMD(~(DSR_ERR)), map->pfow_base + PFOW_DSR); + printk(KERN_WARNING"%s: Bad status on wait: 0x%x \n", + map->name, dsr); + print_drs_error(dsr); + ret = -EIO; + } + chip->state = FL_READY; + return ret; +} + +static int get_chip(struct map_info *map, struct flchip *chip, int mode) +{ + int ret; + DECLARE_WAITQUEUE(wait, current); + + retry: + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING) + && chip->state != FL_SYNCING) { + /* + * OK. We have possibility for contension on the write/erase + * operations which are global to the real chip and not per + * partition. So let's fight it over in the partition which + * currently has authority on the operation. + * + * The rules are as follows: + * + * - any write operation must own shared->writing. + * + * - any erase operation must own _both_ shared->writing and + * shared->erasing. + * + * - contension arbitration is handled in the owner's context. + * + * The 'shared' struct can be read and/or written only when + * its lock is taken. + */ + struct flchip_shared *shared = chip->priv; + struct flchip *contender; + spin_lock(&shared->lock); + contender = shared->writing; + if (contender && contender != chip) { + /* + * The engine to perform desired operation on this + * partition is already in use by someone else. + * Let's fight over it in the context of the chip + * currently using it. If it is possible to suspend, + * that other partition will do just that, otherwise + * it'll happily send us to sleep. In any case, when + * get_chip returns success we're clear to go ahead. + */ + ret = spin_trylock(contender->mutex); + spin_unlock(&shared->lock); + if (!ret) + goto retry; + spin_unlock(chip->mutex); + ret = chip_ready(map, contender, mode); + spin_lock(chip->mutex); + + if (ret == -EAGAIN) { + spin_unlock(contender->mutex); + goto retry; + } + if (ret) { + spin_unlock(contender->mutex); + return ret; + } + spin_lock(&shared->lock); + + /* We should not own chip if it is already in FL_SYNCING + * state. Put contender and retry. */ + if (chip->state == FL_SYNCING) { + put_chip(map, contender); + spin_unlock(contender->mutex); + goto retry; + } + spin_unlock(contender->mutex); + } + + /* Check if we have suspended erase on this chip. + Must sleep in such a case. */ + if (mode == FL_ERASING && shared->erasing + && shared->erasing->oldstate == FL_ERASING) { + spin_unlock(&shared->lock); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + goto retry; + } + + /* We now own it */ + shared->writing = chip; + if (mode == FL_ERASING) + shared->erasing = chip; + spin_unlock(&shared->lock); + } + + ret = chip_ready(map, chip, mode); + if (ret == -EAGAIN) + goto retry; + + return ret; +} + +static int chip_ready(struct map_info *map, struct flchip *chip, int mode) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + int ret = 0; + DECLARE_WAITQUEUE(wait, current); + + /* Prevent setting state FL_SYNCING for chip in suspended state. */ + if (FL_SYNCING == mode && FL_READY != chip->oldstate) + goto sleep; + + switch (chip->state) { + case FL_READY: + case FL_JEDEC_QUERY: + return 0; + + case FL_ERASING: + if (!lpddr->qinfo->SuspEraseSupp || + !(mode == FL_READY || mode == FL_POINT)) + goto sleep; + + map_write(map, CMD(LPDDR_SUSPEND), + map->pfow_base + PFOW_PROGRAM_ERASE_SUSPEND); + chip->oldstate = FL_ERASING; + chip->state = FL_ERASE_SUSPENDING; + ret = wait_for_ready(map, chip, 0); + if (ret) { + /* Oops. something got wrong. */ + /* Resume and pretend we weren't here. */ + map_write(map, CMD(LPDDR_RESUME), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + chip->state = FL_ERASING; + chip->oldstate = FL_READY; + printk(KERN_ERR "%s: suspend operation failed." + "State may be wrong \n", map->name); + return -EIO; + } + chip->erase_suspended = 1; + chip->state = FL_READY; + return 0; + /* Erase suspend */ + case FL_POINT: + /* Only if there's no operation suspended... */ + if (mode == FL_READY && chip->oldstate == FL_READY) + return 0; + + default: +sleep: + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + return -EAGAIN; + } +} + +static void put_chip(struct map_info *map, struct flchip *chip) +{ + if (chip->priv) { + struct flchip_shared *shared = chip->priv; + spin_lock(&shared->lock); + if (shared->writing == chip && chip->oldstate == FL_READY) { + /* We own the ability to write, but we're done */ + shared->writing = shared->erasing; + if (shared->writing && shared->writing != chip) { + /* give back the ownership */ + struct flchip *loaner = shared->writing; + spin_lock(loaner->mutex); + spin_unlock(&shared->lock); + spin_unlock(chip->mutex); + put_chip(map, loaner); + spin_lock(chip->mutex); + spin_unlock(loaner->mutex); + wake_up(&chip->wq); + return; + } + shared->erasing = NULL; + shared->writing = NULL; + } else if (shared->erasing == chip && shared->writing != chip) { + /* + * We own the ability to erase without the ability + * to write, which means the erase was suspended + * and some other partition is currently writing. + * Don't let the switch below mess things up since + * we don't have ownership to resume anything. + */ + spin_unlock(&shared->lock); + wake_up(&chip->wq); + return; + } + spin_unlock(&shared->lock); + } + + switch (chip->oldstate) { + case FL_ERASING: + chip->state = chip->oldstate; + map_write(map, CMD(LPDDR_RESUME), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + chip->oldstate = FL_READY; + chip->state = FL_ERASING; + break; + case FL_READY: + break; + default: + printk(KERN_ERR "%s: put_chip() called with oldstate %d!\n", + map->name, chip->oldstate); + } + wake_up(&chip->wq); +} + +int do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const struct kvec **pvec, + unsigned long *pvec_seek, int len) +{ + struct lpddr_private *lpddr = map->fldrv_priv; + map_word datum; + int ret, wbufsize, word_gap, words; + const struct kvec *vec; + unsigned long vec_seek; + unsigned long prog_buf_ofs; + + wbufsize = 1 << lpddr->qinfo->BufSizeShift; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + /* Figure out the number of words to write */ + word_gap = (-adr & (map_bankwidth(map)-1)); + words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map); + if (!word_gap) { + words--; + } else { + word_gap = map_bankwidth(map) - word_gap; + adr -= word_gap; + datum = map_word_ff(map); + } + /* Write data */ + /* Get the program buffer offset from PFOW register data first*/ + prog_buf_ofs = map->pfow_base + CMDVAL(map_read(map, + map->pfow_base + PFOW_PROGRAM_BUFFER_OFFSET)); + vec = *pvec; + vec_seek = *pvec_seek; + do { + int n = map_bankwidth(map) - word_gap; + + if (n > vec->iov_len - vec_seek) + n = vec->iov_len - vec_seek; + if (n > len) + n = len; + + if (!word_gap && (len < map_bankwidth(map))) + datum = map_word_ff(map); + + datum = map_word_load_partial(map, datum, + vec->iov_base + vec_seek, word_gap, n); + + len -= n; + word_gap += n; + if (!len || word_gap == map_bankwidth(map)) { + map_write(map, datum, prog_buf_ofs); + prog_buf_ofs += map_bankwidth(map); + word_gap = 0; + } + + vec_seek += n; + if (vec_seek == vec->iov_len) { + vec++; + vec_seek = 0; + } + } while (len); + *pvec = vec; + *pvec_seek = vec_seek; + + /* GO GO GO */ + send_pfow_command(map, LPDDR_BUFF_PROGRAM, adr, wbufsize, NULL); + chip->state = FL_WRITING; + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->ProgBufferTime)); + if (ret) { + printk(KERN_WARNING"%s Buffer program error: %d at %lx; \n", + map->name, ret, adr); + goto out; + } + + out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +int do_erase_oneblock(struct mtd_info *mtd, loff_t adr) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_ERASING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + send_pfow_command(map, LPDDR_BLOCK_ERASE, adr, 0, NULL); + chip->state = FL_ERASING; + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->BlockEraseTime)*1000); + if (ret) { + printk(KERN_WARNING"%s Erase block error %d at : %llx\n", + map->name, ret, adr); + goto out; + } + out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_read(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, u_char *buf) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret = 0; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_READY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + map_copy_from(map, buf, adr, len); + *retlen = len; + + put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_point(struct mtd_info *mtd, loff_t adr, size_t len, + size_t *retlen, void **mtdbuf, resource_size_t *phys) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + unsigned long ofs, last_end = 0; + struct flchip *chip = &lpddr->chips[chipnum]; + int ret = 0; + + if (!map->virt || (adr + len > mtd->size)) + return -EINVAL; + + /* ofs: offset within the first chip that the first read should start */ + ofs = adr - (chipnum << lpddr->chipshift); + + *mtdbuf = (void *)map->virt + chip->start + ofs; + *retlen = 0; + + while (len) { + unsigned long thislen; + + if (chipnum >= lpddr->numchips) + break; + + /* We cannot point across chips that are virtually disjoint */ + if (!last_end) + last_end = chip->start; + else if (chip->start != last_end) + break; + + if ((len + ofs - 1) >> lpddr->chipshift) + thislen = (1<<lpddr->chipshift) - ofs; + else + thislen = len; + /* get the chip */ + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_POINT); + spin_unlock(chip->mutex); + if (ret) + break; + + chip->state = FL_POINT; + chip->ref_point_counter++; + *retlen += thislen; + len -= thislen; + + ofs = 0; + last_end += 1 << lpddr->chipshift; + chipnum++; + chip = &lpddr->chips[chipnum]; + } + return 0; +} + +static void lpddr_unpoint (struct mtd_info *mtd, loff_t adr, size_t len) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + unsigned long ofs; + + /* ofs: offset within the first chip that the first read should start */ + ofs = adr - (chipnum << lpddr->chipshift); + + while (len) { + unsigned long thislen; + struct flchip *chip; + + chip = &lpddr->chips[chipnum]; + if (chipnum >= lpddr->numchips) + break; + + if ((len + ofs - 1) >> lpddr->chipshift) + thislen = (1<<lpddr->chipshift) - ofs; + else + thislen = len; + + spin_lock(chip->mutex); + if (chip->state == FL_POINT) { + chip->ref_point_counter--; + if (chip->ref_point_counter == 0) + chip->state = FL_READY; + } else + printk(KERN_WARNING "%s: Warning: unpoint called on non" + "pointed region\n", map->name); + + put_chip(map, chip); + spin_unlock(chip->mutex); + + len -= thislen; + ofs = 0; + chipnum++; + } +} + +static int lpddr_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct kvec vec; + + vec.iov_base = (void *) buf; + vec.iov_len = len; + + return lpddr_writev(mtd, &vec, 1, to, retlen); +} + + +static int lpddr_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int ret = 0; + int chipnum; + unsigned long ofs, vec_seek, i; + int wbufsize = 1 << lpddr->qinfo->BufSizeShift; + + size_t len = 0; + + for (i = 0; i < count; i++) + len += vecs[i].iov_len; + + *retlen = 0; + if (!len) + return 0; + + chipnum = to >> lpddr->chipshift; + + ofs = to; + vec_seek = 0; + + do { + /* We must not cross write block boundaries */ + int size = wbufsize - (ofs & (wbufsize-1)); + + if (size > len) + size = len; + + ret = do_write_buffer(map, &lpddr->chips[chipnum], + ofs, &vecs, &vec_seek, size); + if (ret) + return ret; + + ofs += size; + (*retlen) += size; + len -= size; + + /* Be nice and reschedule with the chip in a usable + * state for other processes */ + cond_resched(); + + } while (len); + + return 0; +} + +static int lpddr_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + unsigned long ofs, len; + int ret; + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int size = 1 << lpddr->qinfo->UniformBlockSizeShift; + + ofs = instr->addr; + len = instr->len; + + if (ofs > mtd->size || (len + ofs) > mtd->size) + return -EINVAL; + + while (len > 0) { + ret = do_erase_oneblock(mtd, ofs); + if (ret) + return ret; + ofs += size; + len -= size; + } + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +#define DO_XXLOCK_LOCK 1 +#define DO_XXLOCK_UNLOCK 2 +int do_xxlock(struct mtd_info *mtd, loff_t adr, uint32_t len, int thunk) +{ + int ret = 0; + struct map_info *map = mtd->priv; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_LOCKING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + if (thunk == DO_XXLOCK_LOCK) { + send_pfow_command(map, LPDDR_LOCK_BLOCK, adr, adr + len, NULL); + chip->state = FL_LOCKING; + } else if (thunk == DO_XXLOCK_UNLOCK) { + send_pfow_command(map, LPDDR_UNLOCK_BLOCK, adr, adr + len, NULL); + chip->state = FL_UNLOCKING; + } else + BUG(); + + ret = wait_for_ready(map, chip, 1); + if (ret) { + printk(KERN_ERR "%s: block unlock error status %d \n", + map->name, ret); + goto out; + } +out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +static int lpddr_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + return do_xxlock(mtd, ofs, len, DO_XXLOCK_LOCK); +} + +static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK); +} + +int word_program(struct map_info *map, loff_t adr, uint32_t curval) +{ + int ret; + struct lpddr_private *lpddr = map->fldrv_priv; + int chipnum = adr >> lpddr->chipshift; + struct flchip *chip = &lpddr->chips[chipnum]; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval); + + ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime)); + if (ret) { + printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n", + map->name, adr, curval); + goto out; + } + +out: put_chip(map, chip); + spin_unlock(chip->mutex); + return ret; +} + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>"); +MODULE_DESCRIPTION("MTD driver for LPDDR flash chips"); diff --git a/drivers/mtd/lpddr/qinfo_probe.c b/drivers/mtd/lpddr/qinfo_probe.c new file mode 100644 index 00000000000..79bf40f48b7 --- /dev/null +++ b/drivers/mtd/lpddr/qinfo_probe.c @@ -0,0 +1,255 @@ +/* + * Probing flash chips with QINFO records. + * (C) 2008 Korolev Alexey <akorolev@infradead.org> + * (C) 2008 Vasiliy Leonenko <vasiliy.leonenko@gmail.com> + * + * 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 <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/interrupt.h> + +#include <linux/mtd/xip.h> +#include <linux/mtd/map.h> +#include <linux/mtd/pfow.h> +#include <linux/mtd/qinfo.h> + +static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr); +struct mtd_info *lpddr_probe(struct map_info *map); +static struct lpddr_private *lpddr_probe_chip(struct map_info *map); +static int lpddr_pfow_present(struct map_info *map, + struct lpddr_private *lpddr); + +static struct qinfo_query_info qinfo_array[] = { + /* General device info */ + {0, 0, "DevSizeShift", "Device size 2^n bytes"}, + {0, 3, "BufSizeShift", "Program buffer size 2^n bytes"}, + /* Erase block information */ + {1, 1, "TotalBlocksNum", "Total number of blocks"}, + {1, 2, "UniformBlockSizeShift", "Uniform block size 2^n bytes"}, + /* Partition information */ + {2, 1, "HWPartsNum", "Number of hardware partitions"}, + /* Optional features */ + {5, 1, "SuspEraseSupp", "Suspend erase supported"}, + /* Operation typical time */ + {10, 0, "SingleWordProgTime", "Single word program 2^n u-sec"}, + {10, 1, "ProgBufferTime", "Program buffer write 2^n u-sec"}, + {10, 2, "BlockEraseTime", "Block erase 2^n m-sec"}, + {10, 3, "FullChipEraseTime", "Full chip erase 2^n m-sec"}, +}; + +static long lpddr_get_qinforec_pos(struct map_info *map, char *id_str) +{ + int qinfo_lines = sizeof(qinfo_array)/sizeof(struct qinfo_query_info); + int i; + int bankwidth = map_bankwidth(map) * 8; + int major, minor; + + for (i = 0; i < qinfo_lines; i++) { + if (strcmp(id_str, qinfo_array[i].id_str) == 0) { + major = qinfo_array[i].major & ((1 << bankwidth) - 1); + minor = qinfo_array[i].minor & ((1 << bankwidth) - 1); + return minor | (major << bankwidth); + } + } + printk(KERN_ERR"%s qinfo id string is wrong! \n", map->name); + BUG(); + return -1; +} + +static uint16_t lpddr_info_query(struct map_info *map, char *id_str) +{ + unsigned int dsr, val; + int bits_per_chip = map_bankwidth(map) * 8; + unsigned long adr = lpddr_get_qinforec_pos(map, id_str); + int attempts = 20; + + /* Write a request for the PFOW record */ + map_write(map, CMD(LPDDR_INFO_QUERY), + map->pfow_base + PFOW_COMMAND_CODE); + map_write(map, CMD(adr & ((1 << bits_per_chip) - 1)), + map->pfow_base + PFOW_COMMAND_ADDRESS_L); + map_write(map, CMD(adr >> bits_per_chip), + map->pfow_base + PFOW_COMMAND_ADDRESS_H); + map_write(map, CMD(LPDDR_START_EXECUTION), + map->pfow_base + PFOW_COMMAND_EXECUTE); + + while ((attempts--) > 0) { + dsr = CMDVAL(map_read(map, map->pfow_base + PFOW_DSR)); + if (dsr & DSR_READY_STATUS) + break; + udelay(10); + } + + val = CMDVAL(map_read(map, map->pfow_base + PFOW_COMMAND_DATA)); + return val; +} + +static int lpddr_pfow_present(struct map_info *map, struct lpddr_private *lpddr) +{ + map_word pfow_val[4]; + + /* Check identification string */ + pfow_val[0] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_P); + pfow_val[1] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_F); + pfow_val[2] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_O); + pfow_val[3] = map_read(map, map->pfow_base + PFOW_QUERY_STRING_W); + + if (!map_word_equal(map, CMD('P'), pfow_val[0])) + goto out; + + if (!map_word_equal(map, CMD('F'), pfow_val[1])) + goto out; + + if (!map_word_equal(map, CMD('O'), pfow_val[2])) + goto out; + + if (!map_word_equal(map, CMD('W'), pfow_val[3])) + goto out; + + return 1; /* "PFOW" is found */ +out: + printk(KERN_WARNING"%s: PFOW string at 0x%lx is not found \n", + map->name, map->pfow_base); + return 0; +} + +static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr) +{ + + lpddr->qinfo = kmalloc(sizeof(struct qinfo_chip), GFP_KERNEL); + if (!lpddr->qinfo) { + printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n", + map->name); + return 0; + } + memset(lpddr->qinfo, 0, sizeof(struct qinfo_chip)); + + /* Get the ManuID */ + lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID)); + /* Get the DeviceID */ + lpddr->DevId = CMDVAL(map_read(map, map->pfow_base + PFOW_DEVICE_ID)); + /* read parameters from chip qinfo table */ + lpddr->qinfo->DevSizeShift = lpddr_info_query(map, "DevSizeShift"); + lpddr->qinfo->TotalBlocksNum = lpddr_info_query(map, "TotalBlocksNum"); + lpddr->qinfo->BufSizeShift = lpddr_info_query(map, "BufSizeShift"); + lpddr->qinfo->HWPartsNum = lpddr_info_query(map, "HWPartsNum"); + lpddr->qinfo->UniformBlockSizeShift = + lpddr_info_query(map, "UniformBlockSizeShift"); + lpddr->qinfo->SuspEraseSupp = lpddr_info_query(map, "SuspEraseSupp"); + lpddr->qinfo->SingleWordProgTime = + lpddr_info_query(map, "SingleWordProgTime"); + lpddr->qinfo->ProgBufferTime = lpddr_info_query(map, "ProgBufferTime"); + lpddr->qinfo->BlockEraseTime = lpddr_info_query(map, "BlockEraseTime"); + return 1; +} +static struct lpddr_private *lpddr_probe_chip(struct map_info *map) +{ + struct lpddr_private lpddr; + struct lpddr_private *retlpddr; + int numvirtchips; + + + if ((map->pfow_base + 0x1000) >= map->size) { + printk(KERN_NOTICE"%s Probe at base (0x%08lx) past the end of" + "the map(0x%08lx)\n", map->name, + (unsigned long)map->pfow_base, map->size - 1); + return NULL; + } + memset(&lpddr, 0, sizeof(struct lpddr_private)); + if (!lpddr_pfow_present(map, &lpddr)) + return NULL; + + if (!lpddr_chip_setup(map, &lpddr)) + return NULL; + + /* Ok so we found a chip */ + lpddr.chipshift = lpddr.qinfo->DevSizeShift; + lpddr.numchips = 1; + + numvirtchips = lpddr.numchips * lpddr.qinfo->HWPartsNum; + retlpddr = kmalloc(sizeof(struct lpddr_private) + + numvirtchips * sizeof(struct flchip), GFP_KERNEL); + if (!retlpddr) + return NULL; + + memset(retlpddr, 0, sizeof(struct lpddr_private) + + numvirtchips * sizeof(struct flchip)); + memcpy(retlpddr, &lpddr, sizeof(struct lpddr_private)); + + retlpddr->numchips = numvirtchips; + retlpddr->chipshift = retlpddr->qinfo->DevSizeShift - + __ffs(retlpddr->qinfo->HWPartsNum); + + return retlpddr; +} + +struct mtd_info *lpddr_probe(struct map_info *map) +{ + struct mtd_info *mtd = NULL; + struct lpddr_private *lpddr; + + /* First probe the map to see if we havecan open PFOW here */ + lpddr = lpddr_probe_chip(map); + if (!lpddr) + return NULL; + + map->fldrv_priv = lpddr; + mtd = lpddr_cmdset(map); + if (mtd) { + if (mtd->size > map->size) { + printk(KERN_WARNING "Reducing visibility of %ldKiB chip" + "to %ldKiB\n", (unsigned long)mtd->size >> 10, + (unsigned long)map->size >> 10); + mtd->size = map->size; + } + return mtd; + } + + kfree(lpddr->qinfo); + kfree(lpddr); + map->fldrv_priv = NULL; + return NULL; +} + +static struct mtd_chip_driver lpddr_chipdrv = { + .probe = lpddr_probe, + .name = "qinfo_probe", + .module = THIS_MODULE +}; + +static int __init lpddr_probe_init(void) +{ + register_mtd_chip_driver(&lpddr_chipdrv); + return 0; +} + +static void __exit lpddr_probe_exit(void) +{ + unregister_mtd_chip_driver(&lpddr_chipdrv); +} + +module_init(lpddr_probe_init); +module_exit(lpddr_probe_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vasiliy Leonenko <vasiliy.leonenko@gmail.com>"); +MODULE_DESCRIPTION("Driver to probe qinfo flash chips"); + diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5ea16936216..0225cbbf22d 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -10,8 +10,8 @@ config MTD_COMPLEX_MAPPINGS paged mappings of flash chips. config MTD_PHYSMAP - tristate "CFI Flash device in physical memory map" - depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM + tristate "Flash device in physical memory map" + depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR help This provides a 'mapping' driver which allows the NOR Flash and ROM driver code to communicate with chips which are mapped @@ -23,9 +23,20 @@ config MTD_PHYSMAP To compile this driver as a module, choose M here: the module will be called physmap. +config MTD_PHYSMAP_COMPAT + bool "Physmap compat support" + depends on MTD_PHYSMAP + default n + help + Setup a simple mapping via the Kconfig options. Normally the + physmap configuration options are done via your board's + resource file. + + If unsure, say N here. + config MTD_PHYSMAP_START hex "Physical start address of flash mapping" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "0x8000000" help This is the physical memory location at which the flash chips @@ -37,7 +48,7 @@ config MTD_PHYSMAP_START config MTD_PHYSMAP_LEN hex "Physical length of flash mapping" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "0" help This is the total length of the mapping of the flash chips on @@ -51,7 +62,7 @@ config MTD_PHYSMAP_LEN config MTD_PHYSMAP_BANKWIDTH int "Bank width in octets" - depends on MTD_PHYSMAP + depends on MTD_PHYSMAP_COMPAT default "2" help This is the total width of the data bus of the flash devices diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c index 82811bcb043..845ad4f2a54 100644 --- a/drivers/mtd/maps/alchemy-flash.c +++ b/drivers/mtd/maps/alchemy-flash.c @@ -111,7 +111,7 @@ static struct mtd_partition alchemy_partitions[] = { static struct mtd_info *mymtd; -int __init alchemy_mtd_init(void) +static int __init alchemy_mtd_init(void) { struct mtd_partition *parts; int nb_parts = 0; diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c index d1eec7d3243..237733d094c 100644 --- a/drivers/mtd/maps/amd76xrom.c +++ b/drivers/mtd/maps/amd76xrom.c @@ -232,8 +232,8 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c index 0ecc3f6d735..b4ed8161191 100644 --- a/drivers/mtd/maps/cfi_flagadm.c +++ b/drivers/mtd/maps/cfi_flagadm.c @@ -88,7 +88,7 @@ struct mtd_partition flagadm_parts[] = { static struct mtd_info *mymtd; -int __init init_flagadm(void) +static int __init init_flagadm(void) { printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", FLASH_SIZE, FLASH_PHYS_ADDR); diff --git a/drivers/mtd/maps/ck804xrom.c b/drivers/mtd/maps/ck804xrom.c index 1a6feb4474d..5f7a245ed13 100644 --- a/drivers/mtd/maps/ck804xrom.c +++ b/drivers/mtd/maps/ck804xrom.c @@ -263,8 +263,8 @@ static int __devinit ck804xrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c index e115667bf1d..cfacfa6f45d 100644 --- a/drivers/mtd/maps/dbox2-flash.c +++ b/drivers/mtd/maps/dbox2-flash.c @@ -69,7 +69,7 @@ struct map_info dbox2_flash_map = { .phys = WINDOW_ADDR, }; -int __init init_dbox2_flash(void) +static int __init init_dbox2_flash(void) { printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); dbox2_flash_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c index 9433738c166..be9e90b4458 100644 --- a/drivers/mtd/maps/edb7312.c +++ b/drivers/mtd/maps/edb7312.c @@ -71,7 +71,7 @@ static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int mtd_parts_nb = 0; static struct mtd_partition *mtd_parts = 0; -int __init init_edb7312nor(void) +static int __init init_edb7312nor(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; diff --git a/drivers/mtd/maps/esb2rom.c b/drivers/mtd/maps/esb2rom.c index bbbcdd4c8d1..11a2f57df9c 100644 --- a/drivers/mtd/maps/esb2rom.c +++ b/drivers/mtd/maps/esb2rom.c @@ -324,8 +324,8 @@ static int __devinit esb2rom_init_one(struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c index a8e3fde4cbd..1e43124d498 100644 --- a/drivers/mtd/maps/fortunet.c +++ b/drivers/mtd/maps/fortunet.c @@ -181,7 +181,7 @@ __setup("MTD_Partition=", MTD_New_Partition); /* Backwards-spelling-compatibility */ __setup("MTD_Partion=", MTD_New_Partition); -int __init init_fortunet(void) +static int __init init_fortunet(void) { int ix,iy; for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++) diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 3b959fad1c4..72c724fa8c2 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -65,7 +65,7 @@ static const char *probes[] = { "cmdlinepart", NULL }; /* * Initialize FLASH support */ -int __init h720x_mtd_init(void) +static int __init h720x_mtd_init(void) { char *part_type = NULL; diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index aeb6c916e23..c32bc28920b 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -258,8 +258,8 @@ static int __devinit ichxrom_init_one (struct pci_dev *pdev, /* Trim the size if we are larger than the map */ if (map->mtd->size > map->map.size) { printk(KERN_WARNING MOD_NAME - " rom(%u) larger than window(%lu). fixing...\n", - map->mtd->size, map->map.size); + " rom(%llu) larger than window(%lu). fixing...\n", + (unsigned long long)map->mtd->size, map->map.size); map->mtd->size = map->map.size; } if (window->rsrc.parent) { diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 2682ab51a36..998a27da97f 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -70,7 +70,7 @@ static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; static const char *probes[] = { "cmdlinepart", NULL }; -int __init init_impa7(void) +static int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index ed58f6a77bd..748c85f635f 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c @@ -202,7 +202,7 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __init h1900_special_case(void); -int __init ipaq_mtd_init(void) +static int __init ipaq_mtd_init(void) { struct mtd_partition *parts = NULL; int nb_parts = 0; diff --git a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c index 706f67394b0..0eb5a7c8538 100644 --- a/drivers/mtd/maps/mbx860.c +++ b/drivers/mtd/maps/mbx860.c @@ -55,7 +55,7 @@ struct map_info mbx_map = { .bankwidth = 4, }; -int __init init_mbx(void) +static int __init init_mbx(void) { printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); mbx_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c index 965e6c6d6ab..a97133eb9d7 100644 --- a/drivers/mtd/maps/nettel.c +++ b/drivers/mtd/maps/nettel.c @@ -226,7 +226,7 @@ static int __init nettel_init(void) if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", - amd_mtd->size>>10); + (int)(amd_mtd->size>>10)); amd_mtd->owner = THIS_MODULE; @@ -357,13 +357,12 @@ static int __init nettel_init(void) *intel1par = 0; } - printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", - (intel_mtd->size >> 10)); + printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %lldKiB\n", + (unsigned long long)(intel_mtd->size >> 10)); intel_mtd->owner = THIS_MODULE; - num_intel_partitions = sizeof(nettel_intel_partitions) / - sizeof(nettel_intel_partitions[0]); + num_intel_partitions = ARRAY_SIZE(nettel_intel_partitions); if (intelboot) { /* diff --git a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c index 43e04c1d22a..2b2e4509321 100644 --- a/drivers/mtd/maps/octagon-5066.c +++ b/drivers/mtd/maps/octagon-5066.c @@ -184,7 +184,7 @@ void cleanup_oct5066(void) release_region(PAGE_IO, 1); } -int __init init_oct5066(void) +static int __init init_oct5066(void) { int i; int ret = 0; diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index 1db16e549e3..87743661d48 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -29,7 +29,6 @@ struct physmap_flash_info { struct map_info map[MAX_RESOURCES]; #ifdef CONFIG_MTD_PARTITIONS int nr_parts; - struct mtd_partition *parts; #endif }; @@ -56,14 +55,10 @@ static int physmap_flash_remove(struct platform_device *dev) for (i = 0; i < MAX_RESOURCES; i++) { if (info->mtd[i] != NULL) { #ifdef CONFIG_MTD_PARTITIONS - if (info->nr_parts) { + if (info->nr_parts || physmap_data->nr_parts) del_mtd_partitions(info->mtd[i]); - kfree(info->parts); - } else if (physmap_data->nr_parts) { - del_mtd_partitions(info->mtd[i]); - } else { + else del_mtd_device(info->mtd[i]); - } #else del_mtd_device(info->mtd[i]); #endif @@ -73,7 +68,12 @@ static int physmap_flash_remove(struct platform_device *dev) return 0; } -static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL }; +static const char *rom_probe_types[] = { + "cfi_probe", + "jedec_probe", + "qinfo_probe", + "map_rom", + NULL }; #ifdef CONFIG_MTD_PARTITIONS static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; #endif @@ -86,6 +86,9 @@ static int physmap_flash_probe(struct platform_device *dev) int err = 0; int i; int devices_found = 0; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; +#endif physmap_data = dev->dev.platform_data; if (physmap_data == NULL) @@ -119,6 +122,7 @@ static int physmap_flash_probe(struct platform_device *dev) info->map[i].size = dev->resource[i].end - dev->resource[i].start + 1; info->map[i].bankwidth = physmap_data->width; info->map[i].set_vpp = physmap_data->set_vpp; + info->map[i].pfow_base = physmap_data->pfow_base; info->map[i].virt = devm_ioremap(&dev->dev, info->map[i].phys, info->map[i].size); @@ -163,9 +167,10 @@ static int physmap_flash_probe(struct platform_device *dev) goto err_out; #ifdef CONFIG_MTD_PARTITIONS - err = parse_mtd_partitions(info->cmtd, part_probe_types, &info->parts, 0); + err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0); if (err > 0) { - add_mtd_partitions(info->cmtd, info->parts, err); + add_mtd_partitions(info->cmtd, parts, err); + kfree(parts); return 0; } @@ -251,14 +256,7 @@ static struct platform_driver physmap_flash_driver = { }; -#ifdef CONFIG_MTD_PHYSMAP_LEN -#if CONFIG_MTD_PHYSMAP_LEN != 0 -#warning using PHYSMAP compat code -#define PHYSMAP_COMPAT -#endif -#endif - -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT static struct physmap_flash_data physmap_flash_data = { .width = CONFIG_MTD_PHYSMAP_BANKWIDTH, }; @@ -302,7 +300,7 @@ static int __init physmap_init(void) int err; err = platform_driver_register(&physmap_flash_driver); -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT if (err == 0) platform_device_register(&physmap_flash); #endif @@ -312,7 +310,7 @@ static int __init physmap_init(void) static void __exit physmap_exit(void) { -#ifdef PHYSMAP_COMPAT +#ifdef CONFIG_MTD_PHYSMAP_COMPAT platform_device_unregister(&physmap_flash); #endif platform_driver_unregister(&physmap_flash_driver); @@ -326,8 +324,7 @@ MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); MODULE_DESCRIPTION("Generic configurable MTD map driver"); /* legacy platform drivers can't hotplug or coldplg */ -#ifndef PHYSMAP_COMPAT +#ifndef CONFIG_MTD_PHYSMAP_COMPAT /* work with hotplug and coldplug */ MODULE_ALIAS("platform:physmap-flash"); #endif - diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index f43ba2815cb..4768bd5459d 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -48,7 +48,7 @@ static int fcnt; #define DEBUG_MARKER printk(KERN_NOTICE "%s[%d]\n", __func__, __LINE__) -int __init init_msp_flash(void) +static int __init init_msp_flash(void) { int i, j; int offset, coff; diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c index de002eb1a7f..933c0b63b01 100644 --- a/drivers/mtd/maps/redwood.c +++ b/drivers/mtd/maps/redwood.c @@ -122,7 +122,7 @@ struct map_info redwood_flash_map = { static struct mtd_info *redwood_mtd; -int __init init_redwood_flash(void) +static int __init init_redwood_flash(void) { int err; diff --git a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c index 14d90edb443..3e3ef53d4fd 100644 --- a/drivers/mtd/maps/rpxlite.c +++ b/drivers/mtd/maps/rpxlite.c @@ -23,7 +23,7 @@ static struct map_info rpxlite_map = { .phys = WINDOW_ADDR, }; -int __init init_rpxlite(void) +static int __init init_rpxlite(void) { printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); rpxlite_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); diff --git a/drivers/mtd/maps/sbc8240.c b/drivers/mtd/maps/sbc8240.c index 6e1e99cd2b5..d5374cdcb16 100644 --- a/drivers/mtd/maps/sbc8240.c +++ b/drivers/mtd/maps/sbc8240.c @@ -136,7 +136,7 @@ static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS]; #endif /* CONFIG_MTD_PARTITIONS */ -int __init init_sbc8240_mtd (void) +static int __init init_sbc8240_mtd (void) { static struct _cjs { u_long addr; diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c index 21169e6d646..7e329f09a54 100644 --- a/drivers/mtd/maps/scb2_flash.c +++ b/drivers/mtd/maps/scb2_flash.c @@ -118,7 +118,8 @@ scb2_fixup_mtd(struct mtd_info *mtd) struct mtd_erase_region_info *region = &mtd->eraseregions[i]; if (region->numblocks * region->erasesize > mtd->size) { - region->numblocks = (mtd->size / region->erasesize); + region->numblocks = ((unsigned long)mtd->size / + region->erasesize); done = 1; } else { region->numblocks = 0; @@ -187,8 +188,9 @@ scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) return -ENODEV; } - printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", - scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); + printk(KERN_NOTICE MODNAME ": chip size 0x%llx at offset 0x%llx\n", + (unsigned long long)scb2_mtd->size, + (unsigned long long)(SCB2_WINDOW - scb2_mtd->size)); add_mtd_device(scb2_mtd); diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c index 026eab02818..b392f096c70 100644 --- a/drivers/mtd/maps/sharpsl-flash.c +++ b/drivers/mtd/maps/sharpsl-flash.c @@ -47,7 +47,7 @@ static struct mtd_partition sharpsl_partitions[1] = { } }; -int __init init_sharpsl(void) +static int __init init_sharpsl(void) { struct mtd_partition *parts; int nb_parts = 0; diff --git a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c index a5d3d8531fa..60146984f4b 100644 --- a/drivers/mtd/maps/tqm8xxl.c +++ b/drivers/mtd/maps/tqm8xxl.c @@ -109,7 +109,7 @@ static struct mtd_partition tqm8xxl_fs_partitions[] = { }; #endif -int __init init_tqm_mtd(void) +static int __init init_tqm_mtd(void) { int idx = 0, ret = 0; unsigned long flash_addr, flash_size, mtd_size = 0; diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c index 0dc645f8152..81756e39771 100644 --- a/drivers/mtd/maps/uclinux.c +++ b/drivers/mtd/maps/uclinux.c @@ -51,7 +51,7 @@ int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len, /****************************************************************************/ -int __init uclinux_mtd_init(void) +static int __init uclinux_mtd_init(void) { struct mtd_info *mtd; struct map_info *mapp; @@ -94,7 +94,7 @@ int __init uclinux_mtd_init(void) /****************************************************************************/ -void __exit uclinux_mtd_cleanup(void) +static void __exit uclinux_mtd_cleanup(void) { if (uclinux_ram_mtdinfo) { del_mtd_partitions(uclinux_ram_mtdinfo); diff --git a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c index 5a0c9a353b0..6d452dcdfe3 100644 --- a/drivers/mtd/maps/vmax301.c +++ b/drivers/mtd/maps/vmax301.c @@ -146,7 +146,7 @@ static void __exit cleanup_vmax301(void) iounmap((void *)vmax_map[0].map_priv_1 - WINDOW_START); } -int __init init_vmax301(void) +static int __init init_vmax301(void) { int i; unsigned long iomapadr; diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 413b0cf9bbd..933a2b6598b 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -74,7 +74,7 @@ do { \ } \ } while (0); -int __init init_sbc82xx_flash(void) +static int __init init_sbc82xx_flash(void) { volatile memctl_cpm2_t *mc = &cpm2_immr->im_memctl; int bigflash; diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index bcffeda2df3..e9ec59e9a56 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -450,16 +450,20 @@ static int mtd_ioctl(struct inode *inode, struct file *file, if (!erase) ret = -ENOMEM; else { + struct erase_info_user einfo; + wait_queue_head_t waitq; DECLARE_WAITQUEUE(wait, current); init_waitqueue_head(&waitq); - if (copy_from_user(&erase->addr, argp, + if (copy_from_user(&einfo, argp, sizeof(struct erase_info_user))) { kfree(erase); return -EFAULT; } + erase->addr = einfo.start; + erase->len = einfo.length; erase->mtd = mtd; erase->callback = mtdchar_erase_callback; erase->priv = (unsigned long)&waitq; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index 1a05cf37851..3dbb1b38db6 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -197,7 +197,7 @@ concat_writev(struct mtd_info *mtd, const struct kvec *vecs, continue; } - size = min(total_len, (size_t)(subdev->size - to)); + size = min_t(uint64_t, total_len, subdev->size - to); wsize = size; /* store for future use */ entry_high = entry_low; @@ -385,7 +385,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) struct mtd_concat *concat = CONCAT(mtd); struct mtd_info *subdev; int i, err; - u_int32_t length, offset = 0; + uint64_t length, offset = 0; struct erase_info *erase; if (!(mtd->flags & MTD_WRITEABLE)) @@ -518,7 +518,7 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return 0; } -static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; @@ -528,7 +528,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size; + uint64_t size; if (ofs >= subdev->size) { size = 0; @@ -556,7 +556,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return err; } -static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; @@ -566,7 +566,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - size_t size; + uint64_t size; if (ofs >= subdev->size) { size = 0; @@ -696,7 +696,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c int i; size_t size; struct mtd_concat *concat; - u_int32_t max_erasesize, curr_erasesize; + uint32_t max_erasesize, curr_erasesize; int num_erase_region; printk(KERN_NOTICE "Concatenating MTD devices:\n"); @@ -842,12 +842,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.erasesize = curr_erasesize; concat->mtd.numeraseregions = 0; } else { + uint64_t tmp64; + /* * erase block size varies across the subdevices: allocate * space to store the data describing the variable erase regions */ struct mtd_erase_region_info *erase_region_p; - u_int32_t begin, position; + uint64_t begin, position; concat->mtd.erasesize = max_erasesize; concat->mtd.numeraseregions = num_erase_region; @@ -879,8 +881,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = - (position - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; begin = position; curr_erasesize = subdev[i]->erasesize; @@ -897,9 +900,9 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = - (position - - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; begin = position; curr_erasesize = @@ -909,14 +912,16 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c } position += subdev[i]->eraseregions[j]. - numblocks * curr_erasesize; + numblocks * (uint64_t)curr_erasesize; } } } /* Now write the final entry */ erase_region_p->offset = begin; erase_region_p->erasesize = curr_erasesize; - erase_region_p->numblocks = (position - begin) / curr_erasesize; + tmp64 = position - begin; + do_div(tmp64, curr_erasesize); + erase_region_p->numblocks = tmp64; } return &concat->mtd; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index a9d24694982..76fe0a1e7a5 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -57,6 +57,19 @@ int add_mtd_device(struct mtd_info *mtd) mtd->index = i; mtd->usecount = 0; + if (is_power_of_2(mtd->erasesize)) + mtd->erasesize_shift = ffs(mtd->erasesize) - 1; + else + mtd->erasesize_shift = 0; + + if (is_power_of_2(mtd->writesize)) + mtd->writesize_shift = ffs(mtd->writesize) - 1; + else + mtd->writesize_shift = 0; + + mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; + mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; + /* Some chips always power up locked. Unlock them now */ if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { @@ -344,7 +357,8 @@ static inline int mtd_proc_info (char *buf, int i) if (!this) return 0; - return sprintf(buf, "mtd%d: %8.8x %8.8x \"%s\"\n", i, this->size, + return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", i, + (unsigned long long)this->size, this->erasesize, this->name); } diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index aebb3b27edb..1a6b3beabe8 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -80,9 +80,9 @@ static int mtdoops_erase_block(struct mtd_info *mtd, int offset) if (ret) { set_current_state(TASK_RUNNING); remove_wait_queue(&wait_q, &wait); - printk (KERN_WARNING "mtdoops: erase of region [0x%x, 0x%x] " + printk (KERN_WARNING "mtdoops: erase of region [0x%llx, 0x%llx] " "on \"%s\" failed\n", - erase.addr, erase.len, mtd->name); + (unsigned long long)erase.addr, (unsigned long long)erase.len, mtd->name); return ret; } @@ -289,7 +289,10 @@ static void mtdoops_notify_add(struct mtd_info *mtd) } cxt->mtd = mtd; - cxt->oops_pages = mtd->size / OOPS_PAGE_SIZE; + if (mtd->size > INT_MAX) + cxt->oops_pages = INT_MAX / OOPS_PAGE_SIZE; + else + cxt->oops_pages = (int)mtd->size / OOPS_PAGE_SIZE; find_next_position(cxt); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 3728913fa5f..144e6b613a7 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -26,7 +26,7 @@ static LIST_HEAD(mtd_partitions); struct mtd_part { struct mtd_info mtd; struct mtd_info *master; - u_int32_t offset; + uint64_t offset; int index; struct list_head list; int registered; @@ -235,7 +235,7 @@ void mtd_erase_callback(struct erase_info *instr) } EXPORT_SYMBOL_GPL(mtd_erase_callback); -static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -243,7 +243,7 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, size_t len) return part->master->lock(part->master, ofs + part->offset, len); } -static int part_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); if ((len + ofs) > mtd->size) @@ -317,7 +317,7 @@ EXPORT_SYMBOL(del_mtd_partitions); static struct mtd_part *add_one_partition(struct mtd_info *master, const struct mtd_partition *part, int partno, - u_int32_t cur_offset) + uint64_t cur_offset) { struct mtd_part *slave; @@ -395,19 +395,19 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->offset = cur_offset; if (slave->offset == MTDPART_OFS_NXTBLK) { slave->offset = cur_offset; - if ((cur_offset % master->erasesize) != 0) { + if (mtd_mod_by_eb(cur_offset, master) != 0) { /* Round up to next erasesize */ - slave->offset = ((cur_offset / master->erasesize) + 1) * master->erasesize; + slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize; printk(KERN_NOTICE "Moving partition %d: " - "0x%08x -> 0x%08x\n", partno, - cur_offset, slave->offset); + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; - printk(KERN_NOTICE "0x%08x-0x%08x : \"%s\"\n", slave->offset, - slave->offset + slave->mtd.size, slave->mtd.name); + printk(KERN_NOTICE "0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset, + (unsigned long long)(slave->offset + slave->mtd.size), slave->mtd.name); /* let's do some sanity checks */ if (slave->offset >= master->size) { @@ -420,13 +420,13 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } if (slave->offset + slave->mtd.size > master->size) { slave->mtd.size = master->size - slave->offset; - printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#x\n", - part->name, master->name, slave->mtd.size); + printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n", + part->name, master->name, (unsigned long long)slave->mtd.size); } if (master->numeraseregions > 1) { /* Deal with variable erase size stuff */ int i, max = master->numeraseregions; - u32 end = slave->offset + slave->mtd.size; + u64 end = slave->offset + slave->mtd.size; struct mtd_erase_region_info *regions = master->eraseregions; /* Find the first erase regions which is part of this @@ -449,7 +449,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->offset % slave->mtd.erasesize)) { + mtd_mod_by_eb(slave->offset, &slave->mtd)) { /* Doesn't start on a boundary of major erase size */ /* FIXME: Let it be writable if it is on a boundary of * _minor_ erase size though */ @@ -458,7 +458,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, part->name); } if ((slave->mtd.flags & MTD_WRITEABLE) && - (slave->mtd.size % slave->mtd.erasesize)) { + mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) { slave->mtd.flags &= ~MTD_WRITEABLE; printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", part->name); @@ -466,7 +466,7 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.ecclayout = master->ecclayout; if (master->block_isbad) { - uint32_t offs = 0; + uint64_t offs = 0; while (offs < slave->mtd.size) { if (master->block_isbad(master, @@ -501,7 +501,7 @@ int add_mtd_partitions(struct mtd_info *master, int nbparts) { struct mtd_part *slave; - u_int32_t cur_offset = 0; + uint64_t cur_offset = 0; int i; printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f8ae0400c49..8b12e6e109d 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC incorrect ECC generation, and if using these, the default of software ECC is preferable. +config MTD_NAND_NDFC + tristate "NDFC NanD Flash Controller" + depends on 4xx + select MTD_NAND_ECC_SMC + help + NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs + config MTD_NAND_S3C2410_CLKSTOP bool "S3C2410 NAND IDLE clock stop" depends on MTD_NAND_S3C2410 diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c index 96238039485..6d9649159a1 100644 --- a/drivers/mtd/nand/alauda.c +++ b/drivers/mtd/nand/alauda.c @@ -676,11 +676,11 @@ static int alauda_probe(struct usb_interface *interface, goto error; al->write_out = usb_sndbulkpipe(al->dev, - ep_wr->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_wr)); al->bulk_in = usb_rcvbulkpipe(al->dev, - ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_in)); al->bulk_out = usb_sndbulkpipe(al->dev, - ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + usb_endpoint_num(ep_out)); /* second device is identical up to now */ memcpy(al+1, al, sizeof(*al)); diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index b8064bf3aee..22a6b2e50e9 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -90,7 +90,7 @@ static int timing[3]; module_param_array(timing, int, &numtimings, 0644); #ifdef CONFIG_MTD_PARTITIONS -static const char *part_probes[] = { "RedBoot", NULL }; +static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; #endif /* Hrm. Why isn't this already conditional on something in the struct device? */ @@ -805,10 +805,13 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, add_mtd_device(mtd); #ifdef CONFIG_MTD_PARTITIONS +#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; - dev_info(&cafe->pdev->dev, "%d RedBoot partitions found\n", nr_parts); + dev_info(&cafe->pdev->dev, "%d partitions found\n", nr_parts); add_mtd_partitions(mtd, parts, nr_parts); } #endif diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 4aa5bd6158d..65929db2944 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -777,7 +777,9 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) /* Fill in fsl_elbc_mtd structure */ priv->mtd.priv = chip; priv->mtd.owner = THIS_MODULE; - priv->fmr = 0; /* rest filled in later */ + + /* Set the ECCM according to the settings in bootloader.*/ + priv->fmr = in_be32(&lbc->fmr) & FMR_ECCM; /* fill in nand_chip structure */ /* set up function call table */ diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0a9c9cd33f9..0c3afccde8a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2014,13 +2014,14 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) { - int page, len, status, pages_per_block, ret, chipnr; + int page, status, pages_per_block, ret, chipnr; struct nand_chip *chip = mtd->priv; - int rewrite_bbt[NAND_MAX_CHIPS]={0}; + loff_t rewrite_bbt[NAND_MAX_CHIPS]={0}; unsigned int bbt_masked_page = 0xffffffff; + loff_t len; - DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n", - (unsigned int)instr->addr, (unsigned int)instr->len); + DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%012llx, len = %llu\n", + (unsigned long long)instr->addr, (unsigned long long)instr->len); /* Start address must align on block boundary */ if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) { @@ -2116,7 +2117,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); instr->state = MTD_ERASE_FAILED; - instr->fail_addr = (page << chip->page_shift); + instr->fail_addr = + ((loff_t)page << chip->page_shift); goto erase_exit; } @@ -2126,7 +2128,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) - rewrite_bbt[chipnr] = (page << chip->page_shift); + rewrite_bbt[chipnr] = + ((loff_t)page << chip->page_shift); /* Increment page address and decrement length */ len -= (1 << chip->phys_erase_shift); @@ -2173,7 +2176,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, continue; /* update the BBT for chip */ DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt " - "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr], + "(%d:0x%0llx 0x%0x)\n", chipnr, rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2365,7 +2368,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (!mtd->name) mtd->name = type->name; - chip->chipsize = type->chipsize << 20; + chip->chipsize = (uint64_t)type->chipsize << 20; /* Newer devices have all the information in additional id bytes */ if (!type->pagesize) { @@ -2423,7 +2426,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->bbt_erase_shift = chip->phys_erase_shift = ffs(mtd->erasesize) - 1; - chip->chip_shift = ffs(chip->chipsize) - 1; + if (chip->chipsize & 0xffffffff) + chip->chip_shift = ffs((unsigned)chip->chipsize) - 1; + else + chip->chip_shift = ffs((unsigned)(chip->chipsize >> 32)) + 32 - 1; /* Set the bad block position */ chip->badblockpos = mtd->writesize > 512 ? @@ -2517,7 +2523,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) /** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure - * @maxchips: Number of chips to scan for * * This is the second phase of the normal nand_scan() function. It * fills out all the uninitialized function pointers with the defaults diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 0b1c48595f1..55c23e5cd21 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -171,16 +171,16 @@ 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%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + printk(KERN_DEBUG "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; } /* Leave it for now, if its matured we can move this * message to MTD_DEBUG_LEVEL0 */ - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + 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 ? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -284,7 +284,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize); td->version[0] = buf[mtd->writesize + td->veroffs]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", @@ -293,7 +293,7 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, + scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize); md->version[0] = buf[mtd->writesize + md->veroffs]; printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", @@ -411,7 +411,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, numblocks = this->chipsize >> (this->bbt_erase_shift - 1); startblock = chip * numblocks; numblocks += startblock; - from = startblock << (this->bbt_erase_shift - 1); + from = (loff_t)startblock << (this->bbt_erase_shift - 1); } for (i = startblock; i < numblocks;) { @@ -428,8 +428,8 @@ 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%08x\n", - i >> 1, (unsigned int)from); + printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n", + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -495,7 +495,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr for (block = 0; block < td->maxblocks; block++) { int actblock = startblock + dir * block; - loff_t offs = actblock << this->bbt_erase_shift; + loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ scan_read_raw(mtd, buf, offs, mtd->writesize); @@ -719,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memset(&einfo, 0, sizeof(einfo)); einfo.mtd = mtd; - einfo.addr = (unsigned long)to; + einfo.addr = to; einfo.len = 1 << this->bbt_erase_shift; res = nand_erase_nand(mtd, &einfo, 1); if (res < 0) @@ -729,8 +729,8 @@ 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%08x, version " - "0x%02X\n", (unsigned int)to, td->version[chip]); + printk(KERN_DEBUG "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; @@ -910,7 +910,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) newval = oldval | (0x2 << (block & 0x06)); this->bbt[(block >> 3)] = newval; if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1)); continue; } update = 0; @@ -931,7 +931,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) 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, (block - 2) << (this->bbt_erase_shift - 1)); + nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } } @@ -1027,7 +1027,6 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (!this->bbt || !td) return -EINVAL; - len = mtd->size >> (this->bbt_erase_shift + 2); /* Allocate a temporary buffer for one eraseblock incl. oob */ len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index ae7c57781a6..cd0711b83ac 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -38,6 +38,9 @@ #include <linux/delay.h> #include <linux/list.h> #include <linux/random.h> +#include <linux/sched.h> +#include <linux/fs.h> +#include <linux/pagemap.h> /* Default simulator parameters values */ #if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \ @@ -100,6 +103,7 @@ static unsigned int bitflips = 0; static char *gravepages = NULL; static unsigned int rptwear = 0; static unsigned int overridesize = 0; +static char *cache_file = NULL; module_param(first_id_byte, uint, 0400); module_param(second_id_byte, uint, 0400); @@ -122,12 +126,13 @@ module_param(bitflips, uint, 0400); module_param(gravepages, charp, 0400); module_param(rptwear, uint, 0400); module_param(overridesize, uint, 0400); +module_param(cache_file, charp, 0400); MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)"); MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)"); MODULE_PARM_DESC(third_id_byte, "The third byte returned by NAND Flash 'read ID' command"); MODULE_PARM_DESC(fourth_id_byte, "The fourth byte returned by NAND Flash 'read ID' command"); -MODULE_PARM_DESC(access_delay, "Initial page access delay (microiseconds)"); +MODULE_PARM_DESC(access_delay, "Initial page access delay (microseconds)"); MODULE_PARM_DESC(programm_delay, "Page programm delay (microseconds"); MODULE_PARM_DESC(erase_delay, "Sector erase delay (milliseconds)"); MODULE_PARM_DESC(output_cycle, "Word output (from flash) time (nanodeconds)"); @@ -153,6 +158,7 @@ MODULE_PARM_DESC(rptwear, "Number of erases inbetween reporting wear, if MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the ID bytes. " "The size is specified in erase blocks and as the exponent of a power of two" " e.g. 5 means a size of 32 erase blocks"); +MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory"); /* The largest possible page size */ #define NS_LARGEST_PAGE_SIZE 2048 @@ -266,6 +272,9 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I */ #define NS_MAX_PREVSTATES 1 +/* Maximum page cache pages needed to read or write a NAND page to the cache_file */ +#define NS_MAX_HELD_PAGES 16 + /* * A union to represent flash memory contents and flash buffer. */ @@ -295,6 +304,9 @@ struct nandsim { /* The simulated NAND flash pages array */ union ns_mem *pages; + /* Slab allocator for nand pages */ + struct kmem_cache *nand_pages_slab; + /* Internal buffer of page + OOB size bytes */ union ns_mem buf; @@ -335,6 +347,13 @@ struct nandsim { int ale; /* address Latch Enable */ int wp; /* write Protect */ } lines; + + /* Fields needed when using a cache file */ + struct file *cfile; /* Open file */ + unsigned char *pages_written; /* Which pages have been written */ + void *file_buf; + struct page *held_pages[NS_MAX_HELD_PAGES]; + int held_cnt; }; /* @@ -420,25 +439,69 @@ static struct mtd_info *nsmtd; static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE]; /* - * Allocate array of page pointers and initialize the array to NULL - * pointers. + * Allocate array of page pointers, create slab allocation for an array + * and initialize the array by NULL pointers. * * RETURNS: 0 if success, -ENOMEM if memory alloc fails. */ static int alloc_device(struct nandsim *ns) { - int i; + struct file *cfile; + int i, err; + + if (cache_file) { + cfile = filp_open(cache_file, O_CREAT | O_RDWR | O_LARGEFILE, 0600); + if (IS_ERR(cfile)) + return PTR_ERR(cfile); + if (!cfile->f_op || (!cfile->f_op->read && !cfile->f_op->aio_read)) { + NS_ERR("alloc_device: cache file not readable\n"); + err = -EINVAL; + goto err_close; + } + if (!cfile->f_op->write && !cfile->f_op->aio_write) { + NS_ERR("alloc_device: cache file not writeable\n"); + err = -EINVAL; + goto err_close; + } + ns->pages_written = vmalloc(ns->geom.pgnum); + if (!ns->pages_written) { + NS_ERR("alloc_device: unable to allocate pages written array\n"); + err = -ENOMEM; + goto err_close; + } + ns->file_buf = kmalloc(ns->geom.pgszoob, GFP_KERNEL); + if (!ns->file_buf) { + NS_ERR("alloc_device: unable to allocate file buf\n"); + err = -ENOMEM; + goto err_free; + } + ns->cfile = cfile; + memset(ns->pages_written, 0, ns->geom.pgnum); + return 0; + } ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem)); if (!ns->pages) { - NS_ERR("alloc_map: unable to allocate page array\n"); + NS_ERR("alloc_device: unable to allocate page array\n"); return -ENOMEM; } for (i = 0; i < ns->geom.pgnum; i++) { ns->pages[i].byte = NULL; } + ns->nand_pages_slab = kmem_cache_create("nandsim", + ns->geom.pgszoob, 0, 0, NULL); + if (!ns->nand_pages_slab) { + NS_ERR("cache_create: unable to create kmem_cache\n"); + return -ENOMEM; + } return 0; + +err_free: + vfree(ns->pages_written); +err_close: + filp_close(cfile, NULL); + return err; } /* @@ -448,11 +511,20 @@ static void free_device(struct nandsim *ns) { int i; + if (ns->cfile) { + kfree(ns->file_buf); + vfree(ns->pages_written); + filp_close(ns->cfile, NULL); + return; + } + if (ns->pages) { for (i = 0; i < ns->geom.pgnum; i++) { if (ns->pages[i].byte) - kfree(ns->pages[i].byte); + kmem_cache_free(ns->nand_pages_slab, + ns->pages[i].byte); } + kmem_cache_destroy(ns->nand_pages_slab); vfree(ns->pages); } } @@ -464,7 +536,7 @@ static char *get_partition_name(int i) return kstrdup(buf, GFP_KERNEL); } -static u_int64_t divide(u_int64_t n, u_int32_t d) +static uint64_t divide(uint64_t n, uint32_t d) { do_div(n, d); return n; @@ -480,8 +552,8 @@ static int init_nandsim(struct mtd_info *mtd) struct nand_chip *chip = (struct nand_chip *)mtd->priv; struct nandsim *ns = (struct nandsim *)(chip->priv); int i, ret = 0; - u_int64_t remains; - u_int64_t next_offset; + uint64_t remains; + uint64_t next_offset; if (NS_IS_INITIALIZED(ns)) { NS_ERR("init_nandsim: nandsim is already initialized\n"); @@ -548,7 +620,7 @@ static int init_nandsim(struct mtd_info *mtd) remains = ns->geom.totsz; next_offset = 0; for (i = 0; i < parts_num; ++i) { - u_int64_t part_sz = (u_int64_t)parts[i] * ns->geom.secsz; + uint64_t part_sz = (uint64_t)parts[i] * ns->geom.secsz; if (!part_sz || part_sz > remains) { NS_ERR("bad partition size.\n"); @@ -1211,6 +1283,97 @@ static int find_operation(struct nandsim *ns, uint32_t flag) return -1; } +static void put_pages(struct nandsim *ns) +{ + int i; + + for (i = 0; i < ns->held_cnt; i++) + page_cache_release(ns->held_pages[i]); +} + +/* Get page cache pages in advance to provide NOFS memory allocation */ +static int get_pages(struct nandsim *ns, struct file *file, size_t count, loff_t pos) +{ + pgoff_t index, start_index, end_index; + struct page *page; + struct address_space *mapping = file->f_mapping; + + start_index = pos >> PAGE_CACHE_SHIFT; + end_index = (pos + count - 1) >> PAGE_CACHE_SHIFT; + if (end_index - start_index + 1 > NS_MAX_HELD_PAGES) + return -EINVAL; + ns->held_cnt = 0; + for (index = start_index; index <= end_index; index++) { + page = find_get_page(mapping, index); + if (page == NULL) { + page = find_or_create_page(mapping, index, GFP_NOFS); + if (page == NULL) { + write_inode_now(mapping->host, 1); + page = find_or_create_page(mapping, index, GFP_NOFS); + } + if (page == NULL) { + put_pages(ns); + return -ENOMEM; + } + unlock_page(page); + } + ns->held_pages[ns->held_cnt++] = page; + } + return 0; +} + +static int set_memalloc(void) +{ + if (current->flags & PF_MEMALLOC) + return 0; + current->flags |= PF_MEMALLOC; + return 1; +} + +static void clear_memalloc(int memalloc) +{ + if (memalloc) + current->flags &= ~PF_MEMALLOC; +} + +static ssize_t read_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + ssize_t tx; + int err, memalloc; + + err = get_pages(ns, file, count, *pos); + if (err) + return err; + old_fs = get_fs(); + set_fs(get_ds()); + memalloc = set_memalloc(); + tx = vfs_read(file, (char __user *)buf, count, pos); + clear_memalloc(memalloc); + set_fs(old_fs); + put_pages(ns); + return tx; +} + +static ssize_t write_file(struct nandsim *ns, struct file *file, void *buf, size_t count, loff_t *pos) +{ + mm_segment_t old_fs; + ssize_t tx; + int err, memalloc; + + err = get_pages(ns, file, count, *pos); + if (err) + return err; + old_fs = get_fs(); + set_fs(get_ds()); + memalloc = set_memalloc(); + tx = vfs_write(file, (char __user *)buf, count, pos); + clear_memalloc(memalloc); + set_fs(old_fs); + put_pages(ns); + return tx; +} + /* * Returns a pointer to the current page. */ @@ -1227,6 +1390,38 @@ static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns) return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off; } +int do_read_error(struct nandsim *ns, int num) +{ + unsigned int page_no = ns->regs.row; + + if (read_error(page_no)) { + int i; + memset(ns->buf.byte, 0xFF, num); + for (i = 0; i < num; ++i) + ns->buf.byte[i] = random32(); + NS_WARN("simulating read error in page %u\n", page_no); + return 1; + } + return 0; +} + +void do_bit_flips(struct nandsim *ns, int num) +{ + if (bitflips && random32() < (1 << 22)) { + int flips = 1; + if (bitflips > 1) + flips = (random32() % (int) bitflips) + 1; + while (flips--) { + int pos = random32() % (num * 8); + ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); + NS_WARN("read_page: flipping bit %d in page %d " + "reading from %d ecc: corrected=%u failed=%u\n", + pos, ns->regs.row, ns->regs.column + ns->regs.off, + nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); + } + } +} + /* * Fill the NAND buffer with data read from the specified page. */ @@ -1234,36 +1429,40 @@ static void read_page(struct nandsim *ns, int num) { union ns_mem *mypage; + if (ns->cfile) { + if (!ns->pages_written[ns->regs.row]) { + NS_DBG("read_page: page %d not written\n", ns->regs.row); + memset(ns->buf.byte, 0xFF, num); + } else { + loff_t pos; + ssize_t tx; + + NS_DBG("read_page: page %d written, reading from %d\n", + ns->regs.row, ns->regs.column + ns->regs.off); + if (do_read_error(ns, num)) + return; + pos = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; + tx = read_file(ns, ns->cfile, ns->buf.byte, num, &pos); + if (tx != num) { + NS_ERR("read_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); + return; + } + do_bit_flips(ns, num); + } + return; + } + mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("read_page: page %d not allocated\n", ns->regs.row); memset(ns->buf.byte, 0xFF, num); } else { - unsigned int page_no = ns->regs.row; NS_DBG("read_page: page %d allocated, reading from %d\n", ns->regs.row, ns->regs.column + ns->regs.off); - if (read_error(page_no)) { - int i; - memset(ns->buf.byte, 0xFF, num); - for (i = 0; i < num; ++i) - ns->buf.byte[i] = random32(); - NS_WARN("simulating read error in page %u\n", page_no); + if (do_read_error(ns, num)) return; - } memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num); - if (bitflips && random32() < (1 << 22)) { - int flips = 1; - if (bitflips > 1) - flips = (random32() % (int) bitflips) + 1; - while (flips--) { - int pos = random32() % (num * 8); - ns->buf.byte[pos / 8] ^= (1 << (pos % 8)); - NS_WARN("read_page: flipping bit %d in page %d " - "reading from %d ecc: corrected=%u failed=%u\n", - pos, ns->regs.row, ns->regs.column + ns->regs.off, - nsmtd->ecc_stats.corrected, nsmtd->ecc_stats.failed); - } - } + do_bit_flips(ns, num); } } @@ -1275,11 +1474,20 @@ static void erase_sector(struct nandsim *ns) union ns_mem *mypage; int i; + if (ns->cfile) { + for (i = 0; i < ns->geom.pgsec; i++) + if (ns->pages_written[ns->regs.row + i]) { + NS_DBG("erase_sector: freeing page %d\n", ns->regs.row + i); + ns->pages_written[ns->regs.row + i] = 0; + } + return; + } + mypage = NS_GET_PAGE(ns); for (i = 0; i < ns->geom.pgsec; i++) { if (mypage->byte != NULL) { NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i); - kfree(mypage->byte); + kmem_cache_free(ns->nand_pages_slab, mypage->byte); mypage->byte = NULL; } mypage++; @@ -1295,16 +1503,57 @@ static int prog_page(struct nandsim *ns, int num) union ns_mem *mypage; u_char *pg_off; + if (ns->cfile) { + loff_t off, pos; + ssize_t tx; + int all; + + NS_DBG("prog_page: writing page %d\n", ns->regs.row); + pg_off = ns->file_buf + ns->regs.column + ns->regs.off; + off = (loff_t)ns->regs.row * ns->geom.pgszoob + ns->regs.column + ns->regs.off; + if (!ns->pages_written[ns->regs.row]) { + all = 1; + memset(ns->file_buf, 0xff, ns->geom.pgszoob); + } else { + all = 0; + pos = off; + tx = read_file(ns, ns->cfile, pg_off, num, &pos); + if (tx != num) { + NS_ERR("prog_page: read error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + } + for (i = 0; i < num; i++) + pg_off[i] &= ns->buf.byte[i]; + if (all) { + pos = (loff_t)ns->regs.row * ns->geom.pgszoob; + tx = write_file(ns, ns->cfile, ns->file_buf, ns->geom.pgszoob, &pos); + if (tx != ns->geom.pgszoob) { + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + ns->pages_written[ns->regs.row] = 1; + } else { + pos = off; + tx = write_file(ns, ns->cfile, pg_off, num, &pos); + if (tx != num) { + NS_ERR("prog_page: write error for page %d ret %ld\n", ns->regs.row, (long)tx); + return -1; + } + } + return 0; + } + mypage = NS_GET_PAGE(ns); if (mypage->byte == NULL) { NS_DBG("prog_page: allocating page %d\n", ns->regs.row); /* * We allocate memory with GFP_NOFS because a flash FS may * utilize this. If it is holding an FS lock, then gets here, - * then kmalloc runs writeback which goes to the FS again - * and deadlocks. This was seen in practice. + * then kernel memory alloc runs writeback which goes to the FS + * again and deadlocks. This was seen in practice. */ - mypage->byte = kmalloc(ns->geom.pgszoob, GFP_NOFS); + mypage->byte = kmem_cache_alloc(ns->nand_pages_slab, GFP_NOFS); if (mypage->byte == NULL) { NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row); return -1; @@ -1736,13 +1985,17 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte) /* Check if chip is expecting command */ if (NS_STATE(ns->nxstate) != STATE_UNKNOWN && !(ns->nxstate & STATE_CMD_MASK)) { - /* - * We are in situation when something else (not command) - * was expected but command was input. In this case ignore - * previous command(s)/state(s) and accept the last one. - */ - NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " - "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); + /* Do not warn if only 2 id bytes are read */ + if (!(ns->regs.command == NAND_CMD_READID && + NS_STATE(ns->state) == STATE_DATAOUT_ID && ns->regs.count == 2)) { + /* + * We are in situation when something else (not command) + * was expected but command was input. In this case ignore + * previous command(s)/state(s) and accept the last one. + */ + NS_WARN("write_byte: command (%#x) wasn't expected, expected state is %s, " + "ignore previous states\n", (uint)byte, get_state_name(ns->nxstate)); + } switch_to_ready_state(ns, NS_STATUS_FAILED(ns)); } @@ -2044,7 +2297,7 @@ static int __init ns_init_module(void) } if (overridesize) { - u_int64_t new_size = (u_int64_t)nsmtd->erasesize << overridesize; + uint64_t new_size = (uint64_t)nsmtd->erasesize << overridesize; if (new_size >> overridesize != nsmtd->erasesize) { NS_ERR("overridesize is too big\n"); goto err_exit; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 955959eb02d..582cf80f555 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -2,12 +2,20 @@ * drivers/mtd/ndfc.c * * Overview: - * Platform independend driver for NDFC (NanD Flash Controller) + * Platform independent driver for NDFC (NanD Flash Controller) * integrated into EP440 cores * + * Ported to an OF platform driver by Sean MacLennan + * + * The NDFC supports multiple chips, but this driver only supports a + * single chip since I do not have access to any boards with + * multiple chips. + * * Author: Thomas Gleixner * * Copyright 2006 IBM + * Copyright 2008 PIKA Technologies + * Sean MacLennan <smaclennan@pikatech.com> * * 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 @@ -21,27 +29,20 @@ #include <linux/mtd/partitions.h> #include <linux/mtd/ndfc.h> #include <linux/mtd/mtd.h> -#include <linux/platform_device.h> - +#include <linux/of_platform.h> #include <asm/io.h> -#ifdef CONFIG_40x -#include <asm/ibm405.h> -#else -#include <asm/ibm44x.h> -#endif - -struct ndfc_nand_mtd { - struct mtd_info mtd; - struct nand_chip chip; - struct platform_nand_chip *pl_chip; -}; -static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS]; struct ndfc_controller { - void __iomem *ndfcbase; - struct nand_hw_control ndfc_control; - atomic_t childs_active; + struct of_device *ofdev; + void __iomem *ndfcbase; + struct mtd_info mtd; + struct nand_chip chip; + int chip_select; + struct nand_hw_control ndfc_control; +#ifdef CONFIG_MTD_PARTITIONS + struct mtd_partition *parts; +#endif }; static struct ndfc_controller ndfc_ctrl; @@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) { uint32_t ccr; struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *nandchip = mtd->priv; - struct ndfc_nand_mtd *nandmtd = nandchip->priv; - struct platform_nand_chip *pchip = nandmtd->pl_chip; - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); + ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); if (chip >= 0) { ccr &= ~NDFC_CCR_BS_MASK; - ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); + ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); } else ccr |= NDFC_CCR_RESET_CE; - __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); } static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) @@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd) { struct ndfc_controller *ndfc = &ndfc_ctrl; - return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; + return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; } static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) @@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) uint32_t ccr; struct ndfc_controller *ndfc = &ndfc_ctrl; - ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); + ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); ccr |= NDFC_CCR_RESET_ECC; - __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); wmb(); } @@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, uint8_t *p = (uint8_t *)&ecc; wmb(); - ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); - ecc_code[0] = p[1]; - ecc_code[1] = p[2]; + ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); + /* The NDFC uses Smart Media (SMC) bytes order */ + ecc_code[0] = p[2]; + ecc_code[1] = p[1]; ecc_code[2] = p[3]; return 0; @@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); + *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); } static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); + out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); } static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) @@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) uint32_t *p = (uint32_t *) buf; for(;len > 0; len -= 4) - if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) + if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA)) return -EFAULT; return 0; } @@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /* * Initialize chip structure */ -static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) +static int ndfc_chip_init(struct ndfc_controller *ndfc, + struct device_node *node) { - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct nand_chip *chip = &mtd->chip; +#ifdef CONFIG_MTD_PARTITIONS +#ifdef CONFIG_MTD_CMDLINE_PARTS + static const char *part_types[] = { "cmdlinepart", NULL }; +#else + static const char *part_types[] = { NULL }; +#endif +#endif + struct device_node *flash_np; + struct nand_chip *chip = &ndfc->chip; + int ret; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; @@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) chip->dev_ready = ndfc_ready; chip->select_chip = ndfc_select_chip; chip->chip_delay = 50; - chip->priv = mtd; - chip->options = mtd->pl_chip->options; chip->controller = &ndfc->ndfc_control; chip->read_buf = ndfc_read_buf; chip->write_buf = ndfc_write_buf; @@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 256; chip->ecc.bytes = 3; - chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout; - mtd->mtd.priv = chip; - mtd->mtd.owner = THIS_MODULE; -} - -static int ndfc_chip_probe(struct platform_device *pdev) -{ - struct platform_nand_chip *nc = pdev->dev.platform_data; - struct ndfc_chip_settings *settings = nc->priv; - struct ndfc_controller *ndfc = &ndfc_ctrl; - struct ndfc_nand_mtd *nandmtd; - - if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS) - return -EINVAL; - - /* Set the bank settings */ - __raw_writel(settings->bank_settings, - ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2)); - nandmtd = &ndfc_mtd[pdev->id]; - if (nandmtd->pl_chip) - return -EBUSY; + ndfc->mtd.priv = chip; + ndfc->mtd.owner = THIS_MODULE; - nandmtd->pl_chip = nc; - ndfc_chip_init(nandmtd); - - /* Scan for chips */ - if (nand_scan(&nandmtd->mtd, nc->nr_chips)) { - nandmtd->pl_chip = NULL; + flash_np = of_get_next_child(node, NULL); + if (!flash_np) return -ENODEV; + + ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", + ndfc->ofdev->dev.bus_id, flash_np->name); + if (!ndfc->mtd.name) { + ret = -ENOMEM; + goto err; } -#ifdef CONFIG_MTD_PARTITIONS - printk("Number of partitions %d\n", nc->nr_partitions); - if (nc->nr_partitions) { - /* Add the full device, so complete dumps can be made */ - add_mtd_device(&nandmtd->mtd); - add_mtd_partitions(&nandmtd->mtd, nc->partitions, - nc->nr_partitions); + ret = nand_scan(&ndfc->mtd, 1); + if (ret) + goto err; - } else -#else - add_mtd_device(&nandmtd->mtd); +#ifdef CONFIG_MTD_PARTITIONS + ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); + if (ret < 0) + goto err; + +#ifdef CONFIG_MTD_OF_PARTS + if (ret == 0) { + ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, + &ndfc->parts); + if (ret < 0) + goto err; + } #endif - atomic_inc(&ndfc->childs_active); - return 0; -} + if (ret > 0) + ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret); + else +#endif + ret = add_mtd_device(&ndfc->mtd); -static int ndfc_chip_remove(struct platform_device *pdev) -{ - return 0; +err: + of_node_put(flash_np); + if (ret) + kfree(ndfc->mtd.name); + return ret; } -static int ndfc_nand_probe(struct platform_device *pdev) +static int __devinit ndfc_probe(struct of_device *ofdev, + const struct of_device_id *match) { - struct platform_nand_ctrl *nc = pdev->dev.platform_data; - struct ndfc_controller_settings *settings = nc->priv; - struct resource *res = pdev->resource; struct ndfc_controller *ndfc = &ndfc_ctrl; - unsigned long long phys = settings->ndfc_erpn | res->start; + const u32 *reg; + u32 ccr; + int err, len; -#ifndef CONFIG_PHYS_64BIT - ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); -#else - ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); -#endif + spin_lock_init(&ndfc->ndfc_control.lock); + init_waitqueue_head(&ndfc->ndfc_control.wq); + ndfc->ofdev = ofdev; + dev_set_drvdata(&ofdev->dev, ndfc); + + /* Read the reg property to get the chip select */ + reg = of_get_property(ofdev->node, "reg", &len); + if (reg == NULL || len != 12) { + dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); + return -ENOENT; + } + ndfc->chip_select = reg[0]; + + ndfc->ndfcbase = of_iomap(ofdev->node, 0); if (!ndfc->ndfcbase) { - printk(KERN_ERR "NDFC: ioremap failed\n"); + dev_err(&ofdev->dev, "failed to get memory\n"); return -EIO; } - __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); + ccr = NDFC_CCR_BS(ndfc->chip_select); - spin_lock_init(&ndfc->ndfc_control.lock); - init_waitqueue_head(&ndfc->ndfc_control.wq); + /* It is ok if ccr does not exist - just default to 0 */ + reg = of_get_property(ofdev->node, "ccr", NULL); + if (reg) + ccr |= *reg; - platform_set_drvdata(pdev, ndfc); + out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); - printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", - __raw_readl(ndfc->ndfcbase + NDFC_REVID)); + /* Set the bank settings if given */ + reg = of_get_property(ofdev->node, "bank-settings", NULL); + if (reg) { + int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); + out_be32(ndfc->ndfcbase + offset, *reg); + } + + err = ndfc_chip_init(ndfc, ofdev->node); + if (err) { + iounmap(ndfc->ndfcbase); + return err; + } return 0; } -static int ndfc_nand_remove(struct platform_device *pdev) +static int __devexit ndfc_remove(struct of_device *ofdev) { - struct ndfc_controller *ndfc = platform_get_drvdata(pdev); + struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); - if (atomic_read(&ndfc->childs_active)) - return -EBUSY; + nand_release(&ndfc->mtd); - if (ndfc) { - platform_set_drvdata(pdev, NULL); - iounmap(ndfc_ctrl.ndfcbase); - ndfc_ctrl.ndfcbase = NULL; - } return 0; } -/* driver device registration */ - -static struct platform_driver ndfc_chip_driver = { - .probe = ndfc_chip_probe, - .remove = ndfc_chip_remove, - .driver = { - .name = "ndfc-chip", - .owner = THIS_MODULE, - }, +static const struct of_device_id ndfc_match[] = { + { .compatible = "ibm,ndfc", }, + {} }; +MODULE_DEVICE_TABLE(of, ndfc_match); -static struct platform_driver ndfc_nand_driver = { - .probe = ndfc_nand_probe, - .remove = ndfc_nand_remove, - .driver = { - .name = "ndfc-nand", - .owner = THIS_MODULE, +static struct of_platform_driver ndfc_driver = { + .driver = { + .name = "ndfc", }, + .match_table = ndfc_match, + .probe = ndfc_probe, + .remove = __devexit_p(ndfc_remove), }; static int __init ndfc_nand_init(void) { - int ret; - - spin_lock_init(&ndfc_ctrl.ndfc_control.lock); - init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq); - - ret = platform_driver_register(&ndfc_nand_driver); - if (!ret) - ret = platform_driver_register(&ndfc_chip_driver); - return ret; + return of_register_platform_driver(&ndfc_driver); } static void __exit ndfc_nand_exit(void) { - platform_driver_unregister(&ndfc_chip_driver); - platform_driver_unregister(&ndfc_nand_driver); + of_unregister_platform_driver(&ndfc_driver); } module_init(ndfc_nand_init); @@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); -MODULE_DESCRIPTION("Platform driver for NDFC"); -MODULE_ALIAS("platform:ndfc-chip"); -MODULE_ALIAS("platform:ndfc-nand"); +MODULE_DESCRIPTION("OF Platform driver for NDFC"); diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index fc414449561..cc55cbc2b30 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -298,7 +298,7 @@ static struct pxa3xx_nand_flash *builtin_flash_types[] = { #define NDTR1_tAR(c) (min((c), 15) << 0) /* convert nano-seconds to nand flash controller clock cycles */ -#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) + 1) +#define ns2cycle(ns, clk) (int)(((ns) * (clk / 1000000) / 1000) - 1) static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, const struct pxa3xx_nand_timing *t) @@ -368,14 +368,14 @@ static int prepare_read_prog_cmd(struct pxa3xx_nand_info *info, /* large block, 2 cycles for column address * row address starts from 3rd cycle */ - info->ndcb1 |= (page_addr << 16) | (column & 0xffff); + info->ndcb1 |= page_addr << 16; if (info->row_addr_cycles == 3) info->ndcb2 = (page_addr >> 16) & 0xff; } else /* small block, 1 cycles for column address * row address starts from 2nd cycle */ - info->ndcb1 = (page_addr << 8) | (column & 0xff); + info->ndcb1 = page_addr << 8; if (cmd == cmdset->program) info->ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS; diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 30a518e211b..54ec7542a7b 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -2,6 +2,7 @@ * drivers/mtd/nand/sharpsl.c * * Copyright (C) 2004 Richard Purdie + * Copyright (C) 2008 Dmitry Baryshkov * * Based on Sharp's NAND driver sharp_sl.c * @@ -19,22 +20,31 @@ #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> #include <linux/mtd/partitions.h> +#include <linux/mtd/sharpsl.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> + #include <asm/io.h> #include <mach/hardware.h> #include <asm/mach-types.h> -static void __iomem *sharpsl_io_base; -static int sharpsl_phys_base = 0x0C000000; +struct sharpsl_nand { + struct mtd_info mtd; + struct nand_chip chip; + + void __iomem *io; +}; + +#define mtd_to_sharpsl(_mtd) container_of(_mtd, struct sharpsl_nand, mtd) /* register offset */ -#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */ -#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */ -#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */ -#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */ -#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */ -#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */ -#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */ +#define ECCLPLB 0x00 /* line parity 7 - 0 bit */ +#define ECCLPUB 0x04 /* line parity 15 - 8 bit */ +#define ECCCP 0x08 /* column parity 5 - 0 bit */ +#define ECCCNTR 0x0C /* ECC byte counter */ +#define ECCCLRR 0x10 /* cleare ECC */ +#define FLASHIO 0x14 /* Flash I/O */ +#define FLASHCTL 0x18 /* Flash Control */ /* Flash control bit */ #define FLRYBY (1 << 5) @@ -45,35 +55,6 @@ static int sharpsl_phys_base = 0x0C000000; #define FLCE0 (1 << 0) /* - * MTD structure for SharpSL - */ -static struct mtd_info *sharpsl_mtd = NULL; - -/* - * Define partitions for flash device - */ -#define DEFAULT_NUM_PARTITIONS 3 - -static int nr_partitions; -static struct mtd_partition sharpsl_nand_default_partition_info[] = { - { - .name = "System Area", - .offset = 0, - .size = 7 * 1024 * 1024, - }, - { - .name = "Root Filesystem", - .offset = 7 * 1024 * 1024, - .size = 30 * 1024 * 1024, - }, - { - .name = "Home Filesystem", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL, - }, -}; - -/* * hardware specific access to control-lines * ctrl: * NAND_CNE: bit 0 -> ! bit 0 & 4 @@ -84,6 +65,7 @@ static struct mtd_partition sharpsl_nand_default_partition_info[] = { static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) { + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); struct nand_chip *chip = mtd->priv; if (ctrl & NAND_CTRL_CHANGE) { @@ -93,103 +75,97 @@ static void sharpsl_nand_hwcontrol(struct mtd_info *mtd, int cmd, bits ^= 0x11; - writeb((readb(FLASHCTL) & ~0x17) | bits, FLASHCTL); + writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL); } if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W); } -static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; - -static struct nand_bbt_descr sharpsl_bbt = { - .options = 0, - .offs = 4, - .len = 2, - .pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr sharpsl_akita_bbt = { - .options = 0, - .offs = 4, - .len = 1, - .pattern = scan_ff_pattern -}; - -static struct nand_ecclayout akita_oobinfo = { - .eccbytes = 24, - .eccpos = { - 0x5, 0x1, 0x2, 0x3, 0x6, 0x7, 0x15, 0x11, - 0x12, 0x13, 0x16, 0x17, 0x25, 0x21, 0x22, 0x23, - 0x26, 0x27, 0x35, 0x31, 0x32, 0x33, 0x36, 0x37}, - .oobfree = {{0x08, 0x09}} -}; - static int sharpsl_nand_dev_ready(struct mtd_info *mtd) { - return !((readb(FLASHCTL) & FLRYBY) == 0); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0); } static void sharpsl_nand_enable_hwecc(struct mtd_info *mtd, int mode) { - writeb(0, ECCCLRR); + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + writeb(0, sharpsl->io + ECCCLRR); } static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, u_char * ecc_code) { - ecc_code[0] = ~readb(ECCLPUB); - ecc_code[1] = ~readb(ECCLPLB); - ecc_code[2] = (~readb(ECCCP) << 2) | 0x03; - return readb(ECCCNTR) != 0; + struct sharpsl_nand *sharpsl = mtd_to_sharpsl(mtd); + ecc_code[0] = ~readb(sharpsl->io + ECCLPUB); + ecc_code[1] = ~readb(sharpsl->io + ECCLPLB); + ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03; + return readb(sharpsl->io + ECCCNTR) != 0; } #ifdef CONFIG_MTD_PARTITIONS -const char *part_probes[] = { "cmdlinepart", NULL }; +static const char *part_probes[] = { "cmdlinepart", NULL }; #endif /* * Main initialization routine */ -static int __init sharpsl_nand_init(void) +static int __devinit sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; +#ifdef CONFIG_MTD_PARTITIONS struct mtd_partition *sharpsl_partition_info; + int nr_partitions; +#endif + struct resource *r; int err = 0; + struct sharpsl_nand *sharpsl; + struct sharpsl_nand_platform_data *data = pdev->dev.platform_data; + + if (!data) { + dev_err(&pdev->dev, "no platform data!\n"); + return -EINVAL; + } /* Allocate memory for MTD device structure and private data */ - sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!sharpsl_mtd) { + sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL); + if (!sharpsl) { printk("Unable to allocate SharpSL NAND MTD device structure.\n"); return -ENOMEM; } + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) { + dev_err(&pdev->dev, "no io memory resource defined!\n"); + err = -ENODEV; + goto err_get_res; + } + /* map physical address */ - sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000); - if (!sharpsl_io_base) { + sharpsl->io = ioremap(r->start, resource_size(r)); + if (!sharpsl->io) { printk("ioremap to access Sharp SL NAND chip failed\n"); - kfree(sharpsl_mtd); - return -EIO; + err = -EIO; + goto err_ioremap; } /* Get pointer to private data */ - this = (struct nand_chip *)(&sharpsl_mtd[1]); - - /* Initialize structures */ - memset(sharpsl_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); + this = (struct nand_chip *)(&sharpsl->chip); /* Link the private data with the MTD structure */ - sharpsl_mtd->priv = this; - sharpsl_mtd->owner = THIS_MODULE; + sharpsl->mtd.priv = this; + sharpsl->mtd.owner = THIS_MODULE; + + platform_set_drvdata(pdev, sharpsl); /* * PXA initialize */ - writeb(readb(FLASHCTL) | FLWP, FLASHCTL); + writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL); /* Set address of NAND IO lines */ - this->IO_ADDR_R = FLASHIO; - this->IO_ADDR_W = FLASHIO; + this->IO_ADDR_R = sharpsl->io + FLASHIO; + this->IO_ADDR_W = sharpsl->io + FLASHIO; /* Set address of hardware control function */ this->cmd_ctrl = sharpsl_nand_hwcontrol; this->dev_ready = sharpsl_nand_dev_ready; @@ -199,68 +175,89 @@ static int __init sharpsl_nand_init(void) this->ecc.mode = NAND_ECC_HW; this->ecc.size = 256; this->ecc.bytes = 3; - this->badblock_pattern = &sharpsl_bbt; - if (machine_is_akita() || machine_is_borzoi()) { - this->badblock_pattern = &sharpsl_akita_bbt; - this->ecc.layout = &akita_oobinfo; - } + this->badblock_pattern = data->badblock_pattern; + this->ecc.layout = data->ecc_layout; this->ecc.hwctl = sharpsl_nand_enable_hwecc; this->ecc.calculate = sharpsl_nand_calculate_ecc; this->ecc.correct = nand_correct_data; /* Scan to find existence of the device */ - err = nand_scan(sharpsl_mtd, 1); - if (err) { - iounmap(sharpsl_io_base); - kfree(sharpsl_mtd); - return err; - } + err = nand_scan(&sharpsl->mtd, 1); + if (err) + goto err_scan; /* Register the partitions */ - sharpsl_mtd->name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes, &sharpsl_partition_info, 0); - + sharpsl->mtd.name = "sharpsl-nand"; +#ifdef CONFIG_MTD_PARTITIONS + nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); if (nr_partitions <= 0) { - nr_partitions = DEFAULT_NUM_PARTITIONS; - sharpsl_partition_info = sharpsl_nand_default_partition_info; - if (machine_is_poodle()) { - sharpsl_partition_info[1].size = 22 * 1024 * 1024; - } else if (machine_is_corgi() || machine_is_shepherd()) { - sharpsl_partition_info[1].size = 25 * 1024 * 1024; - } else if (machine_is_husky()) { - sharpsl_partition_info[1].size = 53 * 1024 * 1024; - } else if (machine_is_spitz()) { - sharpsl_partition_info[1].size = 5 * 1024 * 1024; - } else if (machine_is_akita()) { - sharpsl_partition_info[1].size = 58 * 1024 * 1024; - } else if (machine_is_borzoi()) { - sharpsl_partition_info[1].size = 32 * 1024 * 1024; - } + nr_partitions = data->nr_partitions; + sharpsl_partition_info = data->partitions; } - add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions); + if (nr_partitions > 0) + err = add_mtd_partitions(&sharpsl->mtd, sharpsl_partition_info, nr_partitions); + else +#endif + err = add_mtd_device(&sharpsl->mtd); + if (err) + goto err_add; /* Return happy */ return 0; -} -module_init(sharpsl_nand_init); +err_add: + nand_release(&sharpsl->mtd); + +err_scan: + platform_set_drvdata(pdev, NULL); + iounmap(sharpsl->io); +err_ioremap: +err_get_res: + kfree(sharpsl); + return err; +} /* * Clean up routine */ -static void __exit sharpsl_nand_cleanup(void) +static int __devexit sharpsl_nand_remove(struct platform_device *pdev) { + struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev); + /* Release resources, unregister device */ - nand_release(sharpsl_mtd); + nand_release(&sharpsl->mtd); - iounmap(sharpsl_io_base); + platform_set_drvdata(pdev, NULL); + + iounmap(sharpsl->io); /* Free the MTD device structure */ - kfree(sharpsl_mtd); + kfree(sharpsl); + + return 0; +} + +static struct platform_driver sharpsl_nand_driver = { + .driver = { + .name = "sharpsl-nand", + .owner = THIS_MODULE, + }, + .probe = sharpsl_nand_probe, + .remove = __devexit_p(sharpsl_nand_remove), +}; + +static int __init sharpsl_nand_init(void) +{ + return platform_driver_register(&sharpsl_nand_driver); } +module_init(sharpsl_nand_init); -module_exit(sharpsl_nand_cleanup); +static void __exit sharpsl_nand_exit(void) +{ + platform_driver_unregister(&sharpsl_nand_driver); +} +module_exit(sharpsl_nand_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 320b929abe7..d1c4546513f 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -39,7 +39,7 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) struct NFTLrecord *nftl; unsigned long temp; - if (mtd->type != MTD_NANDFLASH) + if (mtd->type != MTD_NANDFLASH || mtd->size > UINT_MAX) return; /* OK, this is moderately ugly. But probably safe. Alternatives? */ if (memcmp(mtd->name, "DiskOnChip", 10)) diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index ccc4f209fbb..8b22b1836e9 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -51,7 +51,7 @@ static int find_boot_record(struct NFTLrecord *nftl) the mtd device accordingly. We could even get rid of nftl->EraseSize if there were any point in doing so. */ nftl->EraseSize = nftl->mbd.mtd->erasesize; - nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; + nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize; nftl->MediaUnit = BLOCK_NIL; nftl->SpareMediaUnit = BLOCK_NIL; @@ -168,7 +168,7 @@ device is already correct. printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", mh->UnitSizeFactor); nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); - nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; + nftl->nb_blocks = (u32)nftl->mbd.mtd->size / nftl->EraseSize; } #endif nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 90ed319f26e..529af271db1 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1772,7 +1772,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) int len; int ret = 0; - DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); + DEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%012llx, len = %llu\n", (unsigned long long) instr->addr, (unsigned long long) instr->len); block_size = (1 << this->erase_shift); @@ -1810,7 +1810,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) /* Check if we have a bad block, we do not erase bad blocks */ if (onenand_block_isbad_nolock(mtd, addr, 0)) { - printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%08x\n", (unsigned int) addr); + printk (KERN_WARNING "onenand_erase: attempt to erase a bad block at addr 0x%012llx\n", (unsigned long long) addr); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2029,7 +2029,7 @@ static int onenand_do_lock_cmd(struct mtd_info *mtd, loff_t ofs, size_t len, int * * Lock one or more blocks */ -static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; @@ -2047,7 +2047,7 @@ static int onenand_lock(struct mtd_info *mtd, loff_t ofs, size_t len) * * Unlock one or more blocks */ -static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { int ret; diff --git a/drivers/mtd/rfd_ftl.c b/drivers/mtd/rfd_ftl.c index e538c0a72ab..d2aa9c46530 100644 --- a/drivers/mtd/rfd_ftl.c +++ b/drivers/mtd/rfd_ftl.c @@ -21,8 +21,6 @@ #include <asm/types.h> -#define const_cpu_to_le16 __constant_cpu_to_le16 - static int block_size = 0; module_param(block_size, int, 0); MODULE_PARM_DESC(block_size, "Block size to use by RFD, defaults to erase unit size"); @@ -156,7 +154,7 @@ static int scan_header(struct partition *part) size_t retlen; sectors_per_block = part->block_size / SECTOR_SIZE; - part->total_blocks = part->mbd.mtd->size / part->block_size; + part->total_blocks = (u32)part->mbd.mtd->size / part->block_size; if (part->total_blocks < 2) return -ENOENT; @@ -276,16 +274,17 @@ static void erase_callback(struct erase_info *erase) part = (struct partition*)erase->priv; - i = erase->addr / part->block_size; - if (i >= part->total_blocks || part->blocks[i].offset != erase->addr) { - printk(KERN_ERR PREFIX "erase callback for unknown offset %x " - "on '%s'\n", erase->addr, part->mbd.mtd->name); + i = (u32)erase->addr / part->block_size; + if (i >= part->total_blocks || part->blocks[i].offset != erase->addr || + erase->addr > UINT_MAX) { + printk(KERN_ERR PREFIX "erase callback for unknown offset %llx " + "on '%s'\n", (unsigned long long)erase->addr, part->mbd.mtd->name); return; } if (erase->state != MTD_ERASE_DONE) { - printk(KERN_WARNING PREFIX "erase failed at 0x%x on '%s', " - "state %d\n", erase->addr, + printk(KERN_WARNING PREFIX "erase failed at 0x%llx on '%s', " + "state %d\n", (unsigned long long)erase->addr, part->mbd.mtd->name, erase->state); part->blocks[i].state = BLOCK_FAILED; @@ -297,7 +296,7 @@ static void erase_callback(struct erase_info *erase) return; } - magic = const_cpu_to_le16(RFD_MAGIC); + magic = cpu_to_le16(RFD_MAGIC); part->blocks[i].state = BLOCK_ERASED; part->blocks[i].free_sectors = part->data_sectors_per_block; @@ -345,9 +344,9 @@ static int erase_block(struct partition *part, int block) rc = part->mbd.mtd->erase(part->mbd.mtd, erase); if (rc) { - printk(KERN_ERR PREFIX "erase of region %x,%x on '%s' " - "failed\n", erase->addr, erase->len, - part->mbd.mtd->name); + printk(KERN_ERR PREFIX "erase of region %llx,%llx on '%s' " + "failed\n", (unsigned long long)erase->addr, + (unsigned long long)erase->len, part->mbd.mtd->name); kfree(erase); } @@ -587,7 +586,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr) int block, offset, rc; u_long addr; size_t retlen; - u16 del = const_cpu_to_le16(SECTOR_DELETED); + u16 del = cpu_to_le16(SECTOR_DELETED); block = old_addr / part->block_size; offset = (old_addr % part->block_size) / SECTOR_SIZE - @@ -763,7 +762,7 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { struct partition *part; - if (mtd->type != MTD_NORFLASH) + if (mtd->type != MTD_NORFLASH || mtd->size > UINT_MAX) return; part = kzalloc(sizeof(struct partition), GFP_KERNEL); diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 33a5d6ed6f1..3f67e00d98e 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -294,7 +294,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) int cis_sector; /* Check for small page NAND flash */ - if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE) + if (mtd->type != MTD_NANDFLASH || mtd->oobsize != OOB_SIZE || + mtd->size > UINT_MAX) return; /* Check for SSDFC format by reading CIS/IDI sector */ @@ -316,7 +317,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->cis_block = cis_sector / (mtd->erasesize >> SECTOR_SHIFT); ssfdc->erase_size = mtd->erasesize; - ssfdc->map_len = mtd->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", @@ -327,7 +328,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->heads = 16; ssfdc->sectors = 32; get_chs(mtd->size, NULL, &ssfdc->heads, &ssfdc->sectors); - ssfdc->cylinders = (unsigned short)((mtd->size >> SECTOR_SHIFT) / + 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", diff --git a/drivers/mtd/tests/Makefile b/drivers/mtd/tests/Makefile new file mode 100644 index 00000000000..c1d50133500 --- /dev/null +++ b/drivers/mtd/tests/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_MTD_TESTS) += mtd_oobtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_pagetest.o +obj-$(CONFIG_MTD_TESTS) += mtd_readtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_speedtest.o +obj-$(CONFIG_MTD_TESTS) += mtd_stresstest.o +obj-$(CONFIG_MTD_TESTS) += mtd_subpagetest.o +obj-$(CONFIG_MTD_TESTS) += mtd_torturetest.o diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c new file mode 100644 index 00000000000..afbc3f8126d --- /dev/null +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -0,0 +1,742 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test OOB read and write on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <asm/div64.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_oobtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *readbuf; +static unsigned char *writebuf; +static unsigned char *bbt; + +static int ebcnt; +static int pgcnt; +static int errcnt; +static int use_offset; +static int use_len; +static int use_len_max; +static int vary_offset; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + return 0; +} + +static void do_vary_offset(void) +{ + use_len -= 1; + if (use_len < 1) { + use_offset += 1; + if (use_offset >= use_len_max) + use_offset = 0; + use_len = use_len_max - use_offset; + } +} + +static int write_eraseblock(int ebnum) +{ + int i; + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { + set_random_data(writebuf, use_len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = use_len; + ops.oobretlen = 0; + ops.ooboffs = use_offset; + ops.datbuf = 0; + ops.oobbuf = writebuf; + err = mtd->write_oob(mtd, addr, &ops); + if (err || ops.oobretlen != use_len) { + printk(PRINT_PREF "error: writeoob failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "error: use_len %d, use_offset %d\n", + use_len, use_offset); + errcnt += 1; + return err ? err : -1; + } + if (vary_offset) + do_vary_offset(); + } + + return err; +} + +static int write_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + return 0; +} + +static int verify_eraseblock(int ebnum) +{ + int i; + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { + set_random_data(writebuf, use_len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = use_len; + ops.oobretlen = 0; + ops.ooboffs = use_offset; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != use_len) { + printk(PRINT_PREF "error: readoob failed at %#llx\n", + (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf, writebuf, use_len)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + return -1; + } + } + if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { + int k; + + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != mtd->ecclayout->oobavail) { + printk(PRINT_PREF "error: readoob failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf + use_offset, writebuf, use_len)) { + printk(PRINT_PREF "error: verify failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many " + "errors\n"); + return -1; + } + } + for (k = 0; k < use_offset; ++k) + if (readbuf[k] != 0xff) { + printk(PRINT_PREF "error: verify 0xff " + "failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too " + "many errors\n"); + return -1; + } + } + for (k = use_offset + use_len; + k < mtd->ecclayout->oobavail; ++k) + if (readbuf[k] != 0xff) { + printk(PRINT_PREF "error: verify 0xff " + "failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too " + "many errors\n"); + return -1; + } + } + } + if (vary_offset) + do_vary_offset(); + } + return err; +} + +static int verify_eraseblock_in_one_go(int ebnum) +{ + struct mtd_oob_ops ops; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->ecclayout->oobavail * pgcnt; + + set_random_data(writebuf, len); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = len; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err || ops.oobretlen != len) { + printk(PRINT_PREF "error: readoob failed at %#llx\n", + (long long)addr); + errcnt += 1; + return err ? err : -1; + } + if (memcmp(readbuf, writebuf, len)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + return -1; + } + } + + return err; +} + +static int verify_all_eraseblocks(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + return 0; +} + +static int is_block_bad(int ebnum) +{ + int ret; + loff_t addr = ebnum * mtd->erasesize; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_oobtest_init(void) +{ + int err = 0; + unsigned int i; + uint64_t tmp; + struct mtd_oob_ops ops; + loff_t addr = 0, addr0; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + mtd->writesize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + mtd->erasesize = mtd->erasesize; + readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!readbuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 0; + + /* First test: write all OOB, read it back and verify */ + printk(PRINT_PREF "test 1 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + simple_srand(1); + err = write_whole_device(); + if (err) + goto out; + + simple_srand(1); + err = verify_all_eraseblocks(); + if (err) + goto out; + + /* + * Second test: write all OOB, a block at a time, read it back and + * verify. + */ + printk(PRINT_PREF "test 2 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + simple_srand(3); + err = write_whole_device(); + if (err) + goto out; + + /* Check all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock_in_one_go(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + /* + * Third test: write OOB at varying offsets and lengths, read it back + * and verify. + */ + printk(PRINT_PREF "test 3 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks */ + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 1; + simple_srand(5); + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 1; + simple_srand(5); + err = verify_all_eraseblocks(); + if (err) + goto out; + + use_offset = 0; + use_len = mtd->ecclayout->oobavail; + use_len_max = mtd->ecclayout->oobavail; + vary_offset = 0; + + /* Fourth test: try to write off end of device */ + printk(PRINT_PREF "test 4 of 5\n"); + + err = erase_whole_device(); + if (err) + goto out; + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + /* Attempt to write off end of OOB */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = 1; + ops.oobretlen = 0; + ops.ooboffs = mtd->ecclayout->oobavail; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to start write past end of OOB\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, addr0, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: can write past end of OOB\n"); + errcnt += 1; + } + + /* Attempt to read off end of OOB */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = 1; + ops.oobretlen = 0; + ops.ooboffs = mtd->ecclayout->oobavail; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to start read past end of OOB\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, addr0, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: can read past end of OOB\n"); + errcnt += 1; + } + + if (bbt[ebcnt - 1]) + printk(PRINT_PREF "skipping end of device tests because last " + "block is bad\n"); + else { + /* Attempt to write off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail + 1; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to write past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: wrote past end of device\n"); + errcnt += 1; + } + + /* Attempt to read off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail + 1; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to read past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: read past end of device\n"); + errcnt += 1; + } + + err = erase_eraseblock(ebcnt - 1); + if (err) + goto out; + + /* Attempt to write off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 1; + ops.datbuf = 0; + ops.oobbuf = writebuf; + printk(PRINT_PREF "attempting to write past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->write_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: wrote past end of device\n"); + errcnt += 1; + } + + /* Attempt to read off end of device */ + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail; + ops.oobretlen = 0; + ops.ooboffs = 1; + ops.datbuf = 0; + ops.oobbuf = readbuf; + printk(PRINT_PREF "attempting to read past end of device\n"); + printk(PRINT_PREF "an error is expected...\n"); + err = mtd->read_oob(mtd, mtd->size - mtd->writesize, &ops); + if (err) { + printk(PRINT_PREF "error occurred as expected\n"); + err = 0; + } else { + printk(PRINT_PREF "error: read past end of device\n"); + errcnt += 1; + } + } + + /* Fifth test: write / read across block boundaries */ + printk(PRINT_PREF "test 5 of 5\n"); + + /* Erase all eraseblocks */ + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks */ + simple_srand(11); + printk(PRINT_PREF "writing OOBs of whole device\n"); + for (i = 0; i < ebcnt - 1; ++i) { + int cnt = 2; + int pg; + size_t sz = mtd->ecclayout->oobavail; + if (bbt[i] || bbt[i + 1]) + continue; + addr = (i + 1) * mtd->erasesize - mtd->writesize; + for (pg = 0; pg < cnt; ++pg) { + set_random_data(writebuf, sz); + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = sz; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = writebuf; + err = mtd->write_oob(mtd, addr, &ops); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock " + "%u\n", i); + cond_resched(); + addr += mtd->writesize; + } + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(11); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt - 1; ++i) { + if (bbt[i] || bbt[i + 1]) + continue; + set_random_data(writebuf, mtd->ecclayout->oobavail * 2); + addr = (i + 1) * mtd->erasesize - mtd->writesize; + ops.mode = MTD_OOB_AUTO; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->ecclayout->oobavail * 2; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = readbuf; + err = mtd->read_oob(mtd, addr, &ops); + if (err) + goto out; + if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + if (errcnt > 1000) { + printk(PRINT_PREF "error: too many errors\n"); + goto out; + } + } + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + printk(PRINT_PREF "finished with %d errors\n", errcnt); +out: + kfree(bbt); + kfree(writebuf); + kfree(readbuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_oobtest_init); + +static void __exit mtd_oobtest_exit(void) +{ + return; +} +module_exit(mtd_oobtest_exit); + +MODULE_DESCRIPTION("Out-of-band test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c new file mode 100644 index 00000000000..9648818b9e2 --- /dev/null +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -0,0 +1,632 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test page read and write on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <asm/div64.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_pagetest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *twopages; +static unsigned char *writebuf; +static unsigned char *boundary; +static unsigned char *bbt; + +static int pgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static int errcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int write_eraseblock(int ebnum) +{ + int err = 0; + size_t written = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, mtd->erasesize); + cond_resched(); + err = mtd->write(mtd, addr, mtd->erasesize, &written, writebuf); + if (err || written != mtd->erasesize) + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + + return err; +} + +static int verify_eraseblock(int ebnum) +{ + uint32_t j; + size_t read = 0; + int err = 0, i; + loff_t addr0, addrn; + loff_t addr = ebnum * mtd->erasesize; + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + addrn = mtd->size; + for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i) + addrn -= mtd->erasesize; + + set_random_data(writebuf, mtd->erasesize); + 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) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err; + } + err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)(addrn - bufsize)); + return err; + } + memset(twopages, 0, bufsize); + read = 0; + err = mtd->read(mtd, addr, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + break; + } + if (memcmp(twopages, writebuf + (j * pgsize), bufsize)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + } + /* Check boundary between eraseblocks */ + if (addr <= addrn - pgsize - pgsize && !bbt[ebnum + 1]) { + 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) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err; + } + err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)(addrn - bufsize)); + return err; + } + memset(twopages, 0, bufsize); + read = 0; + err = mtd->read(mtd, addr, bufsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != bufsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err; + } + memcpy(boundary, writebuf + mtd->erasesize - pgsize, pgsize); + set_random_data(boundary + pgsize, pgsize); + if (memcmp(twopages, boundary, bufsize)) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + next = oldnext; + } + return err; +} + +static int crosstest(void) +{ + size_t read = 0; + int err = 0, i; + loff_t addr, addr0, addrn; + unsigned char *pp1, *pp2, *pp3, *pp4; + + printk(PRINT_PREF "crosstest\n"); + pp1 = kmalloc(pgsize * 4, GFP_KERNEL); + if (!pp1) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + pp2 = pp1 + pgsize; + pp3 = pp2 + pgsize; + pp4 = pp3 + pgsize; + memset(pp1, 0, pgsize * 4); + + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) + addr0 += mtd->erasesize; + + addrn = mtd->size; + for (i = 0; bbt[ebcnt - i - 1] && i < ebcnt; ++i) + addrn -= mtd->erasesize; + + /* Read 2nd-to-last page to pp1 */ + read = 0; + addr = addrn - pgsize - pgsize; + err = mtd->read(mtd, addr, pgsize, &read, pp1); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read 3rd-to-last page to pp1 */ + read = 0; + addr = addrn - pgsize - pgsize - pgsize; + err = mtd->read(mtd, addr, pgsize, &read, pp1); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read first page to pp2 */ + read = 0; + addr = addr0; + printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + err = mtd->read(mtd, addr, pgsize, &read, pp2); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read last page to pp3 */ + read = 0; + 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) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* Read first page again to pp4 */ + read = 0; + addr = addr0; + printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); + err = mtd->read(mtd, addr, pgsize, &read, pp4); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + kfree(pp1); + return err; + } + + /* pp2 and pp4 should be the same */ + printk(PRINT_PREF "verifying pages read at %#llx match\n", + (long long)addr0); + if (memcmp(pp2, pp4, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + } else if (!err) + printk(PRINT_PREF "crosstest ok\n"); + kfree(pp1); + return err; +} + +static int erasecrosstest(void) +{ + size_t read = 0, written = 0; + int err = 0, i, ebnum, ok = 1, ebnum2; + loff_t addr0; + char *readbuf = twopages; + + printk(PRINT_PREF "erasecrosstest\n"); + + ebnum = 0; + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) { + addr0 += mtd->erasesize; + ebnum += 1; + } + + ebnum2 = ebcnt - 1; + while (ebnum2 && bbt[ebnum2]) + ebnum2 -= 1; + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + strcpy(writebuf, "There is no data like this!"); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + 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) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + if (memcmp(writebuf, readbuf, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + ok = 0; + return err; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + strcpy(writebuf, "There is no data like this!"); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum2); + err = erase_eraseblock(ebnum2); + if (err) + return err; + + 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) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d\n", ebnum); + if (memcmp(writebuf, readbuf, pgsize)) { + printk(PRINT_PREF "verify failed!\n"); + errcnt += 1; + ok = 0; + } + + if (ok && !err) + printk(PRINT_PREF "erasecrosstest ok\n"); + return err; +} + +static int erasetest(void) +{ + size_t read = 0, written = 0; + int err = 0, i, ebnum, ok = 1; + loff_t addr0; + + printk(PRINT_PREF "erasetest\n"); + + ebnum = 0; + addr0 = 0; + for (i = 0; bbt[i] && i < ebcnt; ++i) { + addr0 += mtd->erasesize; + ebnum += 1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "writing 1st page of block %d\n", ebnum); + set_random_data(writebuf, pgsize); + err = mtd->write(mtd, addr0, pgsize, &written, writebuf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "erasing block %d\n", ebnum); + err = erase_eraseblock(ebnum); + if (err) + return err; + + printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); + err = mtd->read(mtd, addr0, pgsize, &read, twopages); + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr0); + return err ? err : -1; + } + + printk(PRINT_PREF "verifying 1st page of block %d is all 0xff\n", + ebnum); + for (i = 0; i < pgsize; ++i) + if (twopages[i] != 0xff) { + printk(PRINT_PREF "verifying all 0xff failed at %d\n", + i); + errcnt += 1; + ok = 0; + break; + } + + if (ok && !err) + printk(PRINT_PREF "erasetest ok\n"); + + return err; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_pagetest_init(void) +{ + int err = 0; + uint64_t tmp; + uint32_t i; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + bufsize = pgsize * 2; + writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + twopages = kmalloc(bufsize, GFP_KERNEL); + if (!twopages) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + boundary = kmalloc(bufsize, GFP_KERNEL); + if (!boundary) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Erase all eraseblocks */ + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + + /* Write all eraseblocks */ + simple_srand(1); + printk(PRINT_PREF "writing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(1); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (err) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = crosstest(); + if (err) + goto out; + + err = erasecrosstest(); + if (err) + goto out; + + err = erasetest(); + if (err) + goto out; + + printk(PRINT_PREF "finished with %d errors\n", errcnt); +out: + + kfree(bbt); + kfree(boundary); + kfree(twopages); + kfree(writebuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_pagetest_init); + +static void __exit mtd_pagetest_exit(void) +{ + return; +} +module_exit(mtd_pagetest_exit); + +MODULE_DESCRIPTION("NAND page test"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c new file mode 100644 index 00000000000..645e77fdc63 --- /dev/null +++ b/drivers/mtd/tests/mtd_readtest.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Check MTD device read. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_readtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *iobuf; +static unsigned char *iobuf1; +static unsigned char *bbt; + +static int pgsize; +static int ebcnt; +static int pgcnt; + +static int read_eraseblock_by_page(int ebnum) +{ + size_t read = 0; + int i, ret, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + void *oobbuf = iobuf1; + + for (i = 0; i < pgcnt; i++) { + memset(buf, 0 , pgcnt); + ret = mtd->read(mtd, addr, pgsize, &read, buf); + if (ret == -EUCLEAN) + ret = 0; + if (ret || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + if (!err) + err = ret; + if (!err) + err = -EINVAL; + } + if (mtd->oobsize) { + struct mtd_oob_ops ops; + + ops.mode = MTD_OOB_PLACE; + ops.len = 0; + ops.retlen = 0; + ops.ooblen = mtd->oobsize; + ops.oobretlen = 0; + ops.ooboffs = 0; + ops.datbuf = 0; + ops.oobbuf = oobbuf; + ret = mtd->read_oob(mtd, addr, &ops); + if (ret || ops.oobretlen != mtd->oobsize) { + printk(PRINT_PREF "error: read oob failed at " + "%#llx\n", (long long)addr); + if (!err) + err = ret; + if (!err) + err = -EINVAL; + } + oobbuf += mtd->oobsize; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static void dump_eraseblock(int ebnum) +{ + int i, j, n; + char line[128]; + int pg, oob; + + printk(PRINT_PREF "dumping eraseblock %d\n", ebnum); + n = mtd->erasesize; + for (i = 0; i < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && i < n; j++, i++) + p += sprintf(p, "%02x", (unsigned int)iobuf[i]); + printk(KERN_CRIT "%s\n", line); + cond_resched(); + } + if (!mtd->oobsize) + return; + printk(PRINT_PREF "dumping oob from eraseblock %d\n", ebnum); + n = mtd->oobsize; + for (pg = 0, i = 0; pg < pgcnt; pg++) + for (oob = 0; oob < n;) { + char *p = line; + + p += sprintf(p, "%05x: ", i); + for (j = 0; j < 32 && oob < n; j++, oob++, i++) + p += sprintf(p, "%02x", + (unsigned int)iobuf1[i]); + printk(KERN_CRIT "%s\n", line); + cond_resched(); + } +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_readtest_init(void) +{ + uint64_t tmp; + int err, i; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: Cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + iobuf1 = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf1) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Read all eraseblocks 1 page at a time */ + printk(PRINT_PREF "testing page read\n"); + for (i = 0; i < ebcnt; ++i) { + int ret; + + if (bbt[i]) + continue; + ret = read_eraseblock_by_page(i); + if (ret) { + dump_eraseblock(i); + if (!err) + err = ret; + } + cond_resched(); + } + + if (err) + printk(PRINT_PREF "finished with errors\n"); + else + printk(PRINT_PREF "finished\n"); + +out: + + kfree(iobuf); + kfree(iobuf1); + kfree(bbt); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_readtest_init); + +static void __exit mtd_readtest_exit(void) +{ + return; +} +module_exit(mtd_readtest_exit); + +MODULE_DESCRIPTION("Read test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c new file mode 100644 index 00000000000..141363a7e80 --- /dev/null +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -0,0 +1,502 @@ +/* + * Copyright (C) 2007 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test read and write speed of a MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_speedtest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *iobuf; +static unsigned char *bbt; + +static int pgsize; +static int ebcnt; +static int pgcnt; +static int goodebcnt; +static struct timeval start, finish; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + return 0; +} + +static int write_eraseblock(int ebnum) +{ + size_t written = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + err = mtd->write(mtd, addr, mtd->erasesize, &written, iobuf); + if (err || written != mtd->erasesize) { + printk(PRINT_PREF "error: write failed at %#llx\n", addr); + if (!err) + err = -EINVAL; + } + + return err; +} + +static int write_eraseblock_by_page(int ebnum) +{ + size_t written = 0; + int i, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < pgcnt; i++) { + err = mtd->write(mtd, addr, pgsize, &written, buf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + break; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static int write_eraseblock_by_2pages(int ebnum) +{ + size_t written = 0, sz = pgsize * 2; + int i, n = pgcnt / 2, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < n; i++) { + err = mtd->write(mtd, addr, sz, &written, buf); + if (err || written != sz) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + return err; + } + addr += sz; + buf += sz; + } + if (pgcnt % 2) { + err = mtd->write(mtd, addr, pgsize, &written, buf); + if (err || written != pgsize) { + printk(PRINT_PREF "error: write failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + } + } + + return err; +} + +static int read_eraseblock(int ebnum) +{ + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != mtd->erasesize) { + printk(PRINT_PREF "error: read failed at %#llx\n", addr); + if (!err) + err = -EINVAL; + } + + return err; +} + +static int read_eraseblock_by_page(int ebnum) +{ + size_t read = 0; + int i, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < pgcnt; i++) { + err = mtd->read(mtd, addr, pgsize, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + break; + } + addr += pgsize; + buf += pgsize; + } + + return err; +} + +static int read_eraseblock_by_2pages(int ebnum) +{ + size_t read = 0, sz = pgsize * 2; + int i, n = pgcnt / 2, err = 0; + loff_t addr = ebnum * mtd->erasesize; + void *buf = iobuf; + + for (i = 0; i < n; i++) { + err = mtd->read(mtd, addr, sz, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != sz) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + return err; + } + addr += sz; + buf += sz; + } + if (pgcnt % 2) { + err = mtd->read(mtd, addr, pgsize, &read, buf); + /* Ignore corrected ECC errors */ + if (err == -EUCLEAN) + err = 0; + if (err || read != pgsize) { + printk(PRINT_PREF "error: read failed at %#llx\n", + addr); + if (!err) + err = -EINVAL; + } + } + + return err; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static inline void start_timing(void) +{ + do_gettimeofday(&start); +} + +static inline void stop_timing(void) +{ + do_gettimeofday(&finish); +} + +static long calc_speed(void) +{ + long ms, k, speed; + + ms = (finish.tv_sec - start.tv_sec) * 1000 + + (finish.tv_usec - start.tv_usec) / 1000; + k = goodebcnt * mtd->erasesize / 1024; + speed = (k * 1000) / ms; + return speed; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + goodebcnt = ebcnt - bad; + return 0; +} + +static int __init mtd_speedtest_init(void) +{ + int err, i; + long speed; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + iobuf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!iobuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + simple_srand(1); + set_random_data(iobuf, mtd->erasesize); + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 1 eraseblock at a time */ + printk(PRINT_PREF "testing eraseblock write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "eraseblock write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 1 eraseblock at a time */ + printk(PRINT_PREF "testing eraseblock read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "eraseblock read speed is %ld KiB/s\n", speed); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 1 page at a time */ + printk(PRINT_PREF "testing page write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock_by_page(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "page write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 1 page at a time */ + printk(PRINT_PREF "testing page read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock_by_page(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "page read speed is %ld KiB/s\n", speed); + + err = erase_whole_device(); + if (err) + goto out; + + /* Write all eraseblocks, 2 pages at a time */ + printk(PRINT_PREF "testing 2 page write speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock_by_2pages(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "2 page write speed is %ld KiB/s\n", speed); + + /* Read all eraseblocks, 2 pages at a time */ + printk(PRINT_PREF "testing 2 page read speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = read_eraseblock_by_2pages(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "2 page read speed is %ld KiB/s\n", speed); + + /* Erase all eraseblocks */ + printk(PRINT_PREF "Testing erase speed\n"); + start_timing(); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + stop_timing(); + speed = calc_speed(); + printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed); + + printk(PRINT_PREF "finished\n"); +out: + kfree(iobuf); + kfree(bbt); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_speedtest_init); + +static void __exit mtd_speedtest_exit(void) +{ + return; +} +module_exit(mtd_speedtest_exit); + +MODULE_DESCRIPTION("Speed test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c new file mode 100644 index 00000000000..63920476b57 --- /dev/null +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2006-2008 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test random reads, writes and erases on MTD device. + * + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> +#include <linux/vmalloc.h> + +#define PRINT_PREF KERN_INFO "mtd_stresstest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static int count = 10000; +module_param(count, int, S_IRUGO); +MODULE_PARM_DESC(count, "Number of operations to do (default is 10000)"); + +static struct mtd_info *mtd; +static unsigned char *writebuf; +static unsigned char *readbuf; +static unsigned char *bbt; +static int *offsets; + +static int pgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static int rand_eb(void) +{ + int eb; + +again: + if (ebcnt < 32768) + eb = simple_rand(); + else + eb = (simple_rand() << 15) | simple_rand(); + /* Read or write up 2 eraseblocks at a time - hence 'ebcnt - 1' */ + eb %= (ebcnt - 1); + if (bbt[eb]) + goto again; + return eb; +} + +static int rand_offs(void) +{ + int offs; + + if (bufsize < 32768) + offs = simple_rand(); + else + offs = (simple_rand() << 15) | simple_rand(); + offs %= bufsize; + return offs; +} + +static int rand_len(int offs) +{ + int len; + + if (bufsize < 32768) + len = simple_rand(); + else + len = (simple_rand() << 15) | simple_rand(); + len %= (bufsize - offs); + return len; +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (unlikely(err)) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (unlikely(ei.state == MTD_ERASE_FAILED)) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int do_read(void) +{ + size_t read = 0; + int eb = rand_eb(); + int offs = rand_offs(); + int len = rand_len(offs), err; + loff_t addr; + + if (bbt[eb + 1]) { + if (offs >= mtd->erasesize) + offs -= mtd->erasesize; + if (offs + len > mtd->erasesize) + len = mtd->erasesize - offs; + } + addr = eb * mtd->erasesize + offs; + err = mtd->read(mtd, addr, len, &read, readbuf); + if (err == -EUCLEAN) + err = 0; + if (unlikely(err || read != len)) { + printk(PRINT_PREF "error: read failed at 0x%llx\n", + (long long)addr); + if (!err) + err = -EINVAL; + return err; + } + return 0; +} + +static int do_write(void) +{ + int eb = rand_eb(), offs, err, len; + size_t written = 0; + loff_t addr; + + offs = offsets[eb]; + if (offs >= mtd->erasesize) { + err = erase_eraseblock(eb); + if (err) + return err; + offs = offsets[eb] = 0; + } + len = rand_len(offs); + len = ((len + pgsize - 1) / pgsize) * pgsize; + if (offs + len > mtd->erasesize) { + if (bbt[eb + 1]) + len = mtd->erasesize - offs; + else { + err = erase_eraseblock(eb + 1); + if (err) + return err; + offsets[eb + 1] = 0; + } + } + addr = eb * mtd->erasesize + offs; + err = mtd->write(mtd, addr, len, &written, writebuf); + if (unlikely(err || written != len)) { + printk(PRINT_PREF "error: write failed at 0x%llx\n", + (long long)addr); + if (!err) + err = -EINVAL; + return err; + } + offs += len; + while (offs > mtd->erasesize) { + offsets[eb++] = mtd->erasesize; + offs -= mtd->erasesize; + } + offsets[eb] = offs; + return 0; +} + +static int do_operation(void) +{ + if (simple_rand() & 1) + return do_read(); + else + return do_write(); +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_stresstest_init(void) +{ + int err; + int i, op; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, count of eraseblocks %u, pages per " + "eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + pgsize, ebcnt, pgcnt, mtd->oobsize); + + /* Read or write up 2 eraseblocks at a time */ + bufsize = mtd->erasesize * 2; + + err = -ENOMEM; + readbuf = vmalloc(bufsize); + writebuf = vmalloc(bufsize); + offsets = kmalloc(ebcnt * sizeof(int), GFP_KERNEL); + if (!readbuf || !writebuf || !offsets) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + for (i = 0; i < ebcnt; i++) + offsets[i] = mtd->erasesize; + simple_srand(current->pid); + for (i = 0; i < bufsize; i++) + writebuf[i] = simple_rand(); + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + /* Do operations */ + printk(PRINT_PREF "doing operations\n"); + for (op = 0; op < count; op++) { + if ((op & 1023) == 0) + printk(PRINT_PREF "%d operations done\n", op); + err = do_operation(); + if (err) + goto out; + cond_resched(); + } + printk(PRINT_PREF "finished, %d operations done\n", op); + +out: + kfree(offsets); + kfree(bbt); + vfree(writebuf); + vfree(readbuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_stresstest_init); + +static void __exit mtd_stresstest_exit(void) +{ + return; +} +module_exit(mtd_stresstest_exit); + +MODULE_DESCRIPTION("Stress test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c new file mode 100644 index 00000000000..5b889724268 --- /dev/null +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -0,0 +1,525 @@ +/* + * Copyright (C) 2006-2007 Nokia Corporation + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Test sub-page read and write on MTD device. + * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_subpagetest: " + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static struct mtd_info *mtd; +static unsigned char *writebuf; +static unsigned char *readbuf; +static unsigned char *bbt; + +static int subpgsize; +static int bufsize; +static int ebcnt; +static int pgcnt; +static int errcnt; +static unsigned long next = 1; + +static inline unsigned int simple_rand(void) +{ + next = next * 1103515245 + 12345; + return (unsigned int)((next / 65536) % 32768); +} + +static inline void simple_srand(unsigned long seed) +{ + next = seed; +} + +static void set_random_data(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; ++i) + buf[i] = simple_rand(); +} + +static inline void clear_data(unsigned char *buf, size_t len) +{ + memset(buf, 0, len); +} + +static int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +static int erase_whole_device(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "erasing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = erase_eraseblock(i); + if (err) + return err; + cond_resched(); + } + printk(PRINT_PREF "erased %u eraseblocks\n", i); + return 0; +} + +static int write_eraseblock(int ebnum) +{ + size_t written = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, subpgsize); + err = mtd->write(mtd, addr, subpgsize, &written, writebuf); + if (unlikely(err || written != subpgsize)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", subpgsize); + printk(PRINT_PREF " written: %#zx\n", written); + } + return err ? err : -1; + } + + addr += subpgsize; + + set_random_data(writebuf, subpgsize); + err = mtd->write(mtd, addr, subpgsize, &written, writebuf); + if (unlikely(err || written != subpgsize)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", subpgsize); + printk(PRINT_PREF " written: %#zx\n", written); + } + return err ? err : -1; + } + + return err; +} + +static int write_eraseblock2(int ebnum) +{ + size_t written = 0; + int err = 0, k; + loff_t addr = ebnum * mtd->erasesize; + + for (k = 1; k < 33; ++k) { + if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + break; + set_random_data(writebuf, subpgsize * k); + err = mtd->write(mtd, addr, subpgsize * k, &written, writebuf); + if (unlikely(err || written != subpgsize * k)) { + printk(PRINT_PREF "error: write failed at %#llx\n", + (long long)addr); + if (written != subpgsize) { + printk(PRINT_PREF " write size: %#x\n", + subpgsize * k); + printk(PRINT_PREF " written: %#08zx\n", + written); + } + return err ? err : -1; + } + addr += subpgsize * k; + } + + return err; +} + +static void print_subpage(unsigned char *p) +{ + int i, j; + + for (i = 0; i < subpgsize; ) { + for (j = 0; i < subpgsize && j < 32; ++i, ++j) + printk("%02x", *p++); + printk("\n"); + } +} + +static int verify_eraseblock(int ebnum) +{ + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + set_random_data(writebuf, subpgsize); + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "------------- written----------------\n"); + print_subpage(writebuf); + printk(PRINT_PREF "------------- read ------------------\n"); + print_subpage(readbuf); + printk(PRINT_PREF "-------------------------------------\n"); + errcnt += 1; + } + + addr += subpgsize; + + set_random_data(writebuf, subpgsize); + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at %#llx\n", + (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + printk(PRINT_PREF "------------- written----------------\n"); + print_subpage(writebuf); + printk(PRINT_PREF "------------- read ------------------\n"); + print_subpage(readbuf); + printk(PRINT_PREF "-------------------------------------\n"); + errcnt += 1; + } + + return err; +} + +static int verify_eraseblock2(int ebnum) +{ + size_t read = 0; + int err = 0, k; + loff_t addr = ebnum * mtd->erasesize; + + for (k = 1; k < 33; ++k) { + if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + break; + set_random_data(writebuf, subpgsize * k); + clear_data(readbuf, subpgsize * k); + read = 0; + err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); + if (unlikely(err || read != subpgsize * k)) { + if (err == -EUCLEAN && read == subpgsize * k) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at " + "%#llx\n", (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize * k))) { + printk(PRINT_PREF "error: verify failed at %#llx\n", + (long long)addr); + errcnt += 1; + } + addr += subpgsize * k; + } + + return err; +} + +static int verify_eraseblock_ff(int ebnum) +{ + uint32_t j; + size_t read = 0; + int err = 0; + loff_t addr = ebnum * mtd->erasesize; + + memset(writebuf, 0xff, subpgsize); + for (j = 0; j < mtd->erasesize / subpgsize; ++j) { + clear_data(readbuf, subpgsize); + read = 0; + err = mtd->read(mtd, addr, subpgsize, &read, readbuf); + if (unlikely(err || read != subpgsize)) { + if (err == -EUCLEAN && read == subpgsize) { + printk(PRINT_PREF "ECC correction at %#llx\n", + (long long)addr); + err = 0; + } else { + printk(PRINT_PREF "error: read failed at " + "%#llx\n", (long long)addr); + return err ? err : -1; + } + } + if (unlikely(memcmp(readbuf, writebuf, subpgsize))) { + printk(PRINT_PREF "error: verify 0xff failed at " + "%#llx\n", (long long)addr); + errcnt += 1; + } + addr += subpgsize; + } + + return err; +} + +static int verify_all_eraseblocks_ff(void) +{ + int err; + unsigned int i; + + printk(PRINT_PREF "verifying all eraseblocks for 0xff\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock_ff(i); + if (err) + return err; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + return 0; +} + +static int is_block_bad(int ebnum) +{ + loff_t addr = ebnum * mtd->erasesize; + int ret; + + ret = mtd->block_isbad(mtd, addr); + if (ret) + printk(PRINT_PREF "block %d is bad\n", ebnum); + return ret; +} + +static int scan_for_bad_eraseblocks(void) +{ + int i, bad = 0; + + bbt = kmalloc(ebcnt, GFP_KERNEL); + if (!bbt) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + return -ENOMEM; + } + memset(bbt, 0 , ebcnt); + + printk(PRINT_PREF "scanning for bad eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + bbt[i] = is_block_bad(i) ? 1 : 0; + if (bbt[i]) + bad += 1; + cond_resched(); + } + printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); + return 0; +} + +static int __init mtd_subpagetest_init(void) +{ + int err = 0; + uint32_t i; + uint64_t tmp; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->type != MTD_NANDFLASH) { + printk(PRINT_PREF "this test requires NAND flash\n"); + goto out; + } + + subpgsize = mtd->writesize >> mtd->subpage_sft; + printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " + "page size %u, subpage size %u, count of eraseblocks %u, " + "pages per eraseblock %u, OOB size %u\n", + (unsigned long long)mtd->size, mtd->erasesize, + mtd->writesize, subpgsize, ebcnt, pgcnt, mtd->oobsize); + + err = -ENOMEM; + bufsize = subpgsize * 32; + writebuf = kmalloc(bufsize, GFP_KERNEL); + if (!writebuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + readbuf = kmalloc(bufsize, GFP_KERNEL); + if (!readbuf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out; + } + + tmp = mtd->size; + do_div(tmp, mtd->erasesize); + ebcnt = tmp; + pgcnt = mtd->erasesize / mtd->writesize; + + err = scan_for_bad_eraseblocks(); + if (err) + goto out; + + err = erase_whole_device(); + if (err) + goto out; + + printk(PRINT_PREF "writing whole device\n"); + simple_srand(1); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + simple_srand(1); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = erase_whole_device(); + if (err) + goto out; + + err = verify_all_eraseblocks_ff(); + if (err) + goto out; + + /* Write all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "writing whole device\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = write_eraseblock2(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "written up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "written %u eraseblocks\n", i); + + /* Check all eraseblocks */ + simple_srand(3); + printk(PRINT_PREF "verifying all eraseblocks\n"); + for (i = 0; i < ebcnt; ++i) { + if (bbt[i]) + continue; + err = verify_eraseblock2(i); + if (unlikely(err)) + goto out; + if (i % 256 == 0) + printk(PRINT_PREF "verified up to eraseblock %u\n", i); + cond_resched(); + } + printk(PRINT_PREF "verified %u eraseblocks\n", i); + + err = erase_whole_device(); + if (err) + goto out; + + err = verify_all_eraseblocks_ff(); + if (err) + goto out; + + printk(PRINT_PREF "finished with %d errors\n", errcnt); + +out: + kfree(bbt); + kfree(readbuf); + kfree(writebuf); + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(mtd_subpagetest_init); + +static void __exit mtd_subpagetest_exit(void) +{ + return; +} +module_exit(mtd_subpagetest_exit); + +MODULE_DESCRIPTION("Subpage test module"); +MODULE_AUTHOR("Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c new file mode 100644 index 00000000000..631a0ab3a33 --- /dev/null +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -0,0 +1,530 @@ +/* + * Copyright (C) 2006-2008 Artem Bityutskiy + * Copyright (C) 2006-2008 Jarkko Lavinen + * Copyright (C) 2006-2008 Adrian Hunter + * + * 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. + * + * 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; see the file COPYING. If not, write to the Free Software + * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Authors: Artem Bityutskiy, Jarkko Lavinen, Adria Hunter + * + * WARNING: this test program may kill your flash and your device. Do not + * use it unless you know what you do. Authors are not responsible for any + * damage caused by this program. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/err.h> +#include <linux/mtd/mtd.h> +#include <linux/sched.h> + +#define PRINT_PREF KERN_INFO "mtd_torturetest: " +#define RETRIES 3 + +static int eb = 8; +module_param(eb, int, S_IRUGO); +MODULE_PARM_DESC(eb, "eraseblock number within the selected MTD device"); + +static int ebcnt = 32; +module_param(ebcnt, int, S_IRUGO); +MODULE_PARM_DESC(ebcnt, "number of consecutive eraseblocks to torture"); + +static int pgcnt; +module_param(pgcnt, int, S_IRUGO); +MODULE_PARM_DESC(pgcnt, "number of pages per eraseblock to torture (0 => all)"); + +static int dev; +module_param(dev, int, S_IRUGO); +MODULE_PARM_DESC(dev, "MTD device number to use"); + +static int gran = 512; +module_param(gran, int, S_IRUGO); +MODULE_PARM_DESC(gran, "how often the status information should be printed"); + +static int check = 1; +module_param(check, int, S_IRUGO); +MODULE_PARM_DESC(check, "if the written data should be checked"); + +static unsigned int cycles_count; +module_param(cycles_count, uint, S_IRUGO); +MODULE_PARM_DESC(cycles_count, "how many erase cycles to do " + "(infinite by default)"); + +static struct mtd_info *mtd; + +/* This buffer contains 0x555555...0xAAAAAA... pattern */ +static unsigned char *patt_5A5; +/* This buffer contains 0xAAAAAA...0x555555... pattern */ +static unsigned char *patt_A5A; +/* This buffer contains all 0xFF bytes */ +static unsigned char *patt_FF; +/* This a temporary buffer is use when checking data */ +static unsigned char *check_buf; +/* How many erase cycles were done */ +static unsigned int erase_cycles; + +static int pgsize; +static struct timeval start, finish; + +static void report_corrupt(unsigned char *read, unsigned char *written); + +static inline void start_timing(void) +{ + do_gettimeofday(&start); +} + +static inline void stop_timing(void) +{ + do_gettimeofday(&finish); +} + +/* + * Erase eraseblock number @ebnum. + */ +static inline int erase_eraseblock(int ebnum) +{ + int err; + struct erase_info ei; + loff_t addr = ebnum * mtd->erasesize; + + memset(&ei, 0, sizeof(struct erase_info)); + ei.mtd = mtd; + ei.addr = addr; + ei.len = mtd->erasesize; + + err = mtd->erase(mtd, &ei); + if (err) { + printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); + return err; + } + + if (ei.state == MTD_ERASE_FAILED) { + printk(PRINT_PREF "some erase error occurred at EB %d\n", + ebnum); + return -EIO; + } + + return 0; +} + +/* + * Check that the contents of eraseblock number @enbum is equivalent to the + * @buf buffer. + */ +static inline int check_eraseblock(int ebnum, unsigned char *buf) +{ + int err, retries = 0; + size_t read = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->erasesize; + + if (pgcnt) { + addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + len = pgcnt * pgsize; + } + +retry: + err = mtd->read(mtd, addr, len, &read, check_buf); + if (err == -EUCLEAN) + printk(PRINT_PREF "single bit flip occurred at EB %d " + "MTD reported that it was fixed.\n", ebnum); + else if (err) { + printk(PRINT_PREF "error %d while reading EB %d, " + "read %zd\n", err, ebnum, read); + return err; + } + + if (read != len) { + printk(PRINT_PREF "failed to read %zd bytes from EB %d, " + "read only %zd, but no error reported\n", + len, ebnum, read); + return -EIO; + } + + if (memcmp(buf, check_buf, len)) { + printk(PRINT_PREF "read wrong data from EB %d\n", ebnum); + report_corrupt(check_buf, buf); + + if (retries++ < RETRIES) { + /* Try read again */ + yield(); + printk(PRINT_PREF "re-try reading data from EB %d\n", + ebnum); + goto retry; + } else { + printk(PRINT_PREF "retried %d times, still errors, " + "give-up\n", RETRIES); + return -EINVAL; + } + } + + if (retries != 0) + printk(PRINT_PREF "only attempt number %d was OK (!!!)\n", + retries); + + return 0; +} + +static inline int write_pattern(int ebnum, void *buf) +{ + int err; + size_t written = 0; + loff_t addr = ebnum * mtd->erasesize; + size_t len = mtd->erasesize; + + if (pgcnt) { + addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + len = pgcnt * pgsize; + } + err = mtd->write(mtd, addr, len, &written, buf); + if (err) { + printk(PRINT_PREF "error %d while writing EB %d, written %zd" + " bytes\n", err, ebnum, written); + return err; + } + if (written != len) { + printk(PRINT_PREF "written only %zd bytes of %zd, but no error" + " reported\n", written, len); + return -EIO; + } + + return 0; +} + +static int __init tort_init(void) +{ + int err = 0, i, infinite = !cycles_count; + int bad_ebs[ebcnt]; + + printk(KERN_INFO "\n"); + printk(KERN_INFO "=================================================\n"); + printk(PRINT_PREF "Warning: this program is trying to wear out your " + "flash, stop it if this is not wanted.\n"); + printk(PRINT_PREF "MTD device: %d\n", dev); + printk(PRINT_PREF "torture %d eraseblocks (%d-%d) of mtd%d\n", + ebcnt, eb, eb + ebcnt - 1, dev); + if (pgcnt) + printk(PRINT_PREF "torturing just %d pages per eraseblock\n", + pgcnt); + printk(PRINT_PREF "write verify %s\n", check ? "enabled" : "disabled"); + + mtd = get_mtd_device(NULL, dev); + if (IS_ERR(mtd)) { + err = PTR_ERR(mtd); + printk(PRINT_PREF "error: cannot get MTD device\n"); + return err; + } + + if (mtd->writesize == 1) { + printk(PRINT_PREF "not NAND flash, assume page size is 512 " + "bytes.\n"); + pgsize = 512; + } else + pgsize = mtd->writesize; + + if (pgcnt && (pgcnt > mtd->erasesize / pgsize || pgcnt < 0)) { + printk(PRINT_PREF "error: invalid pgcnt value %d\n", pgcnt); + goto out_mtd; + } + + err = -ENOMEM; + patt_5A5 = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_5A5) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_mtd; + } + + patt_A5A = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_A5A) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_5A5; + } + + patt_FF = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!patt_FF) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_A5A; + } + + check_buf = kmalloc(mtd->erasesize, GFP_KERNEL); + if (!check_buf) { + printk(PRINT_PREF "error: cannot allocate memory\n"); + goto out_patt_FF; + } + + err = 0; + + /* Initialize patterns */ + memset(patt_FF, 0xFF, mtd->erasesize); + for (i = 0; i < mtd->erasesize / pgsize; i++) { + if (!(i & 1)) { + memset(patt_5A5 + i * pgsize, 0x55, pgsize); + memset(patt_A5A + i * pgsize, 0xAA, pgsize); + } else { + memset(patt_5A5 + i * pgsize, 0xAA, pgsize); + memset(patt_A5A + i * pgsize, 0x55, pgsize); + } + } + + /* + * Check if there is a bad eraseblock among those we are going to test. + */ + memset(&bad_ebs[0], 0, sizeof(int) * ebcnt); + if (mtd->block_isbad) { + for (i = eb; i < eb + ebcnt; i++) { + err = mtd->block_isbad(mtd, + (loff_t)i * mtd->erasesize); + + if (err < 0) { + printk(PRINT_PREF "block_isbad() returned %d " + "for EB %d\n", err, i); + goto out; + } + + if (err) { + printk("EB %d is bad. Skip it.\n", i); + bad_ebs[i - eb] = 1; + } + } + } + + start_timing(); + while (1) { + int i; + void *patt; + + /* Erase all eraseblocks */ + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + err = erase_eraseblock(i); + if (err) + goto out; + cond_resched(); + } + + /* Check if the eraseblocks contain only 0xFF bytes */ + if (check) { + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + err = check_eraseblock(i, patt_FF); + if (err) { + printk(PRINT_PREF "verify failed" + " for 0xFF... pattern\n"); + goto out; + } + cond_resched(); + } + } + + /* Write the pattern */ + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + if ((eb + erase_cycles) & 1) + patt = patt_5A5; + else + patt = patt_A5A; + err = write_pattern(i, patt); + if (err) + goto out; + cond_resched(); + } + + /* Verify what we wrote */ + if (check) { + for (i = eb; i < eb + ebcnt; i++) { + if (bad_ebs[i - eb]) + continue; + if ((eb + erase_cycles) & 1) + patt = patt_5A5; + else + patt = patt_A5A; + err = check_eraseblock(i, patt); + if (err) { + printk(PRINT_PREF "verify failed for %s" + " pattern\n", + ((eb + erase_cycles) & 1) ? + "0x55AA55..." : "0xAA55AA..."); + goto out; + } + cond_resched(); + } + } + + erase_cycles += 1; + + if (erase_cycles % gran == 0) { + long ms; + + stop_timing(); + ms = (finish.tv_sec - start.tv_sec) * 1000 + + (finish.tv_usec - start.tv_usec) / 1000; + printk(PRINT_PREF "%08u erase cycles done, took %lu " + "milliseconds (%lu seconds)\n", + erase_cycles, ms, ms / 1000); + start_timing(); + } + + if (!infinite && --cycles_count == 0) + break; + } +out: + + printk(PRINT_PREF "finished after %u erase cycles\n", + erase_cycles); + kfree(check_buf); +out_patt_FF: + kfree(patt_FF); +out_patt_A5A: + kfree(patt_A5A); +out_patt_5A5: + kfree(patt_5A5); +out_mtd: + put_mtd_device(mtd); + if (err) + printk(PRINT_PREF "error %d occurred during torturing\n", err); + printk(KERN_INFO "=================================================\n"); + return err; +} +module_init(tort_init); + +static void __exit tort_exit(void) +{ + return; +} +module_exit(tort_exit); + +static int countdiffs(unsigned char *buf, unsigned char *check_buf, + unsigned offset, unsigned len, unsigned *bytesp, + unsigned *bitsp); +static void print_bufs(unsigned char *read, unsigned char *written, int start, + int len); + +/* + * Report the detailed information about how the read EB differs from what was + * written. + */ +static void report_corrupt(unsigned char *read, unsigned char *written) +{ + int i; + int bytes, bits, pages, first; + int offset, len; + size_t check_len = mtd->erasesize; + + if (pgcnt) + check_len = pgcnt * pgsize; + + bytes = bits = pages = 0; + for (i = 0; i < check_len; i += pgsize) + if (countdiffs(written, read, i, pgsize, &bytes, + &bits) >= 0) + pages++; + + printk(PRINT_PREF "verify fails on %d pages, %d bytes/%d bits\n", + pages, bytes, bits); + printk(PRINT_PREF "The following is a list of all differences between" + " what was read from flash and what was expected\n"); + + for (i = 0; i < check_len; i += pgsize) { + cond_resched(); + bytes = bits = 0; + first = countdiffs(written, read, i, pgsize, &bytes, + &bits); + if (first < 0) + continue; + + printk("-------------------------------------------------------" + "----------------------------------\n"); + + printk(PRINT_PREF "Page %zd has %d bytes/%d bits failing verify," + " starting at offset 0x%x\n", + (mtd->erasesize - check_len + i) / pgsize, + bytes, bits, first); + + offset = first & ~0x7; + len = ((first + bytes) | 0x7) + 1 - offset; + + print_bufs(read, written, offset, len); + } +} + +static void print_bufs(unsigned char *read, unsigned char *written, int start, + int len) +{ + int i = 0, j1, j2; + char *diff; + + printk("Offset Read Written\n"); + while (i < len) { + printk("0x%08x: ", start + i); + diff = " "; + for (j1 = 0; j1 < 8 && i + j1 < len; j1++) { + printk(" %02x", read[start + i + j1]); + if (read[start + i + j1] != written[start + i + j1]) + diff = "***"; + } + + while (j1 < 8) { + printk(" "); + j1 += 1; + } + + printk(" %s ", diff); + + for (j2 = 0; j2 < 8 && i + j2 < len; j2++) + printk(" %02x", written[start + i + j2]); + printk("\n"); + i += 8; + } +} + +/* + * Count the number of differing bytes and bits and return the first differing + * offset. + */ +static int countdiffs(unsigned char *buf, unsigned char *check_buf, + unsigned offset, unsigned len, unsigned *bytesp, + unsigned *bitsp) +{ + unsigned i, bit; + int first = -1; + + for (i = offset; i < offset + len; i++) + if (buf[i] != check_buf[i]) { + first = i; + break; + } + + while (i < offset + len) { + if (buf[i] != check_buf[i]) { + (*bytesp)++; + bit = 1; + while (bit < 256) { + if ((buf[i] & bit) != (check_buf[i] & bit)) + (*bitsp)++; + bit <<= 1; + } + } + i++; + } + + return first; +} + +MODULE_DESCRIPTION("Eraseblock torturing module"); +MODULE_AUTHOR("Artem Bityutskiy, Jarkko Lavinen, Adrian Hunter"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 7caf22cd5ad..9082768cc6c 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -561,7 +561,7 @@ static int io_init(struct ubi_device *ubi) */ ubi->peb_size = ubi->mtd->erasesize; - ubi->peb_count = ubi->mtd->size / ubi->mtd->erasesize; + ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd); ubi->flash_size = ubi->mtd->size; if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) diff --git a/drivers/mtd/ubi/gluebi.c b/drivers/mtd/ubi/gluebi.c index 605812bb0b1..6dd4f5e77f8 100644 --- a/drivers/mtd/ubi/gluebi.c +++ b/drivers/mtd/ubi/gluebi.c @@ -215,7 +215,8 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) struct ubi_volume *vol; struct ubi_device *ubi; - dbg_gen("erase %u bytes at offset %u", instr->len, instr->addr); + dbg_gen("erase %llu bytes at offset %llu", (unsigned long long)instr->len, + (unsigned long long)instr->addr); if (instr->addr < 0 || instr->addr > mtd->size - mtd->erasesize) return -EINVAL; @@ -223,11 +224,11 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) if (instr->len < 0 || instr->addr + instr->len > mtd->size) return -EINVAL; - if (instr->addr % mtd->writesize || instr->len % mtd->writesize) + if (mtd_mod_by_ws(instr->addr, mtd) || mtd_mod_by_ws(instr->len, mtd)) return -EINVAL; - lnum = instr->addr / mtd->erasesize; - count = instr->len / mtd->erasesize; + lnum = mtd_div_by_eb(instr->addr, mtd); + count = mtd_div_by_eb(instr->len, mtd); vol = container_of(mtd, struct ubi_volume, gluebi_mtd); ubi = vol->ubi; @@ -255,7 +256,7 @@ static int gluebi_erase(struct mtd_info *mtd, struct erase_info *instr) out_err: instr->state = MTD_ERASE_FAILED; - instr->fail_addr = lnum * mtd->erasesize; + instr->fail_addr = (long long)lnum * mtd->erasesize; return err; } @@ -294,7 +295,7 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) * bytes. */ if (vol->vol_type == UBI_DYNAMIC_VOLUME) - mtd->size = vol->usable_leb_size * vol->reserved_pebs; + mtd->size = (long long)vol->usable_leb_size * vol->reserved_pebs; else mtd->size = vol->used_bytes; @@ -304,8 +305,8 @@ int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol) return -ENFILE; } - dbg_gen("added mtd%d (\"%s\"), size %u, EB size %u", - mtd->index, mtd->name, mtd->size, mtd->erasesize); + dbg_gen("added mtd%d (\"%s\"), size %llu, EB size %u", + mtd->index, mtd->name, (unsigned long long)mtd->size, mtd->erasesize); return 0; } diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 5d9bcf109c1..4abbe573fa4 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -564,7 +564,7 @@ EXPORT_SYMBOL_GPL(ubi_leb_unmap); * @dtype: expected data type * * This function maps an un-mapped logical eraseblock @lnum to a physical - * eraseblock. This means, that after a successfull invocation of this + * eraseblock. This means, that after a successful invocation of this * function the logical eraseblock @lnum will be empty (contain only %0xFF * bytes) and be mapped to a physical eraseblock, even if an unclean reboot * happens. diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index c092c392922..5b91a85fe10 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -177,6 +177,7 @@ static const struct net_device_ops el2_netdev_ops = { .ndo_get_stats = eip_get_stats, .ndo_set_multicast_list = eip_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = eip_poll, diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 665e7fdf27a..cdbbb6226fc 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -3109,6 +3109,8 @@ static void acpi_set_WOL(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; + device_set_wakeup_enable(vp->gendev, vp->enable_wol); + if (vp->enable_wol) { /* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */ EL3WINDOW(7); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index dd7ac8290ae..4e19ae3ce6b 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1821,6 +1821,7 @@ static const struct net_device_ops cp_netdev_ops = { .ndo_open = cp_open, .ndo_stop = cp_close, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_set_multicast_list = cp_set_rx_mode, .ndo_get_stats = cp_get_stats, .ndo_do_ioctl = cp_ioctl, @@ -1832,6 +1833,7 @@ static const struct net_device_ops cp_netdev_ops = { #ifdef BROKEN .ndo_change_mtu = cp_change_mtu, #endif + #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cp_poll_controller, #endif diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index fe370f80579..a5b24202d56 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -917,6 +917,7 @@ static const struct net_device_ops rtl8139_netdev_ops = { .ndo_stop = rtl8139_close, .ndo_get_stats = rtl8139_get_stats, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_start_xmit = rtl8139_start_xmit, .ndo_set_multicast_list = rtl8139_set_rx_mode, .ndo_do_ioctl = netdev_ioctl, @@ -924,7 +925,6 @@ static const struct net_device_ops rtl8139_netdev_ops = { #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = rtl8139_poll_controller, #endif - }; static int __devinit rtl8139_init_one (struct pci_dev *pdev, diff --git a/drivers/net/8390.c b/drivers/net/8390.c index fbe609a51e0..ec3e22e6306 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -63,6 +63,7 @@ const struct net_device_ops ei_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index ee70b358a81..da863c91d1d 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -68,6 +68,7 @@ const struct net_device_ops eip_netdev_ops = { .ndo_get_stats = eip_get_stats, .ndo_set_multicast_list = eip_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = eip_poll, diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 97ea7c60e00..9fe8cb7d43a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -830,7 +830,7 @@ config ULTRA32 config BFIN_MAC tristate "Blackfin on-chip MAC support" - depends on NET_ETHERNET && (BF526 || BF527 || BF536 || BF537) + depends on NET_ETHERNET && (BF516 || BF518 || BF526 || BF527 || BF536 || BF537) select CRC32 select MII select PHYLIB @@ -1600,7 +1600,7 @@ config 8139_OLD_RX_RESET old RX-reset behavior. If unsure, say N. config R6040 - tristate "RDC R6040 Fast Ethernet Adapter support (EXPERIMENTAL)" + tristate "RDC R6040 Fast Ethernet Adapter support" depends on NET_PCI && PCI select CRC32 select MII diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 5b396ff6c83..9589d620639 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -460,6 +460,7 @@ static const struct net_device_ops ace_netdev_ops = { .ndo_get_stats = ace_get_stats, .ndo_start_xmit = ace_start_xmit, .ndo_set_multicast_list = ace_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = ace_set_mac_addr, .ndo_change_mtu = ace_change_mtu, #if ACENIC_DO_VLAN diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h deleted file mode 100644 index fd41f7887e2..00000000000 --- a/drivers/net/acenic_firmware.h +++ /dev/null @@ -1,9456 +0,0 @@ -/* - * Declare these here even if Tigon I support is disabled to avoid - * the compiler complaining about undefined symbols. - */ -#define tigonFwReleaseMajor 0xc -#define tigonFwReleaseMinor 0x4 -#define tigonFwReleaseFix 0xb -#define tigonFwStartAddr 0x00004000 -#define tigonFwTextAddr 0x00004000 -#define tigonFwTextLen 0x11140 -#define tigonFwRodataAddr 0x00015140 -#define tigonFwRodataLen 0xac0 -#define tigonFwDataAddr 0x00015c20 -#define tigonFwDataLen 0x170 -#define tigonFwSbssAddr 0x00015d90 -#define tigonFwSbssLen 0x38 -#define tigonFwBssAddr 0x00015dd0 -#define tigonFwBssLen 0x2080 -#ifdef CONFIG_ACENIC_OMIT_TIGON_I -#define tigonFwText NULL -#define tigonFwData NULL -#define tigonFwRodata NULL -#else -/* Generated by genfw.c */ -static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { -0x10000003, -0x0, 0xd, 0xd, 0x3c1d0001, -0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, -0xc00100c, 0x0, 0xd, 0x27bdffd8, -0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, -0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, -0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8, -0x0, 0x3c040001, 0x248451a4, 0x24050001, -0x2e03021, 0x3821, 0x3c100001, 0x26107e50, -0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f, -0x3442ffff, 0x2021024, 0x362102b, 0x10400009, -0x24050003, 0x3c040001, 0x248451b0, 0x2003021, -0x3603821, 0x3c020010, 0xafa20010, 0xc002403, -0xafa00014, 0x2021, 0x3405c000, 0x3c010001, -0x370821, 0xa02083b0, 0x3c010001, 0x370821, -0xa02083b2, 0x3c010001, 0x370821, 0xa02083b3, -0x3c010001, 0x370821, 0xac2083b4, 0xa2e004d8, -0x418c0, 0x24840001, 0x771021, 0xac40727c, -0x771021, 0xac407280, 0x2e31021, 0xa445727c, -0x2c820020, 0x1440fff7, 0x418c0, 0x2021, -0x3405c000, 0x418c0, 0x24840001, 0x771021, -0xac40737c, 0x771021, 0xac407380, 0x2e31021, -0xa445737c, 0x2c820080, 0x5440fff7, 0x418c0, -0xaf800054, 0xaf80011c, 0x8f820044, 0x34420040, -0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, -0x8f420218, 0x30420002, 0x10400009, 0x0, -0x8f420220, 0x3c030002, 0x34630004, 0x431025, -0xaee204c4, 0x8f42021c, 0x8001074, 0x34420004, -0x8f420220, 0x3c030002, 0x34630006, 0x431025, -0xaee204c4, 0x8f42021c, 0x34420006, 0xaee204cc, -0x8f420218, 0x30420010, 0x1040000a, 0x0, -0x8f42021c, 0x34420004, 0xaee204c8, 0x8f420220, -0x3c03000a, 0x34630004, 0x431025, 0x800108a, -0xaee204c0, 0x8f420220, 0x3c03000a, 0x34630006, -0x431025, 0xaee204c0, 0x8f42021c, 0x34420006, -0xaee204c8, 0x8f420218, 0x30420200, 0x10400003, -0x24020001, 0x8001091, 0xa2e27248, 0xa2e07248, -0x24020001, 0xaf8200a0, 0xaf8200b0, 0x8f830054, -0x8f820054, 0x8001099, 0x24630064, 0x8f820054, -0x621023, 0x2c420065, 0x1440fffc, 0x0, -0xaf800044, 0x8f420208, 0x8f43020c, 0xaee20010, -0xaee30014, 0x8ee40010, 0x8ee50014, 0x26e20030, -0xaee20028, 0x24020490, 0xaee20018, 0xaf840090, -0xaf850094, 0x8ee20028, 0xaf8200b4, 0x96e2001a, -0xaf82009c, 0x8f8200b0, 0x8ee304cc, 0x431025, -0xaf8200b0, 0x8f8200b0, 0x30420004, 0x1440fffd, -0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc, -0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, -0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, -0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014, -0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021, -0x26e40030, 0xc002488, 0x24050400, 0x27440080, -0xc002488, 0x24050080, 0x26e4777c, 0xc002488, -0x24050400, 0x8f42025c, 0x26e40094, 0xaee20060, -0x8f420260, 0x27450200, 0x24060008, 0xaee20068, -0x24020006, 0xc00249a, 0xaee20064, 0x3c023b9a, -0x3442ca00, 0x2021, 0x24030002, 0xaee30074, -0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, -0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, -0x641821, 0x90635c20, 0x2e41021, 0x24840001, -0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, -0x8f820040, 0x2e41821, 0x24840001, 0x21702, -0x24420030, 0xa062009c, 0x2e41021, 0xa040009c, -0x96e2046a, 0x30420003, 0x14400009, 0x0, -0x96e2047a, 0x30420003, 0x50400131, 0x3c030800, -0x96e2046a, 0x30420003, 0x1040002a, 0x3c020700, -0x96e2047a, 0x30420003, 0x10400026, 0x3c020700, -0x96e3047a, 0x96e2046a, 0x14620022, 0x3c020700, -0x8ee204c0, 0x24030001, 0xa2e34e20, 0x34420e00, -0xaee204c0, 0x8f420218, 0x30420100, 0x10400005, -0x0, 0x3c020001, 0x2442e168, 0x800111d, -0x21100, 0x3c020001, 0x2442d35c, 0x21100, -0x21182, 0x3c030800, 0x431025, 0x3c010001, -0xac221238, 0x3c020001, 0x2442f680, 0x21100, -0x21182, 0x3c030800, 0x431025, 0x3c010001, -0xac221278, 0x8ee20000, 0x34424000, 0x8001238, -0xaee20000, 0x34423000, 0xafa20018, 0x8ee20608, -0x8f430228, 0x24420001, 0x304900ff, 0x512300e2, -0xafa00010, 0x8ee20608, 0x210c0, 0x571021, -0x8fa30018, 0x8fa4001c, 0xac43060c, 0xac440610, -0x8f870120, 0x27623800, 0x24e80020, 0x102102b, -0x50400001, 0x27683000, 0x8f820128, 0x11020004, -0x0, 0x8f820124, 0x15020007, 0x1021, -0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4, -0x80011a0, 0x8ee201a4, 0x8ee40608, 0x420c0, -0x801821, 0x8ee40430, 0x8ee50434, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xace40000, -0xace50004, 0x8ee30608, 0x24020008, 0xa4e2000e, -0x2402000d, 0xace20018, 0xace9001c, 0x318c0, -0x2463060c, 0x2e31021, 0xace20008, 0x8ee204c4, -0xace20010, 0xaf880120, 0x92e24e20, 0x14400037, -0x24060001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, -0x0, 0x8ee24e34, 0x24420001, 0x10a20005, -0x0, 0x800118a, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80011a0, 0x0, 0x8ee24e30, -0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x24020007, -0xac820000, 0x24020001, 0xac820004, 0x54c0000c, -0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010, -0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f000, 0x8001223, 0x0, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x3021, 0x24420001, 0xaee201a4, -0x8001207, 0x8ee201a4, 0x8ee20608, 0xac62001c, -0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400037, 0x24060001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c830000, 0x24020012, 0x1462001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee54e30, 0x24420001, 0x10430007, 0x0, -0x8ee24e34, 0x24420001, 0x10a20005, 0x0, -0x80011f1, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8001207, 0x0, 0x8ee24e30, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020012, 0xac820000, -0x24020001, 0xac820004, 0x14c0001b, 0x0, -0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, -0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc, -0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, -0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, -0x248451e8, 0x3405f001, 0x24420001, 0xaee20160, -0x8ee20160, 0x3021, 0x3821, 0xafa00010, -0xc002403, 0xafa00014, 0x8001238, 0x0, -0x3c020001, 0x2442f5a8, 0x21100, 0x21182, -0x431025, 0x3c010001, 0xac221278, 0x96e2045a, -0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, -0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, -0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec, -0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, -0x2442a390, 0x451024, 0x21082, 0xaee304c8, -0x3c030800, 0x431025, 0x3c010001, 0xac221220, -0x3c020001, 0x2442add4, 0x451024, 0x21082, -0x431025, 0x3c010001, 0xac221280, 0x96e6045a, -0x3821, 0x24050011, 0xafa00010, 0xc002403, -0xafa00014, 0x8001268, 0x0, 0x3c020001, -0x2442a9d4, 0x21100, 0x21182, 0x3c030800, -0x431025, 0x3c010001, 0xac221280, 0x96e2046a, -0x30420010, 0x14400009, 0x0, 0x96e2047a, -0x30420010, 0x10400112, 0x0, 0x96e2046a, -0x30420010, 0x10400005, 0x3c020700, 0x96e2047a, -0x30420010, 0x14400102, 0x3c020700, 0x34423000, -0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, -0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, -0xac43060c, 0xac440610, 0x8f870120, 0x27623800, -0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, -0x15020007, 0x1021, 0x8ee201a4, 0x3021, -0x24420001, 0xaee201a4, 0x80012ea, 0x8ee201a4, -0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, -0x8ee50434, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xace40000, 0xace50004, 0x8ee30608, -0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, -0xace9001c, 0x318c0, 0x2463060c, 0x2e31021, -0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120, -0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020007, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, -0x24420001, 0x10430007, 0x0, 0x8ee24e34, -0x24420001, 0x10a20005, 0x0, 0x80012d4, -0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80012ea, -0x0, 0x8ee24e30, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x24020007, 0xac820000, 0x24020001, -0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, -0x800136d, 0x0, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x3021, -0x24420001, 0xaee201a4, 0x8001351, 0x8ee201a4, -0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, -0x2462001c, 0xac620008, 0x24020008, 0xa462000e, -0x24020011, 0xac620018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400037, 0x24060001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c830000, 0x24020012, -0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, -0x10430007, 0x0, 0x8ee24e34, 0x24420001, -0x10a20005, 0x0, 0x800133b, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8001351, 0x0, -0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x248451d0, -0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, -0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, -0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, -0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, -0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002, -0x24420001, 0xaee20160, 0x8ee20160, 0x3021, -0x3821, 0xafa00010, 0xc002403, 0xafa00014, -0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200, -0x24050012, 0xafa00010, 0xc002403, 0xafa00014, -0xc004500, 0x0, 0xc002318, 0x0, -0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, -0xaf40022c, 0x96e30458, 0x8ee40000, 0x3c0512d8, -0x34a5c358, 0x27623800, 0xaee27258, 0x27623800, -0xaee27260, 0x27623800, 0xaee27264, 0x3661021, -0xaee27270, 0x2402ffff, 0xaee004d4, 0xaee004e0, -0xaee004e4, 0xaee004f0, 0xa2e004f4, 0xaee00e0c, -0xaee00e18, 0xaee00e10, 0xaee00e14, 0xaee00e1c, -0xaee0724c, 0xaee05244, 0xaee05240, 0xaee0523c, -0xaee07250, 0xaee07254, 0xaee0725c, 0xaee07268, -0xaee004d0, 0x2463ffff, 0x852025, 0xaee304f8, -0xaee40000, 0xaf800060, 0xaf820064, 0x3c020100, -0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, -0x304900ff, 0x512300e2, 0xafa00010, 0x8ee20608, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, -0xac43060c, 0xac440610, 0x8f870120, 0x27623800, -0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, -0x15020007, 0x1021, 0x8ee201a4, 0x3021, -0x24420001, 0xaee201a4, 0x8001422, 0x8ee201a4, -0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, -0x8ee50434, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xace40000, 0xace50004, 0x8ee30608, -0x24020008, 0xa4e2000e, 0x2402000d, 0xace20018, -0xace9001c, 0x318c0, 0x2463060c, 0x2e31021, -0xace20008, 0x8ee204c4, 0xace20010, 0xaf880120, -0x92e24e20, 0x14400037, 0x24060001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020007, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, -0x24420001, 0x10430007, 0x0, 0x8ee24e34, -0x24420001, 0x10a20005, 0x0, 0x800140c, -0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8001422, -0x0, 0x8ee24e30, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x24020007, 0xac820000, 0x24020001, -0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, -0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, -0x80014a5, 0x0, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x3021, -0x24420001, 0xaee201a4, 0x8001489, 0x8ee201a4, -0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, -0x2462001c, 0xac620008, 0x24020008, 0xa462000e, -0x24020011, 0xac620018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400037, 0x24060001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c830000, 0x24020012, -0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, -0x10430007, 0x0, 0x8ee24e34, 0x24420001, -0x10a20005, 0x0, 0x8001473, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8001489, 0x0, -0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x14c0001b, 0x0, 0x3c040001, 0x248451d0, -0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, -0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, -0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, -0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, -0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, -0x8ee20154, 0x8f8200a0, 0x30420004, 0x1440fffd, -0x0, 0x8f820040, 0x30420001, 0x14400008, -0x0, 0x8f430104, 0x24020001, 0x10620004, -0x0, 0x8f420264, 0x10400006, 0x0, -0x8ee2017c, 0x24420001, 0xaee2017c, 0x80014c5, -0x8ee2017c, 0x8f820044, 0x34420004, 0xaf820044, -0x8ee20178, 0x24420001, 0xaee20178, 0x8ee20178, -0x8f8200d8, 0x8f8300d4, 0x431023, 0xaee2726c, -0x8ee2726c, 0x1c400003, 0x3c030001, 0x431021, -0xaee2726c, 0xc004064, 0x0, 0xc004440, -0xaf800228, 0x8fbf0024, 0x8fb00020, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x0, 0x0, 0x2402002c, -0xaf820050, 0xaee07274, 0x8f420238, 0xaee27278, -0x8f820054, 0x24420067, 0xaf820058, 0xaee07b88, -0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821, -0xac2083bc, 0x3c010001, 0x370821, 0x3e00008, -0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020, -0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067, -0x1060000d, 0xaf820058, 0x3c020001, 0x571021, -0x904283b8, 0x10400005, 0x3c030200, 0x3c010001, -0x370821, 0x8001503, 0xa02083b8, 0x8ee20000, -0x431025, 0xaee20000, 0x8f420218, 0x30420100, -0x104000c6, 0x0, 0x8f8200b0, 0x30420004, -0x104000c2, 0x0, 0x3c030001, 0x771821, -0x8c6383d0, 0x8f820104, 0x146200b4, 0x0, -0x3c030001, 0x771821, 0x8c6383d4, 0x8f8200b4, -0x146200ae, 0x0, 0x8f8200b0, 0x3c030080, -0x431024, 0x1040000d, 0x0, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f8200b0, 0x2403fffb, -0x431024, 0xaf8200b0, 0x8f82011c, 0x2403fffd, -0x431024, 0x80015cc, 0xaf82011c, 0x3c030001, -0x771821, 0x8c6383d0, 0x8f820104, 0x14620082, -0x0, 0x3c030001, 0x771821, 0x8c6383d4, -0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, -0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, -0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0, -0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, -0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20006, 0x0, 0x8ee201a4, -0x24420001, 0xaee201a4, 0x80015a0, 0x8ee201a4, -0x8f440208, 0x8f45020c, 0x26e20030, 0xac620008, -0x24020400, 0xa462000e, 0x2402000f, 0xac620018, -0xac60001c, 0xac640000, 0xac650004, 0x8ee204c4, -0xac620010, 0xaf860120, 0x92e24e20, 0x14400037, -0x0, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, -0x0, 0x8ee24e34, 0x24420001, 0x10a20005, -0x0, 0x800158a, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80015a0, 0x0, 0x8ee24e30, -0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x24020007, -0xac820000, 0x24020001, 0xac820004, 0x8f82011c, -0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4, -0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001, -0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c, -0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, -0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, -0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284, -0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, -0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403, -0x34a50900, 0x80015cc, 0x0, 0x8f820104, -0x3c010001, 0x370821, 0xac2283d0, 0x8f8200b4, -0x3c010001, 0x370821, 0xac2283d4, 0x8ee27274, -0x92e304f4, 0x24420067, 0x14600006, 0xaee27274, -0x8ee27274, 0x8f430234, 0x43102b, 0x1440007b, -0x0, 0x8ee304e4, 0x8ee204f8, 0x14620004, -0x0, 0x92e204f4, 0x50400074, 0xa2e004f4, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8001637, 0x8ee201a4, 0x8ee204e4, 0xac62001c, -0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400037, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c830000, 0x24020012, 0x1462001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee54e30, 0x24420001, 0x10430007, 0x0, -0x8ee24e34, 0x24420001, 0x10a20005, 0x0, -0x8001621, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8001637, 0x0, 0x8ee24e30, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020012, 0xac820000, -0x24020001, 0xac820004, 0x5600000b, 0x24100001, -0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014, -0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f006, 0x16000003, 0x24020001, -0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, -0xaee20170, 0x8ee20170, 0x8ee204e4, 0xa2e004f4, -0xaee004f0, 0xaee07274, 0xaee204f8, 0x8ee20e1c, -0x1040006d, 0x0, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x8021, -0x24420001, 0xaee201a4, 0x80016ad, 0x8ee201a4, -0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, -0x2462001c, 0xac620008, 0x24020008, 0xa462000e, -0x24020011, 0xac620018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400037, 0x24100001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c830000, 0x24020012, -0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, -0x10430007, 0x0, 0x8ee24e34, 0x24420001, -0x10a20005, 0x0, 0x8001697, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x80016ad, 0x0, -0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020012, 0xac820000, 0x24020001, 0xac820004, -0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, -0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c, -0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, -0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, -0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, -0x0, 0xaee04e24, 0x8f820040, 0x30420001, -0x14400008, 0x0, 0x8f430104, 0x24020001, -0x10620004, 0x0, 0x8f420264, 0x10400006, -0x0, 0x8ee2017c, 0x24420001, 0xaee2017c, -0x80016da, 0x8ee2017c, 0x8f820044, 0x34420004, -0xaf820044, 0x8ee20178, 0x24420001, 0xaee20178, -0x8ee20178, 0x8ee27278, 0x2442ff99, 0xaee27278, -0x8ee27278, 0x1c4002ad, 0x0, 0x8f420238, -0x104002aa, 0x0, 0x3c020001, 0x571021, -0x904283e0, 0x144002a5, 0x0, 0x8f420080, -0xaee2004c, 0x8f4200c0, 0xaee20048, 0x8f420084, -0xaee20038, 0x8f420084, 0xaee20244, 0x8f420088, -0xaee20248, 0x8f42008c, 0xaee2024c, 0x8f420090, -0xaee20250, 0x8f420094, 0xaee20254, 0x8f420098, -0xaee20258, 0x8f42009c, 0xaee2025c, 0x8f4200a0, -0xaee20260, 0x8f4200a4, 0xaee20264, 0x8f4200a8, -0xaee20268, 0x8f4200ac, 0xaee2026c, 0x8f4200b0, -0xaee20270, 0x8f4200b4, 0xaee20274, 0x8f4200b8, -0xaee20278, 0x8f4200bc, 0x24040001, 0xaee2027c, -0xaee0003c, 0x41080, 0x571021, 0x8ee3003c, -0x8c420244, 0x24840001, 0x621821, 0x2c82000f, -0xaee3003c, 0x1440fff8, 0x41080, 0x8f4200cc, -0xaee20050, 0x8f4200d0, 0xaee20054, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8001775, -0x8ee201a4, 0x8f440208, 0x8f45020c, 0x26e20030, -0xac620008, 0x24020400, 0xa462000e, 0x2402000f, -0xac620018, 0xac60001c, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400037, 0x24100001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c830000, 0x24020007, -0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, -0x10430007, 0x0, 0x8ee24e34, 0x24420001, -0x10a20005, 0x0, 0x800175f, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x8001775, 0x0, -0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x12000212, 0x3c020400, 0xafa20018, 0x3c020001, -0x571021, 0x904283b0, 0x1040010b, 0x0, -0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, -0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, -0xac440610, 0x8f830054, 0x8f820054, 0x24690032, -0x1221023, 0x2c420033, 0x1040006a, 0x5821, -0x24180008, 0x240f000d, 0x240d0007, 0x240c0040, -0x240e0001, 0x8f870120, 0x27623800, 0x24e80020, -0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, -0x1021, 0x8ee201a4, 0x8021, 0x24420001, -0xaee201a4, 0x80017f3, 0x8ee201a4, 0x8ee40608, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0xace40000, 0xace50004, 0x8ee20608, 0xa4f8000e, -0xacef0018, 0xacea001c, 0x210c0, 0x2442060c, -0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010, -0xaf880120, 0x92e24e20, 0x14400033, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x144d001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x104c0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x80017e0, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x80017f3, -0x0, 0x8ee24e30, 0x24420001, 0x504c0003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac8d0000, 0xac8e0004, 0x56000006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d, -0x0, 0x316300ff, 0x24020001, 0x14620077, -0x3c050009, 0xaeea0608, 0x8f830054, 0x8f820054, -0x24690032, 0x1221023, 0x2c420033, 0x10400061, -0x5821, 0x240d0008, 0x240c0011, 0x24080012, -0x24070040, 0x240a0001, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x8021, -0x24420001, 0xaee201a4, 0x800185f, 0x8ee201a4, -0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, -0x2462001c, 0xac620008, 0xa46d000e, 0xac6c0018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400033, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x1448001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x10470007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x800184c, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x800185f, -0x0, 0x8ee24e30, 0x24420001, 0x50470003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac880000, 0xac8a0004, 0x56000006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, -0x0, 0x316300ff, 0x24020001, 0x14620003, -0x3c050009, 0x800197c, 0x24100001, 0x3c040001, -0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, -0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x34a5f010, 0xc002403, 0x8021, -0x800197c, 0x0, 0x3c040001, 0x248452bc, -0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, -0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, -0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, -0x8fa4001c, 0xac43060c, 0xac440610, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, -0x27683000, 0x8f820128, 0x11020004, 0x0, -0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x80018f7, -0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, -0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee30608, 0x24020008, 0xa4e2000e, 0x2402000d, -0xace20018, 0xace9001c, 0x318c0, 0x2463060c, -0x2e31021, 0xace20008, 0x8ee204c4, 0xace20010, -0xaf880120, 0x92e24e20, 0x14400037, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c830000, 0x24020007, 0x1462001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee54e30, 0x24420001, 0x10430007, 0x0, -0x8ee24e34, 0x24420001, 0x10a20005, 0x0, -0x80018e1, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80018f7, 0x0, 0x8ee24e30, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x5600000c, 0xaee90608, -0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f000, 0x800197c, 0x0, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x800195e, -0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, -0x8ee504a4, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, -0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020012, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, -0x24420001, 0x10430007, 0x0, 0x8ee24e34, -0x24420001, 0x10a20005, 0x0, 0x8001948, -0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x800195e, -0x0, 0x8ee24e30, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x24020012, 0xac820000, 0x24020001, -0xac820004, 0x5600001d, 0x24100001, 0x3c040001, -0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, -0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, -0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, -0xc002403, 0x0, 0x8ee201ac, 0x8021, -0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, -0x24020001, 0x3c010001, 0x370821, 0xa02083b0, -0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, -0x8ee30158, 0x800198c, 0xaee27278, 0x24020001, -0x3c010001, 0x370821, 0xa02283b0, 0x3c020001, -0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84, -0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84, -0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84, -0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002, -0xaee204d4, 0xafa30018, 0x8ee20608, 0x8f430228, -0x24420001, 0x304a00ff, 0x514300fd, 0xafa00010, -0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, -0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, -0x1040006a, 0x5821, 0x24180008, 0x240f000d, -0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, -0x27683000, 0x8f820128, 0x11020004, 0x0, -0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8001a15, -0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, -0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c, -0x210c0, 0x2442060c, 0x2e21021, 0xace20008, -0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, -0x14400033, 0x24100001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x144d001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8001a02, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x8001a15, 0x0, 0x8ee24e30, -0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, -0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, -0x24020001, 0x54620078, 0xafa00010, 0xaeea0608, -0x8f830054, 0x8f820054, 0x24690032, 0x1221023, -0x2c420033, 0x10400061, 0x5821, 0x240d0008, -0x240c0011, 0x24080012, 0x24070040, 0x240a0001, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8001a81, 0x8ee201a4, 0x8ee20608, 0xac62001c, -0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, -0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400033, 0x24100001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x1448001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8001a6e, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x8001a81, 0x0, 0x8ee24e30, -0x24420001, 0x50470003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, -0x56000006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, -0x24020001, 0x10620022, 0x0, 0x3c040001, -0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, -0x8001aad, 0x0, 0x3c040001, 0x248452b0, -0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002403, 0x34a5f010, 0x8001aad, 0x0, -0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608, -0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, -0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, -0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, -0x8ee204d4, 0x30420001, 0x10400055, 0x0, -0x8f420218, 0x30420080, 0x10400029, 0x0, -0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b7c, -0x402821, 0x8ee200c0, 0x8ee300c4, 0x24060000, -0x2407ffff, 0x2021, 0x461024, 0x1444000d, -0x671824, 0x1465000b, 0x0, 0x8ee27b80, -0x402821, 0x8ee200e0, 0x8ee300e4, 0x2021, -0x461024, 0x14440003, 0x671824, 0x1065000b, -0x0, 0x8ee200c0, 0x8ee300c4, 0x8ee400e0, -0x8ee500e4, 0xaee37b7c, 0xaee57b80, 0x8f820044, -0x38420020, 0x8001b38, 0xaf820044, 0x8f820044, -0x2403ffdf, 0x431024, 0x8001b38, 0xaf820044, -0x8f820044, 0x2403ffdf, 0x431024, 0xaf820044, -0x8ee27b7c, 0x402821, 0x8ee200c0, 0x8ee300c4, -0x24060000, 0x2407ffff, 0x2021, 0x461024, -0x1444000d, 0x671824, 0x1465000b, 0x0, -0x8ee27b80, 0x402821, 0x8ee200e0, 0x8ee300e4, -0x2021, 0x461024, 0x14440003, 0x671824, -0x1065000b, 0x0, 0x8ee200c0, 0x8ee300c4, -0x8ee400e0, 0x8ee500e4, 0xaee37b7c, 0xaee57b80, -0x8f820044, 0x38420040, 0x8001b38, 0xaf820044, -0x8f820044, 0x34420040, 0x8001b38, 0xaf820044, -0x8f820044, 0x34420040, 0xaf820044, 0x8ee27b8c, -0x24430001, 0x28420015, 0x14400028, 0xaee37b8c, -0x8f820044, 0x38420020, 0xaf820044, 0x8001b38, -0xaee07b8c, 0x8ee204d4, 0x30420001, 0x10400011, -0x0, 0x8f420218, 0x30420080, 0x10400009, -0x0, 0x8f820044, 0x34420020, 0xaf820044, -0x8f820044, 0x2403ffbf, 0x431024, 0x8001b36, -0xaf820044, 0x8f820044, 0x34420060, 0x8001b36, -0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, -0x8ee27b88, 0x24430001, 0x28421389, 0x14400005, -0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044, -0xaee07b88, 0xc004603, 0x0, 0x8fbf0024, -0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8, -0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038, -0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, -0x8f960064, 0x32c20004, 0x1040000c, 0x24020004, -0xaf820064, 0x8f420114, 0xaee204e0, 0x8f820060, -0x34420008, 0xaf820060, 0x8ee2016c, 0x24420001, -0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001, -0x10400004, 0x24020001, 0xaf820064, 0x80022f4, -0x0, 0x32c20002, 0x1440000c, 0x3c050003, -0x3c040001, 0x24845354, 0x34a50001, 0x2c03021, -0x3821, 0xafa00010, 0xc002403, 0xafa00014, -0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, -0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, -0x21080, 0x5a1021, 0x8c420300, 0xafa20020, -0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, -0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360, -0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, -0xc002403, 0x34a5f01f, 0x3821, 0x14e00003, -0x0, 0x80022ed, 0xaf960064, 0x93a20020, -0x2443ffff, 0x2c620011, 0x10400658, 0x31080, -0x3c010001, 0x220821, 0x8c225418, 0x400008, -0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c, -0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118, -0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118, -0x8fa20020, 0x24030001, 0x3c010001, 0x370821, -0xa02383b1, 0x30420fff, 0xaee25238, 0x8f820060, -0x34420100, 0xaf820060, 0x8ee20144, 0x24420001, -0xaee20144, 0x80022e8, 0x8ee20144, 0x8fa20020, -0x21200, 0x22502, 0x24020001, 0x10820005, -0x24020002, 0x10820009, 0x2402fffe, 0x8001bc9, -0xafa00010, 0x8ee204d4, 0xaee40070, 0xaee40074, -0x34420001, 0x8001bbd, 0xaee204d4, 0x8ee304d4, -0xaee40070, 0xaee40074, 0x621824, 0xaee304d4, -0x8f840054, 0x41442, 0x41c82, 0x431021, -0x41cc2, 0x431023, 0x41d02, 0x431021, -0x41d42, 0x431023, 0x8001bd0, 0xaee20078, -0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110, -0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, -0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, -0x920c0, 0x2e41021, 0x9442727c, 0x30424000, -0x1040000a, 0x971021, 0x97430212, 0xa443727e, -0x8f430214, 0x971021, 0xac437280, 0x2e41821, -0x34028000, 0x8001c79, 0xa462727c, 0x9443727e, -0x97420212, 0x14620006, 0x2e41021, 0x971021, -0x8c437280, 0x8f420214, 0x1062009f, 0x2e41021, -0x9442727c, 0x30428000, 0x1040002a, 0x2406ffff, -0x2021, 0x410c0, 0x2e21021, 0x9442737c, -0x30424000, 0x54400005, 0x803021, 0x24840001, -0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010, -0x618c0, 0x610c0, 0x571821, 0x8c63737c, -0x571021, 0xafa30010, 0x8c427380, 0x3c040001, -0x24845378, 0xafa20014, 0x8f470214, 0x3c050003, -0xc002403, 0x34a50013, 0x8001c90, 0x3c020800, -0x97440212, 0x771021, 0xa444737e, 0x8f440214, -0x771021, 0x2e31821, 0xac447380, 0x34028000, -0xa462737c, 0x910c0, 0x2e21021, 0x8001c79, -0xa446727c, 0x2e41021, 0x9445727c, 0x8001c2e, -0x510c0, 0x9443737e, 0x97420212, 0x14620006, -0x510c0, 0x971021, 0x8c437380, 0x8f420214, -0x10620065, 0x510c0, 0x2e21021, 0x9445737c, -0x510c0, 0x2e21021, 0x9442737c, 0x30428000, -0x1040fff0, 0x971021, 0x520c0, 0x971021, -0x9443737e, 0x97420212, 0x14620006, 0x2406ffff, -0x971021, 0x8c437380, 0x8f420214, 0x10620053, -0x3c020800, 0x2021, 0x410c0, 0x2e21021, -0x9442737c, 0x30424000, 0x54400005, 0x803021, -0x24840001, 0x2c820080, 0x1440fff8, 0x410c0, -0x4c10023, 0x618c0, 0x910c0, 0x571821, -0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, -0x3c040001, 0x24845384, 0xafa20014, 0x8f470214, -0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90, -0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, -0x8f430214, 0xb71021, 0xac437780, 0x3c020001, -0x571021, 0x8c4283b4, 0x24420001, 0x3c010001, -0x370821, 0xac2283b4, 0x3c030001, 0x771821, -0x8c6383b4, 0x2e51021, 0x8001c82, 0xa443777c, -0x97440212, 0x771021, 0xa444737e, 0x8f440214, -0x771021, 0x2e31821, 0xac447380, 0x34028000, -0xa462737c, 0x510c0, 0x2e21021, 0xa446737c, -0x2021, 0x428c0, 0x2e51021, 0x9442777c, -0x1040ffdc, 0x24840001, 0x2c820080, 0x5440fffa, -0x428c0, 0x92e204d8, 0x10400006, 0x24020001, -0x8ee304dc, 0x1221004, 0x621825, 0x8001c8f, -0xaee304dc, 0x8f830228, 0x24020001, 0x1221004, -0x621825, 0xaf830228, 0x3c020800, 0x34421000, -0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, -0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, -0xac43060c, 0xac440610, 0x8f830054, 0x8f820054, -0x24690032, 0x1221023, 0x2c420033, 0x1040006a, -0x5821, 0x24100008, 0x240f000d, 0x240d0007, -0x240c0040, 0x240e0001, 0x8f870120, 0x27623800, -0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, -0x15020007, 0x1021, 0x8ee201a4, 0x3821, -0x24420001, 0xaee201a4, 0x8001d08, 0x8ee201a4, -0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, -0x8ee50434, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xace40000, 0xace50004, 0x8ee20608, -0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, -0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4, -0xace20010, 0xaf880120, 0x92e24e20, 0x14400033, -0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c820000, 0x144d001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x104c0007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8001cf5, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8001d08, 0x0, 0x8ee24e30, 0x24420001, -0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, -0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, -0x1440ff9d, 0x0, 0x316300ff, 0x24020001, -0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, -0x10400061, 0x5821, 0x240e0008, 0x240d0011, -0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x3821, 0x24420001, 0xaee201a4, 0x8001d74, -0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, -0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e, -0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4, -0xac620010, 0xaf860120, 0x92e24e20, 0x14400033, -0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c820000, 0x144a001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x10480007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8001d61, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8001d74, 0x0, 0x8ee24e30, 0x24420001, -0x50480003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, -0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, -0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24845390, -0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0, -0x0, 0x3c040001, 0x2484539c, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, -0x34a5f010, 0x8001da0, 0x0, 0x3c040001, -0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, -0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, -0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, -0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, -0x928c0, 0x2e51021, 0x9442727c, 0x30428000, -0x1040002f, 0x2e51021, 0x9442727c, 0x30424000, -0x1440001c, 0xb71021, 0x9443727e, 0x97420212, -0x14620018, 0xb71021, 0x8c437280, 0x8f420214, -0x54620016, 0xafa20010, 0x92e204d8, 0x10400007, -0x24020001, 0x8ee304dc, 0x1221004, 0x21027, -0x621824, 0x8001dc9, 0xaee304dc, 0x8f830228, -0x1221004, 0x21027, 0x621824, 0xaf830228, -0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e, -0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, -0x571021, 0x8c42727c, 0x3c040001, 0x248453b4, -0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, -0xc002403, 0x1203021, 0x8001e83, 0x3c020800, -0xb71021, 0x9443727e, 0x97420212, 0x14620019, -0x918c0, 0xb71021, 0x8c437280, 0x8f420214, -0x14620014, 0x918c0, 0x2e51021, 0x9447727c, -0x720c0, 0x971021, 0x9443737e, 0xb71021, -0xa443727e, 0x971021, 0x8c437380, 0xb71021, -0xac437280, 0x2e41021, 0x9443737c, 0x2e51021, -0xa443727c, 0x2e41821, 0x3402c000, 0x8001e4e, -0xa462737c, 0x2e31021, 0x9447727c, 0x3021, -0x720c0, 0x2e41021, 0x9442737c, 0x4021, -0x30428000, 0x14400025, 0xe02821, 0x605021, -0x340bc000, 0x971021, 0x9443737e, 0x97420212, -0x54620015, 0xe02821, 0x971021, 0x8c437380, -0x8f420214, 0x54620010, 0xe02821, 0x11000006, -0x2e41021, 0x9443737c, 0x510c0, 0x2e21021, -0x8001e1a, 0xa443737c, 0x9443737c, 0x2ea1021, -0xa443727c, 0x710c0, 0x2e21021, 0xa44b737c, -0x8001e28, 0x24060001, 0x510c0, 0x2e21021, -0x9447737c, 0x720c0, 0x2e41021, 0x9442737c, -0x30428000, 0x1040ffdf, 0x25080001, 0x30c200ff, -0x14400025, 0x2021, 0x720c0, 0x971021, -0x9443737e, 0x97420212, 0x1462000f, 0x910c0, -0x971021, 0x8c437380, 0x8f420214, 0x1462000a, -0x910c0, 0x2e41821, 0x3402c000, 0x15000015, -0xa462737c, 0x910c0, 0x2e21821, 0x34028000, -0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, -0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010, -0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, -0x1203021, 0xc002403, 0xafa20014, 0x8001e83, -0x3c020800, 0x2021, 0x428c0, 0xb71021, -0x9443777e, 0x97420212, 0x5462002b, 0x24840001, -0xb71021, 0x8c437780, 0x8f420214, 0x54620026, -0x24840001, 0x3c020001, 0x571021, 0x8c4283b4, -0x2442ffff, 0x3c010001, 0x370821, 0xac2283b4, -0x3c020001, 0x571021, 0x8c4283b4, 0x809021, -0x242102b, 0x1040000e, 0x24b1777c, 0x24b07784, -0x2f02021, 0x2f12821, 0xc002490, 0x24060008, -0x26310008, 0x3c020001, 0x571021, 0x8c4283b4, -0x26520001, 0x242102b, 0x1440fff5, 0x26100008, -0x3c040001, 0x972021, 0x8c8483b4, 0x24050008, -0x420c0, 0x2484777c, 0xc002488, 0x2e42021, -0x8001e83, 0x3c020800, 0x2c820080, 0x1440ffcf, -0x428c0, 0x3c020800, 0x34422000, 0xafa20018, -0x8ee20608, 0x8f430228, 0x24420001, 0x304a00ff, -0x514300fd, 0xafa00010, 0x8ee20608, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, -0xac440610, 0x8f830054, 0x8f820054, 0x24690032, -0x1221023, 0x2c420033, 0x1040006a, 0x5821, -0x24100008, 0x240f000d, 0x240d0007, 0x240c0040, -0x240e0001, 0x8f870120, 0x27623800, 0x24e80020, -0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, -0x1021, 0x8ee201a4, 0x3821, 0x24420001, -0xaee201a4, 0x8001efb, 0x8ee201a4, 0x8ee40608, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0xace40000, 0xace50004, 0x8ee20608, 0xa4f0000e, -0xacef0018, 0xacea001c, 0x210c0, 0x2442060c, -0x2e21021, 0xace20008, 0x8ee204c4, 0xace20010, -0xaf880120, 0x92e24e20, 0x14400033, 0x24070001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x144d001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x104c0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8001ee8, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x8001efb, -0x0, 0x8ee24e30, 0x24420001, 0x504c0003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac8d0000, 0xac8e0004, 0x54e00006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ff9d, -0x0, 0x316300ff, 0x24020001, 0x54620078, -0xafa00010, 0xaeea0608, 0x8f830054, 0x8f820054, -0x24690032, 0x1221023, 0x2c420033, 0x10400061, -0x5821, 0x240e0008, 0x240d0011, 0x240a0012, -0x24080040, 0x240c0001, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x3821, -0x24420001, 0xaee201a4, 0x8001f67, 0x8ee201a4, -0x8ee20608, 0xac62001c, 0x8ee404a0, 0x8ee504a4, -0x2462001c, 0xac620008, 0xa46e000e, 0xac6d0018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400033, 0x24070001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x144a001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x10480007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8001f54, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x8001f67, -0x0, 0x8ee24e30, 0x24420001, 0x50480003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, -0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, -0x0, 0x316300ff, 0x24020001, 0x10620022, -0x0, 0x3c040001, 0x24845390, 0xafa00010, -0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, -0xc002403, 0x34a5f011, 0x8001f93, 0x0, -0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120, -0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, -0x8001f93, 0x0, 0x3c040001, 0x248453a8, -0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, -0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, -0xaee20128, 0x8ee20128, 0x8ee20164, 0x24420001, -0xaee20164, 0x80022e8, 0x8ee20164, 0x8fa20020, -0x21200, 0x21d02, 0x24020001, 0x10620005, -0x24020002, 0x1062000d, 0x0, 0x8001fb7, -0xafa00010, 0x92e204d8, 0x14400006, 0x24020001, -0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228, -0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, -0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, -0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8, -0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, -0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, -0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, -0x22502, 0x24020001, 0x10820005, 0x24020002, -0x1082000f, 0x0, 0x8001fe3, 0xafa00010, -0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420008, 0xaf820220, 0x24020001, 0x3c010001, -0x370821, 0xa02283b2, 0x8001fea, 0xaee40108, -0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, -0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, -0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4, -0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, -0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, -0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, -0x21d02, 0x24020001, 0x10620005, 0x24020002, -0x1062000e, 0x0, 0x8002011, 0xafa00010, -0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420008, 0xaf820220, 0x24020001, 0x3c010001, -0x370821, 0x8002018, 0xa02283b3, 0x3c020001, -0x571021, 0x904283b2, 0x3c010001, 0x370821, -0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, -0x3463fff7, 0x431024, 0x8002018, 0xaf820220, -0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114, -0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, -0x27840208, 0x27450200, 0xc00249a, 0x24060008, -0x26e40094, 0x27450200, 0xc00249a, 0x24060008, -0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, -0x8ee20134, 0x8f460248, 0x2021, 0xc005108, -0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, -0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, -0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, -0xaee20140, 0x8ef00140, 0x8ef10074, 0x8ef20070, -0xc002488, 0x24050400, 0xaef301cc, 0xaef401d0, -0xaef501d8, 0xaef00140, 0xaef10074, 0xaef20070, -0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, -0x27450200, 0x24060008, 0xaee20068, 0x24020006, -0xc00249a, 0xaee20064, 0x3c023b9a, 0x3442ca00, -0xaee2006c, 0x240203e8, 0x24040002, 0x24030001, -0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, -0x30420008, 0x10400004, 0x0, 0xaee30108, -0x8002061, 0x2021, 0xaee40108, 0x2021, -0x3c030001, 0x641821, 0x90635c30, 0x2e41021, -0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, -0x0, 0x8f820040, 0x2e41821, 0x24840001, -0x21702, 0x24420030, 0xa062009c, 0x2e41021, -0x80022e8, 0xa040009c, 0x24020001, 0x3c010001, -0x370821, 0xa02283e0, 0x240b0400, 0x24080014, -0x240a0040, 0x24090001, 0x8f830100, 0x27623000, -0x24660020, 0xc2102b, 0x50400001, 0x27662800, -0x8f820108, 0x10c20004, 0x0, 0x8f820104, -0x14c20007, 0x26e20030, 0x8ee201a8, 0x3821, -0x24420001, 0xaee201a8, 0x80020a8, 0x8ee201a8, -0x8ee404b8, 0x8ee504bc, 0xac620008, 0xa46b000e, -0xac680018, 0xac60001c, 0xac640000, 0xac650004, -0x8ee204cc, 0xac620010, 0xaf860100, 0x92e204ec, -0x1440000e, 0x24070001, 0x8ee24e28, 0x24420001, -0x504a0003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e21021, 0xac480000, 0xac490004, 0x10e0ffd2, -0x0, 0x80022e8, 0x0, 0x3c020900, -0xaee05238, 0xaee0523c, 0xaee05240, 0xaee05244, -0xaee001d0, 0x3c010001, 0x370821, 0xa02083b1, -0xafa20018, 0x8ee20608, 0x8f430228, 0x24420001, -0x304a00ff, 0x514300fd, 0xafa00010, 0x8ee20608, -0x210c0, 0x571021, 0x8fa30018, 0x8fa4001c, -0xac43060c, 0xac440610, 0x8f830054, 0x8f820054, -0x24690032, 0x1221023, 0x2c420033, 0x1040006a, -0x5821, 0x24100008, 0x240f000d, 0x240d0007, -0x240c0040, 0x240e0001, 0x8f870120, 0x27623800, -0x24e80020, 0x102102b, 0x50400001, 0x27683000, -0x8f820128, 0x11020004, 0x0, 0x8f820124, -0x15020007, 0x1021, 0x8ee201a4, 0x3821, -0x24420001, 0xaee201a4, 0x800212c, 0x8ee201a4, -0x8ee40608, 0x420c0, 0x801821, 0x8ee40430, -0x8ee50434, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xace40000, 0xace50004, 0x8ee20608, -0xa4f0000e, 0xacef0018, 0xacea001c, 0x210c0, -0x2442060c, 0x2e21021, 0xace20008, 0x8ee204c4, -0xace20010, 0xaf880120, 0x92e24e20, 0x14400033, -0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c820000, 0x144d001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x104c0007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8002119, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x800212c, 0x0, 0x8ee24e30, 0x24420001, -0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0xac8d0000, 0xac8e0004, 0x54e00006, -0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, -0x1440ff9d, 0x0, 0x316300ff, 0x24020001, -0x54620078, 0xafa00010, 0xaeea0608, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, -0x10400061, 0x5821, 0x240e0008, 0x240d0011, -0x240a0012, 0x24080040, 0x240c0001, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x3821, 0x24420001, 0xaee201a4, 0x8002198, -0x8ee201a4, 0x8ee20608, 0xac62001c, 0x8ee404a0, -0x8ee504a4, 0x2462001c, 0xac620008, 0xa46e000e, -0xac6d0018, 0xac640000, 0xac650004, 0x8ee204c4, -0xac620010, 0xaf860120, 0x92e24e20, 0x14400033, -0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c820000, 0x144a001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x10480007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8002185, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x8002198, 0x0, 0x8ee24e30, 0x24420001, -0x50480003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, -0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, -0x1440ffa6, 0x0, 0x316300ff, 0x24020001, -0x10620022, 0x0, 0x3c040001, 0x24845390, -0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4, -0x0, 0x3c040001, 0x2484539c, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, -0x34a5f010, 0x80021c4, 0x0, 0x3c040001, -0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, -0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, -0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, -0x24420001, 0xaee20168, 0x80022e8, 0x8ee20168, -0x8f42025c, 0x26e40094, 0xaee20060, 0x8f420260, -0x27450200, 0x24060008, 0xc00249a, 0xaee20068, -0x8f820220, 0x30420008, 0x14400002, 0x24020001, -0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, -0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, -0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020, -0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020, -0x3c030700, 0x34631000, 0x431025, 0xafa20018, -0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, -0x512300e2, 0xafa00010, 0x8ee20608, 0x210c0, -0x571021, 0x8fa30018, 0x8fa4001c, 0xac43060c, -0xac440610, 0x8f870120, 0x27623800, 0x24e80020, -0x102102b, 0x50400001, 0x27683000, 0x8f820128, -0x11020004, 0x0, 0x8f820124, 0x15020007, -0x1021, 0x8ee201a4, 0x3821, 0x24420001, -0xaee201a4, 0x800225d, 0x8ee201a4, 0x8ee40608, -0x420c0, 0x801821, 0x8ee40430, 0x8ee50434, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0xace40000, 0xace50004, 0x8ee30608, 0x24020008, -0xa4e2000e, 0x2402000d, 0xace20018, 0xace9001c, -0x318c0, 0x2463060c, 0x2e31021, 0xace20008, -0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, -0x14400037, 0x24070001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c830000, 0x24020007, -0x1462001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee54e30, 0x24420001, -0x10430007, 0x0, 0x8ee24e34, 0x24420001, -0x10a20005, 0x0, 0x8002247, 0x0, -0x14a00005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x800225d, 0x0, -0x8ee24e30, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4, -0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0, -0x0, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, -0x10c20004, 0x0, 0x8f820124, 0x14c20007, -0x0, 0x8ee201a4, 0x3821, 0x24420001, -0xaee201a4, 0x80022c4, 0x8ee201a4, 0x8ee20608, -0xac62001c, 0x8ee404a0, 0x8ee504a4, 0x2462001c, -0xac620008, 0x24020008, 0xa462000e, 0x24020011, -0xac620018, 0xac640000, 0xac650004, 0x8ee204c4, -0xac620010, 0xaf860120, 0x92e24e20, 0x14400037, -0x24070001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c830000, 0x24020012, 0x1462001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee54e30, 0x24420001, 0x10430007, -0x0, 0x8ee24e34, 0x24420001, 0x10a20005, -0x0, 0x80022ae, 0x0, 0x14a00005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80022c4, 0x0, 0x8ee24e30, -0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x24020012, -0xac820000, 0x24020001, 0xac820004, 0x14e0001b, -0x0, 0x3c040001, 0x248453fc, 0xafa00010, -0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, -0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, -0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, -0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228, -0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, -0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, -0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, -0x24420001, 0xaee20160, 0x8ee20160, 0x8f43022c, -0x8f42010c, 0x14620009, 0x24020002, 0xaf820064, -0x8f820064, 0x14400005, 0x0, 0x8f43022c, -0x8f42010c, 0x1462f875, 0x0, 0x8fbf0044, -0x8fb60040, 0x8fb5003c, 0x8fb40038, 0x8fb30034, -0x8fb20030, 0x8fb1002c, 0x8fb00028, 0x3e00008, -0x27bd0048, 0x27bdfff8, 0x2408ffff, 0x10a00014, -0x4821, 0x3c0aedb8, 0x354a8320, 0x90870000, -0x24840001, 0x3021, 0x1071026, 0x30420001, -0x10400002, 0x81842, 0x6a1826, 0x604021, -0x24c60001, 0x2cc20008, 0x1440fff7, 0x73842, -0x25290001, 0x125102b, 0x1440fff0, 0x0, -0x1001021, 0x3e00008, 0x27bd0008, 0x27bdffe8, -0x27642800, 0xafbf0010, 0xc002488, 0x24051000, -0x24020021, 0xaf800100, 0xaf800104, 0xaf800108, -0xaf800110, 0xaf800114, 0xaf800118, 0xaf800120, -0xaf800124, 0xaf800128, 0xaf800130, 0xaf800134, -0xaf800138, 0xaee04e28, 0xaee04e2c, 0xaee04e30, -0xaee04e34, 0xaf82011c, 0x8f420218, 0x30420040, -0x10400004, 0x0, 0x8f82011c, 0x34420004, -0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, -0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, -0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403, -0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, -0x3c020400, 0x10620029, 0x43102b, 0x14400008, -0x3c022000, 0x3c020100, 0x10620024, 0x3c020200, -0x10620011, 0x0, 0x8002374, 0x0, -0x10620008, 0x3c024000, 0x1462001c, 0x0, -0x8ee20190, 0x24420001, 0xaee20190, 0x8002374, -0x8ee20190, 0x8ee2018c, 0x24420001, 0xaee2018c, -0x8002374, 0x8ee2018c, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f830104, 0x8f8200b0, 0x34420001, -0xaf8200b0, 0xaf830104, 0x8f82011c, 0x2403fffd, -0x431024, 0xaf82011c, 0x8ee201a0, 0x24420001, -0xaee201a0, 0x8002377, 0x8ee201a0, 0x8f8200b0, -0x34420001, 0xaf8200b0, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, -0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, -0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001, -0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0, -0x3c027f00, 0x621824, 0x3c020400, 0x10620053, -0x8021, 0x43102b, 0x14400008, 0x3c042000, -0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a, -0x0, 0x80023e0, 0x0, 0x10640003, -0x3c024000, 0x14620045, 0x0, 0x8f8200a0, -0x441024, 0x10400006, 0x0, 0x8ee20194, -0x24420001, 0xaee20194, 0x80023a9, 0x8ee20194, -0x8ee20198, 0x24420001, 0xaee20198, 0x8ee20198, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f82011c, -0x30420200, 0x1040001b, 0x0, 0x8f8300a0, -0x8f840124, 0x8f8200ac, 0x14400007, 0x24020001, -0x3c020001, 0x3442f000, 0x621024, 0x50400001, -0x24100001, 0x24020001, 0x1200000d, 0xaf8200a0, -0x8f820124, 0x2442ffe0, 0xaf820124, 0x8f820124, -0x8f820124, 0x27633000, 0x43102b, 0x10400005, -0x276237e0, 0xaf820124, 0x80023ca, 0x0, -0xaf840124, 0x8f82011c, 0x2403fffd, 0x431024, -0x80023e3, 0xaf82011c, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f830124, 0x8f8200a0, 0x34420001, -0xaf8200a0, 0xaf830124, 0x8f82011c, 0x2403fffd, -0x431024, 0xaf82011c, 0x8ee2019c, 0x24420001, -0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0, -0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, -0x3e00008, 0x27bd0020, 0x0, 0x3c020001, -0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021, -0xc002488, 0x24052000, 0x26021fe0, 0x3c010001, -0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250, -0x24022000, 0xaf500254, 0xaf420258, 0x24020001, -0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94, -0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, -0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004, -0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010, -0xac470014, 0xac480018, 0xac49001c, 0x3c010001, -0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0, -0x62182b, 0x10600005, 0x0, 0x3c020001, -0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, -0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000, -0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40, -0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, -0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0, -0xafb40020, 0x8fb40040, 0xafb00010, 0x808021, -0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, -0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, -0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001, -0x8c425c40, 0xc09021, 0xe09821, 0x10800006, -0xaca20004, 0x24a50008, 0xc002490, 0x24060018, -0x800244e, 0x0, 0x24a40008, 0xc002488, -0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001, -0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94, -0x45102b, 0x10400005, 0x0, 0x3c020001, -0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, -0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001, -0x8c635d94, 0x8e020004, 0xac620004, 0xac710008, -0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94, -0x45102b, 0xac720010, 0xac730014, 0xac740018, -0xac75001c, 0x10400005, 0xac64000c, 0x3c020001, -0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, -0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000, -0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40, -0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, -0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, -0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005, -0x0, 0xac800000, 0x24a5fffc, 0x14a0fffd, -0x24840004, 0x3e00008, 0x0, 0x10c00007, -0x0, 0x8c820000, 0x24840004, 0x24c6fffc, -0xaca20000, 0x14c0fffb, 0x24a50004, 0x3e00008, -0x0, 0x10c00007, 0x0, 0x8ca20000, -0x24a50004, 0x24c6fffc, 0xac820000, 0x14c0fffb, -0x24840004, 0x3e00008, 0x0, 0x3e00008, -0x0, 0x27bdffd8, 0xafbf0020, 0x8ee304e4, -0x8ee204e0, 0x10620436, 0x0, 0x8ee204e4, -0x8ee304fc, 0x21100, 0x626021, 0x95870008, -0x8d8a0000, 0x8d8b0004, 0x958d000a, 0x8ee2725c, -0x8ee3726c, 0x30e4ffff, 0x441021, 0x62182b, -0x10600015, 0x31a20004, 0x8f8200d8, 0x8ee37258, -0x431023, 0xaee2726c, 0x8ee2726c, 0x1c400003, -0x3c030001, 0x431021, 0xaee2726c, 0x8ee2725c, -0x8ee3726c, 0x441021, 0x62182b, 0x10600006, -0x31a20004, 0x8ee201b8, 0x24420001, 0xaee201b8, -0x80028e1, 0x8ee201b8, 0x10400240, 0x31a20200, -0x1040014d, 0x4821, 0x96e2045a, 0x30420010, -0x10400149, 0x0, 0x8f840100, 0x27623000, -0x24850020, 0xa2102b, 0x50400001, 0x27652800, -0x8f820108, 0x10a20004, 0x0, 0x8f820104, -0x14a20006, 0x2402000c, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x800252c, 0x8ee201a8, 0xac8a0000, -0xac8b0004, 0x8ee37264, 0x24060005, 0xa482000e, -0xac860018, 0xac830008, 0x8ee204e4, 0xac82001c, -0x8ee204c8, 0xac820010, 0xaf850100, 0x92e204ec, -0x14400036, 0x24090001, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e22021, 0x8c820000, 0x1446001f, -0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, -0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, -0x0, 0x8002516, 0x0, 0x14a00005, -0x0, 0x8f820108, 0x24420020, 0xaf820108, -0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x800252c, 0x0, 0x8ee24e28, -0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, -0x210c0, 0x24424e38, 0x2e22021, 0x24020005, -0xac820000, 0x24020001, 0xac820004, 0x1520000a, -0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4, -0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800, -0x3641821, 0x24420010, 0x43102b, 0x14400073, -0x0, 0x8ee27264, 0x24480010, 0x3641021, -0x102102b, 0x14400002, 0x3c02ffff, 0x1024021, -0x8f850100, 0x27623000, 0x24a60020, 0xc2102b, -0x50400001, 0x27662800, 0x8f820108, 0x10c20004, -0x0, 0x8f820104, 0x14c20007, 0x2563000c, -0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, -0x80025a0, 0x8ee201a8, 0x2c64000c, 0x1441021, -0xaca20000, 0xaca30004, 0x24e2fff4, 0xa4a2000e, -0x24020006, 0xaca80008, 0xaca20018, 0x8ee204e4, -0xaca2001c, 0x8ee204c8, 0x3c030002, 0x431025, -0xaca20010, 0xaf860100, 0x92e204ec, 0x14400037, -0x24090001, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e22021, 0x8c830000, 0x24020005, 0x1462001f, -0x0, 0x8ee34e28, 0x8ee24e2c, 0x1062001b, -0x24030040, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e2c, 0x8ee54e28, 0x24420001, 0x10430007, -0x0, 0x8ee24e2c, 0x24420001, 0x10a20005, -0x0, 0x800258a, 0x0, 0x14a00005, -0x0, 0x8f820108, 0x24420020, 0xaf820108, -0x8f820108, 0x8c820004, 0x2c420011, 0x50400013, -0xac800000, 0x80025a0, 0x0, 0x8ee24e28, -0x24030040, 0x24420001, 0x50430003, 0x1021, -0x8ee24e28, 0x24420001, 0xaee24e28, 0x8ee24e28, -0x210c0, 0x24424e38, 0x2e22021, 0x24020005, -0xac820000, 0x24020001, 0xac820004, 0x1520000a, -0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, -0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4, -0x80028be, 0x34a5f125, 0x34028100, 0xa5020000, -0x9582000e, 0x800261d, 0xa5020002, 0x8f850100, -0x27623000, 0x24a60020, 0xc2102b, 0x50400001, -0x27662800, 0x8f820108, 0x10c20004, 0x0, -0x8f820104, 0x14c20007, 0x2563000c, 0x8ee201a8, -0x4821, 0x24420001, 0xaee201a8, 0x800260d, -0x8ee201a8, 0x2c64000c, 0x1441021, 0xaca20000, -0xaca30004, 0x8ee37264, 0x24e2fff4, 0xa4a2000e, -0x24020006, 0xaca20018, 0x24630010, 0xaca30008, -0x8ee204e4, 0xaca2001c, 0x8ee204c8, 0x3c030002, -0x431025, 0xaca20010, 0xaf860100, 0x92e204ec, -0x14400037, 0x24090001, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e22021, 0x8c830000, 0x24020005, -0x1462001f, 0x0, 0x8ee34e28, 0x8ee24e2c, -0x1062001b, 0x24030040, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e2c, 0x8ee54e28, 0x24420001, -0x10430007, 0x0, 0x8ee24e2c, 0x24420001, -0x10a20005, 0x0, 0x80025f7, 0x0, -0x14a00005, 0x0, 0x8f820108, 0x24420020, -0xaf820108, 0x8f820108, 0x8c820004, 0x2c420011, -0x50400013, 0xac800000, 0x800260d, 0x0, -0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x24020005, 0xac820000, 0x24020001, 0xac820004, -0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, -0x3c040001, 0x24845730, 0x3c050004, 0xafa20014, -0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264, -0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, -0x8002681, 0x24e70004, 0x8f840100, 0x27623000, -0x24850020, 0xa2102b, 0x50400001, 0x27652800, -0x8f820108, 0x10a20004, 0x0, 0x8f820104, -0x14a20007, 0x24020006, 0x8ee201a8, 0x4821, -0x24420001, 0xaee201a8, 0x8002677, 0x8ee201a8, -0xac8a0000, 0xac8b0004, 0x8ee37264, 0xa487000e, -0xac820018, 0xac830008, 0x8ee204e4, 0xac82001c, -0x8ee204c8, 0x3c030002, 0x431025, 0xac820010, -0xaf850100, 0x92e204ec, 0x14400037, 0x24090001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c830000, 0x24020005, 0x1462001f, 0x0, -0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, -0x8ee54e28, 0x24420001, 0x10430007, 0x0, -0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x8002661, 0x0, 0x14a00005, 0x0, -0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002677, 0x0, 0x8ee24e28, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e28, -0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e22021, 0x24020005, 0xac820000, -0x24020001, 0xac820004, 0x15200009, 0x3c050004, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730, -0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004, -0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, -0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, -0x431021, 0xac44000c, 0x8ee27258, 0xafa20018, -0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c, -0x10400004, 0x24620001, 0x2403fffe, 0x431024, -0xafa2001c, 0x8ee27264, 0x3c060001, 0x34c63800, -0x8ee3725c, 0x2405fff8, 0x471021, 0x24420007, -0x451024, 0x24630007, 0xaee27258, 0x8ee2726c, -0x8ee47258, 0x651824, 0x431023, 0xaee2726c, -0x3661021, 0x82202b, 0x14800004, 0x3c03ffff, -0x8ee27258, 0x431021, 0xaee27258, 0x8ee27258, -0xaee27264, 0x8f8200f0, 0x24470008, 0x27621800, -0xe2102b, 0x50400001, 0x27671000, 0x8f8200f4, -0x14e20007, 0x0, 0x8ee201b4, 0x4821, -0x24420001, 0xaee201b4, 0x80026c4, 0x8ee201b4, -0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, -0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, -0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, -0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018, -0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005, -0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, -0x80028d3, 0xaee0725c, 0x30430003, 0x24020002, -0x10620016, 0x28620003, 0x10400005, 0x24020001, -0x10620008, 0x0, 0x8002703, 0x0, -0x24020003, 0x10620017, 0x0, 0x8002703, -0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, -0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, -0x8ee200e8, 0x8002703, 0x8ee300ec, 0x8ee200f0, -0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, -0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002703, -0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, -0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, -0x8ee200f8, 0x8ee300fc, 0x8ee2725c, 0x8ee400e0, -0x8ee500e4, 0x401821, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xaee400e0, -0xaee500e4, 0x80028d3, 0xaee0725c, 0x30e2ffff, -0x104001c1, 0x31a20200, 0x1040014d, 0x4821, -0x96e2045a, 0x30420010, 0x10400149, 0x0, -0x8f840100, 0x27623000, 0x24850020, 0xa2102b, -0x50400001, 0x27652800, 0x8f820108, 0x10a20004, -0x0, 0x8f820104, 0x14a20006, 0x2402000c, -0x8ee201a8, 0x24420001, 0xaee201a8, 0x800276e, -0x8ee201a8, 0xac8a0000, 0xac8b0004, 0x8ee37264, -0x24060005, 0xa482000e, 0xac860018, 0xac830008, -0x8ee204e4, 0xac82001c, 0x8ee204c8, 0xac820010, -0xaf850100, 0x92e204ec, 0x14400036, 0x24090001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c820000, 0x1446001f, 0x0, 0x8ee34e28, -0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, -0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x8002758, -0x0, 0x14a00005, 0x0, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x800276e, -0x0, 0x8ee24e28, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e22021, 0x24020005, 0xac820000, 0x24020001, -0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004, -0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014, -0x8ee27264, 0x34843800, 0x3641821, 0x24420010, -0x43102b, 0x14400073, 0x0, 0x8ee27264, -0x24480010, 0x3641021, 0x102102b, 0x14400002, -0x3c02ffff, 0x1024021, 0x8f850100, 0x27623000, -0x24a60020, 0xc2102b, 0x50400001, 0x27662800, -0x8f820108, 0x10c20004, 0x0, 0x8f820104, -0x14c20007, 0x2563000c, 0x8ee201a8, 0x4821, -0x24420001, 0xaee201a8, 0x80027e2, 0x8ee201a8, -0x2c64000c, 0x1441021, 0xaca20000, 0xaca30004, -0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca80008, -0xaca20018, 0x8ee204e4, 0xaca2001c, 0x8ee204c8, -0x3c030002, 0x431025, 0xaca20010, 0xaf860100, -0x92e204ec, 0x14400037, 0x24090001, 0x8ee24e28, -0x210c0, 0x24424e38, 0x2e22021, 0x8c830000, -0x24020005, 0x1462001f, 0x0, 0x8ee34e28, -0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, -0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x80027cc, -0x0, 0x14a00005, 0x0, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80027e2, -0x0, 0x8ee24e28, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e22021, 0x24020005, 0xac820000, 0x24020001, -0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, -0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004, -0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015, -0x34028100, 0xa5020000, 0x9582000e, 0x800285f, -0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, -0xc2102b, 0x50400001, 0x27662800, 0x8f820108, -0x10c20004, 0x0, 0x8f820104, 0x14c20007, -0x2563000c, 0x8ee201a8, 0x4821, 0x24420001, -0xaee201a8, 0x800284f, 0x8ee201a8, 0x2c64000c, -0x1441021, 0xaca20000, 0xaca30004, 0x8ee37264, -0x24e2fff4, 0xa4a2000e, 0x24020006, 0xaca20018, -0x24630010, 0xaca30008, 0x8ee204e4, 0xaca2001c, -0x8ee204c8, 0x3c030002, 0x431025, 0xaca20010, -0xaf860100, 0x92e204ec, 0x14400037, 0x24090001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c830000, 0x24020005, 0x1462001f, 0x0, -0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, -0x8ee54e28, 0x24420001, 0x10430007, 0x0, -0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x8002839, 0x0, 0x14a00005, 0x0, -0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x800284f, 0x0, 0x8ee24e28, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e28, -0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e22021, 0x24020005, 0xac820000, -0x24020001, 0xac820004, 0x1520000a, 0x34028100, -0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730, -0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be, -0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, -0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004, -0x8f830100, 0x27623000, 0x24640020, 0x82102b, -0x50400001, 0x27642800, 0x8f820108, 0x10820004, -0x0, 0x8f820104, 0x14820007, 0x24050005, -0x8ee201a8, 0x4821, 0x24420001, 0xaee201a8, -0x80028b6, 0x8ee201a8, 0xac6a0000, 0xac6b0004, -0x8ee27264, 0xa467000e, 0xac650018, 0xac620008, -0x8ee204e4, 0xac62001c, 0x8ee204c8, 0xac620010, -0xaf840100, 0x92e204ec, 0x14400036, 0x24090001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c820000, 0x1445001f, 0x0, 0x8ee34e28, -0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, -0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x80028a0, -0x0, 0x14a00005, 0x0, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x80028b6, -0x0, 0x8ee24e28, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e22021, 0x24020005, 0xac820000, 0x24020001, -0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, -0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4, -0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1, -0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, -0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, -0x34a53800, 0x441021, 0xaee2725c, 0x3651021, -0x62182b, 0x14600004, 0x3c03ffff, 0x8ee27264, -0x431021, 0xaee27264, 0x8ee304e4, 0x96e20458, -0x24630001, 0x2442ffff, 0x621824, 0xaee304e4, -0x8ee304e4, 0x8ee204e0, 0x14620005, 0x0, -0x8f820060, 0x2403fff7, 0x431024, 0xaf820060, -0x8fbf0020, 0x3e00008, 0x27bd0028, 0x27bdffe0, -0xafbf0018, 0x8ee304e8, 0x8ee204e0, 0x10620189, -0x0, 0x8ee204e8, 0x8ee304fc, 0x21100, -0x621821, 0x94670008, 0x92e204ed, 0x8c680000, -0x8c690004, 0x10400023, 0x946a000a, 0x8ee204c8, -0x34460400, 0x31420200, 0x1040001f, 0x0, -0x96e2045a, 0x30420010, 0x1040001b, 0x3c028000, -0x3c010001, 0x370821, 0xac2283d8, 0x8ee27264, -0x9464000e, 0x3c050001, 0x34a53800, 0x24420004, -0xaee27264, 0x8ee37264, 0x42400, 0x3651021, -0x3c010001, 0x370821, 0xac2483dc, 0x62182b, -0x14600005, 0x24e70004, 0x8ee27264, 0x3c03ffff, -0x431021, 0xaee27264, 0x8ee27264, 0x8002917, -0xaee27258, 0x8ee604c8, 0x8ee2726c, 0x30e4ffff, -0x44102a, 0x10400015, 0x0, 0x8f8200d8, -0x8ee37258, 0x431023, 0xaee2726c, 0x8ee2726c, -0x1c400007, 0x44102a, 0x8ee2726c, 0x3c030001, -0x431021, 0xaee2726c, 0x8ee2726c, 0x44102a, -0x10400006, 0x0, 0x8ee201b8, 0x24420001, -0xaee201b8, 0x8002a72, 0x8ee201b8, 0x3c020001, -0x571021, 0x8c4283d8, 0x54400001, 0x24e7fffc, -0x31420004, 0x104000b9, 0x30e2ffff, 0x3c020001, -0x571021, 0x8c4283d8, 0x1040002f, 0x5021, -0x8f840100, 0x27623000, 0x24850020, 0xa2102b, -0x50400001, 0x27652800, 0x8f820108, 0x10a20032, -0x0, 0x8f820104, 0x10a2002f, 0x24020015, -0xac880000, 0xac890004, 0x8ee37264, 0xa487000e, -0xac820018, 0xac830008, 0x8ee204e8, 0x3c030001, -0x771821, 0x8c6383dc, 0xac860010, 0x431025, -0xac82001c, 0xaf850100, 0x92e204ec, 0x14400066, -0x240a0001, 0x8ee24e28, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e21821, 0x24020015, 0xac620000, 0x24020001, -0x80029bf, 0xac620004, 0x8f840100, 0x27623000, -0x24850020, 0xa2102b, 0x50400001, 0x27652800, -0x8f820108, 0x10a20004, 0x0, 0x8f820104, -0x14a20006, 0x24020006, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x80029bf, 0x8ee201a8, 0xac880000, -0xac890004, 0x8ee37264, 0xa487000e, 0xac820018, -0xac830008, 0x8ee204e8, 0xac860010, 0xac82001c, -0xaf850100, 0x92e204ec, 0x14400037, 0x240a0001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c830000, 0x24020005, 0x1462001f, 0x0, -0x8ee34e28, 0x8ee24e2c, 0x1062001b, 0x24030040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e2c, -0x8ee54e28, 0x24420001, 0x10430007, 0x0, -0x8ee24e2c, 0x24420001, 0x10a20005, 0x0, -0x80029a9, 0x0, 0x14a00005, 0x0, -0x8f820108, 0x24420020, 0xaf820108, 0x8f820108, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80029bf, 0x0, 0x8ee24e28, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e28, -0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e22021, 0x24020005, 0xac820000, -0x24020001, 0xac820004, 0x1540000a, 0x24020001, -0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730, -0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f, -0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, -0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, -0x370821, 0xac2083d8, 0x3c010001, 0x370821, -0xac2083dc, 0x21100, 0x431021, 0xac44000c, -0x8ee27264, 0x2405fff8, 0x30e3ffff, 0x431021, -0x24420007, 0x451024, 0x24630007, 0xaee27258, -0x8ee2726c, 0x8ee47258, 0x651824, 0x431023, -0xaee2726c, 0x3661021, 0x82202b, 0x14800004, -0x3c03ffff, 0x8ee27258, 0x431021, 0xaee27258, -0x8ee27258, 0x8002a64, 0xaee27264, 0x10400073, -0x0, 0x8f830100, 0x27623000, 0x24640020, -0x82102b, 0x14400002, 0x5021, 0x27642800, -0x8f820108, 0x10820004, 0x0, 0x8f820104, -0x14820006, 0x24050005, 0x8ee201a8, 0x24420001, -0xaee201a8, 0x8002a46, 0x8ee201a8, 0xac680000, -0xac690004, 0x8ee27264, 0xa467000e, 0xac650018, -0xac620008, 0x8ee204e8, 0xac660010, 0xac62001c, -0xaf840100, 0x92e204ec, 0x14400036, 0x240a0001, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, -0x8c820000, 0x1445001f, 0x0, 0x8ee34e28, -0x8ee24e2c, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e2c, 0x8ee54e28, -0x24420001, 0x10430007, 0x0, 0x8ee24e2c, -0x24420001, 0x10a20005, 0x0, 0x8002a30, -0x0, 0x14a00005, 0x0, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002a46, -0x0, 0x8ee24e28, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e28, 0x24420001, -0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, -0x2e22021, 0x24020005, 0xac820000, 0x24020001, -0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, -0x24845748, 0x3c050004, 0xafa90010, 0xafa00014, -0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff, -0x8002a72, 0x0, 0x8ee27264, 0x451021, -0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, -0x34843800, 0xa2e004ed, 0x451023, 0xaee2726c, -0x3641021, 0x62182b, 0x14600004, 0x3c03ffff, -0x8ee27264, 0x431021, 0xaee27264, 0x8ee304e8, -0x96e20458, 0x24630001, 0x2442ffff, 0x621824, -0xaee304e8, 0x8ee304e8, 0x8ee204e0, 0x14620005, -0x0, 0x8f820060, 0x2403fff7, 0x431024, -0xaf820060, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x27bdffe0, 0xafbf001c, 0xafb00018, 0x8f820100, -0x8ee34e2c, 0x8f820104, 0x8f850108, 0x24020040, -0x24630001, 0x50620003, 0x1021, 0x8ee24e2c, -0x24420001, 0xaee24e2c, 0x8ee24e2c, 0x8ee34e2c, -0x210c0, 0x24424e38, 0x2e22021, 0x8ee24e28, -0x8c870004, 0x14620007, 0xa03021, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8002aa2, -0xac800000, 0x8ee24e2c, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e2c, 0x24420001, -0x210c0, 0x24424e38, 0x2e22021, 0x8c820004, -0x8f830108, 0x21140, 0x621821, 0xaf830108, -0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013, -0x104000c1, 0x31080, 0x3c010001, 0x220821, -0x8c225770, 0x400008, 0x0, 0x8ee204f0, -0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c, -0x43102b, 0x144000be, 0x0, 0x8ee304e4, -0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8002b12, -0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, -0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, -0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020012, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x24030040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee54e30, -0x24420001, 0x10430007, 0x0, 0x8ee24e34, -0x24420001, 0x10a20005, 0x0, 0x8002afc, -0x0, 0x14a00005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002b12, -0x0, 0x8ee24e30, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x24020012, 0xac820000, 0x24020001, -0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24845754, 0xafa00014, 0xafa20010, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f006, 0x16000003, 0x24020001, 0x8002b71, -0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, -0x8ee20170, 0x8ee204e4, 0xa2e004f4, 0xaee004f0, -0xaee204f8, 0x8f42023c, 0x50400045, 0xaee07274, -0x8ee20184, 0x24420001, 0xaee20184, 0x8ee20184, -0x8002b71, 0xaee07274, 0x8ee20504, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee20504, -0x24420001, 0xaee20504, 0x8ee20504, 0x8cc30018, -0x21080, 0x571021, 0x8c440508, 0x24020003, -0x1462000f, 0x0, 0x3c020001, 0x571021, -0x904283b1, 0x10400014, 0x0, 0x8ee201d0, -0x8ee35240, 0x441021, 0xaee201d0, 0x8ee201d8, -0x641821, 0x306300ff, 0x8002b59, 0xaee35240, -0x8ee201cc, 0x8ee30e10, 0x441021, 0xaee201cc, -0x8ee201d8, 0x641821, 0x306301ff, 0xaee30e10, -0x441021, 0xaee201d8, 0x8ee20000, 0x34420040, -0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001, -0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, -0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, -0x3c040001, 0x24845760, 0xafa60014, 0xafa20010, -0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910, -0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, -0xafb50054, 0xafb40050, 0xafb3004c, 0xafb20048, -0xafb10044, 0xafb00040, 0x8f830108, 0x8f820104, -0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001, -0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018, -0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf, -0x31080, 0x3c010001, 0x220821, 0x8c2257c0, -0x400008, 0x0, 0x9663000e, 0x8ee2725c, -0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c, -0x96e20458, 0x24840001, 0xaee404f0, 0x24630001, -0x2442ffff, 0x621824, 0xaee304e4, 0x8f42023c, -0x82202b, 0x148003b9, 0x0, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8021, 0x24420001, 0xaee201a4, 0x8002bfe, -0x8ee201a4, 0x8ee204e4, 0xac62001c, 0x8ee404b0, -0x8ee504b4, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, -0x92e24e20, 0x14400037, 0x24100001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020012, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x240c0040, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x104c0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8002be8, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400013, 0xac800000, 0x8002bfe, -0x0, 0x8ee24e30, 0x240c0040, 0x24420001, -0x504c0003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x24020012, 0x240c0001, 0xac820000, -0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, -0x3c040001, 0x24845754, 0xafa00014, 0xafa20010, -0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, -0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a, -0x240c0001, 0x8002f19, 0x0, 0x966c001c, -0xafac002c, 0x9662001e, 0x3c0c8000, 0xafac0024, -0xae62001c, 0x8e75001c, 0x8ee204fc, 0x8ee404fc, -0x151900, 0x621021, 0x8c52000c, 0x92e27b98, -0x641821, 0x9476000a, 0x14400003, 0x32c20002, -0xaef27ba4, 0xaef57b9c, 0x1040004b, 0x8021, -0x96e2045a, 0x30420002, 0x10400047, 0x0, -0x8e63001c, 0x8ee204fc, 0x32100, 0x821021, -0x8c42000c, 0x37e1821, 0x24420022, 0x43102b, -0x1440000a, 0x24050014, 0x8ee204fc, 0x821021, -0x8c44000c, 0xafab0038, 0xc002f75, 0x2484000e, -0x8fab0038, 0x8002c52, 0x3050ffff, 0x8ee204fc, -0x821021, 0x8c42000c, 0x9450000e, 0x94430010, -0x94440012, 0x94450014, 0x2038021, 0x2048021, -0x2058021, 0x94430016, 0x94440018, 0x9445001a, -0x2038021, 0x2048021, 0x2058021, 0x9443001c, -0x9444001e, 0x94420020, 0x2038021, 0x2048021, -0x2028021, 0x101c02, 0x3202ffff, 0x628021, -0x8e63001c, 0x8ee204fc, 0x102402, 0x32900, -0xa21021, 0x8c43000c, 0x3202ffff, 0x828021, -0x37e1021, 0x24630018, 0x62182b, 0x14600009, -0x0, 0x8ee204fc, 0xa21021, 0x8c43000c, -0x101027, 0x3c01ffff, 0x230821, 0x8002c6f, -0xa4220018, 0x8ee204fc, 0xa21021, 0x8c43000c, -0x101027, 0xa4620018, 0x96e2045a, 0x8821, -0x30420008, 0x14400063, 0xa021, 0x8e63001c, -0x8ee204fc, 0x33100, 0xc21021, 0x8c42000c, -0x37e1821, 0x24420022, 0x43102b, 0x14400035, -0x0, 0x8ee204fc, 0xc21021, 0x8c42000c, -0x24470010, 0x37e1021, 0xe2102b, 0x50400001, -0xeb3821, 0x8ee204fc, 0x94f10000, 0xc21021, -0x8c42000c, 0x24470016, 0x37e1021, 0xe2102b, -0x14400002, 0x2634ffec, 0xeb3821, 0x8ee204fc, -0x90e30001, 0xc21021, 0x8c42000c, 0x2447001a, -0x37e1021, 0xe2102b, 0x14400002, 0x2838821, -0xeb3821, 0x94e20000, 0x24e70002, 0x2228821, -0x37e1021, 0xe2102b, 0x50400001, 0xeb3821, -0x94e20000, 0x24e70002, 0x2228821, 0x37e1021, -0xe2102b, 0x50400001, 0xeb3821, 0x94e20000, -0x24e70002, 0x2228821, 0x37e1021, 0xe2102b, -0x50400001, 0xeb3821, 0x94e20000, 0x8002cd0, -0x2228821, 0x8ee204fc, 0xc21021, 0x8c43000c, -0x8ee204fc, 0x94710010, 0x8ee304fc, 0xc21021, -0x8c44000c, 0xc31821, 0x8c62000c, 0x2634ffec, -0x90840017, 0x8ee304fc, 0x9442001a, 0x2848821, -0xc31821, 0x8c65000c, 0x8ee304fc, 0x2228821, -0x8ee204fc, 0xc31821, 0xc21021, 0x8c44000c, -0x8c62000c, 0x94a3001c, 0x9484001e, 0x94420020, -0x2238821, 0x2248821, 0x2228821, 0x111c02, -0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, -0x628821, 0x32c20001, 0x104000b2, 0x0, -0x96e2045a, 0x30420001, 0x104000ae, 0x32c20080, -0x10400008, 0x0, 0x92e27b98, 0x14400005, -0x0, 0x240c0001, 0xa2ec7b98, 0xaef57b9c, -0xaef27ba4, 0x8ee304fc, 0x151100, 0x431021, -0x8c47000c, 0x37e1821, 0x24e2000e, 0x43102b, -0x14400008, 0xe02021, 0x2405000e, 0xc002f75, -0xafab0038, 0x3042ffff, 0x8fab0038, 0x8002d09, -0x2028021, 0x94e60000, 0x24e70002, 0x94e50000, -0x24e70002, 0x94e30000, 0x24e70002, 0x94e20000, -0x24e70002, 0x94e40000, 0x24e70002, 0x2068021, -0x2058021, 0x2038021, 0x2028021, 0x94e20000, -0x94e30002, 0x2048021, 0x2028021, 0x2038021, -0x101c02, 0x3202ffff, 0x628021, 0x101c02, -0x3202ffff, 0x8ee47b9c, 0x628021, 0x14950004, -0x3205ffff, 0x96620016, 0x8002d17, 0x512021, -0x96620016, 0x542021, 0x41402, 0x3083ffff, -0x432021, 0x852023, 0x41402, 0x822021, -0x3084ffff, 0x50800001, 0x3404ffff, 0x8ee27ba4, -0x24430017, 0x37e1021, 0x62102b, 0x50400001, -0x6b1821, 0x90630000, 0x24020011, 0x14620031, -0x24020006, 0x8ee27ba4, 0x37e1821, 0x24420028, -0x43102b, 0x14400018, 0x0, 0x8ee27b9c, -0x12a2000a, 0x32c20100, 0x8ee27ba4, 0x3c01ffff, -0x220821, 0x94220028, 0x822021, 0x41c02, -0x3082ffff, 0x622021, 0x32c20100, 0x14400004, -0x41027, 0x92e27b98, 0x14400002, 0x41027, -0x3044ffff, 0x8ee27ba4, 0x3c01ffff, 0x220821, -0x8002d8a, 0xa4240028, 0x8ee27b9c, 0x12a20008, -0x32c20100, 0x8ee27ba4, 0x94420028, 0x822021, -0x41c02, 0x3082ffff, 0x622021, 0x32c20100, -0x14400004, 0x41027, 0x92e27b98, 0x14400002, -0x41027, 0x3044ffff, 0x8ee27ba4, 0x8002d8a, -0xa4440028, 0x1462002f, 0x37e1821, 0x8ee27ba4, -0x24420032, 0x43102b, 0x14400018, 0x0, -0x8ee27b9c, 0x12a2000a, 0x32c20100, 0x8ee27ba4, -0x3c01ffff, 0x220821, 0x94220032, 0x822021, -0x41c02, 0x3082ffff, 0x622021, 0x32c20100, -0x14400004, 0x41027, 0x92e27b98, 0x14400002, -0x41027, 0x3044ffff, 0x8ee27ba4, 0x3c01ffff, -0x220821, 0x8002d8a, 0xa4240032, 0x8ee27b9c, -0x12a20008, 0x32c20100, 0x8ee27ba4, 0x94420032, -0x822021, 0x41c02, 0x3082ffff, 0x622021, -0x32c20100, 0x14400004, 0x41027, 0x92e27b98, -0x14400002, 0x41027, 0x3044ffff, 0x8ee27ba4, -0xa4440032, 0x8fac0024, 0x1180002c, 0x37e1821, -0x8e420000, 0xae42fffc, 0x2642000a, 0x43102b, -0x1440001b, 0x34038100, 0x26430004, 0x37e1021, -0x62102b, 0x14400003, 0x602021, 0x6b1821, -0x602021, 0x8c620000, 0x24630004, 0xae420000, -0x37e1021, 0x62102b, 0x50400001, 0x6b1821, -0x8c620000, 0xac820000, 0x34028100, 0xa4620000, -0x24630002, 0x37e1021, 0x62102b, 0x50400001, -0x6b1821, 0x97ac002e, 0x8002db4, 0xa46c0000, -0x8e420004, 0x8e440008, 0xa6430008, 0x97ac002e, -0xa64c000a, 0xae420000, 0xae440004, 0x9662000e, -0x2652fffc, 0x24420004, 0xa662000e, 0x9662000e, -0x8ee3725c, 0x621821, 0xaee3725c, 0xafb20018, -0x8ee3725c, 0xafa3001c, 0x8ee2725c, 0x2c42003c, -0x10400004, 0x24620001, 0x2403fffe, 0x431024, -0xafa2001c, 0x32c20080, 0x1040000c, 0x32c20100, -0x8ee27ba8, 0x24430001, 0x210c0, 0x571021, -0xaee37ba8, 0x8fa30018, 0x8fa4001c, 0xac437bac, -0xac447bb0, 0x8002ea0, 0xaee0725c, 0x10400072, -0x0, 0x8ee27ba8, 0x24430001, 0x210c0, -0x571021, 0xaee37ba8, 0x8fa30018, 0x8fa4001c, -0xac437bac, 0xac447bb0, 0x8ee27ba8, 0x10400063, -0x4821, 0x5021, 0x8f8200f0, 0x24480008, -0x27621800, 0x102102b, 0x50400001, 0x27681000, -0x8f8200f4, 0x15020007, 0x0, 0x8ee201b4, -0x8021, 0x24420001, 0xaee201b4, 0x8002dfa, -0x8ee201b4, 0x8f8300f0, 0x24100001, 0x1571021, -0x8c447bac, 0x8c457bb0, 0xac640000, 0xac650004, -0xaf8800f0, 0x16000006, 0x2ea1021, 0x8ee20088, -0x24420001, 0xaee20088, 0x8002e3f, 0x8ee20088, -0x8c427bb0, 0x8ee400e0, 0x8ee500e4, 0x8ee67b9c, -0x401821, 0x1021, 0xa32821, 0xa3382b, -0x822021, 0x872021, 0x8ee204fc, 0xc93021, -0x63100, 0xaee400e0, 0xaee500e4, 0xc23021, -0x94c2000a, 0x240c0002, 0x21142, 0x30430003, -0x106c0016, 0x28620003, 0x10400005, 0x240c0001, -0x106c0008, 0x0, 0x8002e3f, 0x0, -0x240c0003, 0x106c0017, 0x0, 0x8002e3f, -0x0, 0x8ee200e8, 0x8ee300ec, 0x24630001, -0x2c640001, 0x441021, 0xaee200e8, 0xaee300ec, -0x8ee200e8, 0x8002e3f, 0x8ee300ec, 0x8ee200f0, -0x8ee300f4, 0x24630001, 0x2c640001, 0x441021, -0xaee200f0, 0xaee300f4, 0x8ee200f0, 0x8002e3f, -0x8ee300f4, 0x8ee200f8, 0x8ee300fc, 0x24630001, -0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, -0x8ee200f8, 0x8ee300fc, 0x8ee27ba8, 0x25290001, -0x122102b, 0x1440ffa0, 0x254a0008, 0xa2e07b98, -0x8002e9f, 0xaee07ba8, 0x8f8200f0, 0x24470008, -0x27621800, 0xe2102b, 0x50400001, 0x27671000, -0x8f8200f4, 0x14e20007, 0x0, 0x8ee201b4, -0x8021, 0x24420001, 0xaee201b4, 0x8002e5d, -0x8ee201b4, 0x8f8200f0, 0x24100001, 0x8fa30018, -0x8fa4001c, 0xac430000, 0xac440004, 0xaf8700f0, -0x16000007, 0x0, 0x8ee20088, 0x24420001, -0xaee20088, 0x8ee20088, 0x8002ea0, 0xaee0725c, -0x8ee2725c, 0x8ee400e0, 0x8ee500e4, 0x240c0002, -0x401821, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0x161142, 0x30430003, -0xaee400e0, 0xaee500e4, 0x106c0017, 0x2c620003, -0x10400005, 0x240c0001, 0x106c0008, 0x0, -0x8002ea0, 0xaee0725c, 0x240c0003, 0x106c0019, -0x0, 0x8002ea0, 0xaee0725c, 0x8ee200e8, -0x8ee300ec, 0x24630001, 0x2c640001, 0x441021, -0xaee200e8, 0xaee300ec, 0x8ee200e8, 0x8ee300ec, -0x8002ea0, 0xaee0725c, 0x8ee200f0, 0x8ee300f4, -0x24630001, 0x2c640001, 0x441021, 0xaee200f0, -0xaee300f4, 0x8ee200f0, 0x8ee300f4, 0x8002ea0, -0xaee0725c, 0x8ee200f8, 0x8ee300fc, 0x24630001, -0x2c640001, 0x441021, 0xaee200f8, 0xaee300fc, -0x8ee200f8, 0x8ee300fc, 0xaee0725c, 0x8e62001c, -0x96e30458, 0x8ee404f0, 0x24420001, 0x2463ffff, -0x431024, 0x24840001, 0xaee204e4, 0xaee404f0, -0x8f42023c, 0x82202b, 0x148000b0, 0x0, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8002f07, 0x8ee201a4, 0x8ee204e4, 0xac62001c, -0x8ee404b0, 0x8ee504b4, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400037, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c830000, 0x24020012, 0x1462001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x240c0040, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x104c0007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8002ef1, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x8002f07, 0x0, 0x8ee24e30, 0x240c0040, -0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020012, 0x240c0001, -0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, -0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014, -0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, -0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038, -0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4, -0x8ee20170, 0x24420001, 0xaee20170, 0x8ee20170, -0x8ee204e4, 0xa2e004f4, 0xaee004f0, 0xaee07274, -0xaee204f8, 0x8f42023c, 0x10400038, 0x0, -0x8ee20184, 0x24420001, 0xaee20184, 0x8002f5c, -0x8ee20184, 0x8ee20504, 0x240c0040, 0x24420001, -0x504c0003, 0x1021, 0x8ee20504, 0x24420001, -0xaee20504, 0x8ee20504, 0x8e630018, 0x240c0003, -0x21080, 0x571021, 0x146c000f, 0x8c440508, -0x3c020001, 0x571021, 0x904283b1, 0x10400014, -0x0, 0x8ee201d0, 0x8ee35240, 0x441021, -0xaee201d0, 0x8ee201d8, 0x641821, 0x306300ff, -0x8002f4f, 0xaee35240, 0x8ee201cc, 0x8ee30e10, -0x441021, 0xaee201cc, 0x8ee201d8, 0x641821, -0x306301ff, 0xaee30e10, 0x441021, 0xaee201d8, -0x8ee20000, 0x34420040, 0x8002f5c, 0xaee20000, -0x8ee2014c, 0x3c010001, 0x370821, 0xa02083e0, -0x24420001, 0xaee2014c, 0x8ee2014c, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x8f820108, -0x27633000, 0x43102b, 0x14400002, 0x27622800, -0xaf820108, 0x8f830108, 0x8f820104, 0x1462fc1e, -0x0, 0x8fbf0060, 0x8fbe005c, 0x8fb60058, -0x8fb50054, 0x8fb40050, 0x8fb3004c, 0x8fb20048, -0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0068, -0x52843, 0x10a0000d, 0x3021, 0x3c030001, -0x34633800, 0x3c07ffff, 0x3631021, 0x82102b, -0x50400001, 0x872021, 0x94820000, 0x24840002, -0x24a5ffff, 0x14a0fff8, 0xc23021, 0x61c02, -0x30c2ffff, 0x623021, 0x61c02, 0x30c2ffff, -0x623021, 0x3e00008, 0x30c2ffff, 0x27bdff88, -0x240f0001, 0xafbf0070, 0xafbe006c, 0xafb60068, -0xafb50064, 0xafb40060, 0xafb3005c, 0xafb20058, -0xafb10054, 0xafb00050, 0xa3a00027, 0xafaf002c, -0x8ee204d4, 0x8021, 0x30420001, 0x1440002a, -0xa3a00037, 0x8f8700e0, 0x8f8800c4, 0x8f8200e8, -0xe22023, 0x2c821000, 0x50400001, 0x24841000, -0x420c2, 0x801821, 0x8ee400c8, 0x8ee500cc, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c8, 0xaee500cc, 0x8f8300c8, -0x3c02000a, 0x3442efff, 0x1032023, 0x44102b, -0x10400003, 0x3c02000a, 0x3442f000, 0x822021, -0x801821, 0x8ee400c0, 0x8ee500c4, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0xaee400c0, 0xaee500c4, 0xaf8800c8, 0xaf8700e4, -0x80034cc, 0xaf8700e8, 0x3c020001, 0x571021, -0x904283c0, 0x1040000b, 0x0, 0x3c140001, -0x297a021, 0x8e9483c4, 0x3c130001, 0x2779821, -0x8e7383c8, 0x3c120001, 0x2579021, 0x8003193, -0x8e5283cc, 0x8f8300e0, 0x8f8200e4, 0x10430007, -0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, -0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, -0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, -0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0, -0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000, -0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018, -0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, -0x2409821, 0x3c020080, 0x621024, 0x1040000a, -0x3c040040, 0x8ee2007c, 0x24420001, 0xaee2007c, -0x8ee2007c, 0x8ee201fc, 0x24420001, 0xaee201fc, -0x80034c6, 0x8ee201fc, 0x3c060004, 0x3c0b0001, -0x3c0a0002, 0x3c050010, 0x3c090008, 0x8ee20080, -0x3c080020, 0x34078000, 0x24420001, 0xaee20080, -0x8ee20080, 0x8fa2001c, 0x441824, 0x10660021, -0xc3102b, 0x14400007, 0x0, 0x106b0011, -0x0, 0x106a0015, 0x0, 0x8003049, -0x42042, 0x10650023, 0xa3102b, 0x14400005, -0x0, 0x10690019, 0x0, 0x8003049, -0x42042, 0x10680021, 0x0, 0x8003049, -0x42042, 0x8ee20034, 0x24420001, 0xaee20034, -0x8ee20034, 0x8003049, 0x42042, 0x8ee201ec, -0x24420001, 0xaee201ec, 0x8ee201ec, 0x8003049, -0x42042, 0x8ee201f0, 0x24420001, 0xaee201f0, -0x8ee201f0, 0x8003049, 0x42042, 0x8ee201f4, -0x24420001, 0xaee201f4, 0x8ee201f4, 0x8003049, -0x42042, 0x8ee20030, 0x24420001, 0xaee20030, -0x8ee20030, 0x8003049, 0x42042, 0x8ee201f8, -0x24420001, 0xaee201f8, 0x8ee201f8, 0x42042, -0x1087047c, 0x0, 0x800300e, 0x0, -0x3c020001, 0x571021, 0x904283b2, 0x14400084, -0x24020001, 0x3c030001, 0x771821, 0x906383b3, -0x1462007f, 0x3c020100, 0x8e430000, 0x621024, -0x1040006f, 0x2402ffff, 0x14620005, 0x24100001, -0x96430004, 0x3402ffff, 0x10620075, 0x0, -0x92e204d8, 0x14400072, 0x0, 0x3c020001, -0x571021, 0x8c4283b4, 0x28420005, 0x10400020, -0x3821, 0x3c020001, 0x571021, 0x8c4283b4, -0x18400016, 0x2821, 0x96660000, 0x520c0, -0x971021, 0x9442777e, 0x14460009, 0x971021, -0x94437780, 0x96620002, 0x14620005, 0x971021, -0x94437782, 0x96620004, 0x50620008, 0x24070001, -0x3c020001, 0x571021, 0x8c4283b4, 0x24a50001, -0xa2102a, 0x5440ffee, 0x520c0, 0x30e200ff, -0x10400440, 0x0, 0x80030d5, 0x0, -0x2402021, 0xc0022fe, 0x24050006, 0x3044001f, -0x428c0, 0x2e51021, 0x9442727c, 0x30424000, -0x14400434, 0xb71021, 0x9443727e, 0x96620000, -0x1462000b, 0x418c0, 0xb71021, 0x94437280, -0x96620002, 0x14620006, 0x418c0, 0xb71021, -0x94437282, 0x96620004, 0x10620035, 0x418c0, -0x2e31021, 0x9442727c, 0x30428000, 0x14400421, -0x2e31021, 0x944b727c, 0x96670000, 0xb28c0, -0xb71021, 0x9442737e, 0x80030b7, 0x3021, -0x420c0, 0x2e41021, 0x9443737c, 0x2e41021, -0x944b737c, 0x30638000, 0x14600010, 0xb28c0, -0xb71021, 0x9442737e, 0x1447fff5, 0x1602021, -0xb71021, 0x94437380, 0x96620002, 0x5462fff1, -0x420c0, 0xb71021, 0x94437382, 0x96620004, -0x5462ffec, 0x420c0, 0x24060001, 0x30c200ff, -0x10400400, 0x0, 0x80030d5, 0x0, -0x97430202, 0x96420000, 0x146203fa, 0x0, -0x97430204, 0x96420002, 0x146203f6, 0x0, -0x97430206, 0x96420004, 0x146203f2, 0x0, -0x92420000, 0x3a030001, 0x30420001, 0x431024, -0x10400074, 0x2402ffff, 0x8e630000, 0x14620004, -0x3402ffff, 0x96630004, 0x1062006f, 0x240f0002, -0x3c020001, 0x571021, 0x904283b2, 0x1440006a, -0x240f0003, 0x92e204d8, 0x54400068, 0xafaf002c, -0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, -0x10400020, 0x3821, 0x3c020001, 0x571021, -0x8c4283b4, 0x18400016, 0x2821, 0x96660000, -0x520c0, 0x971021, 0x9442777e, 0x14460009, -0x971021, 0x94437780, 0x96620002, 0x14620005, -0x971021, 0x94437782, 0x96620004, 0x50620008, -0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, -0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x14400044, 0x240f0003, 0x80034c6, -0x0, 0x2402021, 0xc0022fe, 0x24050006, -0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, -0x30424000, 0x144003af, 0xb71021, 0x9443727e, -0x96620000, 0x1462000b, 0x418c0, 0xb71021, -0x94437280, 0x96620002, 0x14620006, 0x418c0, -0xb71021, 0x94437282, 0x96620004, 0x10620027, -0x418c0, 0x2e31021, 0x9442727c, 0x30428000, -0x1440039c, 0x2e31021, 0x944b727c, 0x96670000, -0xb28c0, 0xb71021, 0x9442737e, 0x800313c, -0x3021, 0x420c0, 0x2e41021, 0x9443737c, -0x2e41021, 0x944b737c, 0x30638000, 0x14600010, -0xb28c0, 0xb71021, 0x9442737e, 0x1447fff5, -0x1602021, 0xb71021, 0x94437380, 0x96620002, -0x5462fff1, 0x420c0, 0xb71021, 0x94437382, -0x96620004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x1040037b, 0x0, 0x800314f, -0x240f0003, 0x240f0001, 0xafaf002c, 0x8f420260, -0x54102b, 0x1040003a, 0x0, 0x8f8300e4, -0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, -0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2801821, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, -0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, -0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878, -0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002403, 0x34a5f003, 0x80034cc, 0x0, -0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0, -0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, -0x2403ffbf, 0x431024, 0x8003470, 0xaee20000, -0x96e20468, 0x54102b, 0x10400003, 0x0, -0x240f0001, 0xa3af0027, 0x12800301, 0x24160007, -0x24150040, 0x241e0001, 0x240e0012, 0x8ee2724c, -0x8f430280, 0x24420001, 0x304207ff, 0x106202d3, -0x0, 0x93a20027, 0x10400014, 0x0, -0x8ee35240, 0x8ee25244, 0x10620009, 0x26ed5244, -0x8ee65244, 0x8ee35244, 0x21140, 0x24425248, -0x2e28021, 0x24630001, 0x80031bf, 0x306b00ff, -0x92e27248, 0x1440ffca, 0x0, 0x8ee201e0, -0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, -0x8ee20e18, 0x1062ffc2, 0x26ed0e18, 0x8ee60e18, -0x8ee30e18, 0x21140, 0x24420e20, 0x2e28021, -0x24630001, 0x306b01ff, 0x96e2046a, 0x30420010, -0x10400019, 0x0, 0x9642000c, 0x340f8100, -0x144f0015, 0x0, 0x3c020001, 0x571021, -0x904283c0, 0x14400010, 0x0, 0x9642000e, -0xa6020016, 0x8e420008, 0x8e430004, 0x8e440000, -0x2694fffc, 0xae42000c, 0xae430008, 0xae440004, -0x9602000e, 0x26730004, 0x240f0001, 0xa3af0037, -0x34420200, 0xa602000e, 0x8e020000, 0x8e030004, -0x3c040001, 0x34843800, 0x306a0007, 0x26a9823, -0x3641021, 0x262102b, 0x10400005, 0x28aa021, -0x2641023, 0x3621823, 0x3c020020, 0x439823, -0x26820007, 0x2404fff8, 0x9603000a, 0x446024, -0x6a1821, 0x6c102b, 0x10400002, 0x1803821, -0x603821, 0xae130018, 0x8f880120, 0x24e20007, -0x443824, 0x27623800, 0x25090020, 0x122102b, -0x50400001, 0x27693000, 0x8f820128, 0x11220004, -0x0, 0x8f820124, 0x15220007, 0x1401821, -0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, -0x800324c, 0x8ee201a4, 0x8e040000, 0x8e050004, -0x1021, 0xad130008, 0xa507000e, 0xad160018, -0xad06001c, 0xa3302b, 0xa32823, 0x822023, -0x862023, 0xad040000, 0xad050004, 0x8ee204c0, -0xad020010, 0xaf890120, 0x92e24e20, 0x14400033, -0x24110001, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c820000, 0x1456001f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062001b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x10550007, 0x0, -0x8ee24e34, 0x24420001, 0x10620005, 0x0, -0x8003239, 0x0, 0x14600005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400010, 0xac800000, -0x800324c, 0x0, 0x8ee24e30, 0x24420001, -0x50550003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, -0x3c050006, 0x8e020018, 0x3c040001, 0x24845890, -0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, -0x2003021, 0xc002403, 0xafa30014, 0x93a20037, -0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, -0x8e44000c, 0xa64f000c, 0xae420000, 0xae430004, -0xae440008, 0x96020016, 0x8003470, 0xa642000e, -0x14ec0168, 0x28a1823, 0x960c000a, 0x9603000e, -0x28a1023, 0xa602000a, 0x34620004, 0xa602000e, -0x8f880120, 0x27623800, 0x25090020, 0x122102b, -0x14400002, 0x306affff, 0x27693000, 0x8f820128, -0x11220004, 0x0, 0x8f820124, 0x15220007, -0x24040020, 0x8ee201a4, 0x8821, 0x24420001, -0xaee201a4, 0x80032ca, 0x8ee201a4, 0x8ee5724c, -0x8ee60490, 0x8ee70494, 0xa504000e, 0x24040004, -0xad100008, 0xad040018, 0x52940, 0xa01821, -0x1021, 0xe33821, 0xe3202b, 0xc23021, -0xc43021, 0xad060000, 0xad070004, 0x8ee2724c, -0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120, -0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c820000, -0x1456001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x0, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, -0x10550007, 0x0, 0x8ee24e34, 0x24420001, -0x10620005, 0x0, 0x80032b7, 0x0, -0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400010, 0xac800000, 0x80032ca, 0x0, -0x8ee24e30, 0x24420001, 0x50550003, 0x1021, -0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0xac960000, -0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, -0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014, -0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001, -0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, -0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, -0x24630001, 0x306307ff, 0x26e25244, 0x15a20006, -0xaee3724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, -0x80032ef, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, -0xaee201cc, 0x8ee201cc, 0x8f420240, 0x10400073, -0x0, 0x8ee20e1c, 0x24420001, 0xaee20e1c, -0x8f430240, 0x43102b, 0x14400176, 0xa021, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x8821, 0x24420001, 0xaee201a4, -0x800334f, 0x8ee201a4, 0x8ee2724c, 0xac62001c, -0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400033, 0x24110001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x144e001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x10550007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x800333c, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x800334f, -0x0, 0x8ee24e30, 0x24420001, 0x50550003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, -0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014, -0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, -0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048, -0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, -0xaee20188, 0x80033c8, 0x8ee20188, 0x8f830120, -0x27623800, 0x24660020, 0xc2102b, 0x50400001, -0x27663000, 0x8f820128, 0x10c20004, 0x0, -0x8f820124, 0x14c20007, 0x0, 0x8ee201a4, -0x8821, 0x24420001, 0xaee201a4, 0x80033ba, -0x8ee201a4, 0x8ee2724c, 0xac62001c, 0x8ee404a8, -0x8ee504ac, 0x2462001c, 0xac620008, 0x24020008, -0xa462000e, 0x24020011, 0xac620018, 0xac640000, -0xac650004, 0x8ee204c4, 0xac620010, 0xaf860120, -0x92e24e20, 0x14400033, 0x24110001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c820000, -0x144e001f, 0x0, 0x8ee34e30, 0x8ee24e34, -0x1062001b, 0x0, 0x8c820004, 0x24420001, -0xac820004, 0x8ee24e34, 0x8ee34e30, 0x24420001, -0x10550007, 0x0, 0x8ee24e34, 0x24420001, -0x10620005, 0x0, 0x80033a7, 0x0, -0x14600005, 0x0, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x8c820004, 0x2c420011, -0x50400010, 0xac800000, 0x80033ba, 0x0, -0x8ee24e30, 0x24420001, 0x50550003, 0x1021, -0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, -0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, -0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010, -0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, -0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174, -0x24420001, 0xaee20174, 0x8ee20174, 0x800346e, -0xa021, 0x960c000a, 0x183102b, 0x54400001, -0x1801821, 0xa603000a, 0x8f880120, 0x27623800, -0x25090020, 0x122102b, 0x50400001, 0x27693000, -0x8f820128, 0x11220004, 0x0, 0x8f820124, -0x15220007, 0x24040020, 0x8ee201a4, 0x8821, -0x24420001, 0xaee201a4, 0x800342f, 0x8ee201a4, -0x8ee5724c, 0x8ee60490, 0x8ee70494, 0xa504000e, -0x24040004, 0xad100008, 0xad040018, 0x52940, -0xa01821, 0x1021, 0xe33821, 0xe3202b, -0xc23021, 0xc43021, 0xad060000, 0xad070004, -0x8ee2724c, 0xad02001c, 0x8ee204c4, 0xad020010, -0xaf890120, 0x92e24e20, 0x14400033, 0x24110001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x1456001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x10550007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x800341c, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400010, 0xac800000, 0x800342f, -0x0, 0x8ee24e30, 0x24420001, 0x50550003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0xac960000, 0xac9e0004, 0x1620001d, 0x0, -0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, -0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014, -0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821, -0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, -0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, -0xae430004, 0xae440008, 0x96020016, 0xa642000e, -0x9602000e, 0x3042fdff, 0x8003470, 0xa602000e, -0x8ee201d8, 0x2442ffff, 0xaee201d8, 0x8ee201d8, -0x8ee201cc, 0x3c04001f, 0x3c010001, 0x370821, -0xa03e83c0, 0x2442ffff, 0xaee201cc, 0x9603000a, -0x3484ffff, 0x8ee201cc, 0x6a1821, 0x2639821, -0x93202b, 0x10800003, 0x3c02fff5, 0x34421000, -0x2629821, 0xadab0000, 0x8ee2724c, 0x24420001, -0x304207ff, 0xaee2724c, 0x8f420240, 0x10400004, -0x283a023, 0x8ee20e1c, 0x24420001, 0xaee20e1c, -0xa3a00027, 0x1680fd29, 0x0, 0x12800024, -0x0, 0x3c010001, 0x370821, 0xac3483c4, -0x3c010001, 0x370821, 0xac3383c8, 0x3c010001, -0x370821, 0xac3283cc, 0x93a20037, 0x10400008, -0x0, 0x3c020001, 0x571021, 0x8c4283cc, -0x24420004, 0x3c010001, 0x370821, 0xac2283cc, -0x8ee2724c, 0x8f430280, 0x24420001, 0x304207ff, -0x14620006, 0x0, 0x8ee201c4, 0x24420001, -0xaee201c4, 0x80034cc, 0x8ee201c4, 0x8ee201bc, -0x24420001, 0xaee201bc, 0x80034cc, 0x8ee201bc, -0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, -0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaee400c0, 0xaee500c4, -0x8faf002c, 0x24020002, 0x11e2000f, 0x29e20003, -0x14400017, 0x24020003, 0x15e20015, 0x0, -0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, -0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, -0x80034c6, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, -0x24630001, 0x2c640001, 0x441021, 0xaee200d8, -0xaee300dc, 0x8ee200d8, 0x80034c6, 0x8ee300dc, -0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, -0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, -0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, -0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf0070, -0x8fbe006c, 0x8fb60068, 0x8fb50064, 0x8fb40060, -0x8fb3005c, 0x8fb20058, 0x8fb10054, 0x8fb00050, -0x3e00008, 0x27bd0078, 0x27bdffb0, 0xafb50044, -0xa821, 0xafb00030, 0x8021, 0xafbf004c, -0xafb60048, 0xafb40040, 0xafb3003c, 0xafb20038, -0xafb10034, 0x8ee204d4, 0x24140001, 0x30420001, -0x1440002a, 0xb021, 0x8f8700e0, 0x8f8800c4, -0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, -0x24841000, 0x420c2, 0x801821, 0x8ee400c8, -0x8ee500cc, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaee400c8, 0xaee500cc, -0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023, -0x44102b, 0x10400003, 0x3c02000a, 0x3442f000, -0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, -0xaf8700e4, 0x8003850, 0xaf8700e8, 0x3c020001, -0x571021, 0x904283c0, 0x1040000b, 0x0, -0x3c130001, 0x2779821, 0x8e7383c4, 0x3c110001, -0x2378821, 0x8e3183c8, 0x3c120001, 0x2579021, -0x80036e8, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, -0x10430007, 0x4821, 0x8f8200e4, 0x24090001, -0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, -0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014, -0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, -0x34a5f000, 0x8003850, 0x0, 0x8fa3001c, -0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, -0x10400058, 0x2408821, 0x3c020080, 0x621024, -0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, -0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, -0xaee201fc, 0x800384a, 0x8ee201fc, 0x3c060004, -0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, -0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, -0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, -0x10660021, 0xc3102b, 0x14400007, 0x0, -0x106b0011, 0x0, 0x106a0015, 0x0, -0x8003592, 0x42042, 0x10650023, 0xa3102b, -0x14400005, 0x0, 0x10690019, 0x0, -0x8003592, 0x42042, 0x10680021, 0x0, -0x8003592, 0x42042, 0x8ee20034, 0x24420001, -0xaee20034, 0x8ee20034, 0x8003592, 0x42042, -0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, -0x8003592, 0x42042, 0x8ee201f0, 0x24420001, -0xaee201f0, 0x8ee201f0, 0x8003592, 0x42042, -0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, -0x8003592, 0x42042, 0x8ee20030, 0x24420001, -0xaee20030, 0x8ee20030, 0x8003592, 0x42042, -0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, -0x42042, 0x108702b7, 0x0, 0x8003557, -0x0, 0x3c020001, 0x571021, 0x904283b2, -0x14400084, 0x24020001, 0x3c030001, 0x771821, -0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, -0x621024, 0x1040006f, 0x2402ffff, 0x14620005, -0x24100001, 0x96430004, 0x3402ffff, 0x10620075, -0x0, 0x92e204d8, 0x14400072, 0x0, -0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, -0x10400020, 0x3821, 0x3c020001, 0x571021, -0x8c4283b4, 0x18400016, 0x2821, 0x96260000, -0x520c0, 0x971021, 0x9442777e, 0x14460009, -0x971021, 0x94437780, 0x96220002, 0x14620005, -0x971021, 0x94437782, 0x96220004, 0x50620008, -0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, -0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x1040027b, 0x0, 0x800361e, -0x0, 0x2402021, 0xc0022fe, 0x24050006, -0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, -0x30424000, 0x1440026f, 0xb71021, 0x9443727e, -0x96220000, 0x1462000b, 0x418c0, 0xb71021, -0x94437280, 0x96220002, 0x14620006, 0x418c0, -0xb71021, 0x94437282, 0x96220004, 0x10620035, -0x418c0, 0x2e31021, 0x9442727c, 0x30428000, -0x1440025c, 0x2e31021, 0x9448727c, 0x96270000, -0x828c0, 0xb71021, 0x9442737e, 0x8003600, -0x3021, 0x420c0, 0x2e41021, 0x9443737c, -0x2e41021, 0x9448737c, 0x30638000, 0x14600010, -0x828c0, 0xb71021, 0x9442737e, 0x1447fff5, -0x1002021, 0xb71021, 0x94437380, 0x96220002, -0x5462fff1, 0x420c0, 0xb71021, 0x94437382, -0x96220004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x1040023b, 0x0, 0x800361e, -0x0, 0x97430202, 0x96420000, 0x14620235, -0x0, 0x97430204, 0x96420002, 0x14620231, -0x0, 0x97430206, 0x96420004, 0x1462022d, -0x0, 0x92420000, 0x3a030001, 0x30420001, -0x431024, 0x10400074, 0x2402ffff, 0x8e230000, -0x14620004, 0x3402ffff, 0x96230004, 0x1062006f, -0x24140002, 0x3c020001, 0x571021, 0x904283b2, -0x1440006a, 0x24140003, 0x92e204d8, 0x14400067, -0x0, 0x3c020001, 0x571021, 0x8c4283b4, -0x28420005, 0x10400020, 0x3821, 0x3c020001, -0x571021, 0x8c4283b4, 0x18400016, 0x2821, -0x96260000, 0x520c0, 0x971021, 0x9442777e, -0x14460009, 0x971021, 0x94437780, 0x96220002, -0x14620005, 0x971021, 0x94437782, 0x96220004, -0x50620008, 0x24070001, 0x3c020001, 0x571021, -0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, -0x520c0, 0x30e200ff, 0x14400044, 0x24140003, -0x800384a, 0x0, 0x2402021, 0xc0022fe, -0x24050006, 0x3044001f, 0x428c0, 0x2e51021, -0x9442727c, 0x30424000, 0x144001ea, 0xb71021, -0x9443727e, 0x96220000, 0x1462000b, 0x418c0, -0xb71021, 0x94437280, 0x96220002, 0x14620006, -0x418c0, 0xb71021, 0x94437282, 0x96220004, -0x10620027, 0x418c0, 0x2e31021, 0x9442727c, -0x30428000, 0x144001d7, 0x2e31021, 0x9448727c, -0x96270000, 0x828c0, 0xb71021, 0x9442737e, -0x8003685, 0x3021, 0x420c0, 0x2e41021, -0x9443737c, 0x2e41021, 0x9448737c, 0x30638000, -0x14600010, 0x828c0, 0xb71021, 0x9442737e, -0x1447fff5, 0x1002021, 0xb71021, 0x94437380, -0x96220002, 0x5462fff1, 0x420c0, 0xb71021, -0x94437382, 0x96220004, 0x5462ffec, 0x420c0, -0x24060001, 0x30c200ff, 0x104001b6, 0x0, -0x8003698, 0x24140003, 0x24140001, 0x8f420260, -0x53102b, 0x10400049, 0x0, 0x8f8300e4, -0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, -0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, -0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, -0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878, -0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002403, 0x34a5f003, 0x8003850, 0x0, -0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, -0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, -0x431024, 0x80037f8, 0xaee20000, 0x8ee25240, -0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884, -0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, -0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, -0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468, -0x53102b, 0x54400001, 0x3c158000, 0x12600131, -0x3c0c001f, 0x358cffff, 0x8ee2724c, 0x8f430280, -0x24420001, 0x304207ff, 0x10620108, 0x0, -0x12a00014, 0x0, 0x8ee35240, 0x8ee25244, -0x10620009, 0x26ee5244, 0x8eeb5244, 0x8ee35244, -0x21140, 0x24425248, 0x2e28021, 0x24630001, -0x8003712, 0x306800ff, 0x92e27248, 0x1440ffc0, -0x3c050006, 0x8ee201e0, 0x24420001, 0xaee201e0, -0x8ee201e0, 0x8ee30e10, 0x8ee20e18, 0x1062ffcb, -0x26ee0e18, 0x8eeb0e18, 0xa821, 0x8ee30e18, -0x21140, 0x24420e20, 0x2e28021, 0x24630001, -0x306801ff, 0x96e2046a, 0x30420010, 0x10400017, -0x34028100, 0x9643000c, 0x14620014, 0x0, -0x3c020001, 0x571021, 0x904283c0, 0x1440000f, -0x0, 0x9642000e, 0xa6020016, 0x8e420008, -0x8e430004, 0x8e440000, 0x2673fffc, 0xae42000c, -0xae430008, 0xae440004, 0x9602000e, 0x26310004, -0x24160001, 0x34420200, 0xa602000e, 0x9603000a, -0x2605021, 0x73102b, 0x10400002, 0x2606821, -0x605021, 0x2d42003d, 0x1040002a, 0x3821, -0x9623000c, 0x24020800, 0x54620027, 0xae110018, -0x3c020001, 0x571021, 0x904283c0, 0x54400022, -0xae110018, 0x26220017, 0x182102b, 0x10400013, -0x0, 0x3c02fff5, 0x511021, 0x90421017, -0x38430006, 0x2c630001, 0x38420011, 0x2c420001, -0x621825, 0x10600013, 0x26220010, 0x182102b, -0x1040000e, 0x0, 0x3c07fff5, 0xf13821, -0x94e71010, 0x800375e, 0x24e7000e, 0x92220017, -0x38430006, 0x2c630001, 0x38420011, 0x2c420001, -0x621825, 0x50600004, 0xae110018, 0x96270010, -0x24e7000e, 0xae110018, 0x3c020001, 0x571021, -0x904283c0, 0x2102b, 0x14e00002, 0x24ec0, -0x1403821, 0x8f830120, 0x27623800, 0x24660020, -0xc2102b, 0x50400001, 0x27663000, 0x8f820128, -0x10c20004, 0x0, 0x8f820124, 0x14c20007, -0x2402000b, 0x8ee201a4, 0x4821, 0x24420001, -0xaee201a4, 0x80037bf, 0x8ee201a4, 0x8e040000, -0x8e050004, 0xac620018, 0x1751025, 0x491025, -0xac710008, 0xa467000e, 0xac62001c, 0xac640000, -0xac650004, 0x8ee204c0, 0xac620010, 0xaf860120, -0x92e24e20, 0x14400038, 0x24090001, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020007, 0x14620020, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001c, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee34e34, 0x8ee54e30, -0x24020040, 0x24630001, 0x10620007, 0x0, -0x8ee24e34, 0x24420001, 0x10a20005, 0x0, -0x80037a9, 0x0, 0x14a00005, 0x0, -0x8f820128, 0x24420020, 0xaf820128, 0x8f820128, -0x8c820004, 0x2c420011, 0x50400013, 0xac800000, -0x80037bf, 0x0, 0x8ee24e30, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x15200018, 0x3c050006, -0x8e020018, 0x3c040001, 0x24845890, 0xafa20010, -0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, -0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b, -0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, -0xa642000c, 0xae430000, 0xae440004, 0xae450008, -0x96020016, 0x80037f8, 0xa642000e, 0x154d000a, -0x0, 0x9602000e, 0xa613000a, 0x34420004, -0xa602000e, 0x3c010001, 0x370821, 0xa02083c0, -0x80037f6, 0x9821, 0x9604000a, 0x93102b, -0x10400002, 0x2601821, 0x801821, 0x24020001, -0xa603000a, 0x3c010001, 0x370821, 0xa02283c0, -0x9604000a, 0x2248821, 0x191102b, 0x10400003, -0x3c02fff5, 0x34421000, 0x2228821, 0x2649823, -0xa821, 0x1660fef4, 0xadc80000, 0x12600021, -0x32c200ff, 0x3c010001, 0x370821, 0xac3383c4, -0x3c010001, 0x370821, 0xac3183c8, 0x3c010001, -0x370821, 0x10400008, 0xac3283cc, 0x3c020001, -0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, -0x370821, 0xac2283cc, 0x8ee2724c, 0x8f430280, -0x24420001, 0x14620006, 0x0, 0x8ee201c4, -0x24420001, 0xaee201c4, 0x8003850, 0x8ee201c4, -0x8ee201bc, 0x24420001, 0xaee201bc, 0x8003850, -0x8ee201bc, 0x97a4001e, 0x2484fffc, 0x801821, -0x8ee400c0, 0x8ee500c4, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0x24020002, -0xaee400c0, 0xaee500c4, 0x1282000f, 0x2a820003, -0x14400017, 0x24020003, 0x16820015, 0x0, -0x8ee200d0, 0x8ee300d4, 0x24630001, 0x2c640001, -0x441021, 0xaee200d0, 0xaee300d4, 0x8ee200d0, -0x800384a, 0x8ee300d4, 0x8ee200d8, 0x8ee300dc, -0x24630001, 0x2c640001, 0x441021, 0xaee200d8, -0xaee300dc, 0x8ee200d8, 0x800384a, 0x8ee300dc, -0x8ee200c8, 0x8ee300cc, 0x24630001, 0x2c640001, -0x441021, 0xaee200c8, 0xaee300cc, 0x8ee200c8, -0x8ee300cc, 0x8f8300e4, 0x8f8200e0, 0x10620003, -0x24630008, 0xaf8300e4, 0xaf8300e8, 0x8fbf004c, -0x8fb60048, 0x8fb50044, 0x8fb40040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x27bdff90, 0xafb60060, 0xb021, -0xafbf0068, 0xafbe0064, 0xafb5005c, 0xafb40058, -0xafb30054, 0xafb20050, 0xafb1004c, 0xafb00048, -0x8ee204d4, 0x8821, 0x24150001, 0x30420001, -0x1440002a, 0xa3a0002f, 0x8f8700e0, 0x8f8800c4, -0x8f8200e8, 0xe22023, 0x2c821000, 0x50400001, -0x24841000, 0x420c2, 0x801821, 0x8ee400c8, -0x8ee500cc, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xaee400c8, 0xaee500cc, -0x8f8300c8, 0x3c02000a, 0x3442efff, 0x1032023, -0x44102b, 0x10400003, 0x3c02000a, 0x3442f000, -0x822021, 0x801821, 0x8ee400c0, 0x8ee500c4, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0xaf8800c8, -0xaf8700e4, 0x8003c5b, 0xaf8700e8, 0x3c020001, -0x571021, 0x904283c0, 0x1040000b, 0x0, -0x3c130001, 0x2779821, 0x8e7383c4, 0x3c100001, -0x2178021, 0x8e1083c8, 0x3c120001, 0x2579021, -0x8003a59, 0x8e5283cc, 0x8f8300e0, 0x8f8200e4, -0x10430007, 0x3821, 0x8f8200e4, 0x24070001, -0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, -0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, -0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014, -0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, -0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c, -0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, -0x10400058, 0x2408021, 0x3c020080, 0x621024, -0x1040000a, 0x3c040040, 0x8ee2007c, 0x24420001, -0xaee2007c, 0x8ee2007c, 0x8ee201fc, 0x24420001, -0xaee201fc, 0x8003c55, 0x8ee201fc, 0x3c060004, -0x3c0b0001, 0x3c0a0002, 0x3c050010, 0x3c090008, -0x8ee20080, 0x3c080020, 0x34078000, 0x24420001, -0xaee20080, 0x8ee20080, 0x8fa2001c, 0x441824, -0x10660021, 0xc3102b, 0x14400007, 0x0, -0x106b0011, 0x0, 0x106a0015, 0x0, -0x8003916, 0x42042, 0x10650023, 0xa3102b, -0x14400005, 0x0, 0x10690019, 0x0, -0x8003916, 0x42042, 0x10680021, 0x0, -0x8003916, 0x42042, 0x8ee20034, 0x24420001, -0xaee20034, 0x8ee20034, 0x8003916, 0x42042, -0x8ee201ec, 0x24420001, 0xaee201ec, 0x8ee201ec, -0x8003916, 0x42042, 0x8ee201f0, 0x24420001, -0xaee201f0, 0x8ee201f0, 0x8003916, 0x42042, -0x8ee201f4, 0x24420001, 0xaee201f4, 0x8ee201f4, -0x8003916, 0x42042, 0x8ee20030, 0x24420001, -0xaee20030, 0x8ee20030, 0x8003916, 0x42042, -0x8ee201f8, 0x24420001, 0xaee201f8, 0x8ee201f8, -0x42042, 0x1087033e, 0x0, 0x80038db, -0x0, 0x3c020001, 0x571021, 0x904283b2, -0x14400084, 0x24020001, 0x3c030001, 0x771821, -0x906383b3, 0x1462007f, 0x3c020100, 0x8e430000, -0x621024, 0x1040006f, 0x2402ffff, 0x14620005, -0x24110001, 0x96430004, 0x3402ffff, 0x10620075, -0x0, 0x92e204d8, 0x14400072, 0x0, -0x3c020001, 0x571021, 0x8c4283b4, 0x28420005, -0x10400020, 0x3821, 0x3c020001, 0x571021, -0x8c4283b4, 0x18400016, 0x2821, 0x96060000, -0x520c0, 0x971021, 0x9442777e, 0x14460009, -0x971021, 0x94437780, 0x96020002, 0x14620005, -0x971021, 0x94437782, 0x96020004, 0x50620008, -0x24070001, 0x3c020001, 0x571021, 0x8c4283b4, -0x24a50001, 0xa2102a, 0x5440ffee, 0x520c0, -0x30e200ff, 0x10400302, 0x0, 0x80039a2, -0x0, 0x2402021, 0xc0022fe, 0x24050006, -0x3044001f, 0x428c0, 0x2e51021, 0x9442727c, -0x30424000, 0x144002f6, 0xb71021, 0x9443727e, -0x96020000, 0x1462000b, 0x418c0, 0xb71021, -0x94437280, 0x96020002, 0x14620006, 0x418c0, -0xb71021, 0x94437282, 0x96020004, 0x10620035, -0x418c0, 0x2e31021, 0x9442727c, 0x30428000, -0x144002e3, 0x2e31021, 0x944d727c, 0x96070000, -0xd28c0, 0xb71021, 0x9442737e, 0x8003984, -0x3021, 0x420c0, 0x2e41021, 0x9443737c, -0x2e41021, 0x944d737c, 0x30638000, 0x14600010, -0xd28c0, 0xb71021, 0x9442737e, 0x1447fff5, -0x1a02021, 0xb71021, 0x94437380, 0x96020002, -0x5462fff1, 0x420c0, 0xb71021, 0x94437382, -0x96020004, 0x5462ffec, 0x420c0, 0x24060001, -0x30c200ff, 0x104002c2, 0x0, 0x80039a2, -0x0, 0x97430202, 0x96420000, 0x146202bc, -0x0, 0x97430204, 0x96420002, 0x146202b8, -0x0, 0x97430206, 0x96420004, 0x146202b4, -0x0, 0x92420000, 0x3a230001, 0x30420001, -0x431024, 0x10400074, 0x2402ffff, 0x8e030000, -0x14620004, 0x3402ffff, 0x96030004, 0x1062006f, -0x24150002, 0x3c020001, 0x571021, 0x904283b2, -0x1440006a, 0x24150003, 0x92e204d8, 0x14400067, -0x0, 0x3c020001, 0x571021, 0x8c4283b4, -0x28420005, 0x10400020, 0x3821, 0x3c020001, -0x571021, 0x8c4283b4, 0x18400016, 0x2821, -0x96060000, 0x520c0, 0x971021, 0x9442777e, -0x14460009, 0x971021, 0x94437780, 0x96020002, -0x14620005, 0x971021, 0x94437782, 0x96020004, -0x50620008, 0x24070001, 0x3c020001, 0x571021, -0x8c4283b4, 0x24a50001, 0xa2102a, 0x5440ffee, -0x520c0, 0x30e200ff, 0x14400044, 0x24150003, -0x8003c55, 0x0, 0x2402021, 0xc0022fe, -0x24050006, 0x3044001f, 0x428c0, 0x2e51021, -0x9442727c, 0x30424000, 0x14400271, 0xb71021, -0x9443727e, 0x96020000, 0x1462000b, 0x418c0, -0xb71021, 0x94437280, 0x96020002, 0x14620006, -0x418c0, 0xb71021, 0x94437282, 0x96020004, -0x10620027, 0x418c0, 0x2e31021, 0x9442727c, -0x30428000, 0x1440025e, 0x2e31021, 0x944d727c, -0x96070000, 0xd28c0, 0xb71021, 0x9442737e, -0x8003a09, 0x3021, 0x420c0, 0x2e41021, -0x9443737c, 0x2e41021, 0x944d737c, 0x30638000, -0x14600010, 0xd28c0, 0xb71021, 0x9442737e, -0x1447fff5, 0x1a02021, 0xb71021, 0x94437380, -0x96020002, 0x5462fff1, 0x420c0, 0xb71021, -0x94437382, 0x96020004, 0x5462ffec, 0x420c0, -0x24060001, 0x30c200ff, 0x1040023d, 0x0, -0x8003a1c, 0x24150003, 0x24150001, 0x8f420260, -0x53102b, 0x10400036, 0x0, 0x8f8300e4, -0x8f8200e0, 0x10620003, 0x24630008, 0xaf8300e4, -0xaf8300e8, 0x8ee400c0, 0x8ee500c4, 0x2601821, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, -0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, -0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, -0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0, -0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, -0xc002403, 0x34a5f203, 0x8003c5b, 0x0, -0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, -0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18, -0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0, -0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0, -0x96e20468, 0x53102b, 0x54400001, 0x3c168000, -0x126001cb, 0x3c0e001f, 0x35ceffff, 0x3c0ffff5, -0x35ef1000, 0x241e0040, 0x8ee2724c, 0x8f430280, -0x24420001, 0x304207ff, 0x1062019e, 0x0, -0x12c00012, 0x0, 0x8ee35240, 0x8ee25244, -0x1062000a, 0x26f85244, 0x8ef45244, 0xafb80024, -0x8ee35244, 0x21140, 0x24425248, 0x2e28821, -0x24630001, 0x8003a85, 0x306d00ff, 0x8ee201e0, -0x24420001, 0xaee201e0, 0x8ee201e0, 0x8ee30e10, -0x8ee20e18, 0x1062ffca, 0x26f80e18, 0x8ef40e18, -0xb021, 0xafb80024, 0x8ee30e18, 0x21140, -0x24420e20, 0x2e28821, 0x24630001, 0x306d01ff, -0x96e2046a, 0x30420010, 0x10400018, 0x34028100, -0x9643000c, 0x14620015, 0x0, 0x3c020001, -0x571021, 0x904283c0, 0x14400010, 0x0, -0x9642000e, 0xa6220016, 0x8e420008, 0x8e430004, -0x8e440000, 0x2673fffc, 0xae42000c, 0xae430008, -0xae440004, 0x9622000e, 0x26100004, 0x24180001, -0xa3b8002f, 0x34420200, 0xa622000e, 0x8e220000, -0x8e230004, 0x3c040001, 0x34843800, 0x2003021, -0x306a0007, 0x20a8023, 0x3641021, 0x202102b, -0x10400005, 0x26a9821, 0x2041023, 0x3621823, -0x3c020020, 0x438023, 0x26620007, 0x9623000a, -0x2418fff8, 0x58c824, 0x6a1821, 0x79102b, -0x10400002, 0x3206021, 0x606021, 0x1801821, -0x24620007, 0x2418fff8, 0x586024, 0x26c102b, -0x14400004, 0x1932823, 0x1832823, 0x8003ac3, -0xc31021, 0xd31021, 0x4a2023, 0x1c4102b, -0x54400001, 0x8f2021, 0x25420040, 0x4c102b, -0x14400035, 0x5821, 0x94c3000c, 0x24020800, -0x54620032, 0xae260018, 0x3c020001, 0x571021, -0x904283c0, 0x5440002d, 0xae260018, 0x24c20017, -0x1c2102b, 0x10400013, 0x0, 0x3c02fff5, -0x461021, 0x90421017, 0x38430006, 0x2c630001, -0x38420011, 0x2c420001, 0x621825, 0x10600014, -0x24c20010, 0x1c2102b, 0x1040000e, 0x0, -0x3c0bfff5, 0x1665821, 0x956b1010, 0x8003af4, -0x2562000e, 0x90c20017, 0x38430006, 0x2c630001, -0x38420011, 0x2c420001, 0x621825, 0x10600005, -0x1601821, 0x94cb0010, 0x2562000e, 0x4a5821, -0x1601821, 0x24620007, 0x2418fff8, 0x585824, -0xc31021, 0x4a2023, 0x1c4102b, 0x10400002, -0x1632823, 0x8f2021, 0xae260018, 0x3c020001, -0x571021, 0x904283c0, 0x2102b, 0x216c0, -0x15600002, 0xafa20044, 0x1805821, 0x30820001, -0x10400007, 0x4021, 0x90880000, 0x24840001, -0x1c4102b, 0x10400002, 0x24a5ffff, 0x8f2021, -0x50a00012, 0x81c02, 0x2ca20002, 0x54400009, -0x24a5ffff, 0x94820000, 0x24840002, 0x1024021, -0x1c4102b, 0x10400006, 0x24a5fffe, 0x8003b21, -0x8f2021, 0x90820000, 0x21200, 0x1024021, -0x14a0fff2, 0x2ca20002, 0x81c02, 0x3102ffff, -0x624021, 0x3108ffff, 0x1402821, 0x11400011, -0x2002021, 0x2ca20002, 0x54400009, 0x24a5ffff, -0x94820000, 0x24840002, 0x1024021, 0x1c4102b, -0x10400006, 0x24a5fffe, 0x8003b38, 0x8f2021, -0x90820000, 0x21200, 0x1024021, 0x14a0fff2, -0x2ca20002, 0x81c02, 0x3102ffff, 0x624021, -0x81c02, 0x3102ffff, 0x8f890120, 0x624021, -0x27623800, 0x25230020, 0x62102b, 0x14400002, -0x3108ffff, 0x27633000, 0x8f820128, 0x10620004, -0x0, 0x8f820124, 0x14620007, 0x1402821, -0x8ee201a4, 0x3821, 0x24420001, 0xaee201a4, -0x8003bc9, 0x8ee201a4, 0x8e260000, 0x8e270004, -0x81400, 0x3448000b, 0xad300008, 0xa52b000e, -0xad280018, 0x8fb80044, 0x2021, 0x2961025, -0x581025, 0xad22001c, 0xe5102b, 0xe53823, -0xc43023, 0xc23023, 0xad260000, 0xad270004, -0x8ee204c0, 0xad220010, 0xaf830120, 0x92e24e20, -0x1440005f, 0x24070001, 0x2502ffee, 0x2c420002, -0x14400003, 0x24020011, 0x15020024, 0x0, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c830000, 0x24020012, 0x1462000f, 0x0, -0x8ee34e30, 0x8ee24e34, 0x1062000b, 0x0, -0x8c820004, 0x24420001, 0xac820004, 0x8ee24e34, -0x8ee34e30, 0x24420001, 0x105e002a, 0x0, -0x8003ba8, 0x0, 0x8ee24e30, 0x24420001, -0x505e0003, 0x1021, 0x8ee24e30, 0x24420001, -0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8003bc6, 0x24020012, 0x8ee24e30, -0x210c0, 0x24425038, 0x2e22021, 0x8c830000, -0x24020007, 0x1462001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x105e0007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8003bb4, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400012, 0xac800000, 0x8003bc9, -0x0, 0x8ee24e30, 0x24420001, 0x505e0003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020007, 0xac820000, 0x24020001, 0xac820004, -0x14e00019, 0x3c050006, 0x3c040001, 0x24845890, -0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, -0x8e230004, 0x2203021, 0x1603821, 0xc002403, -0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, -0x8e430004, 0x8e440008, 0x8e45000c, 0xa642000c, -0xae430000, 0xae440004, 0xae450008, 0x96220016, -0x8003c02, 0xa642000e, 0x1599000a, 0x26a1823, -0x9622000e, 0xa623000a, 0x34420004, 0xa622000e, -0x3c010001, 0x370821, 0xa02083c0, 0x8003bff, -0x9821, 0x9624000a, 0x83102b, 0x54400001, -0x801821, 0x24020001, 0xa623000a, 0x3c010001, -0x370821, 0xa02283c0, 0x9622000a, 0x4a1821, -0x2038021, 0x1d0102b, 0x54400001, 0x20f8021, -0x2639823, 0xb021, 0x8fb80024, 0x1660fe5e, -0xaf0d0000, 0x12600022, 0x0, 0x3c010001, -0x370821, 0xac3383c4, 0x3c010001, 0x370821, -0xac3083c8, 0x3c010001, 0x370821, 0xac3283cc, -0x93a2002f, 0x10400008, 0x0, 0x3c020001, -0x571021, 0x8c4283cc, 0x24420004, 0x3c010001, -0x370821, 0xac2283cc, 0x8f430280, 0x8ee2724c, -0x14620006, 0x0, 0x8ee201c4, 0x24420001, -0xaee201c4, 0x8003c5b, 0x8ee201c4, 0x8ee201bc, -0x24420001, 0xaee201bc, 0x8003c5b, 0x8ee201bc, -0x97a4001e, 0x2484fffc, 0x801821, 0x8ee400c0, -0x8ee500c4, 0x1021, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0x24020002, 0xaee400c0, -0xaee500c4, 0x12a2000f, 0x2aa20003, 0x14400017, -0x24020003, 0x16a20015, 0x0, 0x8ee200d0, -0x8ee300d4, 0x24630001, 0x2c640001, 0x441021, -0xaee200d0, 0xaee300d4, 0x8ee200d0, 0x8003c55, -0x8ee300d4, 0x8ee200d8, 0x8ee300dc, 0x24630001, -0x2c640001, 0x441021, 0xaee200d8, 0xaee300dc, -0x8ee200d8, 0x8003c55, 0x8ee300dc, 0x8ee200c8, -0x8ee300cc, 0x24630001, 0x2c640001, 0x441021, -0xaee200c8, 0xaee300cc, 0x8ee200c8, 0x8ee300cc, -0x8f8300e4, 0x8f8200e0, 0x10620003, 0x24630008, -0xaf8300e4, 0xaf8300e8, 0x8fbf0068, 0x8fbe0064, -0x8fb60060, 0x8fb5005c, 0x8fb40058, 0x8fb30054, -0x8fb20050, 0x8fb1004c, 0x8fb00048, 0x3e00008, -0x27bd0070, 0x27bdffe0, 0xafbf0018, 0x8ee30e14, -0x8ee20e0c, 0x10620074, 0x0, 0x8ee30e0c, -0x8ee20e14, 0x622023, 0x4820001, 0x24840200, -0x8ee30e18, 0x8ee20e14, 0x43102b, 0x14400004, -0x24020200, 0x8ee30e14, 0x8003c7d, 0x431823, -0x8ee20e18, 0x8ee30e14, 0x431023, 0x2443ffff, -0x804821, 0x69102a, 0x54400001, 0x604821, -0x8f870100, 0x27623000, 0x24e80020, 0x102102b, -0x50400001, 0x27682800, 0x8f820108, 0x11020004, -0x0, 0x8f820104, 0x15020007, 0x1021, -0x8ee201a8, 0x2021, 0x24420001, 0xaee201a8, -0x8003cbf, 0x8ee201a8, 0x8ee40e14, 0x42140, -0x801821, 0x8ee40460, 0x8ee50464, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xace40000, -0xace50004, 0x8ee30e14, 0x91140, 0xa4e2000e, -0x24020002, 0xace20018, 0x31940, 0x24630e20, -0x2e31021, 0xace20008, 0x8ee20e14, 0xace2001c, -0x8ee204cc, 0xace20010, 0xaf880100, 0x92e204ec, -0x14400011, 0x24040001, 0x8ee24e28, 0x24030040, -0x24420001, 0x50430003, 0x1021, 0x8ee24e28, -0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, -0x24424e38, 0x2e21821, 0x24020002, 0xac620000, -0x24020001, 0xac620004, 0x1480000e, 0x24030040, -0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, -0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, -0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd, -0x0, 0x8ee20500, 0x24420001, 0x50430003, -0x1021, 0x8ee20500, 0x24420001, 0xaee20500, -0x8ee20500, 0x21080, 0x571021, 0xac490508, -0x8ee20e14, 0x491021, 0x304201ff, 0xaee20e14, -0x8ee30e14, 0x8ee20e0c, 0x14620005, 0x0, -0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, -0xafbf0018, 0x8ee3523c, 0x8ee25238, 0x10620074, -0x0, 0x8ee35238, 0x8ee2523c, 0x622023, -0x4820001, 0x24840100, 0x8ee35244, 0x8ee2523c, -0x43102b, 0x14400004, 0x24020100, 0x8ee3523c, -0x8003cff, 0x431823, 0x8ee25244, 0x8ee3523c, -0x431023, 0x2443ffff, 0x804821, 0x69102a, -0x54400001, 0x604821, 0x8f870100, 0x27623000, -0x24e80020, 0x102102b, 0x50400001, 0x27682800, -0x8f820108, 0x11020004, 0x0, 0x8f820104, -0x15020007, 0x1021, 0x8ee201a8, 0x2021, -0x24420001, 0xaee201a8, 0x8003d41, 0x8ee201a8, -0x8ee4523c, 0x42140, 0x801821, 0x8ee40470, -0x8ee50474, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xace40000, 0xace50004, 0x8ee3523c, -0x91140, 0xa4e2000e, 0x24020003, 0xace20018, -0x31940, 0x24635248, 0x2e31021, 0xace20008, -0x8ee2523c, 0xace2001c, 0x8ee204cc, 0xace20010, -0xaf880100, 0x92e204ec, 0x14400011, 0x24040001, -0x8ee24e28, 0x24030040, 0x24420001, 0x50430003, -0x1021, 0x8ee24e28, 0x24420001, 0xaee24e28, -0x8ee24e28, 0x210c0, 0x24424e38, 0x2e21821, -0x24020003, 0xac620000, 0x24020001, 0xac620004, -0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, -0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, -0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403, -0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500, -0x24420001, 0x50430003, 0x1021, 0x8ee20500, -0x24420001, 0xaee20500, 0x8ee20500, 0x21080, -0x571021, 0xac490508, 0x8ee2523c, 0x491021, -0x304200ff, 0xaee2523c, 0x8ee3523c, 0x8ee25238, -0x14620005, 0x0, 0x8f820060, 0x2403feff, -0x431024, 0xaf820060, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x8f820120, 0x8ee34e34, 0x8f820124, -0x8f860128, 0x24020040, 0x24630001, 0x50620003, -0x1021, 0x8ee24e34, 0x24420001, 0xaee24e34, -0x8ee24e34, 0x8ee44e34, 0x8ee34e30, 0x210c0, -0x24425038, 0x14830007, 0x2e22821, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8003d92, -0xaca00000, 0x8ee24e34, 0x24030040, 0x24420001, -0x50430003, 0x1021, 0x8ee24e34, 0x24420001, -0x210c0, 0x24425038, 0x2e22821, 0x8ca20004, -0x8f830128, 0x21140, 0x621821, 0xaf830128, -0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012, -0x10400008, 0x31080, 0x3c010001, 0x220821, -0x8c2258f0, 0x400008, 0x0, 0x24020001, -0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8, -0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, -0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128, -0x8f820124, 0x106202b0, 0x9821, 0x3c11001f, -0x3631ffff, 0x3c12fff5, 0x36521000, 0x24150012, -0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020, -0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe, -0x2c620012, 0x1040029c, 0x31080, 0x3c010001, -0x220821, 0x8c225948, 0x400008, 0x0, -0x8f420218, 0x30420100, 0x10400007, 0x0, -0x95830016, 0x95820018, 0x621823, 0x31402, -0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, -0x3044ffff, 0x436824, 0x3c030800, 0x431824, -0x11a00004, 0xad84001c, 0x41140, 0x8003dd8, -0x24425248, 0x41140, 0x24420e20, 0x2e25821, -0x9562000e, 0x3042fffc, 0x10600004, 0xa562000e, -0x95840016, 0x8003ec0, 0x0, 0x8d690018, -0x4021, 0x952a0000, 0x25290002, 0x95270000, -0x25290002, 0x95260000, 0x25290002, 0x95250000, -0x25290002, 0x95240000, 0x25290002, 0x95230000, -0x25290002, 0x95220000, 0x25290002, 0x1475021, -0x1465021, 0x1455021, 0x1445021, 0x1435021, -0x1425021, 0xa1c02, 0x3142ffff, 0x625021, -0xa1c02, 0x3142ffff, 0x625021, 0x96e2046a, -0x314effff, 0x30420002, 0x10400044, 0x5021, -0x25220014, 0x222102b, 0x10400014, 0x1201821, -0x2405000a, 0x2021, 0x223102b, 0x54400001, -0x721821, 0x94620000, 0x24630002, 0x24a5ffff, -0x14a0fff9, 0x822021, 0x41c02, 0x3082ffff, -0x622021, 0x41402, 0x3083ffff, 0x431021, -0x3042ffff, 0x8003e33, 0x1425021, 0x952a0000, -0x25290002, 0x95280000, 0x25290002, 0x95270000, -0x25290002, 0x95260000, 0x25290002, 0x95250000, -0x25290002, 0x95230000, 0x25290002, 0x95220000, -0x25290002, 0x95240000, 0x25290002, 0x1485021, -0x1475021, 0x1465021, 0x1455021, 0x1435021, -0x1425021, 0x95220000, 0x95230002, 0x1445021, -0x1425021, 0x1435021, 0xa1c02, 0x3142ffff, -0x625021, 0xa1c02, 0x3142ffff, 0x625021, -0x3148ffff, 0x51000001, 0x3408ffff, 0x8d620018, -0x9443000c, 0x24020800, 0x54620005, 0xa5680010, -0x9562000e, 0x34420002, 0xa562000e, 0xa5680010, -0x96e2046a, 0x2821, 0x30420008, 0x14400056, -0x3021, 0x8d630018, 0x24620024, 0x222102b, -0x10400034, 0x24690010, 0x229102b, 0x54400001, -0x1324821, 0x95250000, 0x24690014, 0x229102b, -0x10400002, 0x24a5ffec, 0x1324821, 0x95220000, -0x30420fff, 0x14400003, 0x25290002, 0x8003e60, -0x24130001, 0x9821, 0xa03021, 0x229102b, -0x54400001, 0x1324821, 0x91220001, 0x25290002, -0xa22821, 0x229102b, 0x54400001, 0x1324821, -0x25290002, 0x229102b, 0x54400001, 0x1324821, -0x95220000, 0x25290002, 0xa22821, 0x229102b, -0x54400001, 0x1324821, 0x95220000, 0x25290002, -0xa22821, 0x229102b, 0x54400001, 0x1324821, -0x95220000, 0x25290002, 0xa22821, 0x229102b, -0x54400001, 0x1324821, 0x95220000, 0x8003e99, -0xa22821, 0x94650010, 0x94620014, 0x24690016, -0x30420fff, 0x14400003, 0x24a5ffec, 0x8003e8c, -0x24130001, 0x9821, 0xa03021, 0x91230001, -0x25290004, 0x95220000, 0x25290002, 0x95240000, -0x25290002, 0xa32821, 0xa22821, 0x95220000, -0x95230002, 0xa42821, 0xa22821, 0xa32821, -0x51c02, 0x30a2ffff, 0x622821, 0x51c02, -0x30a2ffff, 0x622821, 0x96e2046a, 0x30420001, -0x1040001e, 0x2021, 0x95820016, 0x4e2023, -0x41402, 0x822021, 0x326200ff, 0x50400002, -0x862021, 0x852021, 0x41402, 0x822021, -0x3084ffff, 0x50800001, 0x3404ffff, 0x8d620018, -0x24430017, 0x223102b, 0x54400001, 0x721821, -0x90620000, 0x38430011, 0x2c630001, 0x38420006, -0x2c420001, 0x621825, 0x10600004, 0x0, -0x9562000e, 0x34420001, 0xa562000e, 0x9562000e, -0x240a0002, 0x30420004, 0x10400002, 0xa5640012, -0x240a0004, 0x8f880120, 0x27623800, 0x25090020, -0x122102b, 0x50400001, 0x27693000, 0x8f820128, -0x11220004, 0x0, 0x8f820124, 0x15220007, -0x24040020, 0x8ee201a4, 0x8021, 0x24420001, -0xaee201a4, 0x8003f4f, 0x8ee201a4, 0x8ee5724c, -0x8ee60490, 0x8ee70494, 0xad0b0008, 0xa504000e, -0xad0a0018, 0x52940, 0xa01821, 0x1021, -0xe33821, 0xe3202b, 0xc23021, 0xc43021, -0xad060000, 0xad070004, 0x8ee2724c, 0x4d1025, -0xad02001c, 0x8ee204c4, 0xad020010, 0xaf890120, -0x92e24e20, 0x14400060, 0x24100001, 0x2543ffee, -0x2c630002, 0x39420011, 0x2c420001, 0x621825, -0x10600024, 0x0, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x1455000f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062000b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x1054002b, -0x0, 0x8003f2e, 0x0, 0x8ee24e30, -0x24420001, 0x50540003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020001, 0x8003f4e, -0xac950000, 0x8ee24e30, 0x210c0, 0x24425038, -0x2e22021, 0x8c830000, 0x24020007, 0x1462001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8003f3a, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400012, -0xac800000, 0x8003f4f, 0x0, 0x8ee24e30, -0x24420001, 0x50540003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020007, 0xac820000, -0x24020001, 0xac820004, 0x1600000d, 0x0, -0x8f820120, 0x3c040001, 0x24845938, 0xafa00014, -0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, -0xc002403, 0x34a50001, 0x8004057, 0x0, -0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, -0xaee2724c, 0x8ee201d0, 0x2442ffff, 0xaee201d0, -0x8003f6b, 0x8ee201d0, 0x8ee201cc, 0x2442ffff, -0xaee201cc, 0x8ee201cc, 0x8ee201d8, 0x2442ffff, -0xaee201d8, 0x8004057, 0x8ee201d8, 0x8f420240, -0x104000e5, 0x0, 0x8ee20e1c, 0x24420001, -0x8004057, 0xaee20e1c, 0x9582001e, 0xad82001c, -0x8f420240, 0x10400072, 0x0, 0x8ee20e1c, -0x24420001, 0xaee20e1c, 0x8f430240, 0x43102b, -0x144000d5, 0x0, 0x8f830120, 0x27623800, -0x24660020, 0xc2102b, 0x50400001, 0x27663000, -0x8f820128, 0x10c20004, 0x0, 0x8f820124, -0x14c20007, 0x0, 0x8ee201a4, 0x8021, -0x24420001, 0xaee201a4, 0x8003fda, 0x8ee201a4, -0x8ee2724c, 0xac62001c, 0x8ee404a8, 0x8ee504ac, -0x2462001c, 0xac620008, 0x24020008, 0xa462000e, -0x24020011, 0xac620018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400034, 0x24100001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x1455001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10540007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8003fc6, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400011, -0xac800000, 0x8003fda, 0x0, 0x8ee24e30, -0x24420001, 0x50540003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x24020001, 0xac950000, -0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, -0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010, -0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403, -0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, -0x24420001, 0xaee20188, 0x8004050, 0x8ee20188, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x8021, 0x24420001, 0xaee201a4, -0x8004044, 0x8ee201a4, 0x8ee2724c, 0xac62001c, -0x8ee404a8, 0x8ee504ac, 0x2462001c, 0xac620008, -0x24020008, 0xa462000e, 0x24020011, 0xac620018, -0xac640000, 0xac650004, 0x8ee204c4, 0xac620010, -0xaf860120, 0x92e24e20, 0x14400034, 0x24100001, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x8c820000, 0x1455001f, 0x0, 0x8ee34e30, -0x8ee24e34, 0x1062001b, 0x0, 0x8c820004, -0x24420001, 0xac820004, 0x8ee24e34, 0x8ee34e30, -0x24420001, 0x10540007, 0x0, 0x8ee24e34, -0x24420001, 0x10620005, 0x0, 0x8004030, -0x0, 0x14600005, 0x0, 0x8f820128, -0x24420020, 0xaf820128, 0x8f820128, 0x8c820004, -0x2c420011, 0x50400011, 0xac800000, 0x8004044, -0x0, 0x8ee24e30, 0x24420001, 0x50540003, -0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, -0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, -0x24020001, 0xac950000, 0xac820004, 0x1600000b, -0x0, 0x8ee2724c, 0x3c040001, 0x248458a8, -0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, -0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174, -0x24420001, 0xaee20174, 0x8004057, 0x8ee20174, -0x24020001, 0xaee24e24, 0x8f830128, 0x8f820124, -0x1462fd58, 0x0, 0x8fbf0030, 0x8fb5002c, -0x8fb40028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8, -0x27840208, 0x27450200, 0x24060008, 0xafbf0014, -0xc00249a, 0xafb00010, 0x2021, 0x24100001, -0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, -0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, -0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8, -0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0, -0x3c010001, 0xac235cc8, 0xc005108, 0x24050004, -0xc004822, 0x0, 0x8ee20000, 0x3c03feff, -0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, -0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, -0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, -0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, -0x248459f0, 0xc002403, 0x3821, 0x8ee20280, -0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, -0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, -0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, -0xafb1001c, 0xafb00018, 0x8f900220, 0x8ee20214, -0x3821, 0x24420001, 0xaee20214, 0x8ee20214, -0x3c020300, 0x2021024, 0x10400027, 0x3c110400, -0xc00429b, 0x0, 0x3c020100, 0x2021024, -0x10400007, 0x0, 0x8ee20218, 0x24420001, -0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff, -0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, -0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, -0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008, -0x2003021, 0x431024, 0xaee20000, 0x8f820220, -0x3821, 0x3c030300, 0x481024, 0x431025, -0xaf820220, 0xafa00010, 0xc002403, 0xafa00014, -0x8004296, 0x0, 0x2111024, 0x1040001f, -0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, -0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008, -0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, -0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000, -0x3463ffff, 0x2002021, 0x431024, 0xc004e54, -0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, -0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x8004295, 0x511025, 0x2021024, -0x10400142, 0x0, 0x8ee2022c, 0x24420001, -0xaee2022c, 0x8ee2022c, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x34420004, 0xaf820220, -0x8f830054, 0x8f820054, 0x800410e, 0x24630002, -0x8f820054, 0x621023, 0x2c420003, 0x1440fffc, -0x0, 0x8f8600e0, 0x8f8400e4, 0x30c20007, -0x10400012, 0x0, 0x8f8300e4, 0x2402fff8, -0xc21024, 0x1043000d, 0x0, 0x8f820054, -0x8f8300e0, 0x14c30009, 0x24440050, 0x8f820054, -0x821023, 0x2c420051, 0x10400004, 0x0, -0x8f8200e0, 0x10c2fff9, 0x0, 0x8f820220, -0x3c0308ff, 0x3463fffd, 0x431024, 0xaf820220, -0x8f8600e0, 0x30c20007, 0x10400003, 0x2402fff8, -0xc23024, 0xaf8600e0, 0x8f8300c4, 0x3c02001f, -0x3442ffff, 0x24680008, 0x48102b, 0x10400003, -0x3c02fff5, 0x34421000, 0x1024021, 0x8f8b00c8, -0x8f850120, 0x8f840124, 0x8004145, 0x6021, -0x27623800, 0x82102b, 0x50400001, 0x27643000, -0x10a40010, 0x318200ff, 0x8c820018, 0x38430007, -0x2c630001, 0x3842000b, 0x2c420001, 0x621825, -0x5060fff3, 0x24840020, 0x8ee20240, 0x240c0001, -0x24420001, 0xaee20240, 0x8ee20240, 0x8c8b0008, -0x318200ff, 0x14400065, 0x0, 0x3c020001, -0x571021, 0x904283c0, 0x14400060, 0x0, -0x8f8400e4, 0xc41023, 0x218c3, 0x4620001, -0x24630200, 0x8f8900c4, 0x10600005, 0x24020001, -0x10620009, 0x0, 0x8004187, 0x0, -0x8ee20230, 0x1205821, 0x24420001, 0xaee20230, -0x80041bc, 0x8ee20230, 0x8ee20234, 0x3c05000a, -0x24420001, 0xaee20234, 0x8c8b0000, 0x34a5f000, -0x8ee20234, 0x12b1823, 0xa3102b, 0x54400001, -0x651821, 0x2c62233f, 0x14400040, 0x0, -0x8f8200e8, 0x24420008, 0xaf8200e8, 0x8f8200e8, -0x8f8200e4, 0x1205821, 0x24420008, 0xaf8200e4, -0x80041bc, 0x8f8200e4, 0x8ee20238, 0x3c03000a, -0x24420001, 0xaee20238, 0x8c840000, 0x3463f000, -0x8ee20238, 0x883823, 0x67102b, 0x54400001, -0xe33821, 0x3c020003, 0x34420d40, 0x47102b, -0x10400003, 0x0, 0x80041bc, 0x805821, -0x8f8200e4, 0x24440008, 0xaf8400e4, 0x8f8400e4, -0x10860018, 0x3c05000a, 0x34a5f000, 0x3c0a0003, -0x354a0d40, 0x8ee2007c, 0x24420001, 0xaee2007c, -0x8c830000, 0x8ee2007c, 0x683823, 0xa7102b, -0x54400001, 0xe53821, 0x147102b, 0x54400007, -0x605821, 0x8f8200e4, 0x24440008, 0xaf8400e4, -0x8f8400e4, 0x1486ffef, 0x0, 0x14860005, -0x0, 0x1205821, 0xaf8600e4, 0x80041bc, -0xaf8600e8, 0xaf8400e4, 0xaf8400e8, 0x8f8200c8, -0x3c03000a, 0x3463f000, 0x483823, 0x67102b, -0x54400001, 0xe33821, 0x3c020003, 0x34420d3f, -0x47102b, 0x54400007, 0x6021, 0x1683823, -0x67102b, 0x54400003, 0xe33821, 0x80041cf, -0x3c020003, 0x3c020003, 0x34420d3f, 0x47102b, -0x14400016, 0x318200ff, 0x14400006, 0x0, -0x3c020001, 0x571021, 0x904283c0, 0x1040000f, -0x0, 0x8ee2023c, 0x3c04fdff, 0x8ee30000, -0x3484ffff, 0x24420001, 0xaee2023c, 0x8ee2023c, -0x24020001, 0x641824, 0x3c010001, 0x370821, -0xa02283b8, 0x800422c, 0xaee30000, 0xaf8b00c8, -0x8f8300c8, 0x8f8200c4, 0x3c04000a, 0x3484f000, -0x623823, 0x87102b, 0x54400001, 0xe43821, -0x3c020003, 0x34420d40, 0x47102b, 0x2ce30001, -0x431025, 0x10400008, 0x0, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x3c034000, -0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, -0x10c4002a, 0x0, 0x8ee2007c, 0x24420001, -0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0, -0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0, -0x431024, 0x1040001d, 0x0, 0x10c4001b, -0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080, -0x24850008, 0x27622800, 0x50a20001, 0x27651800, -0x8c880004, 0x8c820000, 0x8ca90000, 0x3103ffff, -0x431021, 0x4d1024, 0x24430010, 0x6b102b, -0x54400001, 0x6a1821, 0x12b102b, 0x54400001, -0x12a4821, 0x10690002, 0x10c1025, 0xac820004, -0xa02021, 0x14c4ffeb, 0x24850008, 0x8f820220, -0x3c0308ff, 0x3463ffff, 0x431024, 0x34420002, -0xaf820220, 0x8f830054, 0x8f820054, 0x8004237, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820220, 0x3c0308ff, -0x3463fffb, 0x431024, 0xaf820220, 0x6010055, -0x0, 0x8ee20228, 0x24420001, 0xaee20228, -0x8ee20228, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420004, 0xaf820220, 0x8f830054, -0x8f820054, 0x8004251, 0x24630002, 0x8f820054, -0x621023, 0x2c420003, 0x1440fffc, 0x0, -0x8f8600e0, 0x30c20007, 0x10400012, 0x0, -0x8f8300e4, 0x2402fff8, 0xc21024, 0x1043000d, -0x0, 0x8f820054, 0x8f8300e0, 0x14c30009, -0x24440032, 0x8f820054, 0x821023, 0x2c420033, -0x10400004, 0x0, 0x8f8200e0, 0x10c2fff9, -0x0, 0x8f820220, 0x3c0308ff, 0x3463fffd, -0x431024, 0xaf820220, 0x8f8600e0, 0x30c20007, -0x10400003, 0x2402fff8, 0xc23024, 0xaf8600e0, -0x240301f5, 0x8f8200e8, 0x673823, 0x718c0, -0x431021, 0xaf8200e8, 0x8f8200e8, 0xaf8200e4, -0x8ee2007c, 0x3c0408ff, 0x3484ffff, 0x471021, -0xaee2007c, 0x8f820220, 0x3c038000, 0x34630002, -0x441024, 0x431025, 0xaf820220, 0x8f830054, -0x8f820054, 0x800428d, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, -0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8, -0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001, -0x24845a14, 0x3c050008, 0x24020001, 0x3c010001, -0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, -0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8, -0x3c010001, 0xac225ccc, 0xc002403, 0x3821, -0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, -0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, -0x431024, 0x30840002, 0x1080011e, 0xaee204d0, -0x8ee204d4, 0x2403fffd, 0x431024, 0xaee204d4, -0x8f820044, 0x3c030600, 0x34632000, 0x34420020, -0xaf820044, 0xafa30018, 0x8ee20608, 0x8f430228, -0x24420001, 0x304a00ff, 0x514300fe, 0xafa00010, -0x8ee20608, 0x210c0, 0x571021, 0x8fa30018, -0x8fa4001c, 0xac43060c, 0xac440610, 0x8f830054, -0x8f820054, 0x24690032, 0x1221023, 0x2c420033, -0x1040006a, 0x5821, 0x24180008, 0x240f000d, -0x240d0007, 0x240c0040, 0x240e0001, 0x8f870120, -0x27623800, 0x24e80020, 0x102102b, 0x50400001, -0x27683000, 0x8f820128, 0x11020004, 0x0, -0x8f820124, 0x15020007, 0x1021, 0x8ee201a4, -0x2821, 0x24420001, 0xaee201a4, 0x800433d, -0x8ee201a4, 0x8ee40608, 0x420c0, 0x801821, -0x8ee40430, 0x8ee50434, 0xa32821, 0xa3302b, -0x822021, 0x862021, 0xace40000, 0xace50004, -0x8ee20608, 0xa4f8000e, 0xacef0018, 0xacea001c, -0x210c0, 0x2442060c, 0x2e21021, 0xace20008, -0x8ee204c4, 0xace20010, 0xaf880120, 0x92e24e20, -0x14400033, 0x24050001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x144d001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x104c0007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x800432a, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x800433d, 0x0, 0x8ee24e30, -0x24420001, 0x504c0003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0xac8d0000, 0xac8e0004, -0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ff9d, 0x0, 0x316300ff, -0x24020001, 0x54620079, 0xafa00010, 0xaeea0608, -0x8f830054, 0x8f820054, 0x24690032, 0x1221023, -0x2c420033, 0x10400061, 0x5821, 0x240d0008, -0x240c0011, 0x24080012, 0x24070040, 0x240a0001, -0x8f830120, 0x27623800, 0x24660020, 0xc2102b, -0x50400001, 0x27663000, 0x8f820128, 0x10c20004, -0x0, 0x8f820124, 0x14c20007, 0x0, -0x8ee201a4, 0x2821, 0x24420001, 0xaee201a4, -0x80043a9, 0x8ee201a4, 0x8ee20608, 0xac62001c, -0x8ee404a0, 0x8ee504a4, 0x2462001c, 0xac620008, -0xa46d000e, 0xac6c0018, 0xac640000, 0xac650004, -0x8ee204c4, 0xac620010, 0xaf860120, 0x92e24e20, -0x14400033, 0x24050001, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0x8c820000, 0x1448001f, -0x0, 0x8ee34e30, 0x8ee24e34, 0x1062001b, -0x0, 0x8c820004, 0x24420001, 0xac820004, -0x8ee24e34, 0x8ee34e30, 0x24420001, 0x10470007, -0x0, 0x8ee24e34, 0x24420001, 0x10620005, -0x0, 0x8004396, 0x0, 0x14600005, -0x0, 0x8f820128, 0x24420020, 0xaf820128, -0x8f820128, 0x8c820004, 0x2c420011, 0x50400010, -0xac800000, 0x80043a9, 0x0, 0x8ee24e30, -0x24420001, 0x50470003, 0x1021, 0x8ee24e30, -0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, -0x24425038, 0x2e22021, 0xac880000, 0xac8a0004, -0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, -0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, -0x24020001, 0x54620003, 0xafa00010, 0x80043d6, -0x0, 0x3c040001, 0x24845a20, 0xafa00014, -0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, -0x34a5f011, 0x80043d6, 0x0, 0x3c040001, -0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124, -0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6, -0x0, 0x3c040001, 0x24845a38, 0xafa00014, -0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, -0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, -0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, -0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, -0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d, -0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008, -0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, -0x24020001, 0x3c010001, 0xac225cd8, 0xc002403, -0x3821, 0x8ee204d0, 0x3c030001, 0x771821, -0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, -0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, -0x34420008, 0xaf820220, 0x2021, 0xc0052a2, -0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x3c120001, -0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001, -0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, -0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, -0x0, 0xd, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x80014d6, -0x0, 0x80014d8, 0x3c0a0001, 0x80014d8, -0x3c0a0002, 0x80014d8, 0x0, 0x80024a6, -0x0, 0x80014d8, 0x3c0a0003, 0x80014d8, -0x3c0a0004, 0x8002f8c, 0x0, 0x80014d8, -0x3c0a0005, 0x8003ce8, 0x0, 0x8003c66, -0x0, 0x80014d8, 0x3c0a0006, 0x80014d8, -0x3c0a0007, 0x80014d8, 0x0, 0x80014d8, -0x0, 0x80014d8, 0x0, 0x8002a75, -0x0, 0x80014d8, 0x3c0a000b, 0x80014d8, -0x3c0a000c, 0x80014d8, 0x3c0a000d, 0x800237a, -0x0, 0x8002339, 0x0, 0x80014d8, -0x3c0a000e, 0x8001b3c, 0x0, 0x80024a4, -0x0, 0x80014d8, 0x3c0a000f, 0x80040a7, -0x0, 0x8004091, 0x0, 0x80014d8, -0x3c0a0010, 0x80014ee, 0x0, 0x80014d8, -0x3c0a0011, 0x80014d8, 0x3c0a0012, 0x80014d8, -0x3c0a0013, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x3c030001, -0x34633800, 0x24050080, 0x2404001f, 0x2406ffff, -0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220, -0x3631021, 0xaf8200c0, 0x3631021, 0xaf8200c4, -0x3631021, 0xaf8200c8, 0x27623800, 0xaf8200d0, -0x27623800, 0xaf8200d4, 0x27623800, 0xaf8200d8, -0x27621800, 0xaf8200e0, 0x27621800, 0xaf8200e4, -0x27621800, 0xaf8200e8, 0x27621000, 0xaf8200f0, -0x27621000, 0xaf8200f4, 0x27621000, 0xaf8200f8, -0xaca00000, 0x2484ffff, 0x1486fffd, 0x24a50004, -0x8f830040, 0x3c02f000, 0x621824, 0x3c025000, -0x1062000c, 0x43102b, 0x14400006, 0x3c026000, -0x3c024000, 0x10620008, 0x24020800, 0x8004539, -0x0, 0x10620004, 0x24020800, 0x8004539, -0x0, 0x24020700, 0x3c010001, 0xac225cdc, -0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001, -0xac205cc4, 0x8004545, 0x24630064, 0x8f820054, -0x621023, 0x2c420065, 0x1440fffc, 0x0, -0xc004d71, 0x0, 0x24040001, 0x2821, -0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018, -0x8f830054, 0x8f820054, 0x8004556, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x24050001, 0xc00494c, 0x27a60018, -0x8f830054, 0x8f820054, 0x8004562, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x24050001, 0xc00494c, 0x27a60018, -0x8f830054, 0x8f820054, 0x800456e, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c, -0x24050002, 0x8f830054, 0x8f820054, 0x800457b, -0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050003, 0x3c100001, -0x26105da2, 0xc00494c, 0x2003021, 0x97a60018, -0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0, -0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100, -0xc002403, 0xafa20010, 0x97a20018, 0x1040004c, -0x24036040, 0x96020000, 0x3042fff0, 0x1443000a, -0x24020020, 0x3c030001, 0x94635da0, 0x54620009, -0x24027830, 0x24020003, 0x3c010001, 0xac225cc4, -0x80045ac, 0x24020005, 0x3c030001, 0x94635da0, -0x24027830, 0x1462000f, 0x24030010, 0x3c020001, -0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003, -0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001, -0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6, -0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001, -0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4, -0x24020015, 0x1462000f, 0x0, 0x3c020001, -0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001, -0x3842f430, 0x2c420001, 0x621825, 0x10600005, -0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6, -0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810, -0x1462000b, 0x24020002, 0x3c020001, 0x94425da2, -0x3042fff0, 0x14400006, 0x24020002, 0x24020004, -0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0, -0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0, -0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001, -0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4, -0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4, -0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001, -0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc, -0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2, -0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8, -0x491021, 0x3c010001, 0xac225dac, 0xafa30010, -0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001, -0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014, -0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000, -0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc, -0x8004617, 0x34844240, 0x3c040004, 0x3c030001, -0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016, -0x0, 0x3c04003d, 0x800462f, 0x34840900, -0x3c020001, 0x8c427e38, 0x30428000, 0x10400005, -0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a, -0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc, -0x34844240, 0x24020005, 0x14620003, 0x0, -0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac, -0x8f830054, 0x441021, 0x431023, 0x44102b, -0x14400037, 0x0, 0x3c020001, 0x8c425cd0, -0x14400033, 0x0, 0x3c010001, 0x10c00025, -0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001, -0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc, -0x52842, 0x14a00002, 0x24c6ffff, 0x24050008, -0xa91024, 0x10400010, 0x0, 0x14a70008, -0x0, 0x8d020000, 0x441024, 0x1040000a, -0x0, 0x3c010001, 0x800465b, 0xac255ce0, -0x8d420000, 0x441024, 0x10400003, 0x0, -0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0, -0x6182b, 0x2c420001, 0x431024, 0x5440ffe5, -0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0, -0x3c010001, 0xac225dac, 0x1060002a, 0x24020001, -0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc, -0x3c020001, 0x8c425ce0, 0x10400022, 0x0, -0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001, -0x3c010001, 0xac205ccc, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001, -0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac, -0x24020008, 0x10620005, 0x24020001, 0xc004695, -0x0, 0x8004692, 0x0, 0x3c030001, -0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001, -0x8c637dd0, 0x10620003, 0x0, 0xc004e54, -0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000, -0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0, -0x3442ffff, 0x621824, 0x14a40008, 0xaee30000, -0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001, -0x8c425cf4, 0x10620008, 0x0, 0x3c020001, -0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0, -0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8, -0x24020002, 0x10620169, 0x2c620003, 0x10400005, -0x24020001, 0x10620008, 0x0, 0x800481c, -0x0, 0x24020004, 0x106200b1, 0x24020001, -0x800481d, 0x0, 0x3c020001, 0x571021, -0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a, -0x31080, 0x3c010001, 0x220821, 0x8c225ac8, -0x400008, 0x0, 0x3c030001, 0x8c635dbc, -0x24020005, 0x14620014, 0x0, 0x3c020001, -0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822, -0x0, 0x24020002, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4, -0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, -0x800481f, 0xac205c60, 0xc004822, 0x0, -0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60, -0x104000dd, 0x24020002, 0x3c010001, 0x370821, -0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4, -0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003, -0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf, -0x0, 0x3c030001, 0x8c635d00, 0x800478e, -0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001, -0x8cc67e3c, 0xc005108, 0x2021, 0x24020005, -0x3c010001, 0xac205cd4, 0x3c010001, 0x370821, -0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc, -0x3c05000f, 0x34a50100, 0x3021, 0x3821, -0xafa00010, 0xc002403, 0xafa00014, 0x800481f, -0x0, 0x8f820220, 0x3c03f700, 0x431025, -0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004, -0x431024, 0x144000a9, 0x24020007, 0x8f830054, -0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023, -0x2c422710, 0x144000f8, 0x24020001, 0x800481d, -0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2, -0x2021, 0xc005386, 0x2021, 0x3c030001, -0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008, -0x621024, 0x10400006, 0x0, 0x8f820214, -0x3c03ffff, 0x431024, 0x8004741, 0x3442251f, -0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, -0xaf820214, 0x8ee20000, 0x3c030200, 0x431025, -0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, -0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, -0x24020008, 0x3c010001, 0x370821, 0xac2283ac, -0x8f820220, 0x3c030004, 0x431024, 0x14400005, -0x0, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005, -0x1462000a, 0x0, 0x3c020001, 0x94425da2, -0x24429fbc, 0x2c420004, 0x10400004, 0x24040018, -0x24050002, 0xc004d93, 0x24060020, 0xc0043dd, -0x0, 0x3c010001, 0x800481f, 0xac205d50, -0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, -0x2c620008, 0x104000ac, 0x31080, 0x3c010001, -0x220821, 0x8c225ae8, 0x400008, 0x0, -0xc00429b, 0x0, 0x3c010001, 0xac205ccc, -0xaf800204, 0x3c010001, 0xc004822, 0xac207e20, -0x24020001, 0x3c010001, 0xac225ce4, 0x24020002, -0x3c010001, 0x370821, 0x800481f, 0xac2283ac, -0xc00489f, 0x0, 0x3c030001, 0x8c635ce4, -0x24020009, 0x14620090, 0x24020003, 0x3c010001, -0x370821, 0x800481f, 0xac2283ac, 0x3c020001, -0x8c427e38, 0x30424000, 0x10400005, 0x0, -0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff, -0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044, -0x8f830054, 0x80047b9, 0x24020004, 0x8f830054, -0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023, -0x2c422710, 0x14400074, 0x24020005, 0x3c010001, -0x370821, 0x800481f, 0xac2283ac, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0xaf800204, -0x3c010001, 0xac207e20, 0x8f830054, 0x24020006, -0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, -0x800481f, 0xac235da4, 0x8f830054, 0x3c020001, -0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a, -0x14400059, 0x0, 0x24020007, 0x3c010001, -0x370821, 0x800481f, 0xac2283ac, 0x8f820220, -0x3c04f700, 0x441025, 0xaf820220, 0x8f820220, -0x3c030300, 0x431024, 0x14400005, 0x1821, -0x8f820220, 0x24030001, 0x441025, 0xaf820220, -0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff, -0x3c040001, 0x8c845d98, 0x431024, 0x3442251f, -0xaf820214, 0x24020008, 0x3c010001, 0x370821, -0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74, -0x14400007, 0x24020001, 0x3c010001, 0xac227dd0, -0xc004e54, 0x8f840220, 0x800480c, 0x0, -0x8f820220, 0x3c030008, 0x431024, 0x14400017, -0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000, -0x2021, 0x3c030200, 0x431025, 0xc005386, -0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, -0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd, -0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2, -0x2021, 0x800481f, 0x0, 0x3c020001, -0x8c425d74, 0x10400010, 0x0, 0x3c020001, -0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70, -0x14400009, 0x24020002, 0x3c010001, 0xac205d74, -0x3c010001, 0x800481f, 0xac225d70, 0x24020001, -0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, -0x34420004, 0xaf820220, 0x8f820200, 0x3c060001, -0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002, -0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001, -0x10c20008, 0x0, 0x8004868, 0x0, -0x24020004, 0x10c20013, 0x24020001, 0x8004868, -0x0, 0x3c030001, 0x8c635cb8, 0x3c020001, -0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001, -0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022, -0x441025, 0x451025, 0x34420002, 0x8004867, -0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200, -0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74, -0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0, -0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0, -0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, -0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001, -0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825, -0x431025, 0x451025, 0xaf820220, 0x3e00008, -0x0, 0x8f820220, 0x3c030001, 0x8c635cc8, -0x34420004, 0xaf820220, 0x24020001, 0x1062000f, -0x0, 0x8f830054, 0x8f820054, 0x24630002, -0x621023, 0x2c420003, 0x10400011, 0x0, -0x8f820054, 0x621023, 0x2c420003, 0x1040000c, -0x0, 0x8004879, 0x0, 0x8f830054, -0x8f820054, 0x8004885, 0x24630007, 0x8f820054, -0x621023, 0x2c420008, 0x1440fffc, 0x0, -0x8f8400e0, 0x30820007, 0x1040000d, 0x0, -0x8f820054, 0x8f8300e0, 0x14830009, 0x24450032, -0x8f820054, 0xa21023, 0x2c420033, 0x10400004, -0x0, 0x8f8200e0, 0x1082fff9, 0x0, -0x8f820220, 0x2403fffd, 0x431024, 0xaf820220, -0x3e00008, 0x0, 0x3c030001, 0x8c635ce4, -0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff, -0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009, -0x1040009d, 0x31080, 0x3c010001, 0x220821, -0x8c225b08, 0x400008, 0x0, 0x8f820044, -0x34428080, 0xaf820044, 0x8f830054, 0x8004938, -0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8, -0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a, -0x24020003, 0x8004945, 0x0, 0x8f820044, -0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044, -0x8f830054, 0x8004938, 0x24020004, 0x8f830054, -0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023, -0x2c42000a, 0x14400078, 0x24020005, 0x8004945, -0x0, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0x8f820220, 0x2403fffb, 0x431024, -0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, -0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200, -0x2403fffd, 0x431024, 0xaf820200, 0x24040001, -0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054, -0x80048ec, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820224, -0x42040, 0xa4102b, 0x1040fff2, 0x0, -0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, -0x8f820214, 0x3c03ffff, 0x431024, 0x3442251f, -0xaf820214, 0x8f820220, 0x2403fffb, 0x431024, -0xaf820220, 0x8f820220, 0x3c04f700, 0x34840008, -0x34420002, 0xaf820220, 0x8f820220, 0x3c033f00, -0x346300e2, 0x441025, 0xaf820220, 0xaf830200, -0x8f8400f0, 0x276217f8, 0x14820002, 0x24850008, -0x27651000, 0x8f8200f4, 0x10a20007, 0x3c038000, -0x34630040, 0x3c020001, 0x24425c70, 0xac820000, -0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938, -0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8, -0x2463fff6, 0x431023, 0x2c42000a, 0x14400022, -0x24020007, 0x8004945, 0x0, 0x8f8200e0, -0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220, -0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7, -0x431024, 0xaf820220, 0x8f820044, 0x34428080, -0xaf820044, 0x8f830054, 0x24020008, 0x3c010001, -0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8, -0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0, -0x431023, 0x2c422710, 0x14400003, 0x24020009, -0x3c010001, 0xac225ce4, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x27bdffd8, -0xafb20018, 0x809021, 0xafb3001c, 0xa09821, -0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d4b, 0x2021, 0xc004d4b, 0x24040001, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x1600fffa, -0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x2701024, 0xc004d71, 0x34108000, -0xc004d71, 0x0, 0xc004d2b, 0x0, -0x50400005, 0x108042, 0x96220000, 0x501025, -0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c, -0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, -0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, -0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x2501024, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x34108000, -0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, -0x0, 0xc004d71, 0x0, 0x8fbf0020, -0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00, -0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020, -0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, -0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c225b30, -0x400008, 0x0, 0xc004d71, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b, -0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc004d4b, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004d4b, -0x2021, 0xc004d4b, 0x24040001, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004d4b, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc004d71, 0x34108000, -0xc004d71, 0x0, 0xc004d2b, 0x0, -0x50400005, 0x108042, 0x96220000, 0x501025, -0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004d71, 0x0, 0x97a20010, 0x30428000, -0x144002dc, 0x24020003, 0x8004d24, 0x0, -0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc004d4b, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc004d4b, 0x24040001, 0xc004d4b, -0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fff8, 0x0, 0xc004d71, -0x0, 0x8f830054, 0x8004d16, 0x24020004, -0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c, -0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003, -0x14400296, 0x24020011, 0x24020003, 0x10620005, -0x24020004, 0x10620291, 0x2402000f, 0x8004d24, -0x24020011, 0x8004d24, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020012, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, -0x0, 0xc004d71, 0x0, 0x8f830054, -0x8004d16, 0x24020006, 0x8f830054, 0x3c020001, -0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400250, 0x24020007, 0x8004d24, 0x0, -0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020013, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8f830054, 0x8004d16, 0x24020008, 0x8f830054, -0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440020f, 0x24020009, 0x8004d24, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, -0xc004d4b, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, -0xc004d71, 0x34108000, 0xc004d71, 0x0, -0xc004d2b, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004d71, 0x8021, -0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, -0xc004d4b, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020017, -0xc004d71, 0x34108000, 0xc004d71, 0x0, -0xc004d2b, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004d71, 0x8021, -0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020017, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400127, 0x24020012, 0x8004d24, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, -0xc004d4b, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020014, -0xc004d71, 0x34108000, 0xc004d71, 0x0, -0xc004d2b, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004d71, 0x8021, -0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020014, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8f830054, 0x8004d16, 0x24020013, 0x8f830054, -0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, -0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, -0xc004d4b, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, -0xc004d71, 0x34108000, 0xc004d71, 0x0, -0xc004d2b, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004d71, 0x8021, -0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0xc004d4b, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, -0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fff8, 0x0, 0xc004d71, 0x0, -0x8f830054, 0x8004d16, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x32020013, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, -0x0, 0xc004d71, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac225d00, 0x3c010001, -0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001, -0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, -0x3c030001, 0x431025, 0x3c030008, 0xaf820044, -0x8f840054, 0x8f820054, 0xa32824, 0x8004d37, -0x24840001, 0x8f820054, 0x821023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, -0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004d45, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, -0x3442ffff, 0x42480, 0x621824, 0x3c020002, -0x822025, 0x641825, 0xaf830044, 0x8f820044, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, -0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820044, 0x3c030001, 0x431025, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x3e00008, 0x0, -0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, -0xaf820044, 0x8f820044, 0x3c030001, 0x431025, -0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, -0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x3e00008, 0x0, 0x27bdffc8, 0xafb30024, -0x809821, 0xafb5002c, 0xa0a821, 0xafb20020, -0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028, -0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010, -0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2301024, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x2301024, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x34108000, -0x96420000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x12000075, -0x0, 0x8004dc9, 0x0, 0x3274ffff, -0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b, -0x2021, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2901024, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x2901024, 0xc004d71, -0x34108000, 0xc004d71, 0x0, 0xc004d2b, -0x0, 0x50400005, 0x108042, 0x96220000, -0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004d71, 0x0, 0x32a5ffff, -0x24020001, 0x54a20004, 0x24020002, 0x97a20010, -0x8004e14, 0x521025, 0x14a20006, 0x3271ffff, -0x97a20010, 0x121827, 0x431024, 0xa7a20010, -0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d4b, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2301024, -0x10400002, 0x2021, 0x24040001, 0xc004d4b, -0x108042, 0x1600fffa, 0x2301024, 0xc004d4b, -0x24040001, 0xc004d4b, 0x2021, 0x34108000, -0x96420000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, -0x0, 0xc004d71, 0x0, 0x8fbf0030, -0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, -0x0, 0x0, 0x0, 0x27bdffe8, -0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac, -0x24020008, 0x1462022c, 0x803021, 0x3c020001, -0x8c425d98, 0x14400033, 0x0, 0x8f850224, -0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001, -0x621825, 0x1460000d, 0x38a30030, 0x2c630001, -0x38a20400, 0x2c420001, 0x621825, 0x14600007, -0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, -0x621825, 0x10600005, 0x0, 0xc00429b, -0x0, 0x8004e8d, 0x2402000e, 0xc0043dd, -0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2, -0x2021, 0x3c030001, 0x8c635cc8, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4, -0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4, -0x431024, 0x3c010001, 0xac225cc4, 0x2402000e, -0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087, -0x0, 0x8f820220, 0x3c030400, 0x431024, -0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, -0x8c427ddc, 0xa32024, 0x431024, 0x1482000c, -0x0, 0x3c020001, 0x8c427de0, 0x24420001, -0x3c010001, 0xac227de0, 0x2c420002, 0x14400008, -0x24020001, 0x3c010001, 0x8004ead, 0xac227e00, -0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00, -0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040, -0x10400004, 0x24020001, 0x3c010001, 0x8004eb8, -0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001, -0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10, -0x24020001, 0x3c010001, 0xac227e10, 0x3c010001, -0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001, -0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001, -0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003, -0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024, -0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, -0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700, -0x2c62000e, 0x104001a8, 0x31080, 0x3c010001, -0x220821, 0x8c225b80, 0x400008, 0x0, -0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0, -0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04, -0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0, -0xc00486a, 0xaf800224, 0x24020002, 0x3c010001, -0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056, -0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, -0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200, -0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, -0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8, -0x24040001, 0x3c010001, 0xac247e0c, 0x24420001, -0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001, -0xac237df4, 0x14400006, 0x24020003, 0x3c010001, -0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8, -0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054, -0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023, -0x2c422710, 0x14400003, 0x24020004, 0x3c010001, -0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026, -0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, -0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c, -0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001, -0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10, -0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff, -0x431024, 0xaee20000, 0x8f820204, 0x30420030, -0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c, -0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001, -0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10, -0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c, -0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002, -0x14400131, 0x24020001, 0x3c010001, 0xac225d74, -0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083, -0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024, -0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122, -0x0, 0x3c020001, 0x8c427ddc, 0x1040011e, -0x0, 0x3c010001, 0xac227e08, 0x24020003, -0x3c010001, 0xac227de0, 0x8005024, 0x24020006, -0x3c010001, 0xac207de8, 0x8f820204, 0x34420040, -0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007, -0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001, -0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005, -0x0, 0x3c020001, 0x8c427ddc, 0x104000f9, -0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000, -0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001, -0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001, -0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024, -0x641824, 0x10430004, 0x24020001, 0x3c010001, -0x8005083, 0xac227dd0, 0x24020003, 0xaca20000, -0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001, -0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001, -0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28, -0x14400005, 0x24020001, 0x3c020001, 0x8c427e24, -0x10400006, 0x24020001, 0x3c010001, 0xac225ccc, -0x3c010001, 0x8005083, 0xac207df8, 0x3c020001, -0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001, -0x210c0, 0x30630008, 0x3c010001, 0xac227df0, -0x3c010001, 0xac237dec, 0x8f830054, 0x24020009, -0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083, -0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4, -0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8, -0x0, 0x3c020001, 0x8c427e00, 0x10400005, -0x0, 0x3c020001, 0x8c427ddc, 0x104000a9, -0x24020002, 0x3c030001, 0x24637de0, 0x8c620000, -0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001, -0x8c427e0c, 0x1040000e, 0x0, 0x3c020001, -0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080, -0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, -0x1440000c, 0x24020003, 0x8005011, 0x2402000c, -0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005, -0x24020003, 0x8f820204, 0x30420080, 0x1040001f, -0x24020003, 0xac620000, 0x2402000a, 0x3c010001, -0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000, -0x3c030001, 0x8c637df0, 0x431025, 0xaf820204, -0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b, -0x3c010001, 0xac227dd0, 0x641825, 0x3c010001, -0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000, -0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001, -0x8c427e10, 0x10400005, 0x0, 0x2402000c, -0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001, -0x8c427e00, 0x1040006c, 0x0, 0x3c040001, -0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001, -0x8c637dec, 0x10620064, 0x24020003, 0x3c010001, -0xac247e08, 0xaca20000, 0x24020006, 0x3c010001, -0x8005083, 0xac227dd0, 0x8f820200, 0x34420002, -0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, -0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054, -0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023, -0x2c422710, 0x1440003a, 0x0, 0x3c020001, -0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001, -0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0, -0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8, -0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8, -0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, -0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001, -0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4, -0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, -0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220, -0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0x8005083, 0xaf820220, 0x3c020001, -0x8c427e00, 0x10400005, 0x0, 0x3c020001, -0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001, -0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002, -0x3c020001, 0x8c427e00, 0x1040000f, 0x0, -0x3c020001, 0x8c427ddc, 0x1440000b, 0x0, -0x24020002, 0x3c010001, 0x8005083, 0xac227dd0, -0x3c020001, 0x8c427e00, 0x10400003, 0x0, -0xc00429b, 0x0, 0x8f820220, 0x3c03f700, -0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000, -0x10400005, 0x34422000, 0x3c010001, 0xac227e1c, -0x8005095, 0xac600000, 0x3c010001, 0xac247e1c, -0x3e00008, 0x0, 0x27bdffe0, 0x30820030, -0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067, -0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, -0x24020030, 0x30822000, 0x1040005d, 0x30838000, -0x31a02, 0x30820001, 0x21200, 0x3c040001, -0x8c845d9c, 0x621825, 0x331c2, 0x3c030001, -0x24635d78, 0x30828000, 0x21202, 0x30840001, -0x42200, 0x441025, 0x239c2, 0x61080, -0x431021, 0x471021, 0x90430000, 0x24020001, -0x10620025, 0x0, 0x10600007, 0x24020002, -0x10620013, 0x24020003, 0x1062002c, 0x3c05000f, -0x80050f9, 0x0, 0x8f820200, 0x2403feff, -0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, -0x3463ffff, 0x431024, 0xaf820220, 0x3c010001, -0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c, -0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x24020100, 0x3c010001, 0xac227e44, 0x3c010001, -0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff, -0x431024, 0xaf820200, 0x8f820220, 0x3c030001, -0x431025, 0xaf820220, 0x3c010001, 0xac207e44, -0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200, -0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, -0x431025, 0xaf820220, 0x24020100, 0x3c010001, -0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c, -0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010, -0xc002403, 0xafa00014, 0x8005104, 0x0, -0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018, -0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, -0xafb20028, 0x809021, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0, -0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001, -0x2403021, 0x2603821, 0xafbf0030, 0xafb10024, -0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010, -0x24020002, 0x12620083, 0x2e620003, 0x10400005, -0x24020001, 0x1262000a, 0x0, 0x800529b, -0x0, 0x24020004, 0x126200fa, 0x24020008, -0x126200f9, 0x3c02ffec, 0x800529b, 0x0, -0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004, -0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024, -0x3c010001, 0x310821, 0xac307e3c, 0x3c024000, -0x2021024, 0x1040004e, 0x1023c2, 0x30840030, -0x101382, 0x3042001c, 0x3c030001, 0x24635d08, -0x431021, 0x823821, 0x3c020020, 0x2021024, -0x10400006, 0x24020100, 0x3c010001, 0x310821, -0xac227e40, 0x8005150, 0x3c020080, 0x3c010001, -0x310821, 0xac207e40, 0x3c020080, 0x2021024, -0x10400006, 0x121940, 0x3c020001, 0x3c010001, -0x230821, 0x800515c, 0xac227e48, 0x121140, -0x3c010001, 0x220821, 0xac207e48, 0x94e40000, -0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010, -0xa7a40018, 0x32024000, 0x10400002, 0x34824000, -0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, -0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002, -0x24040001, 0x2821, 0xc00498e, 0x27a60018, -0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001, -0xac315cd4, 0x14530004, 0x32028000, 0xc00429b, -0x0, 0x32028000, 0x1040011f, 0x0, -0xc00429b, 0x0, 0x3c030001, 0x8c635dbc, -0x24020005, 0x10620118, 0x24020002, 0x3c010001, -0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8, -0x24040001, 0x24050004, 0x27b0001a, 0xc00498e, -0x2003021, 0x24040001, 0x2821, 0xc00498e, -0x2003021, 0x3c020001, 0x511021, 0x8c427e34, -0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff, -0x3c010001, 0xac335cd4, 0x431024, 0x3c010001, -0x310821, 0x109300fa, 0xac227e34, 0x800529b, -0x0, 0x3c022000, 0x2021024, 0x10400005, -0x24020001, 0x3c010001, 0xac225d98, 0x80051ad, -0x128940, 0x3c010001, 0xac205d98, 0x128940, -0x3c010001, 0x310821, 0xac307e38, 0x3c024000, -0x2021024, 0x14400016, 0x0, 0x3c020001, -0x8c425d98, 0x10400008, 0x24040004, 0x24050001, -0xc004d93, 0x24062000, 0x24020001, 0x3c010001, -0x370821, 0xac2283ac, 0x3c020001, 0x511021, -0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024, -0x3c010001, 0x310821, 0x8005299, 0xac227e30, -0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0, -0x2031024, 0x5443000d, 0x3c020020, 0x3c020001, -0x8c425d9c, 0x24030100, 0x3c010001, 0x310821, -0xac237e44, 0x3c030001, 0x3c010001, 0x310821, -0xac237e4c, 0x80051f0, 0x34420400, 0x2021024, -0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c, -0x3c010001, 0x310821, 0xac237e44, 0x80051f0, -0x34420800, 0x3c020080, 0x2021024, 0x1040002e, -0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001, -0x310821, 0xac237e4c, 0x34420c00, 0x3c010001, -0xac225d9c, 0x8005218, 0x24040001, 0x3c020020, -0x2021024, 0x10400006, 0x24020100, 0x3c010001, -0x310821, 0xac227e44, 0x8005201, 0x3c020080, -0x3c010001, 0x310821, 0xac207e44, 0x3c020080, -0x2021024, 0x10400007, 0x121940, 0x3c020001, -0x3c010001, 0x230821, 0xac227e4c, 0x800520f, -0x24040001, 0x121140, 0x3c010001, 0x220821, -0xac207e4c, 0x24040001, 0x2821, 0x27b0001e, -0xc00494c, 0x2003021, 0x24040001, 0x2821, -0xc00494c, 0x2003021, 0x24040001, 0x24050001, -0x27b0001c, 0xc00494c, 0x2003021, 0x24040001, -0x24050001, 0xc00494c, 0x2003021, 0x8005299, -0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, -0x3c020008, 0x2028025, 0x121140, 0x3c010001, -0x220821, 0xac307e38, 0x3c022000, 0x2021024, -0x10400009, 0x0, 0x3c020001, 0x8c425d74, -0x14400005, 0x24020001, 0x3c010001, 0xac225d98, -0x800523a, 0x3c024000, 0x3c010001, 0xac205d98, -0x3c024000, 0x2021024, 0x1440001e, 0x0, -0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0, -0x10400007, 0x24022020, 0x3c010001, 0xac225d9c, -0x24020001, 0x3c010001, 0x370821, 0xac2283ac, -0x3c04bfff, 0x121940, 0x3c020001, 0x431021, -0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff, -0x441024, 0x3c010001, 0x230821, 0xac227e30, -0x24020001, 0x10a20044, 0x0, 0x8005299, -0x0, 0x3c020001, 0x8c425d98, 0x1040001c, -0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0, -0x2031024, 0x14430005, 0x121140, 0x3402a000, -0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001, -0x621821, 0x8c637e38, 0x3c020020, 0x621024, -0x10400004, 0x24022001, 0x3c010001, 0x8005294, -0xac225d9c, 0x3c020080, 0x621024, 0x1040001f, -0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c, -0x3c020020, 0x2021024, 0x10400007, 0x121940, -0x24020100, 0x3c010001, 0x230821, 0xac227e44, -0x8005288, 0x3c020080, 0x121140, 0x3c010001, -0x220821, 0xac207e44, 0x3c020080, 0x2021024, -0x10400006, 0x121940, 0x3c020001, 0x3c010001, -0x230821, 0x8005294, 0xac227e4c, 0x121140, -0x3c010001, 0x220821, 0xac207e4c, 0x3c030001, -0x8c635cc8, 0x24020001, 0x10620003, 0x0, -0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, -0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021, -0xafb1001c, 0x8821, 0x24020002, 0xafbf0024, -0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010, -0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a, -0x128140, 0x8005380, 0x2201021, 0x24020004, -0x10a2007d, 0x24020008, 0x10a2007c, 0x122940, -0x8005380, 0x2201021, 0x3c030001, 0x701821, -0x8c637e3c, 0x3c024000, 0x621024, 0x14400009, -0x24040001, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010001, 0x300821, 0xac317e34, 0x8005380, -0x2201021, 0x24050001, 0xc00494c, 0x27a60010, -0x24040001, 0x24050001, 0xc00494c, 0x27a60010, -0x97a20010, 0x30420004, 0x10400034, 0x3c114000, -0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006, -0x10400034, 0x31080, 0x3c010001, 0x220821, -0x8c225be0, 0x400008, 0x0, 0x24040001, -0x24050011, 0x27b00012, 0xc00494c, 0x2003021, -0x24040001, 0x24050011, 0xc00494c, 0x2003021, -0x97a50012, 0x30a24000, 0x10400002, 0x3c040010, -0x3c040008, 0x3c030001, 0x8005301, 0x30a28000, -0x24040001, 0x24050014, 0x27b00012, 0xc00494c, -0x2003021, 0x24040001, 0x24050014, 0xc00494c, -0x2003021, 0x97a50012, 0x30a21000, 0x10400002, -0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800, -0x54400001, 0x3c030002, 0x3c028000, 0x2221025, -0x641825, 0x800530e, 0x438825, 0x3c110001, -0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff, -0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d, -0x121140, 0x3c020001, 0x8c425d98, 0x10400002, -0x3c022000, 0x2228825, 0x121140, 0x3c010001, -0x220821, 0x8c227e40, 0x10400003, 0x3c020020, -0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff, -0x2228824, 0x121140, 0x3c010001, 0x220821, -0x8c227e48, 0x10400003, 0x3c020080, 0x800532d, -0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, -0x121140, 0x3c010001, 0x220821, 0xac317e34, -0x8005380, 0x2201021, 0x122940, 0x3c030001, -0x651821, 0x8c637e38, 0x3c024000, 0x621024, -0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010001, 0x250821, 0xac317e30, 0x8005380, -0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033, -0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c, -0x34842000, 0x3c030001, 0x8c635d98, 0x2102b, -0x21023, 0x441024, 0x10600003, 0x518825, -0x3c022000, 0x2228825, 0x3c020001, 0x451021, -0x8c427e44, 0x10400003, 0x3c020020, 0x800535d, -0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x121140, 0x3c010001, 0x220821, 0x8c227e4c, -0x10400003, 0x3c020080, 0x8005368, 0x2228825, -0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, -0x8c425d60, 0x10400002, 0x3c020800, 0x2228825, -0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400, -0x2228825, 0x3c020001, 0x8c425d68, 0x10400006, -0x3c020100, 0x800537b, 0x2228825, 0x3c027fff, -0x3442ffff, 0x628824, 0x121140, 0x3c010001, -0x220821, 0xac317e30, 0x2201021, 0x8fbf0024, -0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, -0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021, -0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, -0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8, -0x8f930220, 0x24020002, 0x10620063, 0x2c620003, -0x10400005, 0x24020001, 0x1062000a, 0x141940, -0x8005448, 0x0, 0x24020004, 0x1062005a, -0x24020008, 0x10620059, 0x149140, 0x8005448, -0x0, 0x3c040001, 0x832021, 0x8c847e3c, -0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000, -0x821024, 0x1040003e, 0x3c020008, 0x2221024, -0x10400020, 0x36100002, 0x3c020001, 0x431021, -0x8c427e40, 0x10400005, 0x36100020, 0x36100100, -0x3c020020, 0x80053bd, 0x2228825, 0x2402feff, -0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x141140, 0x3c010001, 0x220821, 0x8c227e48, -0x10400005, 0x3c020001, 0x2629825, 0x3c020080, -0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff, -0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc, -0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, -0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, -0x2228824, 0x3c010001, 0x230821, 0xac207e40, -0x3c010001, 0x230821, 0xac207e48, 0xc00486a, -0x0, 0xaf900200, 0xaf930220, 0x8f820220, -0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, -0x34420002, 0xaf820220, 0x80053f3, 0x141140, -0x8f820200, 0x2403fffd, 0x431024, 0xc00486a, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, -0x2228824, 0x141140, 0x3c010001, 0x220821, -0x8005448, 0xac317e34, 0x149140, 0x3c040001, -0x922021, 0x8c847e38, 0x3c110001, 0x2328821, -0x8e317e30, 0x3c024000, 0x821024, 0x14400011, -0x0, 0x3c020001, 0x8c425d98, 0x14400006, -0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a, -0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, -0x2228824, 0x3c010001, 0x320821, 0x8005448, -0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005, -0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b, -0x3c020020, 0x821024, 0x10400007, 0x36100020, -0x24020100, 0x3c010001, 0x320821, 0xac227e44, -0x8005428, 0x36100100, 0x3c010001, 0x320821, -0xac207e44, 0x2402feff, 0x2028024, 0x3c020080, -0x821024, 0x10400007, 0x141940, 0x3c020001, -0x3c010001, 0x230821, 0xac227e4c, 0x8005439, -0x2629825, 0x141140, 0x3c010001, 0x220821, -0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824, -0xc00486a, 0x0, 0xaf900200, 0xaf930220, -0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, -0x8f820220, 0x34420002, 0xaf820220, 0x141140, -0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, -0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, -0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; -static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { -0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f66776d, 0x61696e2e, 0x632c7620, 0x312e312e, -0x322e3131, 0x20313939, 0x382f3034, 0x2f323720, -0x32323a31, 0x333a3432, 0x20736875, 0x616e6720, -0x45787020, 0x24000000, 0x7468655f, 0x4441574e, -0x0, 0x53544143, 0x4b5f3120, 0x0, -0x42616453, 0x6e64526e, 0x67000000, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, -0x6576526e, 0x6746756c, 0x6c000000, 0x496c6c43, -0x6f6e6652, 0x78000000, 0x53656e64, 0x436b5375, -0x6d000000, 0x52656376, 0x566c616e, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f74696d, 0x65722e63, 0x2c762031, 0x2e312e32, -0x2e382031, 0x3939382f, 0x30372f33, 0x31203137, -0x3a35383a, 0x34352073, 0x6875616e, 0x67204578, -0x70202400, 0x542d446d, 0x61526431, 0x0, -0x542d446d, 0x61424200, 0x542d446d, 0x61320000, -0x3f6e6f51, 0x64547845, 0x0, 0x3f6e6f51, -0x64527845, 0x0, 0x656e714d, 0x45765046, -0x61696c00, 0x656e714d, 0x45764661, 0x696c0000, -0x6661696c, 0x456e454d, 0x0, 0x3f456e71, -0x45767400, 0x3f6e6f51, 0x64457650, 0x0, -0x6576526e, 0x6746756c, 0x6c000000, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f636f6d, 0x6d616e64, 0x2e632c76, 0x20312e31, -0x2e322e31, 0x30203139, 0x39382f31, 0x312f3138, -0x2031373a, 0x31313a31, 0x38207368, 0x75616e67, -0x20457870, 0x20240000, 0x3f4d626f, 0x78457674, -0x0, 0x4e4f636f, 0x6d616e64, 0x0, -0x68737465, 0x5f455252, 0x0, 0x412d4572, -0x72427563, 0x0, 0x4552524f, 0x522d4164, -0x64000000, 0x656e714d, 0x45765046, 0x61696c00, -0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, -0x456e454d, 0x0, 0x442d4572, 0x724c6173, -0x74000000, 0x442d4572, 0x72320000, 0x6d437374, -0x4d644552, 0x52000000, 0x70726f6d, 0x4d644552, -0x52000000, 0x46696c74, 0x4d644552, 0x52000000, -0x636d645f, 0x45525200, 0x3f456e71, 0x45767400, -0x3f6e6f51, 0x64457650, 0x0, 0x6576526e, -0x6746756c, 0x6c000000, 0x0, 0x6ea0, -0x7fbc, 0x6e38, 0x8734, 0x82b0, -0x8780, 0x8780, 0x6f54, 0x7694, -0x7f0c, 0x80a8, 0x8074, 0x8780, -0x7e70, 0x80cc, 0x6e64, 0x81cc, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f646d61, 0x2e632c76, 0x20312e31, 0x2e322e33, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3431, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x646d6172, 0x6441544e, 0x0, -0x646d6177, 0x7241544e, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f747261, 0x63652e63, 0x2c762031, 0x2e312e32, -0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, -0x3a31333a, 0x35302073, 0x6875616e, 0x67204578, -0x70202400, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f646174, 0x612e632c, 0x7620312e, 0x312e322e, -0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, -0x31333a34, 0x30207368, 0x75616e67, 0x20457870, -0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, -0x23312046, 0x72692041, 0x70722037, 0x2031373a, -0x35353a34, 0x38205044, 0x54203230, 0x30300000, -0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, -0x2031373a, 0x35353a34, 0x38000000, 0x46575f43, -0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, -0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, -0x4f53543a, 0x20636f6d, 0x70757465, 0x0, -0x46575f43, 0x4f4d5049, 0x4c455f44, 0x4f4d4149, -0x4e3a2065, 0x6e672e61, 0x6374656f, 0x6e2e636f, -0x6d000000, 0x46575f43, 0x4f4d5049, 0x4c45523a, -0x20676363, 0x20766572, 0x73696f6e, 0x20322e37, -0x2e320000, 0x0, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f6d656d, 0x2e632c76, 0x20312e31, 0x2e322e32, -0x20313939, 0x382f3034, 0x2f323720, 0x32323a31, -0x333a3434, 0x20736875, 0x616e6720, 0x45787020, -0x24000000, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f73656e, 0x642e632c, 0x7620312e, 0x312e322e, -0x31312031, 0x3939382f, 0x31322f32, 0x32203137, -0x3a31373a, 0x35352073, 0x6875616e, 0x67204578, -0x70202400, 0x736e6464, 0x654e6f51, 0x20000000, -0x6e6f454e, 0x515f5458, 0x0, 0x736e6464, -0x744e6f51, 0x20000000, 0x3f6e6f51, 0x64547845, -0x0, 0x756e6b72, 0x64747970, 0x65000000, -0x0, 0xaccc, 0xaccc, 0xad9c, -0xaab0, 0xaab0, 0xad9c, 0xad9c, -0xad9c, 0xad9c, 0xad9c, 0xad9c, -0xad9c, 0xad9c, 0xad9c, 0xad9c, -0xad9c, 0xad9c, 0xad9c, 0xad7c, -0x0, 0xbca8, 0xbca8, 0xbd70, -0xae4c, 0xb058, 0xbd70, 0xbd70, -0xbd70, 0xbd70, 0xbd70, 0xbd70, -0xbd70, 0xbd70, 0xbd70, 0xbd70, -0xbd70, 0xbd70, 0xbd70, 0xbd54, -0xb040, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f726563, 0x762e632c, 0x7620312e, 0x312e322e, -0x31392031, 0x3939382f, 0x30372f32, 0x34203231, -0x3a33303a, 0x30352073, 0x6875616e, 0x67204578, -0x70202400, 0x706b5278, 0x45525200, 0x66726d32, -0x4c617267, 0x65000000, 0x72784e6f, 0x52784264, -0x0, 0x72785144, 0x6d614446, 0x0, -0x72785144, 0x6d614246, 0x0, 0x3f6e6f51, -0x64527845, 0x0, 0x706b5278, 0x45525273, -0x0, 0x66726d32, 0x4c726753, 0x0, -0x72784e6f, 0x42645300, 0x3f724264, 0x446d6146, -0x0, 0x3f724a42, 0x64446d46, 0x0, -0x0, 0xf678, 0xf678, 0xf678, -0xf678, 0xf678, 0xf678, 0xf678, -0xf678, 0xf678, 0xf678, 0xf678, -0xf678, 0xf678, 0xf678, 0xf678, -0xf670, 0xf670, 0xf670, 0x572d444d, -0x41456e46, 0x0, 0x0, 0xfdc0, -0x1015c, 0xfddc, 0x1015c, 0x1015c, -0x1015c, 0x1015c, 0x1015c, 0x1015c, -0xf704, 0x1015c, 0x1015c, 0x1015c, -0x1015c, 0x1015c, 0x10154, 0x10154, -0x10154, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f6d6163, 0x2e632c76, 0x20312e31, 0x2e322e31, -0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, -0x31333a34, 0x32207368, 0x75616e67, 0x20457870, -0x20240000, 0x6d616374, 0x7841544e, 0x0, -0x4e745379, 0x6e264c6b, 0x0, 0x72656d61, -0x73737274, 0x0, 0x6c696e6b, 0x444f574e, -0x0, 0x656e714d, 0x45765046, 0x61696c00, -0x656e714d, 0x45764661, 0x696c0000, 0x6661696c, -0x456e454d, 0x0, 0x6c696e6b, 0x55500000, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, -0x2f636b73, 0x756d2e63, 0x2c762031, 0x2e312e32, -0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, -0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, -0x70202400, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0x11b2c, -0x11bc4, 0x11bf8, 0x11c2c, 0x11c58, -0x11c6c, 0x11ca8, 0x1207c, 0x11de4, -0x11e24, 0x11e50, 0x11e90, 0x11ec0, -0x11efc, 0x11f30, 0x1207c, 0x122c0, -0x122d8, 0x12300, 0x12320, 0x12348, -0x12478, 0x124a0, 0x124f4, 0x1251c, -0x0, 0x1278c, 0x1285c, 0x12934, -0x12a04, 0x12a60, 0x12b3c, 0x12b64, -0x12c40, 0x12c68, 0x12e10, 0x12e38, -0x12fe0, 0x131d8, 0x1346c, 0x13380, -0x1346c, 0x13498, 0x13008, 0x131b0, -0x0, 0x13b84, 0x13bc8, 0x13c60, -0x13cac, 0x13d1c, 0x13db4, 0x13de8, -0x13e70, 0x13f08, 0x13fd8, 0x14018, -0x1409c, 0x140c0, 0x141f4, 0x646f4261, -0x73655067, 0x0, 0x0, 0x0, -0x0, 0x73746d61, 0x634c4e4b, 0x0, -0x0, 0x14c38, 0x14c38, 0x14b80, -0x14bc4, 0x14c38, 0x14c38, 0x0, -0x0, 0x0 }; -static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { -0x416c7465, -0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, -0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, -0x0, 0x0, 0x0, 0x135418, -0x13e7fc, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x60cf00, -0x60, 0xcf000000, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x3, 0x0, -0x1, 0x0, 0x0, 0x0, -0x1, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x1, -0x1, 0x0, 0x0, 0x0, -0x0, 0x0, 0x1000000, 0x21000000, -0x12000140, 0x0, 0x0, 0x20000000, -0x120000a0, 0x0, 0x12000060, 0x12000180, -0x120001e0, 0x0, 0x0, 0x0, -0x1, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x2, -0x0, 0x0, 0x30001, 0x1, -0x30201, 0x0, 0x0, 0x0 }; -#endif -/* Generated by genfw.c */ -#define tigon2FwReleaseMajor 0xc -#define tigon2FwReleaseMinor 0x4 -#define tigon2FwReleaseFix 0xb -#define tigon2FwStartAddr 0x00004000 -#define tigon2FwTextAddr 0x00004000 -#define tigon2FwTextLen 0x11bc0 -#define tigon2FwRodataAddr 0x00015bc0 -#define tigon2FwRodataLen 0x10d0 -#define tigon2FwDataAddr 0x00016cc0 -#define tigon2FwDataLen 0x1c0 -#define tigon2FwSbssAddr 0x00016e80 -#define tigon2FwSbssLen 0xcc -#define tigon2FwBssAddr 0x00016f50 -#define tigon2FwBssLen 0x20c0 -static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { -0x0, -0x10000003, 0x0, 0xd, 0xd, -0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, -0x26104000, 0xc0010c0, 0x0, 0xd, -0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000, -0x26104000, 0xc0017e0, 0x0, 0xd, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x2000008, -0x0, 0x800172f, 0x3c0a0001, 0x800172f, -0x3c0a0002, 0x800172f, 0x0, 0x8002cac, -0x0, 0x8002c4f, 0x0, 0x800172f, -0x3c0a0004, 0x800328a, 0x0, 0x8001a52, -0x0, 0x800394d, 0x0, 0x80038f4, -0x0, 0x800172f, 0x3c0a0006, 0x80039bb, -0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f, -0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6, -0x0, 0x800172f, 0x3c0a000b, 0x800172f, -0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb, -0x0, 0x8002890, 0x0, 0x800172f, -0x3c0a000e, 0x800208c, 0x0, 0x8001964, -0x0, 0x8001a04, 0x0, 0x8003ca6, -0x0, 0x8003c94, 0x0, 0x800172f, -0x0, 0x800191a, 0x0, 0x800172f, -0x0, 0x800172f, 0x3c0a0013, 0x800172f, -0x3c0a0014, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x27bdffe0, -0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, -0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20, -0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc, -0x401821, 0x3c020010, 0x3c010001, 0xac236e9c, -0x10620011, 0x43102b, 0x14400002, 0x3c020020, -0x3c020008, 0x1062000c, 0x24050100, 0x3c060001, -0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020, -0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001, -0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4, -0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe, -0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002, -0x24639010, 0x3c040001, 0x8c846cc4, 0x431023, -0x14800002, 0x458021, 0x2610fa38, 0x2402f000, -0x2028024, 0xc001785, 0x2002021, 0x2022823, -0x3c040020, 0x821823, 0x651823, 0x247bb000, -0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf, -0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf, -0x3463e000, 0x852023, 0x3c010001, 0xac246ea8, -0x822023, 0x3c010001, 0xac256e90, 0x52842, -0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001, -0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823, -0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac, -0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011, -0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021, -0xc001749, 0x0, 0x3c020001, 0x8c426cd0, -0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200, -0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004, -0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, -0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38, -0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, -0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8, -0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4, -0x3c020001, 0x8c426cc8, 0x14400003, 0x0, -0x3c010001, 0xac206cd0, 0xc001151, 0x0, -0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, -0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8, -0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060, -0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c, -0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, -0x8f860040, 0x3c040001, 0x24845c80, 0x24050200, -0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821, -0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, -0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, -0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014, -0x8f860040, 0x24050300, 0xc002b3b, 0x2003821, -0x8f820240, 0x3c030001, 0x431025, 0xaf820240, -0xaf800048, 0x8f820048, 0x14400005, 0x0, -0xaf800048, 0x8f820048, 0x10400004, 0x0, -0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, -0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8, -0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001, -0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001, -0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001, -0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001, -0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001, -0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c, -0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138, -0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150, -0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140, -0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014, -0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014, -0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0, -0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014, -0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac, -0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c, -0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff, -0x1061824, 0xe81024, 0x43102b, 0x10400006, -0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010, -0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010, -0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, -0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000, -0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, -0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010, -0xc002b3b, 0xafa30014, 0xaf800054, 0xaf80011c, -0x8c020218, 0x30420002, 0x10400009, 0x0, -0x8c020220, 0x3c030002, 0x34630004, 0x431025, -0xaf42000c, 0x8c02021c, 0x10000008, 0x34420004, -0x8c020220, 0x3c030002, 0x34630006, 0x431025, -0xaf42000c, 0x8c02021c, 0x34420006, 0xaf420014, -0x8c020218, 0x30420010, 0x1040000a, 0x0, -0x8c02021c, 0x34420004, 0xaf420010, 0x8c020220, -0x3c03000a, 0x34630004, 0x431025, 0x10000009, -0xaf420008, 0x8c020220, 0x3c03000a, 0x34630006, -0x431025, 0xaf420008, 0x8c02021c, 0x34420006, -0xaf420010, 0x24020001, 0xaf8200a0, 0xaf8200b0, -0x8f830054, 0x8f820054, 0xaf8000d0, 0xaf8000c0, -0x10000002, 0x24630064, 0x8f820054, 0x621023, -0x2c420065, 0x1440fffc, 0x0, 0x8c040208, -0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490, -0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008, -0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, -0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c, -0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004, -0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00, -0x431024, 0x10400021, 0x0, 0x8f8200b4, -0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001, -0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c, -0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001, -0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014, -0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b, -0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, -0x3c030001, 0x431025, 0xaf820140, 0x96e20472, -0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482, -0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b, -0xafa20014, 0x96f00452, 0x32020001, 0x10400002, -0xb021, 0x24160001, 0x32020002, 0x54400001, -0x36d60002, 0x32020008, 0x54400001, 0x36d60004, -0x32020010, 0x54400001, 0x36d60008, 0x32020020, -0x54400001, 0x36d60010, 0x32020040, 0x54400001, -0x36d60020, 0x32020080, 0x54400001, 0x36d60040, -0x96e60482, 0x30c20200, 0x54400001, 0x36d64000, -0x96e30472, 0x30620200, 0x10400003, 0x30620100, -0x10000003, 0x36d62000, 0x54400001, 0x36d61000, -0x96f00462, 0x32c24000, 0x14400004, 0x3207009b, -0x30c2009b, 0x14e20007, 0x240e0001, 0x32c22000, -0x1440000d, 0x32020001, 0x3062009b, 0x10e20009, -0x240e0001, 0x3c040001, 0x24845d20, 0x24051300, -0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b, -0xafa00014, 0x32020001, 0x54400001, 0x36d60080, -0x32020002, 0x54400001, 0x36d60100, 0x32020008, -0x54400001, 0x36d60200, 0x32020010, 0x54400001, -0x36d60400, 0x32020080, 0x54400001, 0x36d60800, -0x8c020218, 0x30420200, 0x10400002, 0x3c020008, -0x2c2b025, 0x8c020218, 0x30420800, 0x10400002, -0x3c020080, 0x2c2b025, 0x8c020218, 0x30420400, -0x10400002, 0x3c020100, 0x2c2b025, 0x8c020218, -0x30420100, 0x10400002, 0x3c020200, 0x2c2b025, -0x8c020218, 0x30420080, 0x10400002, 0x3c020400, -0x2c2b025, 0x8c020218, 0x30422000, 0x10400002, -0x3c020010, 0x2c2b025, 0x8c020218, 0x30424000, -0x10400002, 0x3c020020, 0x2c2b025, 0x8c020218, -0x30421000, 0x10400002, 0x3c020040, 0x2c2b025, -0x8ee20498, 0x8ee3049c, 0xaf420160, 0xaf430164, -0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c, -0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174, -0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c, -0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184, -0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c, -0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194, -0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c, -0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4, -0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8, -0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c, -0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200, -0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a, -0x3484ca00, 0x3821, 0x24020006, 0x24030002, -0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200, -0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290, -0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8, -0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f, -0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001, -0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c, -0x24051400, 0x21702, 0x24420030, 0xa062022c, -0x3471021, 0xa040022c, 0x8c070218, 0x2c03021, -0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014, -0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80, -0x24060010, 0x27b10030, 0x2203821, 0x27b30034, -0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8, -0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00, -0x8fa20034, 0x246400ff, 0x852024, 0x831823, -0x431023, 0xafa20034, 0xafa40030, 0x3c040001, -0x24845d44, 0x3c050000, 0x24a54100, 0x24060108, -0x2203821, 0xc0017a3, 0xafb30010, 0x409021, -0x32c20003, 0x3c010001, 0xac326e80, 0x10400045, -0x2203821, 0x8f820050, 0x3c030010, 0x431024, -0x10400016, 0x0, 0x8c020218, 0x30420040, -0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, -0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f, -0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, -0xc002b3b, 0x2c03021, 0x10000004, 0x0, -0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, -0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001, -0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030, -0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, -0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70, -0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90, -0xc53023, 0x2603821, 0xaf420108, 0xc0017a3, -0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001, -0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023, -0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3, -0xafb10010, 0x3c040001, 0x24845da4, 0x10000024, -0x24051600, 0x3c040001, 0x24845dac, 0x3c050001, -0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023, -0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc, -0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c, -0xc53023, 0x2203821, 0xaf420108, 0xc0017a3, -0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001, -0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023, -0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3, -0xafb30010, 0x3c040001, 0x24845de4, 0x24051650, -0x2c03021, 0x3821, 0x3c010001, 0xac226ef8, -0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020, -0x10400021, 0x27a70030, 0x3c040001, 0x24845df0, -0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8, -0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, -0xc0017a3, 0xafa20010, 0x21900, 0x31982, -0x3c040800, 0x641825, 0xae430028, 0x24030010, -0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, -0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010, -0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0, -0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, -0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, -0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10, -0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, -0x24051700, 0xc002b3b, 0x3821, 0x3c020000, -0x24425cbc, 0x21100, 0x21182, 0x3c030800, -0x431025, 0xae420028, 0x24020008, 0xaf42003c, -0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, -0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c, -0x24051800, 0x32c60020, 0xc002b3b, 0x0, -0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff, -0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800, -0x651824, 0x31882, 0x641825, 0x451024, -0x21082, 0x441025, 0xacc20080, 0x32c20180, -0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080, -0x431024, 0x1040000d, 0x0, 0x8f820050, -0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001, -0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040, -0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050, -0x3c030010, 0x431024, 0x10400016, 0x0, -0x8c020218, 0x30420040, 0x1040000f, 0x24020001, -0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001, -0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014, -0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021, -0x10000004, 0x0, 0x3c010001, 0x370821, -0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001, -0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023, -0x8f420008, 0x27b30030, 0x2603821, 0x27b10034, -0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010, -0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4, -0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821, -0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001, -0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001, -0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001, -0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001, -0x24845e7c, 0x10000027, 0x24052100, 0x3c040001, -0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001, -0x24c6a104, 0xc53023, 0x27b10030, 0x2203821, -0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001, -0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001, -0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c, -0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4, -0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4, -0xc53023, 0x2203821, 0x3c010001, 0xac226f04, -0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8, -0x24052150, 0x2c03021, 0x3821, 0x3c010001, -0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014, -0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff, -0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800, -0x711824, 0x31882, 0x6e1825, 0x511024, -0x21082, 0x4e1025, 0xae630038, 0xae620078, -0x8c020218, 0x30420040, 0x14400004, 0x24020001, -0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, -0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001, -0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821, -0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001, -0xac226efc, 0x511024, 0x21082, 0x3c0e0800, -0x4e1025, 0xae620050, 0x32c22000, 0x10400006, -0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024, -0x1000000f, 0x21082, 0x3c040001, 0x24845ed8, -0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4, -0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001, -0xac226f14, 0x511024, 0x21082, 0x3c0e0800, -0x4e1025, 0xae620048, 0x32c24000, 0x10400005, -0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e, -0x21100, 0x3c040001, 0x24845ef0, 0x3c050001, -0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023, -0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001, -0xac226f08, 0x21100, 0x21182, 0x3c030800, -0x431025, 0xae420060, 0x3c040001, 0x24845f08, -0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650, -0xc53023, 0x27b10030, 0x2203821, 0x27b30034, -0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff, -0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468, -0x3c060000, 0x24c66588, 0xc53023, 0x2203821, -0x240f021, 0x3c010001, 0xac226edc, 0x4e1024, -0x21082, 0x3c150800, 0x551025, 0xafae0044, -0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001, -0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000, -0x24c66808, 0x8fae0044, 0xc53023, 0x2203821, -0x3c010001, 0xac226ed0, 0x4e1024, 0x21082, -0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010, -0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810, -0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023, -0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024, -0x21082, 0x551025, 0xafc200c0, 0xc0017a3, -0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001, -0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044, -0xc53023, 0x2203821, 0x3c010001, 0xac226ed4, -0x4e1024, 0x21082, 0x551025, 0xafc200c8, -0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c, -0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20, -0xc53023, 0x2203821, 0xaf420110, 0xc0017a3, -0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001, -0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023, -0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010, -0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80, -0x3c060001, 0x24c65aac, 0xc53023, 0x2203821, -0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010, -0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298, -0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821, -0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044, -0x3c010001, 0xac226f18, 0x4e1024, 0x21082, -0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40, -0x0, 0xc0027a8, 0x0, 0xac000228, -0xac00022c, 0x96e20450, 0x2442ffff, 0xaf420038, -0x96e20460, 0xaf420080, 0x32c24000, 0x14400003, -0x0, 0x96e20480, 0xaf420084, 0x96e70490, -0x50e00001, 0x24070800, 0x24e2ffff, 0xaf420088, -0xaf42007c, 0x24020800, 0x10e2000f, 0x32c24000, -0x10400003, 0x24020400, 0x10e2000b, 0x0, -0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f, -0x96e60490, 0x24052170, 0x2c03821, 0xafa00010, -0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138, -0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098, -0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084, -0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200, -0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58, -0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0, -0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c, -0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, -0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010, -0x3c010001, 0xac226eb8, 0x21100, 0x21182, -0x511025, 0xc0018fc, 0xae420000, 0x8f820240, -0x3c030001, 0x431025, 0xaf820240, 0x3c020000, -0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, -0x511024, 0x14400005, 0x3c030800, 0x8f820060, -0x431024, 0x1040fffd, 0x0, 0xc003c4d, -0x8821, 0x3c020100, 0xafa20020, 0x8f530018, -0x240200ff, 0x56620001, 0x26710001, 0x8c020228, -0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001, -0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, -0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0xc01821, 0x8f440178, 0x8f45017c, 0x1021, -0x24070004, 0xafa70010, 0xafb10014, 0x8f48000c, -0x24c604c0, 0x2e63021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x1440000b, 0x24070008, -0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, -0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020, -0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164, -0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, -0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400010, 0x0, -0x8f420340, 0x24420001, 0xaf420340, 0x8f420340, -0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, -0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020, -0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4, -0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f, -0x10400069, 0x3c020700, 0x34423000, 0xafa20028, -0x8f530018, 0x240200ff, 0x12620002, 0x8821, -0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, -0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, -0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, -0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, -0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, -0x8f45017c, 0x1021, 0x24070004, 0xafa70010, -0xafb10014, 0x8f48000c, 0x24c604c0, 0x2e63021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009, -0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, -0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018, -0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, -0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400010, 0x0, 0x8f420340, 0x24420001, -0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009, -0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b, -0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0, -0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010, -0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b, -0x3821, 0x10000004, 0x0, 0x8c020264, -0x10400005, 0x0, 0x8f8200a0, 0x30420004, -0x1440fffa, 0x0, 0x8f820044, 0x34420004, -0xaf820044, 0x8f420308, 0x24420001, 0xaf420308, -0x8f420308, 0x8f8200d8, 0x8f8300d4, 0x431023, -0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81, -0x10400006, 0x24020001, 0x8f420090, 0x8f430144, -0x431021, 0xaf420090, 0x24020001, 0xaf42008c, -0x32c20008, 0x10400006, 0x0, 0x8f820214, -0x3c038100, 0x3042ffff, 0x431025, 0xaf820214, -0x3c030001, 0x8c636d94, 0x30620002, 0x10400009, -0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000, -0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012, -0xc53023, 0x10400009, 0x0, 0x3c040001, -0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000, -0x24c67678, 0x10000008, 0xc53023, 0x3c040001, -0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000, -0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034, -0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc, -0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100, -0x21182, 0x431025, 0xae420040, 0x8f8200a0, -0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c, -0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001, -0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001, -0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001, -0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b, -0x24052400, 0x8f820200, 0xafa20010, 0x8f820220, -0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001, -0x24846008, 0xc002b3b, 0x24052500, 0x8f830060, -0x74100b, 0x242000a, 0x200f821, 0x0, -0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058, -0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, -0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001, -0x24846014, 0x24052600, 0x3021, 0x3821, -0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008, -0x0, 0x3e00008, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x3e00008, 0x0, 0x3e00008, 0x0, -0x27bdfde0, 0x27a50018, 0x3c04dead, 0x3484beef, -0xafbf0218, 0x8f820150, 0x3c03001f, 0x3463ffff, -0xafa40018, 0xa22823, 0xa32824, 0x8ca20000, -0x1044000a, 0x0, 0xafa50010, 0x8ca20000, -0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001, -0x2484601c, 0xc002b3b, 0x24052700, 0x8fbf0218, -0x3e00008, 0x27bd0220, 0x27bdffe0, 0x3c06abba, -0x34c6babe, 0xafb00018, 0x3c100004, 0x3c07007f, -0x34e7ffff, 0xafbf001c, 0x102840, 0x8e040000, -0x8ca30000, 0xaca00000, 0xae060000, 0x8ca20000, -0xaca30000, 0x10460005, 0xae040000, 0xa08021, -0xf0102b, 0x1040fff5, 0x102840, 0x3c040001, -0x24846028, 0x24052800, 0x2003021, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021, -0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, -0x8c020224, 0x3047003f, 0x10e00010, 0x803021, -0x2821, 0x24030020, 0xe31024, 0x10400002, -0x63042, 0xa62821, 0x31842, 0x1460fffb, -0xe31024, 0x2402f000, 0xa22824, 0x3402ffff, -0x45102b, 0x14400003, 0x3c020001, 0x10000008, -0x3c020001, 0x3442ffff, 0x851823, 0x43102b, -0x14400003, 0xa01021, 0x3c02fffe, 0x821021, -0x3e00008, 0x0, 0x27bdffd0, 0xafb50028, -0x8fb50040, 0xafb20020, 0xa09021, 0xafb1001c, -0x24c60003, 0xafbf002c, 0xafb30024, 0xafb00018, -0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b, -0x1440001b, 0xe08821, 0x8e330000, 0xafb00010, -0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000, -0xc002b3b, 0x2403021, 0x8e230000, 0x702021, -0x64102b, 0x10400007, 0x2402821, 0x8ca20000, -0xac620000, 0x24630004, 0x64102b, 0x1440fffb, -0x24a50004, 0x8ea20000, 0x501023, 0xaea20000, -0x8e220000, 0x501021, 0x1000000b, 0xae220000, -0x2402002d, 0xa0820000, 0xafb00010, 0x8ea20000, -0x2409821, 0xafa20014, 0x8e270000, 0x24053100, -0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c, -0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8, -0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84, -0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc, -0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001, -0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0, -0xac201ffc, 0x431023, 0x441023, 0x245bb000, -0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021, -0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0, -0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0, -0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001, -0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d, -0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200, -0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, -0x3021, 0x3603821, 0xafbf0030, 0xafb3002c, -0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c, -0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014, -0xc001916, 0x0, 0x8f820240, 0x34420004, -0xaf820240, 0x24020001, 0xaf420000, 0x3c020001, -0x571021, 0x904240f4, 0x10400092, 0x2403fffc, -0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c, -0x2121023, 0x438024, 0x8fa3001c, 0x3c040001, -0x24846040, 0x70102b, 0x1440001a, 0x27b30018, -0x8fb10018, 0x24053000, 0x2403021, 0xafb00010, -0xafa30014, 0xc002b3b, 0x2203821, 0x8fa30018, -0x702021, 0x64102b, 0x10400007, 0x2403021, -0x8cc20000, 0xac620000, 0x24630004, 0x64102b, -0x1440fffb, 0x24c60004, 0x8fa2001c, 0x501023, -0xafa2001c, 0x8e620000, 0x501021, 0x1000000a, -0xae620000, 0x2408821, 0x24053100, 0xafb00010, -0xafa30014, 0x8fa70018, 0x2203021, 0x2402002d, -0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c, -0x3c040001, 0x2484605c, 0x24120020, 0x3c010001, -0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018, -0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50, -0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821, -0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020, -0x65102b, 0x10400007, 0x0, 0x8c820000, -0xac620000, 0x24630004, 0x65102b, 0x1440fffb, -0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, -0x8e220000, 0x521021, 0x1000000b, 0xae220000, -0x3c100001, 0x26106f50, 0x24053100, 0xafa70010, -0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d, -0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001, -0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001, -0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018, -0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70, -0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821, -0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020, -0x65102b, 0x10400007, 0x0, 0x8c820000, -0xac620000, 0x24630004, 0x65102b, 0x1440fffb, -0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, -0x8e220000, 0x521021, 0x1000000b, 0xae220000, -0x3c100001, 0x26106f70, 0x24053100, 0xafa70010, -0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d, -0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031, -0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001, -0x2652809c, 0x2121023, 0x438024, 0x8fa3001c, -0x3c040001, 0x24846084, 0x70102b, 0x1440001a, -0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, -0xafb00010, 0xafa30014, 0xc002b3b, 0x2203821, -0x8fa30018, 0x702021, 0x64102b, 0x10400007, -0x2403021, 0x8cc20000, 0xac620000, 0x24630004, -0x64102b, 0x1440fffb, 0x24c60004, 0x8fa2001c, -0x501023, 0xafa2001c, 0x8e620000, 0x501021, -0x1000000a, 0xae620000, 0x2408821, 0x24053100, -0xafb00010, 0xafa30014, 0x8fa70018, 0x2203021, -0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001, -0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400, -0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, -0x27bd0038, 0x0, 0x0, 0x8f820040, -0x3c03f000, 0x431024, 0x3c036000, 0x14430006, -0x0, 0x8f820050, 0x2403ff80, 0x431024, -0x34420055, 0xaf820050, 0x8f820054, 0x244203e8, -0xaf820058, 0x240201f4, 0xaf4200e0, 0x24020004, -0xaf4200e8, 0x24020002, 0xaf4001b0, 0xaf4000e4, -0xaf4200dc, 0xaf4000d8, 0xaf4000d4, 0x3e00008, -0xaf4000d0, 0x8f820054, 0x24420005, 0x3e00008, -0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, -0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, -0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, -0x36940040, 0x3c020001, 0x8c426da8, 0x10400017, -0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016, -0x282a025, 0x3c020001, 0x8c426e44, 0x14400012, -0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003, -0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002, -0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf, -0x0, 0x10000004, 0x3c020200, 0xc004196, -0x0, 0x3c020200, 0x2c21024, 0x10400003, -0x0, 0xc001f4b, 0x0, 0x8f4200d8, -0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, -0x14400003, 0x0, 0xaf4000d8, 0x36940080, -0x8c030238, 0x1060000c, 0x0, 0x8f4201b0, -0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006, -0x0, 0x934205c5, 0x14400003, 0x0, -0xc001da0, 0x0, 0x8fbf0010, 0x3e00008, -0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059, -0x0, 0x3c020001, 0x571021, 0x904240f0, -0x10400026, 0x24070008, 0x8f440170, 0x8f450174, -0x8f48000c, 0x8f860120, 0x24020020, 0xafa20010, -0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, -0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x24846128, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b, -0x34a50900, 0x1000005c, 0x0, 0x8f420300, -0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c, -0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170, -0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120, -0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, -0x24020001, 0x3c010001, 0x370821, 0xa02240f1, -0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120, -0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036, -0x0, 0x8f420300, 0x8f43002c, 0x24420001, -0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1, -0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, -0x3c010001, 0x370821, 0xa02040f0, 0x10000026, -0xaf400034, 0x934205c1, 0x1040001d, 0x0, -0xa34005c1, 0x8f820040, 0x30420001, 0x14400008, -0x2021, 0x8c030104, 0x24020001, 0x50620005, -0x24040001, 0x8c020264, 0x10400003, 0x801021, -0x24040001, 0x801021, 0x10400006, 0x0, -0x8f42030c, 0x24420001, 0xaf42030c, 0x10000008, -0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044, -0x8f420308, 0x24420001, 0xaf420308, 0x8f420308, -0x3c010001, 0x370821, 0xa02040f0, 0x3c010001, -0x370821, 0xa02040f1, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x3c03ff7f, 0x3463ffff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0020, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0020, 0x8f430044, 0x8f42007c, 0x10620029, -0x24070008, 0x8f440168, 0x8f45016c, 0x8f48000c, -0x8f860120, 0x24020040, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400011, 0x24020001, 0x3c010001, 0x370821, -0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044, -0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300, -0x1000000f, 0x0, 0x8f420304, 0x24420001, -0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c, -0x3c010001, 0x370821, 0xa02040f2, 0x10000004, -0xaf400078, 0x3c010001, 0x370821, 0xa02040f2, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x3c03feff, 0x3463ffff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8, -0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, -0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, -0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, -0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, -0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, -0x8c636d98, 0x34420002, 0xaf420004, 0x24020001, -0x14620003, 0x3c020600, 0x10000002, 0x34423000, -0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, -0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, -0x11420002, 0x1821, 0x25430001, 0x8c020228, -0x609821, 0x1662000e, 0x3c050009, 0x8f42033c, -0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228, -0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014, -0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, -0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, -0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, -0x8f820054, 0x247103e8, 0x2221023, 0x2c4203e9, -0x1040001b, 0xa821, 0xe09021, 0x265e04c0, -0x8f440178, 0x8f45017c, 0x2401821, 0x240a0004, -0xafaa0010, 0xafb30014, 0x8f48000c, 0x1021, -0x2fe3021, 0xafa80018, 0x8f48010c, 0x24070008, -0xa32821, 0xa3482b, 0x822021, 0x100f809, -0x892021, 0x54400006, 0x24150001, 0x8f820054, -0x2221023, 0x2c4203e9, 0x1440ffe9, 0x0, -0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378, -0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, -0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24846118, 0xafa20014, 0x8d460000, -0x3c050009, 0x10000035, 0x34a50600, 0x8f420308, -0x24150001, 0x24420001, 0xaf420308, 0x8f420308, -0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, -0x247103e8, 0x2221023, 0x2c4203e9, 0x10400016, -0xa821, 0x3c1e0020, 0x24120010, 0x8f42000c, -0x8f440160, 0x8f450164, 0x8f860120, 0xafb20010, -0xafb30014, 0x5e1025, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, -0x0, 0x8f820054, 0x2221023, 0x2c4203e9, -0x1440ffee, 0x0, 0x32a200ff, 0x14400011, -0x3c050009, 0x8f420378, 0x24420001, 0xaf420378, -0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034, -0xafa20010, 0x8f820124, 0x3c040001, 0x24846120, -0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, -0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec, -0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029, -0x36100040, 0x3c020400, 0x2c21024, 0x10400013, -0x2404ffdf, 0x8f420250, 0x8f430254, 0x8f4401b4, -0x14640006, 0x36100040, 0x8f420270, 0x8f430274, -0x8f4401b8, 0x10640007, 0x2402ffdf, 0x8f420250, -0x8f430254, 0x8f440270, 0x8f450274, 0x10000012, -0x3a100020, 0x1000002b, 0x2028024, 0x8f420250, -0x8f430254, 0x8f4501b4, 0x14650006, 0x2048024, -0x8f420270, 0x8f430274, 0x8f4401b8, 0x50640021, -0x36100040, 0x8f420250, 0x8f430254, 0x8f440270, -0x8f450274, 0x3a100040, 0xaf4301b4, 0x10000019, -0xaf4501b8, 0x8f4200d4, 0x24430001, 0x10000011, -0x28420033, 0x8f420004, 0x30420001, 0x10400009, -0x3c020400, 0x2c21024, 0x10400004, 0x2402ffdf, -0x2028024, 0x1000000b, 0x36100040, 0x10000009, -0x36100060, 0x8f4200d4, 0x36100040, 0x24430001, -0x284201f5, 0x14400003, 0xaf4300d4, 0xaf4000d4, -0x3a100020, 0xaf900044, 0x2402ff7f, 0x282a024, -0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, -0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, -0x27bd0058, 0x3e00008, 0x0, 0x3c020001, -0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044, -0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, -0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001, -0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004, -0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004, -0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004, -0x24020001, 0x14620003, 0x3c020600, 0x10000002, -0x34423000, 0x34421000, 0xafa20020, 0x1821, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, -0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, -0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, -0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24846118, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000035, 0x34a50600, 0x8f420308, -0x24130001, 0x24420001, 0xaf420308, 0x8f420308, -0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400016, -0x9821, 0x3c150020, 0x24110010, 0x8f42000c, -0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010, -0xafb20014, 0x551025, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe3, -0x0, 0x8f820054, 0x2021023, 0x2c4203e9, -0x1440ffee, 0x0, 0x326200ff, 0x14400011, -0x0, 0x8f420378, 0x24420001, 0xaf420378, -0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24846120, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, -0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec, -0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018, -0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4, -0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270, -0x8f430274, 0x8f4401b8, 0x10640021, 0x0, -0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0, -0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4, -0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0, -0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001, -0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001, -0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001, -0x8f420004, 0x30420001, 0x10400008, 0x0, -0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1, -0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4, -0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5, -0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1, -0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1, -0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c, -0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001, -0x5462001f, 0x2021, 0x3c020001, 0x90426cf0, -0x1443001b, 0x24040005, 0x10000019, 0x24040006, -0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b, -0x24020001, 0x3c030001, 0x90636cf1, 0x54620010, -0x2021, 0x3c020001, 0x90426cf0, 0x1443000c, -0x24040003, 0x1000000a, 0x24040004, 0x3c030001, -0x90636cf1, 0x14620006, 0x2021, 0x3c020001, -0x90426cf0, 0x24040001, 0x50440001, 0x24040002, -0xc00565a, 0x0, 0x2402ff7f, 0x282a024, -0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x3e00008, 0x0, 0x3c020001, -0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044, -0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, -0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, -0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8, -0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, -0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, -0xaf420004, 0x24020001, 0x14820003, 0x3c020600, -0x10000002, 0x34423000, 0x34421000, 0xafa20020, -0x1821, 0x8f5e0018, 0x27aa0020, 0x240200ff, -0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, -0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c, -0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228, -0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014, -0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, -0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, -0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, -0x2021023, 0x2c4203e9, 0x1040001b, 0x9821, -0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c, -0x2201821, 0x240a0004, 0xafaa0010, 0xafb20014, -0x8f48000c, 0x1021, 0x2f53021, 0xafa80018, -0x8f48010c, 0x24070008, 0xa32821, 0xa3482b, -0x822021, 0x100f809, 0x892021, 0x54400006, -0x24130001, 0x8f820054, 0x2021023, 0x2c4203e9, -0x1440ffe9, 0x0, 0x326200ff, 0x54400017, -0xaf520018, 0x8f420378, 0x24420001, 0xaf420378, -0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24846118, 0x3c050009, -0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, -0x8f420308, 0x24130001, 0x24420001, 0xaf420308, -0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054, -0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, -0x10400016, 0x9821, 0x3c150020, 0x24110010, -0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120, -0xafb10010, 0xafb20014, 0x551025, 0xafa20018, -0x8f42010c, 0x24070008, 0x40f809, 0x24c6001c, -0x1440ffe3, 0x0, 0x8f820054, 0x2021023, -0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, -0x14400011, 0x0, 0x8f420378, 0x24420001, -0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x24846120, -0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, -0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001, -0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001, -0x10400033, 0x3c020400, 0x2c21024, 0x10400017, -0x0, 0x934205c0, 0x8f440250, 0x8f450254, -0x8f4301b4, 0x34420020, 0x14a30006, 0xa34205c0, -0x8f420270, 0x8f430274, 0x8f4401b8, 0x10640008, -0x0, 0x8f420250, 0x8f430254, 0x934405c0, -0x8f460270, 0x8f470274, 0x10000016, 0x38840040, -0x934205c0, 0x10000048, 0x304200bf, 0x934205c0, -0x8f440250, 0x8f450254, 0x8f4301b4, 0x304200bf, -0x14a30006, 0xa34205c0, 0x8f420270, 0x8f430274, -0x8f4401b8, 0x1064000b, 0x0, 0x8f420250, -0x8f430254, 0x934405c0, 0x8f460270, 0x8f470274, -0x38840020, 0xaf4301b4, 0xaf4701b8, 0x10000033, -0xa34405c0, 0x934205c0, 0x1000002f, 0x34420020, -0x934205c0, 0x8f4300d4, 0x34420020, 0xa34205c0, -0x24620001, 0x10000023, 0x28630033, 0x8f4200e4, -0x8f4300e0, 0x24420001, 0xaf4200e4, 0x43102a, -0x14400006, 0x24030001, 0x8f4200e8, 0x14430002, -0xaf4000e4, 0x24030004, 0xaf4300e8, 0x8f420004, -0x30420001, 0x1040000d, 0x3c020400, 0x2c21024, -0x10400007, 0x0, 0x934205c0, 0x34420040, -0xa34205c0, 0x934205c0, 0x1000000f, 0x304200df, -0x934205c0, 0x1000000c, 0x34420060, 0x934205c0, -0x8f4300d4, 0x34420020, 0xa34205c0, 0x24620001, -0x286300fb, 0x14600005, 0xaf4200d4, 0x934205c0, -0xaf4000d4, 0x38420040, 0xa34205c0, 0x934205c0, -0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001, -0x14620005, 0x0, 0x934405c0, 0x42102, -0x10000003, 0x348400f0, 0x934405c0, 0x3484000f, -0xc005640, 0x0, 0x2402ff7f, 0x282a024, -0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, -0x274401c0, 0x26e30028, 0x24650400, 0x65102b, -0xafbf0048, 0xafbe0044, 0xafb50040, 0xafb3003c, -0xafb20038, 0xafb10034, 0x10400007, 0xafb00030, -0x8c820000, 0xac620000, 0x24630004, 0x65102b, -0x1440fffb, 0x24840004, 0x8c020080, 0xaee20044, -0x8c0200c0, 0xaee20040, 0x8c020084, 0xaee20030, -0x8c020084, 0xaee2023c, 0x8c020088, 0xaee20240, -0x8c02008c, 0xaee20244, 0x8c020090, 0xaee20248, -0x8c020094, 0xaee2024c, 0x8c020098, 0xaee20250, -0x8c02009c, 0xaee20254, 0x8c0200a0, 0xaee20258, -0x8c0200a4, 0xaee2025c, 0x8c0200a8, 0xaee20260, -0x8c0200ac, 0xaee20264, 0x8c0200b0, 0xaee20268, -0x8c0200b4, 0xaee2026c, 0x8c0200b8, 0xaee20270, -0x8c0200bc, 0x24040001, 0xaee20274, 0xaee00034, -0x41080, 0x571021, 0x8ee30034, 0x8c42023c, -0x24840001, 0x621821, 0x2c82000f, 0xaee30034, -0x1440fff8, 0x41080, 0x8c0200cc, 0xaee20048, -0x8c0200d0, 0xaee2004c, 0x8c0200e0, 0xaee201f8, -0x8c0200e4, 0xaee201fc, 0x8c0200e8, 0xaee20200, -0x8c0200ec, 0xaee20204, 0x8c0200f0, 0xaee20208, -0x8ee400c0, 0x8ee500c4, 0x8c0200fc, 0x45102b, -0x1040000b, 0x0, 0x8ee200c0, 0x8ee300c4, -0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c0, 0xaee300c4, -0x8c0200fc, 0x8ee400c0, 0x8ee500c4, 0x2408ffff, -0x24090000, 0x401821, 0x1021, 0x882024, -0xa92824, 0x822025, 0xa32825, 0xaee400c0, -0xaee500c4, 0x8ee400d0, 0x8ee500d4, 0x8c0200f4, -0x45102b, 0x1040000b, 0x0, 0x8ee200d0, -0x8ee300d4, 0x24040001, 0x24050000, 0x651821, -0x65302b, 0x441021, 0x461021, 0xaee200d0, -0xaee300d4, 0x8c0200f4, 0x8ee400d0, 0x8ee500d4, -0x401821, 0x1021, 0x882024, 0xa92824, -0x822025, 0xa32825, 0xaee400d0, 0xaee500d4, -0x8ee400c8, 0x8ee500cc, 0x8c0200f8, 0x45102b, -0x1040000b, 0x0, 0x8ee200c8, 0x8ee300cc, -0x24040001, 0x24050000, 0x651821, 0x65302b, -0x441021, 0x461021, 0xaee200c8, 0xaee300cc, -0x8c0200f8, 0x8ee400c8, 0x8ee500cc, 0x401821, -0x1021, 0x882024, 0xa92824, 0x822025, -0xa32825, 0x24020008, 0xaee400c8, 0xaee500cc, -0xafa20010, 0xafa00014, 0x8f42000c, 0x8c040208, -0x8c05020c, 0xafa20018, 0x8f42010c, 0x26e60028, -0x40f809, 0x24070400, 0x104000f0, 0x3c020400, -0xafa20020, 0x934205c6, 0x10400089, 0x1821, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, -0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, -0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, -0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24846118, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000033, 0x34a50600, 0x8f420308, -0x24130001, 0x24420001, 0xaf420308, 0x8f420308, -0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, -0x9821, 0x24110010, 0x8f42000c, 0x8f440160, -0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014, -0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, -0x326200ff, 0x54400012, 0x24020001, 0x8f420378, -0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, -0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x24846120, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc002b3b, 0x3c03821, 0x1021, -0x1440005b, 0x24020001, 0x10000065, 0x0, -0x8f510018, 0x240200ff, 0x12220002, 0x8021, -0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, -0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, -0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, -0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, -0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, -0x8f45017c, 0x1021, 0x24070004, 0xafa70010, -0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009, -0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, -0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018, -0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, -0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x54400011, 0x24020001, 0x8f420340, 0x24420001, -0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24846104, 0x3c050009, -0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b, -0x2203821, 0x1021, 0x1040000d, 0x24020001, -0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001, -0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001, -0xaee20150, 0x10000003, 0x8ee20150, 0x24020001, -0xa34205c6, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x27bdffd8, 0xafbf0020, -0x8f8200b0, 0x30420004, 0x10400068, 0x0, -0x8f430128, 0x8f820104, 0x14620005, 0x0, -0x8f430130, 0x8f8200b4, 0x10620006, 0x0, -0x8f820104, 0xaf420128, 0x8f8200b4, 0x1000005b, -0xaf420130, 0x8f8200b0, 0x3c030080, 0x431024, -0x1040000d, 0x0, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f8200b0, 0x2403fffb, 0x431024, -0xaf8200b0, 0x8f82011c, 0x2403fffd, 0x431024, -0x1000004a, 0xaf82011c, 0x8f430128, 0x8f820104, -0x14620005, 0x0, 0x8f430130, 0x8f8200b4, -0x10620010, 0x0, 0x8f820104, 0xaf420128, -0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010, -0x8f420130, 0x3c040001, 0x24846144, 0xafa20014, -0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, -0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130, -0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c, -0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000, -0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, -0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, -0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, -0x8c040208, 0x8c05020c, 0xafa20018, 0x8f42010c, -0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, -0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, -0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128, -0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c, -0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, -0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0, -0x30420004, 0x10400069, 0x0, 0x8f43012c, -0x8f820124, 0x14620005, 0x0, 0x8f430134, -0x8f8200a4, 0x10620006, 0x0, 0x8f820124, -0xaf42012c, 0x8f8200a4, 0x1000005c, 0xaf420134, -0x8f8200a0, 0x3c030080, 0x431024, 0x1040000d, -0x0, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f8200a0, 0x2403fffb, 0x431024, 0xaf8200a0, -0x8f82011c, 0x2403fffd, 0x431024, 0x1000004b, -0xaf82011c, 0x8f43012c, 0x8f820124, 0x14620005, -0x0, 0x8f430134, 0x8f8200a4, 0x10620010, -0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4, -0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134, -0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c, -0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, -0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001, -0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0, -0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c, -0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, -0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, -0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, -0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, -0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c, -0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, -0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c, -0xafa20010, 0x8f420134, 0x3c040001, 0x24846180, -0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, -0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020, -0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, -0x3c060080, 0x3c050100, 0x8f820070, 0x481024, -0x1040fffd, 0x0, 0x8f820054, 0x24420005, -0xaf820078, 0x8c040234, 0x10800016, 0x1821, -0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, -0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, -0x571021, 0x8c4240e8, 0x44102b, 0x14400009, -0x0, 0x3c030080, 0x3c010001, 0x370821, -0xac2040e8, 0x3c010001, 0x370821, 0x1000000b, -0xa02740f0, 0x3c020001, 0x571021, 0x904240f0, -0x54400006, 0x661825, 0x3c020001, 0x571021, -0x904240f1, 0x54400001, 0x661825, 0x8c040230, -0x10800013, 0x0, 0x3c020001, 0x571021, -0x8c4240ec, 0x24420005, 0x3c010001, 0x370821, -0xac2240ec, 0x3c020001, 0x571021, 0x8c4240ec, -0x44102b, 0x14400006, 0x0, 0x3c010001, -0x370821, 0xac2040ec, 0x10000006, 0x651825, -0x3c020001, 0x571021, 0x904240f2, 0x54400001, -0x651825, 0x1060ffbc, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x431025, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x1000ffa7, 0xaf80004c, -0x1000ffa5, 0xaf800048, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x27bdffe0, -0xafbf0018, 0x8f860064, 0x30c20004, 0x10400025, -0x24040004, 0x8c020114, 0xaf420020, 0xaf840064, -0x8f4202fc, 0x24420001, 0xaf4202fc, 0x8f4202fc, -0x8f820064, 0x30420004, 0x14400005, 0x0, -0x8c030114, 0x8f420020, 0x1462fff2, 0x0, -0x8f420000, 0x10400007, 0x8f43003c, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x431025, 0xaf820060, -0x8f420000, 0x10400073, 0x0, 0x1000006f, -0x0, 0x30c20008, 0x10400020, 0x24040008, -0x8c02011c, 0xaf420048, 0xaf840064, 0x8f4202a8, -0x24420001, 0xaf4202a8, 0x8f4202a8, 0x8f820064, -0x30420008, 0x14400005, 0x0, 0x8c03011c, -0x8f420048, 0x1462fff2, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x1000ffd9, 0x34420200, 0x30c20020, -0x10400023, 0x24040020, 0x8c02012c, 0xaf420068, -0xaf840064, 0x8f4202d8, 0x24420001, 0xaf4202d8, -0x8f4202d8, 0x8f820064, 0x30420020, 0x14400005, -0x32c24000, 0x8c03012c, 0x8f420068, 0x1462fff2, -0x32c24000, 0x14400002, 0x3c020001, 0x2c2b025, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x1000ffb4, 0x34420800, -0x30c20010, 0x10400029, 0x24040010, 0x8c020124, -0xaf420058, 0xaf840064, 0x8f4202d4, 0x24420001, -0xaf4202d4, 0x8f4202d4, 0x8f820064, 0x30420010, -0x14400005, 0x32c22000, 0x8c030124, 0x8f420058, -0x1462fff2, 0x32c22000, 0x50400001, 0x36d68000, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420100, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x1000006c, -0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001, -0x10400004, 0x24020001, 0xaf820064, 0x10000064, -0x0, 0x30c20002, 0x1440000b, 0x3c050003, -0x3c040001, 0x24846244, 0x34a50500, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0, -0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c, -0x10a20048, 0x51080, 0x8c460300, 0x24a20001, -0x3045003f, 0x24020003, 0xac05022c, 0x61e02, -0x10620005, 0x24020010, 0x1062001d, 0x30c20fff, -0x10000039, 0x0, 0x8f4302a8, 0x8f440000, -0x30c20fff, 0xaf420048, 0x24630001, 0xaf4302a8, -0x10800007, 0x8f4202a8, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x34420200, 0xaf820060, 0x8f420000, -0x1040001f, 0x0, 0x1000001b, 0x0, -0xaf420058, 0x32c22000, 0x50400001, 0x36d68000, -0x8f4202d4, 0x8f430000, 0x24420001, 0xaf4202d4, -0x10600007, 0x8f4202d4, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x34420100, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x10000006, 0xaf80004c, -0x10000004, 0xaf800048, 0xc002196, 0xc02021, -0x402821, 0x8c02010c, 0x14a20002, 0x24020002, -0xaf820064, 0x8f820064, 0x30420002, 0x14400004, -0x0, 0x8c02010c, 0x14a2ffac, 0x0, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008, -0x0, 0x27bdffa0, 0xafb00040, 0x808021, -0x101602, 0x2442ffff, 0x304300ff, 0x2c620013, -0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c, -0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034, -0x31080, 0x3c010001, 0x220821, 0x8c226288, -0x400008, 0x0, 0x101302, 0x30440fff, -0x24020001, 0x10820005, 0x24020002, 0x1082000c, -0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004, -0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204, -0x3c040001, 0x8c846e80, 0x10000009, 0x34630001, -0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001, -0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28, -0x21100, 0x21182, 0xaf430004, 0x3c030800, -0x431025, 0xac820038, 0x8f840054, 0x41442, -0x41c82, 0x431021, 0x41cc2, 0x431023, -0x41d02, 0x431021, 0x41d42, 0x431023, -0x10000009, 0xaf420208, 0x3c040001, 0x24846250, -0x34a51000, 0x2003021, 0x3821, 0xafa00010, -0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001, -0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028, -0x2002021, 0x24050210, 0xc002bbf, 0x24060008, -0xc002518, 0x2002021, 0x10000216, 0x0, -0x8faa0034, 0x27a40028, 0xa1880, 0x25420001, -0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034, -0x21080, 0x8c430300, 0x25420001, 0x3042003f, -0xafa20034, 0xac02022c, 0xafa50028, 0xc002518, -0xafa3002c, 0x10000203, 0x0, 0x27b00028, -0x2002021, 0x24050210, 0xc002bbf, 0x24060008, -0xc002657, 0x2002021, 0x100001fa, 0x0, -0x8faa0034, 0x27a40028, 0xa1880, 0x25420001, -0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034, -0x21080, 0x8c430300, 0x25420001, 0x3042003f, -0xafa20034, 0xac02022c, 0xafa50028, 0xc002657, -0xafa3002c, 0x100001e7, 0x0, 0x101302, -0x30430fff, 0x24020001, 0x10620005, 0x24020002, -0x1062001e, 0x3c020002, 0x10000033, 0x3c050003, -0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025, -0x8f820228, 0x3c010001, 0x370821, 0xac2238d8, -0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc, -0x8f820230, 0x3c010001, 0x370821, 0xac2238e0, -0x8f820234, 0x3c010001, 0x370821, 0xac2238e4, -0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230, -0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024, -0x10400012, 0x3c02fffd, 0x3c020001, 0x571021, -0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021, -0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021, -0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021, -0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff, -0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c, -0x34a51100, 0x2003021, 0x3821, 0xafa00010, -0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001, -0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302, -0x30450fff, 0x24020001, 0x10a20005, 0x24020002, -0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003, -0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004, -0x2c4b025, 0x621824, 0x34630008, 0xaf830220, -0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb, -0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024, -0xaf820220, 0x10000009, 0xaf450298, 0x3c040001, -0x24846268, 0x34a51200, 0x2003021, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc, -0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc, -0x27840208, 0x24050200, 0xc002bbf, 0x24060008, -0x27440224, 0x24050200, 0xc002bbf, 0x24060008, -0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169, -0x8f4202c4, 0x101302, 0x30430fff, 0x24020001, -0x10620011, 0x28620002, 0x50400005, 0x24020002, -0x10600007, 0x0, 0x10000017, 0x0, -0x1062000f, 0x0, 0x10000013, 0x0, -0x8c060248, 0x2021, 0xc005104, 0x24050004, -0x10000007, 0x0, 0x8c060248, 0x2021, -0xc005104, 0x24050004, 0x10000010, 0x0, -0x8c06024c, 0x2021, 0xc005104, 0x24050001, -0x1000000a, 0x0, 0x3c040001, 0x24846274, -0x3c050003, 0x34a51300, 0x2003021, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0, -0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0, -0xc002426, 0x0, 0x10000136, 0x0, -0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8, -0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014, -0xafa20018, 0x8f420108, 0x26e60028, 0x40f809, -0x24070400, 0x1040fff5, 0x0, 0x10000125, -0x0, 0x3c03ffff, 0x34637fff, 0x8f420368, -0x8f440360, 0x2c3b024, 0x1821, 0xaf400058, -0xaf40005c, 0xaf400060, 0xaf400064, 0x441023, -0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020, -0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, -0xafaa003c, 0x27c30001, 0x8c020228, 0x609021, -0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, -0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, -0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821, -0x240a0004, 0xafaa0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124, -0x3c040001, 0x24846218, 0x3c050009, 0xafa20014, -0x8d460000, 0x10000033, 0x34a50600, 0x8f420308, -0x24130001, 0x24420001, 0xaf420308, 0x8f420308, -0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, -0x9821, 0x24110010, 0x8f42000c, 0x8f440160, -0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014, -0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, -0x326200ff, 0x14400011, 0x0, 0x8f420378, -0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, -0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001, -0x24846220, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0, -0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8, -0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8, -0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260, -0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8, -0x8f820220, 0x30420008, 0x14400002, 0x24020001, -0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001, -0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff, -0x3442ffff, 0x2021824, 0x32c20180, 0x14400006, -0x3402fffb, 0x43102b, 0x14400003, 0x0, -0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280, -0x3c050003, 0x34a51500, 0x2003021, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700, -0x34421000, 0x101e02, 0x621825, 0xafa30020, -0x8f510018, 0x240200ff, 0x12220002, 0x8021, -0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, -0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, -0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, -0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, -0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, -0x8f45017c, 0x1021, 0x24070004, 0xafa70010, -0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009, -0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, -0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018, -0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, -0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400010, 0x0, 0x8f420340, 0x24420001, -0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, -0x8f820124, 0x3c040001, 0x24846204, 0x3c050009, -0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b, -0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0, -0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0, -0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054, -0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, -0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8, -0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8, -0x354a8320, 0x90870000, 0x24840001, 0x3021, -0x1071026, 0x30420001, 0x10400002, 0x81842, -0x6a1826, 0x604021, 0x24c60001, 0x2cc20008, -0x1440fff7, 0x73842, 0x25290001, 0x125102b, -0x1440fff0, 0x0, 0x1001021, 0x3e00008, -0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044, -0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, -0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200, -0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420004, 0xaf820220, 0x8f820200, -0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004, -0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360, -0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c, -0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0, -0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8, -0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360, -0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368, -0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c, -0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200, -0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf, -0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc, -0x240203e8, 0x24040002, 0x24030001, 0xaf420294, -0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008, -0x10400004, 0x0, 0xaf430298, 0x10000003, -0x3021, 0xaf440298, 0x3021, 0x3c030001, -0x661821, 0x90636d00, 0x3461021, 0x24c60001, -0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821, -0x24c60001, 0x8f820040, 0x24040080, 0x24050080, -0x21702, 0x24420030, 0xa062022c, 0x3461021, -0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004, -0x14400006, 0x0, 0x8f820220, 0x3c0308ff, -0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c, -0x30e20004, 0x14400006, 0x0, 0x8f820200, -0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200, -0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, -0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, -0x27bd0050, 0x0, 0x0, 0xaf400104, -0x24040001, 0x410c0, 0x2e21821, 0x24820001, -0x3c010001, 0x230821, 0xa42234d0, 0x402021, -0x2c820080, 0x1440fff8, 0x410c0, 0x24020001, -0x3c010001, 0x370821, 0xa42038d0, 0xaf420100, -0xaf800228, 0xaf80022c, 0xaf800230, 0xaf800234, -0x3e00008, 0x0, 0x27bdffe8, 0xafbf0014, -0xafb00010, 0x8f420104, 0x28420005, 0x10400026, -0x808021, 0x3c020001, 0x8f430104, 0x344230d0, -0x2e22021, 0x318c0, 0x621821, 0x2e31821, -0x83102b, 0x10400015, 0x1021, 0x96070000, -0x24840006, 0x24660006, 0x9482fffc, 0x14470009, -0x2821, 0x9483fffe, 0x96020002, 0x14620006, -0xa01021, 0x94820000, 0x96030004, 0x431026, -0x2c450001, 0xa01021, 0x14400009, 0x24840008, -0x86102b, 0x1440fff0, 0x1021, 0x304200ff, -0x14400030, 0x24020001, 0x1000002e, 0x1021, -0x1000fffa, 0x24020001, 0x2002021, 0xc00240c, -0x24050006, 0x3042007f, 0x218c0, 0x2e31021, -0x3c010001, 0x220821, 0x942230d0, 0x1040fff2, -0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0, -0x10c0ffed, 0x3c080001, 0x350834d2, 0x96070000, -0x610c0, 0x572021, 0x882021, 0x94820000, -0x14470009, 0x2821, 0x94830002, 0x96020002, -0x14620006, 0xa01021, 0x94820004, 0x96030004, -0x431026, 0x2c450001, 0xa01021, 0x14400007, -0x610c0, 0x2e21021, 0x3c060001, 0xc23021, -0x94c634d0, 0x14c0ffeb, 0x610c0, 0x10c0ffd2, -0x24020001, 0x8fbf0014, 0x8fb00010, 0x3e00008, -0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0, -0x801021, 0xafb00030, 0x24500002, 0x2002021, -0x24050006, 0xafb10034, 0x408821, 0xafbf0048, -0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c, -0xafb20038, 0x3047007f, 0x710c0, 0x2e21021, -0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c, -0xa03021, 0x3c090001, 0x352934d2, 0x96280002, -0x510c0, 0x572021, 0x892021, 0x94820000, -0x14480009, 0x3021, 0x94830002, 0x96020002, -0x14620006, 0xc01021, 0x94820004, 0x96030004, -0x431026, 0x2c460001, 0xc01021, 0x14400007, -0x510c0, 0x2e21021, 0x3c050001, 0xa22821, -0x94a534d0, 0x14a0ffeb, 0x510c0, 0xa03021, -0x10c00014, 0x610c0, 0x571821, 0x3c010001, -0x230821, 0x8c2334d0, 0x571021, 0xafa30010, -0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, -0x24846394, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063, -0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, -0x2e21021, 0x3c010001, 0x220821, 0x942234d0, -0xaf420100, 0xa03021, 0x14c00011, 0x628c0, -0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, -0x220821, 0x942230d0, 0x3c040001, 0x248463a0, -0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, -0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800, -0xb71821, 0x3c020001, 0x96040000, 0x344234d2, -0x621821, 0xa4640000, 0x8e020002, 0x720c0, -0xac620002, 0x2e41021, 0x3c030001, 0x621821, -0x946330d0, 0x2e51021, 0x3c010001, 0x220821, -0xa42334d0, 0x2e41021, 0x3c010001, 0x220821, -0xa42630d0, 0x8f420104, 0x24420001, 0x28420080, -0x1040000f, 0x3c020002, 0x8f420104, 0x3c040001, -0x348430d2, 0x96030000, 0x210c0, 0x571021, -0x441021, 0xa4430000, 0x8e030002, 0xac430002, -0x8f420104, 0x24420001, 0xaf420104, 0x3c020002, -0x2c21024, 0x10400011, 0x72142, 0x3c030001, -0x346338d8, 0x24020003, 0x441023, 0x21080, -0x572021, 0x832021, 0x571021, 0x431021, -0x30e5001f, 0x8c430000, 0x24020001, 0xa21004, -0x621825, 0x1000000c, 0xac830000, 0x24020003, -0x441023, 0x21080, 0x5c2821, 0x5c1021, -0x30e4001f, 0x8c430228, 0x24020001, 0x821004, -0x621825, 0xaca30228, 0x3c020800, 0x34421000, -0x1821, 0xafa20020, 0x8f5e0018, 0x27aa0020, -0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, -0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, -0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, -0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, -0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, -0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, -0x9821, 0xe08821, 0x263504c0, 0x8f440178, -0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010, -0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x54400006, 0x24130001, 0x8f820054, 0x2021023, -0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, -0x54400017, 0xaf520018, 0x8f420378, 0x24420001, -0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x24846368, -0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, -0x34a50600, 0x8f420308, 0x24130001, 0x24420001, -0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x10400014, 0x9821, 0x24110010, -0x8f42000c, 0x8f440160, 0x8f450164, 0x8f860120, -0xafb10010, 0xafb20014, 0xafa20018, 0x8f42010c, -0x24070008, 0x40f809, 0x24c6001c, 0x1440ffe5, -0x0, 0x8f820054, 0x2021023, 0x2c4203e9, -0x1440ffef, 0x0, 0x326200ff, 0x14400011, -0x0, 0x8f420378, 0x24420001, 0xaf420378, -0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, -0x8f820124, 0x3c040001, 0x24846370, 0x3c050009, -0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, -0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4, -0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4, -0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021, -0xafb00040, 0x24500002, 0x2002021, 0x24050006, -0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054, -0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048, -0x3048007f, 0x810c0, 0x2e21021, 0x3c060001, -0xc23021, 0x94c630d0, 0x10c0001c, 0x3821, -0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0, -0x572021, 0x8a2021, 0x94820000, 0x14490009, -0x2821, 0x94830002, 0x96020002, 0x14620006, -0xa01021, 0x94820004, 0x96030004, 0x431026, -0x2c450001, 0xa01021, 0x14400008, 0x610c0, -0xc03821, 0x2e21021, 0x3c060001, 0xc23021, -0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, -0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, -0x3c010001, 0x220821, 0x942230d0, 0x3c040001, -0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004, -0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075, -0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, -0x3c030001, 0x621821, 0x946334d0, 0x710c0, -0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, -0x1000000b, 0x3c040001, 0x2e21021, 0x3c030001, -0x621821, 0x946334d0, 0x810c0, 0x2e21021, -0x3c010001, 0x220821, 0xa42330d0, 0x3c040001, -0x348430d0, 0x8f430100, 0x610c0, 0x2e21021, -0x3c010001, 0x220821, 0xa42334d0, 0x8f420104, -0x2e43821, 0x2821, 0x18400029, 0xaf460100, -0x24e60006, 0x94c3fffc, 0x96020000, 0x14620009, -0x2021, 0x94c3fffe, 0x96020002, 0x14620006, -0x801021, 0x94c20000, 0x96030004, 0x431026, -0x2c440001, 0x801021, 0x50400014, 0x24a50001, -0x8f420104, 0x2442ffff, 0xa2102a, 0x1040000b, -0x24e40004, 0x94820006, 0x8c830008, 0xa482fffe, -0xac830000, 0x8f420104, 0x24a50001, 0x2442ffff, -0xa2102a, 0x1440fff7, 0x24840008, 0x8f420104, -0x2442ffff, 0x10000006, 0xaf420104, 0x8f420104, -0x24c60008, 0xa2102a, 0x1440ffda, 0x24e70008, -0x810c0, 0x2e21021, 0x3c010001, 0x220821, -0x942230d0, 0x14400023, 0x3c020800, 0x3c020002, -0x2c21024, 0x10400012, 0x82142, 0x3c030001, -0x346338d8, 0x24020003, 0x441023, 0x21080, -0x572021, 0x832021, 0x571021, 0x431021, -0x3105001f, 0x24030001, 0x8c420000, 0xa31804, -0x31827, 0x431024, 0x1000000d, 0xac820000, -0x24020003, 0x441023, 0x21080, 0x5c2821, -0x5c1021, 0x3104001f, 0x24030001, 0x8c420228, -0x831804, 0x31827, 0x431024, 0xaca20228, -0x3c020800, 0x34422000, 0x1821, 0xafa20020, -0x8f5e0018, 0x27ab0020, 0x240200ff, 0x13c20002, -0xafab0034, 0x27c30001, 0x8c020228, 0x609021, -0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, -0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, -0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010, -0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, -0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, -0x263504c0, 0x8f440178, 0x8f45017c, 0x2201821, -0x240b0004, 0xafab0010, 0xafb20014, 0x8f48000c, -0x1021, 0x2f53021, 0xafa80018, 0x8f48010c, -0x24070008, 0xa32821, 0xa3482b, 0x822021, -0x100f809, 0x892021, 0x54400006, 0x24130001, -0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffe9, -0x0, 0x326200ff, 0x54400017, 0xaf520018, -0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, -0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, -0x3c040001, 0x24846368, 0x3c050009, 0xafa20014, -0x8d660000, 0x10000033, 0x34a50600, 0x8f420308, -0x24130001, 0x24420001, 0xaf420308, 0x8f420308, -0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, -0x9821, 0x24110010, 0x8f42000c, 0x8f440160, -0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014, -0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, -0x326200ff, 0x14400011, 0x0, 0x8f420378, -0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, -0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, -0x24846370, 0x3c050009, 0xafa20014, 0x8d660000, -0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8, -0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4, -0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058, -0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, -0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, -0x0, 0x0, 0x0, 0x27bdffe0, -0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000, -0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, -0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, -0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, -0xaf800118, 0xaf800120, 0xaf800124, 0xaf800128, -0xaf800130, 0xaf800134, 0xaf800138, 0xaf4200ec, -0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, -0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, -0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, -0x3c040001, 0x24846470, 0x3c050001, 0x34420001, -0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x34a50100, 0xc002b3b, 0x3821, 0x8c020218, -0x30420040, 0x10400014, 0x0, 0x8f82011c, -0x3c040001, 0x2484647c, 0x3c050001, 0x34420004, -0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, -0x10000007, 0x34a50200, 0x3c040001, 0x24846484, -0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, -0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, -0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, -0x24680020, 0x27684800, 0x8f820128, 0x11020004, -0x0, 0x8f820124, 0x15020007, 0x0, -0x8f430334, 0x1021, 0x24630001, 0xaf430334, -0x10000039, 0x8f430334, 0xac640000, 0xac650004, -0xac660008, 0xa467000e, 0xac690018, 0xac6a001c, -0xac6b0010, 0xac620014, 0xaf880120, 0x8f4200fc, -0x8f4400f4, 0x2442ffff, 0xaf4200fc, 0x8c820000, -0x10490005, 0x3042ff8f, 0x10400019, 0x3122ff8f, -0x10400018, 0x3c020001, 0x8c830004, 0x2c620010, -0x10400013, 0x3c020001, 0x24630001, 0xac830004, -0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, -0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, -0x14440015, 0x24020001, 0x8f820128, 0x24420020, -0xaf820128, 0x8f820128, 0x1000000f, 0x24020001, -0x3c020001, 0x344230c8, 0x2e21021, 0x54820004, -0x24820008, 0x3c020001, 0x34422ec8, 0x2e21021, -0x402021, 0x24020001, 0xaf4400f4, 0xac890000, -0xac820004, 0x24020001, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x8fa90010, 0x8f83010c, -0x8faa0014, 0x8fab0018, 0x1060000a, 0x276247e0, -0x14620002, 0x24680020, 0x27684000, 0x8f820108, -0x11020004, 0x0, 0x8f820104, 0x15020007, -0x0, 0x8f430338, 0x1021, 0x24630001, -0xaf430338, 0x10000035, 0x8f430338, 0xac640000, -0xac650004, 0xac660008, 0xa467000e, 0xac690018, -0xac6a001c, 0xac6b0010, 0xac620014, 0xaf880100, -0x8f4400ec, 0x8c820000, 0x30420006, 0x10400019, -0x31220006, 0x10400018, 0x3c020001, 0x8c830004, -0x2c620010, 0x10400013, 0x3c020001, 0x24630001, -0xac830004, 0x8f4300f0, 0x34422ec0, 0x2e21021, -0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, -0x2e21021, 0x14440015, 0x24020001, 0x8f820108, -0x24420020, 0xaf820108, 0x8f820108, 0x1000000f, -0x24020001, 0x3c020001, 0x34422ec0, 0x2e21021, -0x54820004, 0x24820008, 0x3c020001, 0x34422cc0, -0x2e21021, 0x402021, 0x24020001, 0xaf4400ec, -0xac890000, 0xac820004, 0x24020001, 0x3e00008, -0x0, 0x3e00008, 0x0, 0x27bdffd8, -0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024, -0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, -0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, -0x2403021, 0x2203821, 0xafa20010, 0xc002b3b, -0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, -0x3c040001, 0x24846498, 0xafa20014, 0x8e060000, -0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510, -0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, -0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014, -0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00, -0x2221024, 0x3c030800, 0x54430016, 0x3c030200, -0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200, -0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030, -0x3021, 0x3821, 0x36420002, 0xaf82011c, -0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, -0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024, -0x0, 0x2c31024, 0x1040000d, 0x2231024, -0x1040000b, 0x36420002, 0xaf82011c, 0x36220001, -0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330, -0x24420001, 0xaf420330, 0x10000015, 0x8f420330, -0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010, -0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0, -0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002, -0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, -0x8f820140, 0x3c030001, 0x431025, 0xaf820140, -0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001, -0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020, -0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0, -0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021, -0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014, -0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001, -0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004, -0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018, -0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500, -0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001, -0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024, -0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac, -0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001, -0x2484650c, 0x3c050001, 0x34a5f030, 0x3021, -0x3821, 0x36420002, 0xaf82011c, 0x36220001, -0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010, -0xc002b3b, 0xafa00014, 0x10000024, 0x0, -0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, -0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, -0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001, -0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001, -0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014, -0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b, -0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, -0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, -0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, -0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, -0x27bd0028, 0x6021, 0x5021, 0x3021, -0x2821, 0x6821, 0x4821, 0x7821, -0x7021, 0x8f880124, 0x8f870104, 0x1580002e, -0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, -0x10460029, 0x0, 0x3c040001, 0x8c846ee4, -0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, -0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, -0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, -0x10000012, 0x24c60020, 0x10400017, 0x0, -0x3c040001, 0x8c846ee4, 0x8d020000, 0x8d030004, -0xac820000, 0xac830004, 0x8d020008, 0xac820008, -0x9502000e, 0xa482000e, 0x8d020010, 0x25060020, -0xac820010, 0x8d020014, 0x240c0001, 0xc01821, -0xac820014, 0x27624fe0, 0x43102b, 0x54400001, -0x27634800, 0x603021, 0x1540002f, 0x31620100, -0x11200014, 0x31628000, 0x8f820100, 0x1045002a, -0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000, -0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, -0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, -0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, -0x24a50020, 0x10400018, 0x31620100, 0x3c040001, -0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000, -0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, -0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, -0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, -0x276247e0, 0x43102b, 0x54400001, 0x27634000, -0x602821, 0x31620100, 0x5440001d, 0x31621000, -0x11a00009, 0x31a20800, 0x10400004, 0x25020020, -0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, -0x8f880124, 0x6821, 0x11800011, 0x31621000, -0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004, -0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, -0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, -0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, -0x1440ff82, 0x0, 0x1120000f, 0x31220800, -0x10400004, 0x3c020002, 0x8f8200b8, 0xa5c20000, -0x3c020002, 0x1221024, 0x10400004, 0x24e20020, -0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, -0x8f870104, 0x4821, 0x1140ff70, 0x0, -0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004, -0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, -0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, -0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, -0x3e00008, 0x0, 0x6021, 0x5821, -0x3021, 0x2821, 0x6821, 0x5021, -0x7821, 0x7021, 0x8f880124, 0x8f870104, -0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, -0x31220800, 0x8f820120, 0x10460029, 0x0, -0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004, -0xac820000, 0xac830004, 0x8cc20008, 0xac820008, -0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, -0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, -0x10400017, 0x0, 0x3c040001, 0x8c846ee4, -0x8d020000, 0x8d030004, 0xac820000, 0xac830004, -0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, -0x8d020010, 0x25060020, 0xac820010, 0x8d020014, -0x240c0001, 0xc01821, 0xac820014, 0x27624fe0, -0x43102b, 0x54400001, 0x27634800, 0x603021, -0x1560002f, 0x31220100, 0x11400014, 0x31228000, -0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, -0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000, -0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, -0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, -0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, -0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000, -0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, -0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, -0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, -0xa01821, 0xac820014, 0x276247e0, 0x43102b, -0x54400001, 0x27634000, 0x602821, 0x31220100, -0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, -0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, -0x25020020, 0xaf820124, 0x8f880124, 0x6821, -0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4, -0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, -0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, -0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, -0x8c8f0014, 0x31221000, 0x14400022, 0x0, -0x1140000f, 0x31420800, 0x10400004, 0x3c020002, -0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, -0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, -0x24e20020, 0xaf820104, 0x8f870104, 0x5021, -0x11600010, 0x0, 0x3c040001, 0x8c846ee0, -0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, -0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, -0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, -0x8c8e0014, 0x8f820070, 0x3c031000, 0x431024, -0x1040ff5c, 0x0, 0x8f820054, 0x24420005, -0xaf820078, 0x8c040234, 0x10800016, 0x1821, -0x3c020001, 0x571021, 0x8c4240e8, 0x24420005, -0x3c010001, 0x370821, 0xac2240e8, 0x3c020001, -0x571021, 0x8c4240e8, 0x44102b, 0x14400009, -0x24020001, 0x3c030080, 0x3c010001, 0x370821, -0xac2040e8, 0x3c010001, 0x370821, 0x1000000c, -0xa02240f0, 0x3c020001, 0x571021, 0x904240f0, -0x14400006, 0x3c020080, 0x3c020001, 0x571021, -0x904240f1, 0x10400002, 0x3c020080, 0x621825, -0x8c040230, 0x10800013, 0x0, 0x3c020001, -0x571021, 0x8c4240ec, 0x24420005, 0x3c010001, -0x370821, 0xac2240ec, 0x3c020001, 0x571021, -0x8c4240ec, 0x44102b, 0x14400006, 0x0, -0x3c010001, 0x370821, 0xac2040ec, 0x10000006, -0x781825, 0x3c020001, 0x571021, 0x904240f2, -0x54400001, 0x781825, 0x1060ff1a, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x431025, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x1000ff05, -0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, -0x0, 0x0, 0x0, 0x3c020001, -0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012, -0xafb00010, 0x3c100001, 0x26106f90, 0x2002021, -0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001, -0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250, -0x24022000, 0xac100254, 0xac020258, 0x24020001, -0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010, -0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec, -0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, -0x8c820004, 0xad250008, 0xad220004, 0x8f820054, -0xad260010, 0xad270014, 0xad230018, 0xad28001c, -0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90, -0x122102b, 0x10400003, 0x0, 0x3c090001, -0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000, -0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec, -0xad220004, 0xac090250, 0x3e00008, 0x0, -0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec, -0x3c020001, 0x8c426d10, 0xafb10014, 0x808821, -0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, -0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, -0xae020000, 0x3c020001, 0x8c426d10, 0xc09821, -0xe0a821, 0x10800006, 0xae020004, 0x26050008, -0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0, -0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0, -0x3c030001, 0x24636f90, 0x203102b, 0x10400003, -0x0, 0x3c100001, 0x8e106ee8, 0x8e220000, -0xae020000, 0x8e220004, 0xae120008, 0xae020004, -0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, -0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, -0x203102b, 0x10400003, 0x0, 0x3c100001, -0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000, -0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec, -0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, -0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, -0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, -0x83102b, 0x10400006, 0x0, 0xac800000, -0x24840004, 0x83102b, 0x5440fffd, 0xac800000, -0x3e00008, 0x0, 0xa61821, 0xa3102b, -0x10400007, 0x0, 0x8c820000, 0xaca20000, -0x24a50004, 0xa3102b, 0x1440fffb, 0x24840004, -0x3e00008, 0x0, 0x861821, 0x83102b, -0x10400007, 0x0, 0x8ca20000, 0xac820000, -0x24840004, 0x83102b, 0x1440fffb, 0x24a50004, -0x3e00008, 0x0, 0x63080, 0x861821, -0x83102b, 0x10400006, 0x0, 0xac850000, -0x24840004, 0x83102b, 0x5440fffd, 0xac850000, -0x3e00008, 0x0, 0x0, 0x26e50028, -0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c, -0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204, -0x8f4c0200, 0x24640400, 0x64102b, 0x10400008, -0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004, -0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff, -0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c, -0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204, -0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200, -0x821024, 0x34420004, 0xc31824, 0x34630004, -0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084, -0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c, -0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094, -0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c, -0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4, -0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac, -0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4, -0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc, -0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0, -0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0, -0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4, -0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec, -0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c, -0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4, -0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8, -0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff, -0x3463fffb, 0x431024, 0xaf820220, 0x30c20004, -0x14400006, 0x0, 0x8f820200, 0x3c03c0ff, -0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc, -0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc, -0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f430024, 0x8f420020, 0x10620038, -0x0, 0x8f430020, 0x8f420024, 0x622023, -0x4810003, 0x0, 0x8f420040, 0x822021, -0x8f430030, 0x8f420024, 0x43102b, 0x14400005, -0x0, 0x8f430040, 0x8f420024, 0x10000005, -0x621023, 0x8f420030, 0x8f430024, 0x431023, -0x2442ffff, 0x406021, 0x8c102a, 0x54400001, -0x806021, 0x8f4a0024, 0x8f490040, 0x8f480024, -0x8f440180, 0x8f450184, 0x8f460024, 0x8f4b001c, -0x24070001, 0xafa70010, 0x84100, 0x1001821, -0x14c5021, 0x2529ffff, 0x1498024, 0xafb00014, -0x8f470014, 0x1021, 0x63100, 0xafa70018, -0xa32821, 0xa3382b, 0x822021, 0x872021, -0x8f420108, 0x1663021, 0x40f809, 0xc3900, -0x54400001, 0xaf500024, 0x8f430024, 0x8f420020, -0x14620018, 0x0, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x2403ffef, 0x431024, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x8fbf0024, 0x8fb00020, 0x3e00008, -0x27bd0028, 0x3e00008, 0x0, 0x27bdffc0, -0x32c20020, 0xafbf0038, 0xafb30034, 0xafb20030, -0xafb1002c, 0x10400004, 0xafb00028, 0x8f530028, -0x10000002, 0x0, 0x8f530020, 0x8f420030, -0x105300eb, 0x21100, 0x8f43001c, 0x628021, -0x8e040000, 0x8e050004, 0x96120008, 0x8f420090, -0x9611000a, 0x3246ffff, 0x46102a, 0x10400017, -0x0, 0x8f8200d8, 0x8f430098, 0x431023, -0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf, -0x10400005, 0x0, 0x8f420090, 0x8f430144, -0x431021, 0xaf420090, 0x8f420090, 0x46102a, -0x10400006, 0x0, 0x8f420348, 0x24420001, -0xaf420348, 0x100000e1, 0x8f420348, 0x8f8200fc, -0x14400006, 0x0, 0x8f420344, 0x24420001, -0xaf420344, 0x100000d9, 0x8f420344, 0x934205c2, -0x1040000b, 0x32c20008, 0x10400008, 0x32220200, -0x10400006, 0x3c034000, 0x9602000e, 0xaf4300ac, -0x21400, 0x10000002, 0xaf4200b0, 0xaf4000ac, -0x32220004, 0x1040007f, 0x32220800, 0x10400003, -0x3247ffff, 0x10000002, 0x24020020, 0x24020004, -0xafa20010, 0x8f420030, 0xafa20014, 0x8f420010, -0x3c030002, 0x431025, 0xafa20018, 0x8f460098, -0x8f420108, 0x40f809, 0x0, 0x104000b7, -0x0, 0x8f42009c, 0x8f430094, 0x2421021, -0xaf42009c, 0xae03000c, 0x8f4200ac, 0x10400008, -0x3c034000, 0x8f420094, 0x431025, 0xafa20020, -0x8f42009c, 0x8f4300b0, 0x10000004, 0x431025, -0x8f420094, 0xafa20020, 0x8f42009c, 0xafa20024, -0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000, -0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c, -0x8f440270, 0x8f450274, 0x401821, 0x1021, -0xa32821, 0xa3302b, 0x822021, 0x862021, -0x32230060, 0x24020040, 0xaf440270, 0xaf450274, -0x10620017, 0x2c620041, 0x10400005, 0x24020020, -0x10620008, 0x24020001, 0x10000026, 0x0, -0x24020060, 0x10620019, 0x24020001, 0x10000021, -0x0, 0x8f420278, 0x8f43027c, 0x24630001, -0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, -0x8f420278, 0x8f43027c, 0x10000016, 0x24020001, -0x8f420280, 0x8f430284, 0x24630001, 0x2c640001, -0x441021, 0xaf420280, 0xaf430284, 0x8f420280, -0x8f430284, 0x1000000b, 0x24020001, 0x8f420288, -0x8f43028c, 0x24630001, 0x2c640001, 0x441021, -0xaf420288, 0xaf43028c, 0x8f420288, 0x8f43028c, -0x24020001, 0xa34205c2, 0x8f420098, 0x3244ffff, -0x2406fff8, 0x8f45013c, 0x441021, 0x24420007, -0x461024, 0x24840007, 0xaf420094, 0x8f420090, -0x8f430094, 0x862024, 0x441023, 0x65182b, -0x14600005, 0xaf420090, 0x8f420094, 0x8f430144, -0x431023, 0xaf420094, 0x8f420094, 0x10000023, -0xaf40009c, 0x3247ffff, 0x50e00022, 0x32c20020, -0x14400002, 0x24020010, 0x24020002, 0xafa20010, -0x8f420030, 0xafa20014, 0x8f420010, 0xafa20018, -0x8f460098, 0x8f420108, 0x40f809, 0x0, -0x1040003a, 0x3245ffff, 0x8f420098, 0x8f430090, -0x8f46013c, 0x451021, 0xaf420098, 0x8f42009c, -0x8f440098, 0xa34005c2, 0x651823, 0xaf430090, -0x451021, 0x86202b, 0x14800005, 0xaf42009c, -0x8f420098, 0x8f430144, 0x431023, 0xaf420098, -0x32c20020, 0x10400005, 0x0, 0x8f420358, -0x2442ffff, 0xaf420358, 0x8f420358, 0x8f420030, -0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf420030, 0x8f420030, 0x14530018, 0x0, -0x8f420000, 0x10400007, 0x0, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x2403fff7, 0x431024, -0xaf820060, 0x8f420000, 0x10400003, 0x0, -0x10000002, 0xaf80004c, 0xaf800048, 0x8fbf0038, -0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, -0x3e00008, 0x27bd0040, 0x3e00008, 0x0, -0x27bdffd0, 0x32c20020, 0xafbf002c, 0xafb20028, -0xafb10024, 0x10400004, 0xafb00020, 0x8f520028, -0x10000002, 0x0, 0x8f520020, 0x8f420030, -0x105200b5, 0x21100, 0x8f43001c, 0x628021, -0x8e040000, 0x8e050004, 0x96110008, 0x8f420090, -0x9607000a, 0x3226ffff, 0x46102a, 0x10400017, -0x0, 0x8f8200d8, 0x8f430098, 0x431023, -0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47, -0x10400005, 0x0, 0x8f420090, 0x8f430144, -0x431021, 0xaf420090, 0x8f420090, 0x46102a, -0x10400006, 0x0, 0x8f420348, 0x24420001, -0xaf420348, 0x100000ab, 0x8f420348, 0x8f8600fc, -0x10c0000c, 0x0, 0x8f8200f4, 0x2403fff8, -0x431024, 0x461023, 0x218c3, 0x58600001, -0x24630100, 0x8f42008c, 0x43102b, 0x14400006, -0x712c2, 0x8f420344, 0x24420001, 0xaf420344, -0x10000098, 0x8f420344, 0x934305c2, 0x1060000f, -0x30460001, 0x8f420010, 0x34480400, 0x32c20008, -0x10400008, 0x30e20200, 0x10400006, 0x3c034000, -0x9602000e, 0xaf4300ac, 0x21400, 0x10000004, -0xaf4200b0, 0x10000002, 0xaf4000ac, 0x8f480010, -0x30e20004, 0x10400045, 0x3227ffff, 0x8f4900ac, -0x11200005, 0x30c200ff, 0x14400006, 0x24020040, -0x10000004, 0x24020008, 0x14400002, 0x24020020, -0x24020004, 0xafa20010, 0x8f430030, 0x11200004, -0xafa30014, 0x8f4200b0, 0x621025, 0xafa20014, -0x3c020002, 0x1021025, 0xafa20018, 0x8f460098, -0x8f420108, 0x40f809, 0x0, 0x10400069, -0x3224ffff, 0x8f42008c, 0x8f430094, 0x24420001, -0xaf42008c, 0x24020001, 0xae03000c, 0xa34205c2, -0x8f420098, 0x2406fff8, 0x8f45013c, 0x441021, -0x24420007, 0x461024, 0x24840007, 0xaf420094, -0x8f420090, 0x8f430094, 0x862024, 0x441023, -0x65182b, 0x14600005, 0xaf420090, 0x8f420094, -0x8f430144, 0x431023, 0xaf420094, 0x8f430094, -0x8f420140, 0x43102b, 0x10400009, 0x0, -0x8f43013c, 0x8f440094, 0x8f420090, 0x8f450138, -0x641823, 0x431023, 0xaf420090, 0xaf450094, -0x8f420094, 0x1000001f, 0xaf420098, 0x10e0001d, -0x30c200ff, 0x14400002, 0x24020010, 0x24020002, -0xafa20010, 0x8f420030, 0xafa80018, 0xafa20014, -0x8f460098, 0x8f420108, 0x40f809, 0x0, -0x10400030, 0x3225ffff, 0x8f420098, 0x8f44013c, -0x451021, 0xaf420098, 0x8f420090, 0x8f430098, -0xa34005c2, 0x451023, 0x64182b, 0x14600005, -0xaf420090, 0x8f420098, 0x8f430144, 0x431023, -0xaf420098, 0x8f420030, 0x8f430040, 0x24420001, -0x2463ffff, 0x431024, 0xaf420030, 0x8f420030, -0x14520018, 0x0, 0x8f420000, 0x10400007, -0x0, 0xaf80004c, 0x8f82004c, 0x1040fffd, -0x0, 0x10000005, 0x0, 0xaf800048, -0x8f820048, 0x1040fffd, 0x0, 0x8f820060, -0x2403fff7, 0x431024, 0xaf820060, 0x8f420000, -0x10400003, 0x0, 0x10000002, 0xaf80004c, -0xaf800048, 0x8fbf002c, 0x8fb20028, 0x8fb10024, -0x8fb00020, 0x3e00008, 0x27bd0030, 0x3e00008, -0x0, 0x27bdffd8, 0x3c020001, 0x34422ec0, -0xafbf0020, 0x8f4300f0, 0x8f840108, 0x2e21021, -0x54620004, 0x24620008, 0x3c020001, 0x34422cc0, -0x2e21021, 0x401821, 0xaf4300f0, 0xac600000, -0x8f4200ec, 0x8c660004, 0x14620004, 0x3c020001, -0x24820020, 0x1000000f, 0xaf820108, 0x8f4300f0, -0x34422ec0, 0x2e21021, 0x54620004, 0x24620008, -0x3c020001, 0x34422cc0, 0x2e21021, 0x401821, -0x8c620004, 0x21140, 0x821021, 0xaf820108, -0xac600000, 0x8c850018, 0x30a20036, 0x1040006c, -0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034, -0x24420001, 0x2463ffff, 0x431024, 0x862021, -0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034, -0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4, -0x0, 0x32c20010, 0x10400028, 0x24070008, -0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c, -0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400011, 0x24020001, 0x3c010001, 0x370821, -0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100, -0x10000036, 0x0, 0x8f420300, 0x8f43002c, -0x24420001, 0xaf420300, 0x8f420300, 0x24020001, -0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170, -0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120, -0x24020020, 0xafa20010, 0xafa30014, 0xafa80018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, -0x24020001, 0x3c010001, 0x370821, 0xa02240f0, -0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120, -0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f, -0x0, 0x8f420300, 0x24420001, 0xaf420300, -0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038, -0x3c010001, 0x370821, 0xa02040f1, 0x3c010001, -0x370821, 0xa02040f0, 0xaf400034, 0x8f420314, -0x24420001, 0xaf420314, 0x10000059, 0x8f420314, -0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028, -0xa22023, 0x4810003, 0x0, 0x8f420040, -0x822021, 0x8f420358, 0x8f430000, 0xaf450028, -0x441021, 0x10600007, 0xaf420358, 0xaf80004c, -0x8f82004c, 0x1040fffd, 0x0, 0x10000005, -0x0, 0xaf800048, 0x8f820048, 0x1040fffd, -0x0, 0x8f820060, 0x34420008, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000038, -0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f, -0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c, -0x8f420050, 0x622023, 0x4820001, 0x24840200, -0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368, -0x1000001a, 0xaf430050, 0x1040000c, 0x32c28000, -0x8c83001c, 0x8f420070, 0x622023, 0x4820001, -0x24840400, 0x8f420364, 0x441021, 0xaf420364, -0x8f420368, 0x1000000d, 0xaf430070, 0x1040000e, -0x3c020800, 0x8c83001c, 0x8f420060, 0x622023, -0x4820001, 0x24840100, 0x8f420360, 0x441021, -0xaf420360, 0x8f420368, 0xaf430060, 0x441021, -0xaf420368, 0x3c020800, 0x2c21024, 0x50400008, -0x36940040, 0x10000006, 0x0, 0x30a20100, -0x10400003, 0x0, 0xc002bd8, 0x0, -0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, -0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c, -0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, -0xafb00038, 0x8f910108, 0x26220020, 0xaf820108, -0x8e320018, 0xa821, 0x32420024, 0x104001ba, -0xf021, 0x8e26001c, 0x8f43001c, 0x61100, -0x621821, 0x8c70000c, 0x9604000c, 0x962d0016, -0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001, -0x621825, 0x10600015, 0x2821, 0x32c20040, -0x10400015, 0x24020800, 0x96030014, 0x14620012, -0x3402aaaa, 0x9603000e, 0x14620007, 0x2021, -0x96030010, 0x24020300, 0x14620004, 0x801021, -0x96020012, 0x2c440001, 0x801021, 0x54400006, -0x24050016, 0x10000004, 0x0, 0x24020800, -0x50820001, 0x2405000e, 0x934205c3, 0x14400008, -0x5821, 0x240b0001, 0x32620180, 0xaf4500a8, -0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3, -0x10a00085, 0x2054021, 0x91020000, 0x3821, -0x3042000f, 0x25080, 0x32c20002, 0x10400012, -0x10a1821, 0x32620002, 0x10400010, 0x32c20001, -0x1002021, 0x94820000, 0x24840002, 0xe23821, -0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02, -0x623821, 0x71c02, 0x30e2ffff, 0x623821, -0x71027, 0xa502000a, 0x32c20001, 0x1040006a, -0x32620001, 0x10400068, 0x0, 0x8f4200a8, -0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8, -0x431021, 0x904c0009, 0x318900ff, 0x39230006, -0x3182b, 0x39220011, 0x2102b, 0x621824, -0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, -0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600, -0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e, -0x0, 0x32c20004, 0x14400013, 0x2821, -0x316200ff, 0x14400004, 0x0, 0x95020002, -0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, -0x95030010, 0xa22821, 0xa32821, 0x95030012, -0x91040009, 0x95020002, 0xa32821, 0xa42821, -0x4a1023, 0xa22821, 0x2002021, 0x94820000, -0x24840002, 0xe23821, 0x88102b, 0x1440fffb, -0x71c02, 0x30e2ffff, 0x623821, 0x71c02, -0x30e2ffff, 0x623821, 0x1a52821, 0x51c02, -0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff, -0x622821, 0xa72823, 0x51402, 0xa22821, -0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff, -0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8, -0x624021, 0x91020000, 0x3042000f, 0x25080, -0x318300ff, 0x24020006, 0x14620003, 0x10a1021, -0x10000002, 0x24440010, 0x24440006, 0x316200ff, -0x14400006, 0x0, 0x94820000, 0xa22821, -0x51c02, 0x30a2ffff, 0x622821, 0x934205c3, -0x10400003, 0x32620100, 0x50400003, 0xa4850000, -0x52827, 0xa4850000, 0x9622000e, 0x8f43009c, -0x621821, 0x32a200ff, 0x10400007, 0xaf43009c, -0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c, -0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c, -0xafa20024, 0x32620080, 0x10400010, 0x32620100, -0x8f4200b4, 0x24430001, 0x210c0, 0x571021, -0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, -0x220821, 0xac2338e8, 0x3c010001, 0x220821, -0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064, -0x0, 0x8f4200b4, 0x24430001, 0x210c0, -0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, -0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, -0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051, -0x3821, 0x3c090001, 0x352938e8, 0x3c08001f, -0x3508ffff, 0x240bffff, 0x340affff, 0x710c0, -0x571021, 0x491021, 0x8c430000, 0x8c440004, -0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028, -0x8fa4002c, 0xac430000, 0xac440004, 0x24420008, -0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c, -0x97a2002e, 0x8f440270, 0x8f450274, 0x401821, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaf440270, 0xaf450274, 0x8fa20028, -0x481024, 0x90430000, 0x30630001, 0x1460000b, -0x402021, 0x8f420278, 0x8f43027c, 0x24630001, -0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, -0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000, -0x144b000e, 0x0, 0x94820004, 0x144a000b, -0x0, 0x8f420288, 0x8f43028c, 0x24630001, -0x2c640001, 0x441021, 0xaf420288, 0xaf43028c, -0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280, -0x8f430284, 0x24630001, 0x2c640001, 0x441021, -0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284, -0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8, -0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4, -0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000, -0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c, -0x8f46008c, 0x8f440270, 0x8f450274, 0x401821, -0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xaf440270, -0xaf450274, 0x92020000, 0x30420001, 0x1440000c, -0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001, -0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, -0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020, -0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004, -0x1462000c, 0x0, 0x8f420288, 0x8f43028c, -0x24630001, 0x2c640001, 0x441021, 0xaf420288, -0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b, -0x32c20020, 0x8f420280, 0x8f430284, 0x24630001, -0x2c640001, 0x441021, 0xaf420280, 0xaf430284, -0x8f420280, 0x8f430284, 0x32c20020, 0x10400005, -0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358, -0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001, -0x2463ffff, 0x431024, 0xaf42002c, 0x32420060, -0x14400008, 0x32c20010, 0x8f420034, 0x24420001, -0xaf420034, 0x8c03023c, 0x43102b, 0x14400102, -0x32c20010, 0x10400018, 0x24070008, 0x8f440170, -0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120, -0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047, -0x24020001, 0x8f420300, 0x8f43002c, 0x24420001, -0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1, -0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174, -0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x10400057, 0x24020001, -0x10000065, 0x0, 0x32420012, 0x10400075, -0x32420001, 0x9622000e, 0x8f43009c, 0x621821, -0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358, -0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c, -0x8f430040, 0x24420001, 0x2463ffff, 0x431024, -0xaf42002c, 0x32420010, 0x14400008, 0x32c20010, -0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c, -0x43102b, 0x144000bc, 0x32c20010, 0x10400028, -0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c, -0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, -0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, -0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, -0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, -0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014, -0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b, -0x34a51100, 0x10000036, 0x0, 0x8f420300, -0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300, -0x24020001, 0xa34205c1, 0x10000026, 0xaf430038, -0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c, -0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, -0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, -0x14400011, 0x24020001, 0x3c010001, 0x370821, -0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, -0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c, -0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900, -0x1000000f, 0x0, 0x8f420300, 0x24420001, -0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1, -0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, -0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, -0x8f420314, 0x24420001, 0xaf420314, 0x10000062, -0x8f420314, 0x10400022, 0x32427000, 0x8e25001c, -0x8f420028, 0xa22023, 0x4810003, 0x0, -0x8f420040, 0x822021, 0x8f420358, 0x8f430000, -0xaf450028, 0x441021, 0x10600007, 0xaf420358, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x34420008, -0xaf820060, 0x8f420000, 0x10400003, 0x0, -0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048, -0x1040002f, 0x32421000, 0x1040000c, 0x32424000, -0x8e23001c, 0x8f420050, 0x622023, 0x4820001, -0x24840200, 0x8f42035c, 0x441021, 0xaf42035c, -0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c, -0x32c28000, 0x8e23001c, 0x8f420070, 0x622023, -0x4820001, 0x24840400, 0x8f420364, 0x441021, -0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070, -0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060, -0x622023, 0x4820001, 0x24840100, 0x8f420360, -0x441021, 0xaf420360, 0x8f420368, 0xaf430060, -0x441021, 0xaf420368, 0x3c020800, 0x2c21024, -0x50400011, 0x36940040, 0x1000000f, 0x0, -0x32420048, 0x10400007, 0x24150001, 0x8e22001c, -0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75, -0xae22001c, 0x32420100, 0x10400003, 0x0, -0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c, -0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c, -0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008, -0x0, 0x0, 0x0, 0x8f8300e4, -0x8f8200e0, 0x2404fff8, 0x441024, 0x621026, -0x2102b, 0x21023, 0x3e00008, 0x621024, -0x3e00008, 0x0, 0x27bdffe0, 0xafbf001c, -0xafb00018, 0x8f8600c4, 0x8f8400e0, 0x8f8500e4, -0x2402fff8, 0x821824, 0x10a30009, 0x27623ff8, -0x14a20002, 0x24a20008, 0x27623000, 0x408021, -0x16030005, 0x30820004, 0x10400004, 0xc02021, -0x10000022, 0x1021, 0x8e040000, 0x8f42011c, -0x14a20003, 0x0, 0x8f420120, 0xaf420114, -0x8ca30000, 0x8f420148, 0x831823, 0x43102b, -0x10400003, 0x0, 0x8f420148, 0x621821, -0x94a20006, 0x24420050, 0x62102b, 0x1440000f, -0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000, -0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894, -0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c, -0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c, -0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008, -0x0, 0x8f8400e0, 0x8f8800c4, 0x8f8300e8, -0x2402fff8, 0x823824, 0xe32023, 0x2c821000, -0x50400001, 0x24841000, 0x420c2, 0x801821, -0x8f440258, 0x8f45025c, 0x1021, 0xa32821, -0xa3302b, 0x822021, 0x862021, 0xaf440258, -0xaf45025c, 0x8f8300c8, 0x8f420148, 0x1032023, -0x82102b, 0x14400004, 0x801821, 0x8f420148, -0x822021, 0x801821, 0x8f440250, 0x8f450254, -0x1021, 0xa32821, 0xa3302b, 0x822021, -0x862021, 0xaf440250, 0xaf450254, 0xaf8800c8, -0xaf8700e4, 0xaf8700e8, 0x3e00008, 0x0, -0x27bdff30, 0x240a0001, 0xafbf00c8, 0xafbe00c4, -0xafb500c0, 0xafb300bc, 0xafb200b8, 0xafb100b4, -0xafb000b0, 0xa3a00097, 0xafa00044, 0xafaa005c, -0x934205c4, 0xa7a0008e, 0x1040000a, 0xa7a00086, -0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c, -0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129, -0xafaa007c, 0x8f420114, 0x40f809, 0x0, -0x403021, 0x10c0034f, 0x0, 0x8cc20000, -0x8cc30004, 0xafa20020, 0xafa30024, 0x8fab0024, -0x8faa0020, 0x3162ffff, 0x2442fffc, 0xafa2006c, -0x3c020006, 0x2c21024, 0xafab007c, 0x14400015, -0xafaa0064, 0x91420000, 0x30420001, 0x10400011, -0x2402ffff, 0x8d430000, 0x14620004, 0x3402ffff, -0x95430004, 0x1062000b, 0x0, 0xc0024bb, -0x8fa40064, 0x304200ff, 0x14400006, 0x0, -0x8f420118, 0x40f809, 0x0, 0x1000032d, -0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, -0x431024, 0x3c03ffff, 0x431824, 0x14600003, -0xafa20024, 0x10000040, 0x1821, 0x3c020080, -0x621024, 0x10400007, 0x0, 0x8f42038c, -0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036, -0x24030001, 0x8f420210, 0x24420001, 0xaf420210, -0x8f420210, 0x3c020001, 0x621024, 0x10400006, -0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4, -0x8f4201c4, 0x3c020002, 0x621024, 0x10400006, -0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c, -0x8f42037c, 0x3c020004, 0x621024, 0x10400006, -0x3c020008, 0x8f420380, 0x24420001, 0xaf420380, -0x8f420380, 0x3c020008, 0x621024, 0x10400006, -0x3c020010, 0x8f420384, 0x24420001, 0xaf420384, -0x8f420384, 0x3c020010, 0x621024, 0x10400006, -0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0, -0x8f4201c0, 0x3c020020, 0x621024, 0x10400006, -0x24030001, 0x8f420388, 0x24420001, 0xaf420388, -0x8f420388, 0x24030001, 0x8c020260, 0x8fab006c, -0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8, -0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c, -0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010, -0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0, -0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007, -0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080, -0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c, -0x3c020080, 0x34420100, 0x1621024, 0x10400005, -0x0, 0x8f42020c, 0x24420001, 0xaf42020c, -0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400, -0x10400015, 0x34028100, 0x8faa0064, 0x9543000c, -0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e, -0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000, -0x8faa006c, 0x8fab0064, 0x254afffc, 0xafaa006c, -0xa7a20086, 0xad63000c, 0xad640008, 0xad650004, -0x256b0004, 0xafab0064, 0x3c020100, 0x2c21024, -0x10400004, 0x0, 0x8faa006c, 0x254a0004, -0xafaa006c, 0x8f4200bc, 0x5040000a, 0xafa00074, -0x8fab006c, 0x4b102b, 0x50400006, 0xafa00074, -0x8f4200bc, 0x1621023, 0xafa20074, 0x8f4a00bc, -0xafaa006c, 0x8f420080, 0x8fab006c, 0x4b102b, -0x10400056, 0x32c28000, 0x1040005e, 0x240a0003, -0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058, -0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024, -0x24420001, 0xaf420350, 0x1000024f, 0x8f420350, -0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, -0x3c040001, 0x248468d0, 0x26620001, 0xafa20014, -0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007, -0xc002b3b, 0x34a52250, 0x1000023f, 0x0, -0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, -0x3c040001, 0x248468d0, 0x24020002, 0xafa20014, -0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007, -0xc002b3b, 0x34a52450, 0x1000022f, 0x0, -0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8, -0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800, -0xc002b3b, 0x603021, 0x10000223, 0x0, -0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0, -0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, -0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216, -0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124, -0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010, -0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b, -0x34a53200, 0x10000208, 0x0, 0x8f420084, -0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001, -0x2c21024, 0x10400004, 0x0, 0x240b0002, -0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020, -0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c, -0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002, -0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054, -0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001, -0x304201ff, 0xafa20054, 0x1e1140, 0x431021, -0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c, -0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010, -0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b, -0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024, -0x24630001, 0xaf430350, 0x100001d3, 0x8f420350, -0x156a001d, 0x0, 0x8f430074, 0x8f420070, -0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c, -0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140, -0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, -0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007, -0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070, -0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c, -0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, -0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c, -0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054, -0x24020004, 0x1562000e, 0x1e1140, 0x1e1180, -0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, -0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024, -0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097, -0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, -0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014, -0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007, -0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024, -0x1440ff34, 0x0, 0x8f420370, 0x240a0001, -0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90, -0x8f420370, 0x27a30036, 0x131040, 0x621821, -0x94620000, 0x441021, 0x10000020, 0xa4620000, -0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072, -0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4, -0x25420020, 0xafa20028, 0x25420008, 0xafa20030, -0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a, -0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a, -0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018, -0x24630002, 0x822023, 0x1880ffde, 0x26730001, -0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, -0x26650001, 0xa2102a, 0x1440002b, 0x24030001, -0x8f83012c, 0x10600023, 0x0, 0x8f820124, -0x431023, 0x22143, 0x58800001, 0x24840040, -0x8f820128, 0x431023, 0x21943, 0x58600001, -0x24630040, 0x64102a, 0x54400001, 0x602021, -0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011, -0x24030001, 0x10000015, 0x306200ff, 0x8fab0064, -0x96070018, 0xafab0010, 0x8e220008, 0x3c040001, -0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400, -0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b, -0x0, 0x8f420334, 0x1821, 0x24420001, -0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc, -0x3c020800, 0x12600021, 0x9021, 0x8fb100a4, -0x2208021, 0x8e220008, 0x96070018, 0x8fa60064, -0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010, -0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c, -0x40f809, 0x0, 0x1040ffd8, 0x3c050007, -0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821, -0x14b102b, 0x10400004, 0xafab0064, 0x8f420148, -0x1625823, 0xafab0064, 0x26100002, 0x26520001, -0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c, -0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002, -0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c, -0x10600013, 0x0, 0x8f820124, 0x431023, -0x22143, 0x58800001, 0x24840040, 0x8f820128, -0x431023, 0x21943, 0x58600001, 0x24630040, -0x64102a, 0x54400001, 0x602021, 0xaf4400fc, -0x8f4200fc, 0xa2102a, 0x14400006, 0x24030001, -0x8f420334, 0x1821, 0x24420001, 0xaf420334, -0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800, -0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b, -0x54400001, 0x608021, 0x8ea40000, 0x8ea50004, -0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008, -0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809, -0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e, -0x97aa008e, 0x11400007, 0x609021, 0x934205c4, -0x14400004, 0x0, 0x97ab0086, 0x6a1825, -0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024, -0x10400003, 0xa1402, 0x34630400, 0xa6a20014, -0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004, -0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a, -0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000, -0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, -0xafa20014, 0x8f42000c, 0x31940, 0x604821, -0xafa20018, 0x8f42010c, 0x4021, 0xa92821, -0xa9182b, 0x882021, 0x40f809, 0x832021, -0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c, -0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c, -0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002, -0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c, -0x8f42035c, 0x156a0006, 0x0, 0x8f420364, -0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364, -0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360, -0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044, -0x8f440088, 0x8f430078, 0x24420001, 0x441024, -0x24630001, 0xaf420044, 0xaf430078, 0x8c020240, -0x62182b, 0x14600075, 0x24070008, 0x8f440168, -0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120, -0x24020040, 0xafa20010, 0xafa30014, 0xafa80018, -0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, -0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2, -0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, -0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120, -0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b, -0x0, 0x8f420304, 0x24420001, 0xaf420304, -0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001, -0x370821, 0xa02040f2, 0xaf400078, 0x8f420318, -0x24420001, 0xaf420318, 0x10000048, 0x8f420318, -0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4, -0x34028000, 0xafa20010, 0x8f420044, 0x2a03021, -0x24070020, 0xafa20014, 0x8f42000c, 0x31940, -0x604821, 0xafa20018, 0x8f42010c, 0x4021, -0xa92821, 0xa9182b, 0x882021, 0x40f809, -0x832021, 0x1040fe1f, 0x240a0001, 0xa34a05c4, -0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c, -0x8fab009c, 0x1505021, 0x16a102b, 0x10400004, -0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064, -0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c, -0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002, -0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c, -0x8f42035c, 0x114b0006, 0x0, 0x8f420360, -0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360, -0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364, -0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044, -0x8f440088, 0x8f430078, 0x24420001, 0x441024, -0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c, -0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e, -0x0, 0x934205c4, 0x10400009, 0x0, -0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c, -0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc, -0x97ab008e, 0x1160000b, 0x34038100, 0x8fa20020, -0x8c46000c, 0xa443000c, 0x97aa0086, 0x8c440004, -0x8c450008, 0xa44a000e, 0xac440000, 0xac450004, -0xac460008, 0x8f42034c, 0x24420001, 0xaf42034c, -0x10000010, 0x8f42034c, 0x8fab007c, 0x3164ffff, -0x2484fffc, 0x801821, 0x8f440250, 0x8f450254, -0x8f460118, 0x1021, 0xa32821, 0xa3382b, -0x822021, 0x872021, 0xaf440250, 0xc0f809, -0xaf450254, 0x8fbf00c8, 0x8fbe00c4, 0x8fb500c0, -0x8fb300bc, 0x8fb200b8, 0x8fb100b4, 0x8fb000b0, -0x3e00008, 0x27bd00d0, 0x3e00008, 0x0, -0x27bdff38, 0x240b0001, 0xafbf00c0, 0xafbe00bc, -0xafb500b8, 0xafb300b4, 0xafb200b0, 0xafb100ac, -0xafb000a8, 0xa3a00087, 0xafa00044, 0xafab005c, -0x934205c4, 0xa7a00076, 0x10400007, 0xa7a0007e, -0x8f4c00c0, 0xafac0064, 0x8f4b00c8, 0x8f5e00c4, -0x10000130, 0xafab006c, 0x8f420114, 0x40f809, -0x0, 0x403021, 0x10c002a1, 0x0, -0x8cc20000, 0x8cc30004, 0xafa20020, 0xafa30024, -0x8fac0024, 0x8fbe0020, 0x3182ffff, 0x2442fffc, -0xafa20064, 0x3c020006, 0x2c21024, 0x14400015, -0xafac006c, 0x93c20000, 0x30420001, 0x10400011, -0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff, -0x97c30004, 0x1062000b, 0x0, 0xc0024bb, -0x3c02021, 0x304200ff, 0x14400006, 0x0, -0x8f420118, 0x40f809, 0x0, 0x10000280, -0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, -0x431024, 0x3c03ffff, 0x431824, 0x14600003, -0xafa20024, 0x10000040, 0x8021, 0x3c020080, -0x621024, 0x10400007, 0x0, 0x8f42038c, -0x24420001, 0xaf42038c, 0x8f42038c, 0x10000036, -0x24100001, 0x8f420210, 0x24420001, 0xaf420210, -0x8f420210, 0x3c020001, 0x621024, 0x10400006, -0x3c020002, 0x8f4201c4, 0x24420001, 0xaf4201c4, -0x8f4201c4, 0x3c020002, 0x621024, 0x10400006, -0x3c020004, 0x8f42037c, 0x24420001, 0xaf42037c, -0x8f42037c, 0x3c020004, 0x621024, 0x10400006, -0x3c020008, 0x8f420380, 0x24420001, 0xaf420380, -0x8f420380, 0x3c020008, 0x621024, 0x10400006, -0x3c020010, 0x8f420384, 0x24420001, 0xaf420384, -0x8f420384, 0x3c020010, 0x621024, 0x10400006, -0x3c020020, 0x8f4201c0, 0x24420001, 0xaf4201c0, -0x8f4201c0, 0x3c020020, 0x621024, 0x10400006, -0x24100001, 0x8f420388, 0x24420001, 0xaf420388, -0x8f420388, 0x24100001, 0x8c020260, 0x8fab0064, -0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8, -0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c, -0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010, -0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0, -0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007, -0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010, -0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, -0x8fab006c, 0x3c020080, 0x34420100, 0x1621024, -0x10400005, 0x0, 0x8f42020c, 0x24420001, -0xaf42020c, 0x8f42020c, 0x10000202, 0x8fa30064, -0x32c20400, 0x10400012, 0x34028100, 0x97c3000c, -0x1462000f, 0x0, 0x240c0200, 0xa7ac0076, -0x97c2000e, 0x8fc30008, 0x8fc40004, 0x8fab0064, -0x8fc50000, 0x256bfffc, 0xafab0064, 0xa7a2007e, -0xafc3000c, 0xafc40008, 0xafc50004, 0x27de0004, -0x8fa70064, 0x320200ff, 0x14400034, 0x3c020100, -0x97c4000c, 0x2c8305dd, 0x38828870, 0x2c420001, -0x621825, 0x10600015, 0x2821, 0x32c20800, -0x10400015, 0x24020800, 0x97c30014, 0x14620012, -0x3402aaaa, 0x97c3000e, 0x14620007, 0x2021, -0x97c30010, 0x24020300, 0x14620004, 0x801021, -0x97c20012, 0x2c440001, 0x801021, 0x54400006, -0x24050016, 0x10000004, 0x0, 0x24020800, -0x50820001, 0x2405000e, 0x10a00013, 0x3c52021, -0x24830009, 0x3c02001f, 0x3442ffff, 0x43102b, -0x10400003, 0x0, 0x8f420148, 0x621823, -0x90620000, 0x38430006, 0x2c630001, 0x38420011, -0x2c420001, 0x621825, 0x10600004, 0x3c020100, -0x94820002, 0x453821, 0x3c020100, 0x2c21024, -0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, -0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064, -0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014, -0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, -0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, -0x10400034, 0x240b0003, 0x32c21000, 0x10400031, -0xafab005c, 0x1000002e, 0x240c0004, 0x8f420350, -0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350, -0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025, -0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, -0x248468d0, 0x26620001, 0xafa20014, 0xafa30010, -0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b, -0x34a55300, 0x10000162, 0x0, 0x8ea20000, -0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010, -0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b, -0x603021, 0x10000156, 0x0, 0x8f420084, -0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, -0x2c21024, 0x10400004, 0x0, 0x240c0002, -0xafac005c, 0x8fab0064, 0x11600166, 0x27ac0020, -0xafac008c, 0x8fab005c, 0x240c0001, 0x556c0021, -0x240c0002, 0x8f430054, 0x8f420050, 0x1062000b, -0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, -0x26220001, 0x304201ff, 0xafa20054, 0x111140, -0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, -0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014, -0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, -0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf, -0x282a024, 0x24630001, 0xaf430350, 0x10000124, -0x8f420350, 0x156c001d, 0x0, 0x8f430074, -0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, -0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, -0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, -0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8, -0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, -0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b, -0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, -0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, -0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, -0xafa20054, 0x24020004, 0x1562000e, 0x111140, -0x111180, 0x24420cc0, 0x2e21021, 0xafa20044, -0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, -0x10400024, 0x25950020, 0x240c0001, 0x10000021, -0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, -0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4, -0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, -0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008, -0x2c21024, 0x1440ff61, 0x0, 0x8f420370, -0x240c0001, 0xafac005c, 0x24420001, 0xaf420370, -0x1000ff90, 0x8f420370, 0x27a30036, 0x131040, -0x621821, 0x94620000, 0x441021, 0x1000001f, -0xa4620000, 0xaebe0018, 0x93a20087, 0x10400084, -0x9821, 0x8fab0044, 0x8fa40064, 0x8fa3008c, -0x25620020, 0xafa20028, 0x25620008, 0xafa20030, -0x25620010, 0xafab002c, 0xafa20034, 0x9562002a, -0xa7a20038, 0x95620018, 0xa7a2003a, 0x9562001a, -0xa7a2003c, 0x9562001c, 0xa7a2003e, 0x94620018, -0x24630002, 0x822023, 0x1880ffdf, 0x26730001, -0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, -0x262102a, 0x14400030, 0x24030001, 0x8f83012c, -0x10600028, 0x0, 0x8f820124, 0x431023, -0x22143, 0x58800001, 0x24840040, 0x8f820128, -0x431023, 0x21943, 0x58600001, 0x24630040, -0x64102a, 0x54400001, 0x602021, 0xaf4400fc, -0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, -0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, -0x4c1021, 0x94470018, 0x101080, 0x4c1021, -0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc, -0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, -0x2003021, 0xc002b3b, 0xafa30014, 0x10000039, -0x0, 0x8f420334, 0x1821, 0x24420001, -0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06, -0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, -0x625024, 0x3c0b4000, 0x22b4025, 0x8fb1008c, -0x2669ffff, 0x2209021, 0x8e420008, 0x96270018, -0x8c440000, 0x8c450004, 0x56090004, 0x240b0001, -0x240c0002, 0x10000002, 0xafac0010, 0xafab0010, -0x16000004, 0xafa80014, 0x8f420008, 0x10000002, -0xafa20018, 0xafaa0018, 0x8f42010c, 0x3c03021, -0xafa80098, 0xafa9009c, 0x40f809, 0xafaa00a0, -0x8fa80098, 0x8fa9009c, 0x8faa00a0, 0x1040ffc2, -0x3c02001f, 0x96230018, 0x3442ffff, 0x3c3f021, -0x5e102b, 0x10400003, 0x26310002, 0x8f420148, -0x3c2f023, 0x26100001, 0x213102b, 0x1440ffda, -0x26520004, 0x8fb00064, 0x1000001a, 0x0, -0x96a3000a, 0x8fb00064, 0x70102b, 0x54400001, -0x608021, 0x8ea40000, 0x8ea50004, 0x8fab005c, -0x240c0002, 0xafac0010, 0x934305c4, 0xb1700, -0x10600003, 0x2223025, 0x3c020800, 0xc23025, -0xafa60014, 0x8f420008, 0xafa20018, 0x8f42010c, -0x3c03021, 0x40f809, 0x2003821, 0x1040fecb, -0x3c050007, 0x97ac0076, 0x11800007, 0x96a3000e, -0x934205c4, 0x14400004, 0x0, 0x97ab007e, -0x6c1825, 0xa6ab0016, 0x8fac006c, 0x3c02ffff, -0x1821024, 0x10400003, 0xc1402, 0x34630400, -0xa6a20014, 0xa6b0000a, 0x8fab0064, 0x560b0006, -0x3d0f021, 0x34620004, 0xafa00064, 0xa6a2000e, -0x1000000d, 0xa34005c4, 0x8fac0064, 0x3c02001f, -0x3442ffff, 0x5e102b, 0x1906023, 0xafac0064, -0xa6a3000e, 0x240b0001, 0x10400003, 0xa34b05c4, -0x8f420148, 0x3c2f023, 0x8fab0054, 0x8fac004c, -0xad8b0000, 0x8fac0064, 0x1580feba, 0x0, -0x8fab0064, 0x1160001b, 0x0, 0x934205c4, -0x10400006, 0x0, 0xaf5e00c4, 0xaf4b00c0, -0x8fac006c, 0x1000000e, 0xaf4c00c8, 0x97ab0076, -0x1160000b, 0x34038100, 0x8fa20020, 0x8c46000c, -0xa443000c, 0x97ac007e, 0x8c440004, 0x8c450008, -0xa44c000e, 0xac440000, 0xac450004, 0xac460008, -0x8f42034c, 0x24420001, 0xaf42034c, 0x10000010, -0x8f42034c, 0x8fab006c, 0x3164ffff, 0x2484fffc, -0x801821, 0x8f440250, 0x8f450254, 0x8f460118, -0x1021, 0xa32821, 0xa3382b, 0x822021, -0x872021, 0xaf440250, 0xc0f809, 0xaf450254, -0x8fbf00c0, 0x8fbe00bc, 0x8fb500b8, 0x8fb300b4, -0x8fb200b0, 0x8fb100ac, 0x8fb000a8, 0x3e00008, -0x27bd00c8, 0x3e00008, 0x0, 0x27bdffd8, -0xafbf0024, 0xafb00020, 0x8f43004c, 0x8f420048, -0x10620034, 0x0, 0x8f430048, 0x8f42004c, -0x622023, 0x4820001, 0x24840200, 0x8f430054, -0x8f42004c, 0x43102b, 0x14400004, 0x24020200, -0x8f43004c, 0x10000005, 0x431023, 0x8f420054, -0x8f43004c, 0x431023, 0x2442ffff, 0x405021, -0x8a102a, 0x54400001, 0x805021, 0x8f49004c, -0x8f48004c, 0x8f440188, 0x8f45018c, 0x8f46004c, -0x24071000, 0xafa70010, 0x84140, 0x1001821, -0x12a4821, 0x313001ff, 0xafb00014, 0x8f470014, -0x1021, 0x63140, 0xafa70018, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0x3402ecc0, -0xc23021, 0x8f420108, 0x2e63021, 0x40f809, -0xa3940, 0x54400001, 0xaf50004c, 0x8f43004c, -0x8f420048, 0x14620018, 0x0, 0x8f420000, -0x10400007, 0x0, 0xaf80004c, 0x8f82004c, -0x1040fffd, 0x0, 0x10000005, 0x0, -0xaf800048, 0x8f820048, 0x1040fffd, 0x0, -0x8f820060, 0x2403fdff, 0x431024, 0xaf820060, -0x8f420000, 0x10400003, 0x0, 0x10000002, -0xaf80004c, 0xaf800048, 0x8fbf0024, 0x8fb00020, -0x3e00008, 0x27bd0028, 0x3e00008, 0x0, -0x27bdffd8, 0xafbf0024, 0xafb00020, 0x8f43005c, -0x8f420058, 0x10620049, 0x0, 0x8f430058, -0x8f42005c, 0x622023, 0x4820001, 0x24840100, -0x8f430064, 0x8f42005c, 0x43102b, 0x14400004, -0x24020100, 0x8f43005c, 0x10000005, 0x431023, -0x8f420064, 0x8f43005c, 0x431023, 0x2442ffff, -0x403821, 0x87102a, 0x54400001, 0x803821, -0x8f42005c, 0x471021, 0x305000ff, 0x32c21000, -0x10400015, 0x24082000, 0x8f49005c, 0x8f440190, -0x8f450194, 0x8f46005c, 0x73980, 0xafa80010, -0xafb00014, 0x8f480014, 0x94980, 0x1201821, -0x1021, 0xa32821, 0xa3482b, 0x822021, -0x892021, 0x63180, 0xafa80018, 0x8f420108, -0x10000014, 0x24c60cc0, 0x8f49005c, 0x8f440190, -0x8f450194, 0x8f46005c, 0x73940, 0xafa80010, -0xafb00014, 0x8f480014, 0x94940, 0x1201821, -0x1021, 0xa32821, 0xa3482b, 0x822021, -0x892021, 0x63140, 0xafa80018, 0x8f420108, -0x24c64cc0, 0x40f809, 0x2e63021, 0x54400001, -0xaf50005c, 0x8f43005c, 0x8f420058, 0x14620018, -0x0, 0x8f420000, 0x10400007, 0x0, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403feff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, -0xafb00020, 0x8f43006c, 0x8f420068, 0x10620033, -0x0, 0x8f430068, 0x8f42006c, 0x622023, -0x4820001, 0x24840400, 0x8f430074, 0x8f42006c, -0x43102b, 0x14400004, 0x24020400, 0x8f43006c, -0x10000005, 0x431023, 0x8f420074, 0x8f43006c, -0x431023, 0x2442ffff, 0x405021, 0x8a102a, -0x54400001, 0x805021, 0x8f49006c, 0x8f48006c, -0x8f440198, 0x8f45019c, 0x8f46006c, 0x24074000, -0xafa70010, 0x84140, 0x1001821, 0x12a4821, -0x313003ff, 0xafb00014, 0x8f470014, 0x1021, -0x63140, 0x24c66cc0, 0xafa70018, 0xa32821, -0xa3382b, 0x822021, 0x872021, 0x8f420108, -0x2e63021, 0x40f809, 0xa3940, 0x54400001, -0xaf50006c, 0x8f43006c, 0x8f420068, 0x14620018, -0x0, 0x8f420000, 0x10400007, 0x0, -0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, -0x10000005, 0x0, 0xaf800048, 0x8f820048, -0x1040fffd, 0x0, 0x8f820060, 0x2403f7ff, -0x431024, 0xaf820060, 0x8f420000, 0x10400003, -0x0, 0x10000002, 0xaf80004c, 0xaf800048, -0x8fbf0024, 0x8fb00020, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x8f4200fc, 0x3c030001, -0x8f4400f8, 0x346330c8, 0x24420001, 0xaf4200fc, -0x8f850128, 0x2e31021, 0x54820004, 0x24820008, -0x3c020001, 0x34422ec8, 0x2e21021, 0x401821, -0xaf4300f8, 0xac600000, 0x8f4200f4, 0x14620004, -0x3c020001, 0x24a20020, 0x1000000f, 0xaf820128, -0x8f4300f8, 0x344230c8, 0x2e21021, 0x54620004, -0x24620008, 0x3c020001, 0x34422ec8, 0x2e21021, -0x401821, 0x8c620004, 0x21140, 0xa21021, -0xaf820128, 0xac600000, 0x8ca30018, 0x30620070, -0x1040002d, 0x30620020, 0x10400004, 0x3c020010, -0x2c21024, 0x1040000d, 0x0, 0x30620040, -0x10400004, 0x3c020020, 0x2c21024, 0x10400007, -0x0, 0x30620010, 0x1040001f, 0x3c020040, -0x2c21024, 0x1440001c, 0x0, 0x8f820040, -0x30420001, 0x14400008, 0x2021, 0x8c030104, -0x24020001, 0x50620005, 0x24040001, 0x8c020264, -0x10400003, 0x801021, 0x24040001, 0x801021, -0x10400006, 0x0, 0x8f42030c, 0x24420001, -0xaf42030c, 0x10000008, 0x8f42030c, 0x8f820044, -0x34420004, 0xaf820044, 0x8f420308, 0x24420001, -0xaf420308, 0x8f420308, 0x3e00008, 0x0, -0x3e00008, 0x0, 0x27bdff98, 0xafbf0060, -0xafbe005c, 0xafb50058, 0xafb30054, 0xafb20050, -0xafb1004c, 0xafb00048, 0x8f4200fc, 0x24420001, -0xaf4200fc, 0x8f880128, 0x25020020, 0xaf820128, -0x8d030018, 0x30620070, 0x1040002e, 0x30620020, -0x10400004, 0x3c020010, 0x2c21024, 0x1040000d, -0x0, 0x30620040, 0x10400004, 0x3c020020, -0x2c21024, 0x10400007, 0x0, 0x30620010, -0x104001a9, 0x3c020040, 0x2c21024, 0x144001a6, -0x0, 0x8f820040, 0x30420001, 0x14400008, -0x2021, 0x8c030104, 0x24020001, 0x50620005, -0x24040001, 0x8c020264, 0x10400003, 0x801021, -0x24040001, 0x801021, 0x10400006, 0x0, -0x8f42030c, 0x24420001, 0xaf42030c, 0x10000192, -0x8f42030c, 0x8f820044, 0x34420004, 0xaf820044, -0x8f420308, 0x24420001, 0xaf420308, 0x1000018a, -0x8f420308, 0x30620002, 0x1040014b, 0x3c020800, -0x8d1e001c, 0x1e5702, 0xafaa0034, 0x950a0016, -0x3c22024, 0xafaa0024, 0x8faa0034, 0x24020001, -0x15420006, 0x33deffff, 0x1e1140, 0x3403ecc0, -0x431021, 0x10000010, 0x2e2a821, 0x24020002, -0x15420005, 0x24020003, 0x1e1140, 0x24426cc0, -0x10000009, 0x2e2a821, 0x15420005, 0x1e1180, -0x1e1140, 0x24424cc0, 0x10000003, 0x2e2a821, -0x571021, 0x24550ce0, 0x96a2000e, 0x304afffc, -0x30420400, 0x10400003, 0xafaa002c, 0x100000e1, -0x8821, 0x10800004, 0x8821, 0x97b10026, -0x100000dd, 0xa6b10012, 0x8eb30018, 0x966a000c, -0xa7aa003e, 0x97a5003e, 0x2ca305dd, 0x38a28870, -0x2c420001, 0x621825, 0x10600015, 0x2021, -0x32c20800, 0x10400015, 0x24020800, 0x96630014, -0x14620012, 0x3402aaaa, 0x9663000e, 0x14620007, -0x2821, 0x96630010, 0x24020300, 0x14620004, -0xa01021, 0x96620012, 0x2c450001, 0xa01021, -0x54400006, 0x24040016, 0x10000004, 0x0, -0x24020800, 0x50a20001, 0x2404000e, 0x108000b9, -0x2649021, 0x92420000, 0x3042000f, 0x28080, -0x32c20100, 0x10400020, 0x2501821, 0x3c020020, -0x43102b, 0x1440000e, 0x2402021, 0x2821, -0x94820000, 0x24840002, 0xa22821, 0x83102b, -0x1440fffb, 0x30a2ffff, 0x51c02, 0x622821, -0x51c02, 0x30a2ffff, 0x10000009, 0x622821, -0x8f470148, 0x8f420110, 0x102842, 0x3c060020, -0x40f809, 0xafa80040, 0x3045ffff, 0x8fa80040, -0x50a00001, 0x3405ffff, 0x8faa002c, 0x354a0002, -0x10000002, 0xafaa002c, 0x2821, 0x32c20080, -0x10400090, 0xa6a50010, 0x26430009, 0x3c02001f, -0x3442ffff, 0x43102b, 0x10400003, 0x0, -0x8f420148, 0x621823, 0x90660000, 0x30c200ff, -0x38430006, 0x2c630001, 0x38420011, 0x2c420001, -0x621825, 0x1060007f, 0x24020800, 0x8821, -0x97a3003e, 0x1462000f, 0x2602021, 0x96710000, -0x96620002, 0x96630004, 0x96640006, 0x2228821, -0x2238821, 0x2248821, 0x96620008, 0x9663000a, -0x9664000c, 0x2228821, 0x2238821, 0x10000007, -0x2248821, 0x94820000, 0x24840002, 0x2228821, -0x92102b, 0x1440fffb, 0x0, 0x111c02, -0x3222ffff, 0x628821, 0x111c02, 0x3222ffff, -0x628821, 0x32c20200, 0x10400003, 0x26440006, -0x1000003e, 0x8021, 0x3c05001f, 0x34a5ffff, -0xa4102b, 0x10400003, 0x0, 0x8f420148, -0x822023, 0x94820000, 0x30421fff, 0x10400004, -0x2644000c, 0x96420002, 0x10000030, 0x508023, -0x96420002, 0x26430014, 0x508023, 0x3c020020, -0x43102b, 0x1440000a, 0xd08021, 0x9642000c, -0x2028021, 0x9642000e, 0x96430010, 0x96440012, -0x2028021, 0x2038021, 0x10000020, 0x2048021, -0xa4102b, 0x10400003, 0x0, 0x8f420148, -0x822023, 0x94820000, 0x24840002, 0x2028021, -0xa4102b, 0x10400003, 0x0, 0x8f420148, -0x822023, 0x94820000, 0x24840002, 0x2028021, -0xa4102b, 0x10400003, 0x0, 0x8f420148, -0x822023, 0x94820000, 0x24840002, 0x2028021, -0xa4102b, 0x10400003, 0x0, 0x8f420148, -0x822023, 0x94820000, 0x2028021, 0x3c020100, -0x2c21024, 0x1040000e, 0x0, 0x8faa002c, -0x31420004, 0x1040000a, 0x0, 0x9504000e, -0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff, -0x2228821, 0x111c02, 0x3222ffff, 0x628821, -0x8faa0024, 0x1518823, 0x111402, 0x2228821, -0x2308821, 0x111402, 0x2228821, 0x3231ffff, -0x52200001, 0x3411ffff, 0x8faa002c, 0x354a0001, -0xafaa002c, 0xa6b10012, 0x97aa002e, 0xa6aa000e, -0x8faa002c, 0x31420004, 0x10400002, 0x24091000, -0x34098000, 0x8f480044, 0x8f4401a0, 0x8f4501a4, -0xafa90010, 0x8f490044, 0x84140, 0x1001821, -0xafa90014, 0x8f48000c, 0x2a03021, 0x24070020, -0xafa80018, 0x8f48010c, 0x1021, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x1440000b, 0x0, 0x8f820128, 0x3c040001, -0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124, -0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920, -0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044, -0x8f430088, 0x24420001, 0x431024, 0xaf420044, -0x8faa0034, 0x8f440368, 0x24020001, 0x15420006, -0x24020002, 0x8f42035c, 0x2442ffff, 0xaf42035c, -0x10000049, 0x8f42035c, 0x15420006, 0x0, -0x8f420364, 0x2442ffff, 0xaf420364, 0x10000042, -0x8f420364, 0x8f420360, 0x2442ffff, 0xaf420360, -0x1000003d, 0x8f420360, 0x30621000, 0x10400005, -0x30628000, 0x8f420078, 0x24420001, 0x10000036, -0xaf420078, 0x10400034, 0x0, 0x8f420078, -0x24420001, 0xaf420078, 0x8c030240, 0x43102b, -0x1440002d, 0x24070008, 0x8f440168, 0x8f45016c, -0x8f430044, 0x8f48000c, 0x8f860120, 0x24020040, -0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, -0x40f809, 0x24c6001c, 0x14400011, 0x24020001, -0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, -0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c, -0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, -0xc002b3b, 0x34a51300, 0x1000000b, 0x0, -0x8f420304, 0x24420001, 0xaf420304, 0x8f420304, -0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, -0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001, -0xaf420318, 0x8f420318, 0x8fbf0060, 0x8fbe005c, -0x8fb50058, 0x8fb30054, 0x8fb20050, 0x8fb1004c, -0x8fb00048, 0x3e00008, 0x27bd0068, 0x3e00008, -0x0, 0x0, 0x0, 0x8f42013c, -0xaf8200c0, 0x8f42013c, 0xaf8200c4, 0x8f42013c, -0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138, -0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8, -0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, -0xc002bbf, 0x24060008, 0x8c020204, 0xc004012, -0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002, -0x1040000e, 0x2021, 0x8c060248, 0x24020002, -0x3c010001, 0xac226d98, 0xc005104, 0x24050002, -0x2021, 0x8c060248, 0x24020001, 0x3c010001, -0xac226d98, 0x10000011, 0x24050001, 0x8c060248, -0x24020004, 0x3c010001, 0xac226d98, 0xc005104, -0x24050004, 0x3c020001, 0x8c426d94, 0x30420001, -0x10400008, 0x24020001, 0x3c010001, 0xac226d98, -0x2021, 0x24050001, 0x3c06601b, 0xc005104, -0x0, 0x3c040001, 0x248469d0, 0x8f420150, -0x8f430154, 0x3c050008, 0x8f460158, 0x21640, -0x31940, 0x34630403, 0x431025, 0x633c0, -0x461025, 0xaf82021c, 0xafa00010, 0xafa00014, -0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821, -0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8, -0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, -0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010, -0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc, -0xc002b3b, 0x3821, 0x8f420410, 0x24420001, -0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, -0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4, -0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010, -0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8, -0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821, -0x3c044000, 0x2041024, 0x504000b4, 0x3c040100, -0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc, -0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823, -0x43102b, 0x10400003, 0x0, 0x8f420148, -0x621821, 0x10600005, 0x0, 0x8f42014c, -0x43102b, 0x1040000b, 0x0, 0x8f8200e0, -0x8f430124, 0xaf42011c, 0xaf430114, 0x8f820220, -0x3c0308ff, 0x3463fffb, 0x431024, 0x100000ce, -0x441025, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420004, 0xaf820220, 0x8f8200e0, -0x8f430124, 0xaf42011c, 0xaf430114, 0x8f8600c8, -0x8f840120, 0x8f830124, 0x10000005, 0x2821, -0x14620002, 0x24620020, 0x27624800, 0x401821, -0x1064000c, 0x30a200ff, 0x8c620018, 0x30420003, -0x1040fff7, 0x27624fe0, 0x8f4203d0, 0x24050001, -0x24420001, 0xaf4203d0, 0x8f4203d0, 0x8c660008, -0x30a200ff, 0x14400058, 0x0, 0x934205c4, -0x14400055, 0x0, 0x8f8700c4, 0x8f8800e0, -0x8f8400e4, 0x2402fff8, 0x1024024, 0x1041023, -0x218c3, 0x4620001, 0x24630200, 0x10600005, -0x24020001, 0x10620009, 0x0, 0x1000001f, -0x0, 0x8f4203c0, 0xe03021, 0x24420001, -0xaf4203c0, 0x10000040, 0x8f4203c0, 0x8f4203c4, -0x24420001, 0xaf4203c4, 0x8c860000, 0x8f420148, -0x8f4303c4, 0xe61823, 0x43102b, 0x10400004, -0x2c62233f, 0x8f420148, 0x621821, 0x2c62233f, -0x14400031, 0x0, 0x8f42020c, 0x24420001, -0xaf42020c, 0x8f42020c, 0xe03021, 0x24820008, -0xaf8200e4, 0x10000028, 0xaf8200e8, 0x8f4203c8, -0x24420001, 0xaf4203c8, 0x8f4203c8, 0x8c850000, -0x8f420148, 0xa71823, 0x43102b, 0x10400003, -0x0, 0x8f420148, 0x621821, 0x8f42014c, -0x43102b, 0x5440000a, 0xa03021, 0x8f42020c, -0x24420001, 0xaf42020c, 0x8f42020c, 0x24820008, -0xaf8200e4, 0x8f8400e4, 0x1488ffec, 0xaf8400e8, -0x1488000d, 0x27623000, 0x14820002, 0x2482fff8, -0x27623ff8, 0x94430006, 0x3c02001f, 0x3442ffff, -0xc33021, 0x46102b, 0x10400003, 0x0, -0x8f420148, 0xc23023, 0xaf8600c8, 0x8f8300c4, -0x8f420148, 0xc31823, 0x43102b, 0x10400003, -0x0, 0x8f420148, 0x621821, 0x10600005, -0x0, 0x8f42014c, 0x43102b, 0x50400008, -0x3c02fdff, 0x8f820220, 0x3c0308ff, 0x3463fffb, -0x431024, 0x3c034000, 0x1000003f, 0x431025, -0x8f4303cc, 0x3442ffff, 0x282a024, 0x24630001, -0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024, -0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001, -0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff, -0x3463ffff, 0x431024, 0x441025, 0xc003daf, -0xaf820220, 0x10000029, 0x0, 0x2111024, -0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001, -0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019, -0x0, 0x2111024, 0x1040001c, 0x0, -0x8f830224, 0x24021402, 0x14620009, 0x3c050008, -0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014, -0x8f860224, 0x34a50500, 0xc002b3b, 0x3821, -0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0, -0x8f820220, 0x2002021, 0x34420002, 0xc004e9c, -0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x511025, 0xaf820220, 0x8fbf0020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, -0x3e00008, 0x0, 0x3c020001, 0x8c426da8, -0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, -0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f, -0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008, -0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600, -0x24020001, 0x3c010001, 0xac206da8, 0x3c010001, -0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff, -0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024, -0xac020268, 0x8f420004, 0x3484ffff, 0x30420002, -0x10400092, 0x284a024, 0x3c040600, 0x34842000, -0x8f420004, 0x2821, 0x2403fffd, 0x431024, -0xaf420004, 0xafa40020, 0x8f5e0018, 0x27aa0020, -0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001, -0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0, -0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, -0x8c020228, 0x3c040001, 0x24846998, 0x3c050009, -0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, -0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, -0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, -0x247003e8, 0x2021023, 0x2c4203e9, 0x1040001b, -0x9821, 0xe08821, 0x263504c0, 0x8f440178, -0x8f45017c, 0x2201821, 0x240a0004, 0xafaa0010, -0xafb20014, 0x8f48000c, 0x1021, 0x2f53021, -0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, -0xa3482b, 0x822021, 0x100f809, 0x892021, -0x54400006, 0x24130001, 0x8f820054, 0x2021023, -0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, -0x54400017, 0xaf520018, 0x8f420378, 0x24420001, -0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, -0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4, -0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, -0x34a50600, 0x8f420308, 0x24130001, 0x24420001, -0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff, -0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, -0x2c4203e9, 0x10400016, 0x9821, 0x3c150020, -0x24110010, 0x8f42000c, 0x8f440160, 0x8f450164, -0x8f860120, 0xafb10010, 0xafb20014, 0x551025, -0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, -0x24c6001c, 0x1440ffe3, 0x0, 0x8f820054, -0x2021023, 0x2c4203e9, 0x1440ffee, 0x0, -0x326200ff, 0x14400011, 0x0, 0x8f420378, -0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, -0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, -0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000, -0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec, -0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048, -0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, -0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, -0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d, -0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008, -0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700, -0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b, -0x3821, 0x3c020004, 0x2c21024, 0x10400007, -0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff, -0x431024, 0x34420008, 0xaf820220, 0x3c050001, -0x8ca56d98, 0x24020001, 0x14a20007, 0x2021, -0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c, -0x10000006, 0x3c020007, 0xc00529b, 0x2021, -0xac020268, 0x8c030268, 0x3c020007, 0x621824, -0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b, -0x14400006, 0x3c020004, 0x3c020001, 0x10620009, -0x3c020098, 0x1000000b, 0x0, 0x14620009, -0x3c023b9a, 0x10000004, 0x3442ca00, 0x10000002, -0x3442e100, 0x34429680, 0xaf4201fc, 0x8f4201fc, -0xaee20064, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x0, 0x0, 0x0, 0x86102b, -0x50400001, 0x872023, 0xc41023, 0x24843, -0x125102b, 0x1040001b, 0x91040, 0x824021, -0x88102b, 0x10400007, 0x1821, 0x94820000, -0x24840002, 0x621821, 0x88102b, 0x1440fffb, -0x0, 0x602021, 0xc73023, 0xa91023, -0x21040, 0xc22821, 0xc5102b, 0x10400007, -0x1821, 0x94c20000, 0x24c60002, 0x621821, -0xc5102b, 0x1440fffb, 0x0, 0x1000000d, -0x832021, 0x51040, 0x822821, 0x85102b, -0x10400007, 0x1821, 0x94820000, 0x24840002, -0x621821, 0x85102b, 0x1440fffb, 0x0, -0x602021, 0x41c02, 0x3082ffff, 0x622021, -0x41c02, 0x3082ffff, 0x622021, 0x3e00008, -0x3082ffff, 0x3e00008, 0x0, 0x802821, -0x30a20001, 0x1040002b, 0x3c03001f, 0x3463ffff, -0x24a20004, 0x62102b, 0x54400007, 0x65102b, -0x90a20001, 0x90a40003, 0x90a30000, 0x90a50002, -0x1000002a, 0x441021, 0x10400003, 0x0, -0x8f420148, 0xa22823, 0x90a40000, 0x24a50001, -0x65102b, 0x10400003, 0x0, 0x8f420148, -0xa22823, 0x90a20000, 0x24a50001, 0x21200, -0x822021, 0x65102b, 0x10400003, 0x0, -0x8f420148, 0xa22823, 0x90a20000, 0x24a50001, -0x822021, 0x65102b, 0x10400003, 0x0, -0x8f420148, 0xa22823, 0x90a20000, 0x1000002d, -0x21200, 0x3463ffff, 0x24a20004, 0x62102b, -0x5440000a, 0x65102b, 0x90a20000, 0x90a40002, -0x90a30001, 0x90a50003, 0x441021, 0x21200, -0x651821, 0x10000020, 0x432021, 0x10400003, -0x0, 0x8f420148, 0xa22823, 0x90a20000, -0x24a50001, 0x22200, 0x65102b, 0x10400003, -0x0, 0x8f420148, 0xa22823, 0x90a20000, -0x24a50001, 0x822021, 0x65102b, 0x10400003, -0x0, 0x8f420148, 0xa22823, 0x90a20000, -0x24a50001, 0x21200, 0x822021, 0x65102b, -0x10400003, 0x0, 0x8f420148, 0xa22823, -0x90a20000, 0x822021, 0x41c02, 0x3082ffff, -0x622021, 0x41c02, 0x3082ffff, 0x622021, -0x3e00008, 0x3082ffff, 0x0, 0x8f820220, -0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8, -0x30424000, 0x10400054, 0x24040001, 0x8f820200, -0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, -0x621824, 0xaf830200, 0xaf840204, 0x8f830054, -0x8f820054, 0x10000002, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820224, 0x1444004d, 0x42040, 0xc4102b, -0x1040fff1, 0x0, 0x8f820200, 0x451025, -0xaf820200, 0x8f820220, 0x34428000, 0xaf820220, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820220, 0x3c030004, 0x431024, -0x1440000f, 0x0, 0x8f820220, 0x3c03ffff, -0x34637fff, 0x431024, 0xaf820220, 0x8f830054, -0x8f820054, 0x10000002, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820220, 0x3c030004, 0x431024, 0x1440000d, -0x0, 0x8f820220, 0x34428000, 0xaf820220, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x8f820220, 0x3c030004, 0x431024, -0x1040001b, 0x1021, 0x8f830220, 0x24020001, -0x10000015, 0x3c04f700, 0x8f820220, 0x3c04f700, -0x441025, 0xaf820220, 0x8f820220, 0x2403fffd, -0x431024, 0xaf820220, 0x8f820220, 0x3c030300, -0x431024, 0x14400003, 0x0, 0x10000008, -0x1021, 0x8f820220, 0x34420002, 0xaf820220, -0x8f830220, 0x24020001, 0x641825, 0xaf830220, -0x3e00008, 0x0, 0x2021, 0x3c050100, -0x24020001, 0xaf80021c, 0xaf820200, 0xaf820220, -0x27625000, 0xaf8200c0, 0x27625000, 0xaf8200c4, -0x27625000, 0xaf8200c8, 0x27625000, 0xaf8200d0, -0x27625000, 0xaf8200d4, 0x27625000, 0xaf8200d8, -0x27623000, 0xaf8200e0, 0x27623000, 0xaf8200e4, -0x27623000, 0xaf8200e8, 0x27622800, 0xaf8200f0, -0x27622800, 0xaf8200f4, 0x27622800, 0xaf8200f8, -0x418c0, 0x24840001, 0x3631021, 0xac453004, -0x3631021, 0xac403000, 0x28820200, 0x1440fff9, -0x418c0, 0x2021, 0x418c0, 0x24840001, -0x3631021, 0xac402804, 0x3631021, 0xac402800, -0x28820100, 0x1440fff9, 0x418c0, 0xaf80023c, -0x24030080, 0x24040100, 0xac600000, 0x24630004, -0x64102b, 0x5440fffd, 0xac600000, 0x8f830040, -0x3c02f000, 0x621824, 0x3c025000, 0x1062000c, -0x43102b, 0x14400006, 0x3c026000, 0x3c024000, -0x10620008, 0x24020800, 0x10000008, 0x0, -0x10620004, 0x24020800, 0x10000004, 0x0, -0x24020700, 0x3c010001, 0xac226dac, 0x3e00008, -0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0, -0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020, -0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e, -0x0, 0x3c010001, 0xac206dbc, 0x8f830054, -0x8f820054, 0x10000002, 0x24630064, 0x8f820054, -0x621023, 0x2c420065, 0x1440fffc, 0x0, -0xc004db9, 0x0, 0x24040001, 0x2821, -0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x24050001, 0xc00457c, 0x27a60018, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x24050001, 0xc00457c, 0x27a60018, -0x8f830054, 0x8f820054, 0x10000002, 0x24630064, -0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, -0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c, -0x24050002, 0x8f830054, 0x8f820054, 0x10000002, -0x24630064, 0x8f820054, 0x621023, 0x2c420065, -0x1440fffc, 0x24040001, 0x24050003, 0x3c100001, -0x26106f26, 0xc00457c, 0x2003021, 0x97a60018, -0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0, -0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100, -0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d, -0x24036040, 0x96020000, 0x3042fff0, 0x1443000c, -0x24020020, 0x3c030001, 0x94636f24, 0x1462000b, -0x24027830, 0x24020003, 0x3c010001, 0xac226d94, -0x24020005, 0x3c010001, 0x1000003f, 0xac226f34, -0x3c030001, 0x94636f24, 0x24027830, 0x1462000c, -0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0, -0x14430007, 0x24020003, 0x3c010001, 0xac226d94, -0x24020006, 0x3c010001, 0x1000002f, 0xac226f34, -0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24, -0x34420001, 0x3c010001, 0xac226d94, 0x24020015, -0x1462000b, 0x0, 0x3c020001, 0x94426f26, -0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430, -0x2c420001, 0x621825, 0x1460001b, 0x24020003, -0x3c030001, 0x94636f24, 0x24027810, 0x14620016, -0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0, -0x14400011, 0x24020002, 0x1000000f, 0x24020004, -0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001, -0xac226d94, 0x1000005e, 0x24020004, 0x3c020001, -0x8c426d94, 0x34420004, 0x3c010001, 0x100000af, -0xac226d94, 0x24020001, 0x3c010001, 0xac226f40, -0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2, -0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054, -0x8f820054, 0x24030008, 0x3c010001, 0xac236d98, -0x10000002, 0x248401f4, 0x8f820054, 0x821023, -0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, -0xaf820238, 0x8f830054, 0x8f820054, 0x10000002, -0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, -0x1440fffc, 0x8021, 0x24120001, 0x24110009, -0xc004482, 0x0, 0x3c010001, 0xac326db4, -0xc004547, 0x0, 0x3c020001, 0x8c426db4, -0x1451fffb, 0x3c0200c8, 0x344201f6, 0xaf820238, -0x8f830054, 0x8f820054, 0x10000002, 0x2463000a, -0x8f820054, 0x621023, 0x2c42000b, 0x1440fffc, -0x0, 0x8f820220, 0x24040001, 0x34420002, -0xaf820220, 0x8f830200, 0x24057fff, 0x2402fffd, -0x621824, 0xaf830200, 0xaf840204, 0x8f830054, -0x8f820054, 0x10000002, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x8f820224, 0x14440005, 0x34028000, 0x42040, -0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0, -0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, -0x3c010001, 0xac226d98, 0x8021, 0x24120009, -0x3c11ffff, 0x36313f7f, 0xc004482, 0x0, -0x24020001, 0x3c010001, 0xac226db4, 0xc004547, -0x0, 0x3c020001, 0x8c426db4, 0x1452fffb, -0x0, 0x8f820044, 0x511024, 0x34425080, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x2463000a, 0x8f820054, 0x621023, 0x2c42000b, -0x1440fffc, 0x0, 0x8f820044, 0x511024, -0x3442f080, 0xaf820044, 0x8f830054, 0x8f820054, -0x10000002, 0x2463000a, 0x8f820054, 0x621023, -0x2c42000b, 0x1440fffc, 0x0, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, -0x8f820054, 0x10000002, 0x24630064, 0x8f820054, -0x621023, 0x2c420065, 0x1440fffc, 0x0, -0x8f820220, 0x24040001, 0x34420002, 0xaf820220, -0x8f830200, 0x24057fff, 0x2402fffd, 0x621824, -0xaf830200, 0xaf840204, 0x8f830054, 0x8f820054, -0x10000002, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820224, -0x14440005, 0x34028000, 0x42040, 0xa4102b, -0x1040fff0, 0x34028000, 0x1082ff50, 0x26100001, -0x2e020064, 0x1440ffb0, 0x0, 0x3c020001, -0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0, -0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, -0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001, -0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001, -0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001, -0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001, -0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001, -0xac206d98, 0x491021, 0x3c010001, 0xac226f30, -0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c, -0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, -0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98, -0x24060004, 0x24020001, 0x14a20014, 0xafbf0010, -0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005, -0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005, -0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40, -0x348493e0, 0x24020005, 0x14620016, 0x0, -0x3c04003d, 0x10000013, 0x34840900, 0x3c020002, -0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e, -0x3c030001, 0x8c636f40, 0x10000005, 0x34848480, -0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240, -0x24020005, 0x14620003, 0x0, 0x3c04007a, -0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054, -0x441021, 0x431023, 0x44102b, 0x1440004c, -0x0, 0x3c020001, 0x8c426da0, 0x14400048, -0x0, 0x3c010001, 0x10c00025, 0xac206db0, -0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000, -0x3c080002, 0x25088ffc, 0x250afffc, 0x52842, -0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024, -0x10400010, 0x0, 0x14a70008, 0x0, -0x8d020000, 0x441024, 0x1040000a, 0x0, -0x3c010001, 0x10000007, 0xac256db0, 0x8d420000, -0x441024, 0x10400003, 0x0, 0x3c010001, -0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b, -0x2c420001, 0x431024, 0x5440ffe5, 0x52842, -0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001, -0xac226f30, 0x1060003b, 0x24020005, 0x3c030001, -0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012, -0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000, -0x34635000, 0x431024, 0x14400006, 0x24020001, -0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98, -0x24020001, 0x3c010001, 0xac226e24, 0x3c010001, -0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c, -0x3c020001, 0x8c426db0, 0x1040001e, 0x0, -0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001, -0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001, -0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8, -0x24020008, 0x10620005, 0x24020001, 0xc004239, -0x0, 0x1000000b, 0x0, 0x3c030001, -0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002, -0x8c638f90, 0x10620003, 0x0, 0xc004e9c, -0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, -0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98, -0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024, -0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, -0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8, -0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4, -0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c, -0x2c620003, 0x10400005, 0x24020001, 0x1062000a, -0x0, 0x10000226, 0x0, 0x24020004, -0x106200b6, 0x24020008, 0x1062010a, 0x24020001, -0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff, -0x2c620008, 0x1040021c, 0x31080, 0x3c010001, -0x220821, 0x8c226af8, 0x400008, 0x0, -0x3c030001, 0x8c636f40, 0x24020005, 0x14620010, -0x0, 0x3c020001, 0x8c426da4, 0x10400008, -0x24020003, 0xc004482, 0x0, 0x24020002, -0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4, -0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30, -0xc004482, 0x0, 0x3c020001, 0x8c426da4, -0x3c010001, 0xac206d30, 0x1440017a, 0x24020002, -0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40, -0x24020005, 0x14620003, 0x24020001, 0x3c010001, -0xac226dd0, 0xc0045ff, 0x0, 0x3c030001, -0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001, -0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104, -0x2021, 0x24020005, 0x3c010001, 0xac206da4, -0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec, -0x3c05000f, 0x34a50100, 0x3021, 0x3821, -0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6, -0x0, 0x8f820220, 0x3c030004, 0x431024, -0x14400175, 0x24020007, 0x8f830054, 0x3c020001, -0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020001, 0x3c010001, 0xac226d9c, -0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2, -0x0, 0x8f820220, 0x30428000, 0x1040017d, -0x0, 0x10000175, 0x0, 0x3c050001, -0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b, -0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0, -0x24020001, 0x3c020008, 0x621024, 0x10400006, -0x0, 0x8f820214, 0x3c03ffff, 0x431024, -0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff, -0x431024, 0x3442241f, 0xaf820214, 0x8f820220, -0x3c030200, 0x34420002, 0xaf820220, 0x24020008, -0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004, -0x431024, 0x14400016, 0x0, 0x3c020002, -0x8c428ffc, 0x30425000, 0x1040000d, 0x0, -0x8f820220, 0x30428000, 0x10400006, 0x0, -0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003, -0x431024, 0x8f820220, 0x34428000, 0xaf820220, -0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, -0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a, -0x0, 0x3c020001, 0x94426f26, 0x24429fbc, -0x2c420004, 0x10400004, 0x24040018, 0x24050002, -0xc004ddb, 0x24060020, 0xc003e6d, 0x0, -0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8, -0x2443ffff, 0x2c620008, 0x1040016b, 0x31080, -0x3c010001, 0x220821, 0x8c226b18, 0x400008, -0x0, 0xc004547, 0x0, 0x3c030001, -0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002, -0x8c428ff8, 0x30424000, 0x10400004, 0x0, -0x8f820044, 0x10000006, 0x3442f080, 0x8f820044, -0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080, -0xaf820044, 0x8f830054, 0x100000ea, 0x24020004, -0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0, -0x431023, 0x2c422710, 0x14400147, 0x24020005, -0x100000d8, 0x0, 0x8f820220, 0x3c03f700, -0x431025, 0xaf820220, 0xaf800204, 0x3c010002, -0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001, -0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a, -0x14400135, 0x24020007, 0x100000d7, 0x0, -0xc003f50, 0x0, 0x1040012d, 0x24020001, -0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c, -0x431024, 0x3442251f, 0xaf820214, 0x24020008, -0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44, -0x10400064, 0x24020001, 0x8f820220, 0x3c030008, -0x431024, 0x1040006a, 0x3c020200, 0x10000078, -0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007, -0x10400115, 0x31080, 0x3c010001, 0x220821, -0x8c226b38, 0x400008, 0x0, 0xc003daf, -0x0, 0x3c010001, 0xac206d9c, 0xaf800204, -0x3c010002, 0xc004482, 0xac208fe0, 0x24020001, -0x3c010001, 0xac226db4, 0x24020002, 0x10000102, -0xaee204b8, 0xc004547, 0x0, 0x3c030001, -0x8c636db4, 0x10000084, 0x24020009, 0x3c020002, -0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8, -0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, -0x8f830054, 0x1000008b, 0x24020004, 0x8f830054, -0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023, -0x2c422710, 0x144000e8, 0x24020005, 0x10000079, -0x0, 0x8f820220, 0x3c03f700, 0x431025, -0xaf820220, 0xaf800204, 0x3c010002, 0x10000077, -0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28, -0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6, -0x24020007, 0x10000078, 0x0, 0xc003f50, -0x0, 0x104000ce, 0x24020001, 0x8f820214, -0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024, -0x3442251f, 0xaf820214, 0x24020008, 0x1080000f, -0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b, -0x0, 0x8f820220, 0x34420002, 0xaf820220, -0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c, -0x8f840220, 0x10000016, 0x0, 0x8f820220, -0x3c030008, 0x431024, 0x14400011, 0x3c020200, -0x282a025, 0x2402000e, 0x3c010002, 0xac228f90, -0xc00551b, 0x2021, 0x8f820220, 0x34420002, -0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98, -0xc00529b, 0x2021, 0x100000a3, 0x0, -0x3c020001, 0x8c426e44, 0x1040009f, 0x0, -0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001, -0xac226e40, 0x14400098, 0x24020002, 0x3c010001, -0xac206e44, 0x3c010001, 0x10000093, 0xac226e40, -0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e, -0x31080, 0x3c010001, 0x220821, 0x8c226b58, -0x400008, 0x0, 0x3c020001, 0x8c426da4, -0x10400018, 0x24020005, 0xc004482, 0x0, -0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e, -0xac206da4, 0xc004963, 0x0, 0x3c030001, -0x8c636dd4, 0x24020006, 0x14620077, 0x24020003, -0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98, -0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021, -0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, -0x24020006, 0xaee204b8, 0x3c010001, 0x10000062, -0xac236f28, 0x8f820220, 0x3c030004, 0x431024, -0x10400003, 0x24020007, 0x1000005b, 0xaee204b8, -0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0, -0x431023, 0x2c422710, 0x14400003, 0x24020001, -0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8, -0x30425000, 0x1040004c, 0x0, 0x8f820220, -0x30428000, 0x10400007, 0x0, 0x8f820220, -0x3c03ffff, 0x34637fff, 0x431024, 0x10000042, -0xaf820220, 0x8f820220, 0x34428000, 0x1000003e, -0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b, -0x2021, 0xc00551b, 0x2021, 0x3c020002, -0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214, -0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214, -0x24020008, 0xaee204b8, 0x8f820220, 0x34420002, -0xaf820220, 0x8f820220, 0x3c030004, 0x431024, -0x14400016, 0x0, 0x3c020002, 0x8c428ff8, -0x30425000, 0x1040000d, 0x0, 0x8f820220, -0x30428000, 0x10400006, 0x0, 0x8f820220, -0x3c03ffff, 0x34637fff, 0x10000003, 0x431024, -0x8f820220, 0x34428000, 0xaf820220, 0x8f820220, -0x3c03f700, 0x431025, 0xaf820220, 0x3c020001, -0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004, -0x24040018, 0x24050002, 0xc004ddb, 0x24060020, -0xc003e6d, 0x0, 0x10000003, 0x0, -0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008, -0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, -0x34420004, 0xaf820220, 0x8f820200, 0x3c050001, -0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002, -0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001, -0x10a2000a, 0x0, 0x100000b1, 0x0, -0x24020004, 0x10a20072, 0x24020008, 0x10a20085, -0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050, -0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40, -0x621824, 0x3c020700, 0x621825, 0x24020e00, -0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200, -0xaf850220, 0x14800006, 0xaf820238, 0x8f820044, -0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, -0x3c030001, 0x8c636f40, 0x24020005, 0x14620004, -0x0, 0x8f820044, 0x34425000, 0xaf820044, -0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40, -0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c, -0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001, -0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000, -0x621825, 0x641825, 0x1000000a, 0x34620002, -0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac, -0x3c040001, 0x8c846d8c, 0x431025, 0x441025, -0x34420002, 0xaf820220, 0x1000002f, 0x24020001, -0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff, -0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824, -0x3c020d00, 0x621825, 0x24020001, 0xaf830050, -0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00, -0x3c020001, 0x8c426d80, 0x10000004, 0x34630070, -0x3c020001, 0x8c426d80, 0x34630072, 0x431025, -0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700, -0x621825, 0x3c020001, 0x8c426d90, 0x3c040001, -0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025, -0x441025, 0xaf820220, 0x24020005, 0x14a20006, -0x24020001, 0x8f820044, 0x2403afff, 0x431024, -0xaf820044, 0x24020001, 0x1000003d, 0xaf820238, -0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001, -0x8c846f1c, 0x621824, 0x3c020a00, 0x621825, -0x24020001, 0xaf830050, 0xaf820200, 0x1080001e, -0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a, -0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a, -0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c, -0x3442ffff, 0x621824, 0x1080000f, 0xaf830050, -0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00, -0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001, -0xaf820200, 0xaf820220, 0x641825, 0xaf830200, -0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80, -0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, -0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84, -0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac, -0x651825, 0x431025, 0x441025, 0xaf820220, -0x3e00008, 0x0, 0x3c030001, 0x8c636db4, -0x3c020001, 0x8c426db8, 0x10620003, 0x24020002, -0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003, -0x10400025, 0x24020001, 0x14620023, 0x24020004, -0x3c030001, 0x8c636d98, 0x10620006, 0x24020008, -0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009, -0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044, -0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080, -0xaf820044, 0x8f830054, 0x24020002, 0x3c010001, -0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c, -0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0, -0x431023, 0x2c422710, 0x14400003, 0x24020009, -0x3c010001, 0xac226db4, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x27bdffd8, -0xafb20018, 0x809021, 0xafb3001c, 0xa09821, -0xafb10014, 0xc08821, 0xafb00010, 0x8021, -0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x24100010, 0x2501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x2501024, 0x24100010, 0x2701024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x2701024, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x96220000, 0x501025, -0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c, -0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, -0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, -0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, -0xafb00010, 0x8021, 0xafbf0020, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x2301024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x2301024, 0x24100010, 0x2501024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x2501024, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x34108000, -0x96620000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fff8, -0x0, 0xc004db9, 0x0, 0x8fbf0020, -0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, -0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0, -0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020, -0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001, -0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005, -0x14620005, 0x2483ffff, 0xc004963, 0x0, -0x1000034c, 0x0, 0x2c620013, 0x10400349, -0x31080, 0x3c010001, 0x220821, 0x8c226b80, -0x400008, 0x0, 0xc004db9, 0x8021, -0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc004d78, -0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, -0x8021, 0xc004d78, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004d78, -0x2021, 0xc004d78, 0x24040001, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004d78, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x96220000, 0x501025, -0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x0, 0x97a20010, 0x30428000, -0x144002dc, 0x24020003, 0x100002d8, 0x0, -0x24021200, 0xa7a20010, 0x27b10010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0xc004d78, 0x2021, 0x108042, 0x1600fffc, -0x0, 0xc004d78, 0x24040001, 0xc004d78, -0x2021, 0x34108000, 0x96220000, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fff8, 0x0, 0xc004db9, -0x0, 0x8f830054, 0x10000296, 0x24020004, -0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c, -0x431023, 0x2c420064, 0x1440029e, 0x24020002, -0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003, -0x14400296, 0x24020011, 0x24020003, 0x10620005, -0x24020004, 0x10620291, 0x2402000f, 0x1000028f, -0x24020011, 0x1000028d, 0x24020005, 0x24020014, -0xa7a20010, 0x27b10010, 0x8021, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020012, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020012, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fff8, -0x0, 0xc004db9, 0x0, 0x8f830054, -0x10000248, 0x24020006, 0x8f830054, 0x3c020001, -0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400250, 0x24020007, 0x1000024c, 0x0, -0x24020006, 0xa7a20010, 0x27b10010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020013, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020013, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x8f830054, 0x10000207, 0x24020008, 0x8f830054, -0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020018, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020018, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, -0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, -0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020017, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020017, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020017, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, -0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, -0x2c420064, 0x14400127, 0x24020012, 0x10000123, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020014, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020014, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020014, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, -0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, -0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, -0x0, 0x27b10010, 0xa7a00010, 0x8021, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020018, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020018, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x96220000, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x8f830054, 0x10000037, 0x2402000e, 0x24020840, -0xa7a20010, 0x27b10010, 0x8021, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x32020013, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020013, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x34108000, -0x96220000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fff8, -0x0, 0xc004db9, 0x0, 0x8f830054, -0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001, -0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001, -0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064, -0x14400004, 0x0, 0x24020011, 0x3c010001, -0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, -0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98, -0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030, -0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002, -0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc, -0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c, -0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c, -0x2463ffff, 0x2c620006, 0x10400377, 0x31080, -0x3c010001, 0x220821, 0x8c226bd8, 0x400008, -0x0, 0x2021, 0x2821, 0xc004ddb, -0x34068000, 0x24040010, 0x24050002, 0x24060002, -0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002, -0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018, -0xa7a00018, 0x8021, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x24100010, 0x32020001, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x32020001, 0x24100010, 0xc004d78, 0x2021, -0x108042, 0x1600fffc, 0x0, 0xc004db9, -0x34108000, 0xc004db9, 0x0, 0xc004d58, -0x0, 0x50400005, 0x108042, 0x96220000, -0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004db9, 0x0, 0x97a20018, -0x30428000, 0x14400004, 0x24020003, 0x3c010001, -0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a, -0xac226dd4, 0x24040010, 0x24050002, 0x24060002, -0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001, -0x8c636e20, 0x24020001, 0x146201e1, 0x8021, -0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x24100010, 0x32020001, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x32020001, 0x24100010, 0x32020018, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020018, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x96220000, 0x501025, -0xa6220000, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x8021, 0x27b10018, 0xa7a00018, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0x32020001, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x32020001, 0x24100010, -0x32020018, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020018, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x96220000, 0x501025, 0xa6220000, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0x24040018, 0x2821, 0xc004ddb, 0x24060404, -0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004d78, -0x2021, 0xc004d78, 0x24040001, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0x32020018, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x32020018, 0xc004db9, 0x34108000, 0xc004db9, -0x0, 0xc004d58, 0x0, 0x50400005, -0x108042, 0x97a2001a, 0x501025, 0xa7a2001a, -0x108042, 0x1600fff7, 0x0, 0xc004db9, -0x8021, 0xa7a0001a, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x24100010, 0x32020001, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x32020001, 0x24100010, 0x32020018, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020018, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x97a2001a, 0x501025, -0xa7a2001a, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x24040001, 0xc004d78, -0x2021, 0x24100010, 0xc004d78, 0x2021, -0x108042, 0x1600fffc, 0x0, 0x24100010, -0x3202001e, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x3202001e, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x97a2001c, 0x501025, 0xa7a2001c, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x8021, -0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004d78, -0x2021, 0xc004d78, 0x24040001, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x24100010, -0xc004d78, 0x2021, 0x108042, 0x1600fffc, -0x0, 0x24100010, 0x3202001e, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x97a2001c, 0x501025, -0xa7a2001c, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x8021, 0x24020002, 0xa7a2001e, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0x24100010, 0xc004d78, -0x2021, 0x108042, 0x1600fffc, 0x0, -0x24100010, 0x3202001e, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x3202001e, 0xc004d78, 0x24040001, 0xc004d78, -0x2021, 0x34108000, 0x97a2001e, 0x501024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fff8, 0x0, 0xc004db9, -0x8021, 0xa7a00020, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x24100010, 0xc004d78, 0x2021, 0x108042, -0x1600fffc, 0x0, 0x24100010, 0x3202001e, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x3202001e, 0xc004db9, -0x34108000, 0xc004db9, 0x0, 0xc004d58, -0x0, 0x50400005, 0x108042, 0x97a20020, -0x501025, 0xa7a20020, 0x108042, 0x1600fff7, -0x0, 0xc004db9, 0x8021, 0xa7a00020, -0xc004d78, 0x24040001, 0x26100001, 0x2e020020, -0x1440fffb, 0x0, 0xc004d78, 0x2021, -0xc004d78, 0x24040001, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0x24100010, 0xc004d78, -0x2021, 0x108042, 0x1600fffc, 0x0, -0x24100010, 0x3202001e, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fffa, -0x3202001e, 0xc004db9, 0x34108000, 0xc004db9, -0x0, 0xc004d58, 0x0, 0x50400005, -0x108042, 0x97a20020, 0x501025, 0xa7a20020, -0x108042, 0x1600fff7, 0x0, 0xc004db9, -0x8021, 0xa7a00022, 0xc004d78, 0x24040001, -0x26100001, 0x2e020020, 0x1440fffb, 0x0, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0xc004d78, 0x2021, 0xc004d78, 0x24040001, -0x24100010, 0xc004d78, 0x2021, 0x108042, -0x1600fffc, 0x0, 0x24100010, 0xc004d78, -0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004d78, 0x24040001, 0xc004d78, 0x2021, -0x34108000, 0x97a20022, 0x501024, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fff8, 0x0, 0xc004db9, 0x0, -0x24040018, 0x24050002, 0xc004ddb, 0x24060004, -0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d, -0x0, 0x3c020001, 0x94426f26, 0x3c010001, -0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c, -0x24040009, 0x24050001, 0xc004ddb, 0x24060400, -0x24040018, 0x24050001, 0xc004ddb, 0x24060020, -0x24040018, 0x24050001, 0xc004ddb, 0x24062000, -0x3c024000, 0x2421024, 0x10400123, 0x3c022000, -0x2421024, 0x10400004, 0x0, 0x3c010001, -0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c, -0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9, -0x0, 0x3c020001, 0x8c426f1c, 0x10400067, -0x3c020004, 0x2421024, 0x10400011, 0xa7a00018, -0x3c020008, 0x2421024, 0x10400002, 0x24020200, -0xa7a20018, 0x3c020010, 0x2421024, 0x10400004, -0x0, 0x97a20018, 0x34420100, 0xa7a20018, -0x97a60018, 0x24040009, 0x10000004, 0x2821, -0x24040009, 0x2821, 0x3021, 0xc004ddb, -0x0, 0x24020001, 0xa7a2001a, 0x3c020008, -0x2421024, 0x1040000c, 0x3c020002, 0x2421024, -0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001, -0x2421024, 0x10400005, 0x3c020010, 0x97a2001a, -0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024, -0x1040000e, 0x3c020002, 0x2421024, 0x10400005, -0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a, -0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0, -0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0, -0x2431024, 0x54430004, 0x3c020020, 0x97a2001a, -0x1000000c, 0x34420400, 0x2421024, 0x50400004, -0x3c020080, 0x97a2001a, 0x10000006, 0x34420800, -0x2421024, 0x10400004, 0x0, 0x97a2001a, -0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004, -0xc004ddb, 0x2821, 0x3c020004, 0x2421024, -0x10400004, 0xa7a0001c, 0x32425000, 0x14400004, -0x0, 0x32424000, 0x10400005, 0x2021, -0xc004cf9, 0x2402021, 0x10000096, 0x0, -0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb, -0xa7a6001c, 0x1000008f, 0x0, 0x2421024, -0x10400004, 0xa7a00018, 0x32425000, 0x14400004, -0x0, 0x32424000, 0x10400005, 0x3c020010, -0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a, -0x2421024, 0x10400004, 0x0, 0x97a20018, -0x10000004, 0xa7a20018, 0x97a20018, 0x34420100, -0xa7a20018, 0x3c020001, 0x2421024, 0x10400004, -0x0, 0x97a20018, 0x10000004, 0xa7a20018, -0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018, -0x2021, 0xc004ddb, 0x2821, 0xa7a0001a, -0x8021, 0xc004d78, 0x24040001, 0x26100001, -0x2e020020, 0x1440fffb, 0x0, 0xc004d78, -0x2021, 0xc004d78, 0x24040001, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x24100010, -0x32020001, 0x10400002, 0x2021, 0x24040001, -0xc004d78, 0x108042, 0x1600fffa, 0x32020001, -0x24100010, 0xc004d78, 0x2021, 0x108042, -0x1600fffc, 0x0, 0xc004db9, 0x34108000, -0xc004db9, 0x0, 0xc004d58, 0x0, -0x50400005, 0x108042, 0x97a2001a, 0x501025, -0xa7a2001a, 0x108042, 0x1600fff7, 0x0, -0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x24040001, 0xc004d78, -0x2021, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0xc004d78, -0x2021, 0x108042, 0x1600fffc, 0x0, -0xc004db9, 0x34108000, 0xc004db9, 0x0, -0xc004d58, 0x0, 0x50400005, 0x108042, -0x97a2001a, 0x501025, 0xa7a2001a, 0x108042, -0x1600fff7, 0x0, 0xc004db9, 0x0, -0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a, -0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c, -0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b, -0xafa30014, 0x8f830054, 0x24020004, 0x3c010001, -0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38, -0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c, -0x431023, 0x2c420064, 0x1440000f, 0x0, -0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4, -0x3c03f700, 0x431025, 0x10000007, 0xaf820220, -0x24020006, 0x3c010001, 0xac226dd4, 0x24020011, -0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030, -0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038, -0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c, -0x8821, 0x32024000, 0x10400013, 0xafbf0020, -0x3c020010, 0x2021024, 0x2c420001, 0x21023, -0x30434100, 0x3c020001, 0x2021024, 0x14400006, -0x34714000, 0x3c020002, 0x2021024, 0x14400002, -0x34716000, 0x34714040, 0x2021, 0x2821, -0x10000036, 0x2203021, 0x32021000, 0x10400035, -0x2021, 0x2821, 0xc004ddb, 0x24060040, -0x24040018, 0x2821, 0xc004ddb, 0x24060c00, -0x24040017, 0x2821, 0xc004ddb, 0x24060400, -0x24040016, 0x2821, 0xc004ddb, 0x24060006, -0x24040017, 0x2821, 0xc004ddb, 0x24062500, -0x24040016, 0x2821, 0xc004ddb, 0x24060006, -0x24040017, 0x2821, 0xc004ddb, 0x24064600, -0x24040016, 0x2821, 0xc004ddb, 0x24060006, -0x24040017, 0x2821, 0xc004ddb, 0x24066700, -0x24040016, 0x2821, 0xc004ddb, 0x24060006, -0x2404001f, 0x2821, 0xc004ddb, 0x24060010, -0x24040009, 0x2821, 0xc004ddb, 0x24061500, -0x24040009, 0x2821, 0x24061d00, 0xc004ddb, -0x0, 0x3c040001, 0x24846bf0, 0x3c05000e, -0x34a50100, 0x2003021, 0x2203821, 0xafa00010, -0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c, -0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, -0x8f820044, 0x3c030001, 0x431025, 0x3c030008, -0xaf820044, 0x8f840054, 0x8f820054, 0xa32824, -0x10000002, 0x24840001, 0x8f820054, 0x821023, -0x2c420002, 0x1440fffc, 0x0, 0x8f820044, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, -0x8f830054, 0x8f820054, 0x10000002, 0x24630001, -0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, -0x0, 0x3e00008, 0xa01021, 0x8f830044, -0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, -0x3c020002, 0x822025, 0x641825, 0xaf830044, -0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820044, 0x3c030001, -0x431025, 0xaf820044, 0x8f830054, 0x8f820054, -0x10000002, 0x24630001, 0x8f820054, 0x621023, -0x2c420002, 0x1440fffc, 0x0, 0x3e00008, -0x0, 0x8f820044, 0x2403ff7f, 0x431024, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820044, 0x34420080, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x3e00008, 0x0, -0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, -0xaf820044, 0x8f820044, 0x3c030001, 0x431025, -0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, -0x24630001, 0x8f820054, 0x621023, 0x2c420002, -0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, -0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, -0x8f820054, 0x10000002, 0x24630001, 0x8f820054, -0x621023, 0x2c420002, 0x1440fffc, 0x0, -0x3e00008, 0x0, 0x27bdffc8, 0xafb30024, -0x809821, 0xafbe002c, 0xa0f021, 0xafb20020, -0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028, -0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010, -0x3271ffff, 0x27b20010, 0x8021, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2301024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x2301024, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x34108000, -0x96420000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x12000075, -0x0, 0x1000fff6, 0x0, 0x3275ffff, -0x27b10010, 0xa7a00010, 0x8021, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x24040001, 0xc004d78, -0x2021, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2b01024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x2b01024, 0xc004db9, -0x34108000, 0xc004db9, 0x0, 0xc004d58, -0x0, 0x50400005, 0x108042, 0x96220000, -0x501025, 0xa6220000, 0x108042, 0x1600fff7, -0x0, 0xc004db9, 0x0, 0x33c5ffff, -0x24020001, 0x54a20004, 0x24020002, 0x97a20010, -0x10000006, 0x521025, 0x14a20006, 0x3271ffff, -0x97a20010, 0x121827, 0x431024, 0xa7a20010, -0x3271ffff, 0x27b20010, 0x8021, 0xc004d78, -0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, -0x0, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0xc004d78, -0x24040001, 0x24100010, 0x32020001, 0x10400002, -0x2021, 0x24040001, 0xc004d78, 0x108042, -0x1600fffa, 0x32020001, 0x24100010, 0x2301024, -0x10400002, 0x2021, 0x24040001, 0xc004d78, -0x108042, 0x1600fffa, 0x2301024, 0xc004d78, -0x24040001, 0xc004d78, 0x2021, 0x34108000, -0x96420000, 0x501024, 0x10400002, 0x2021, -0x24040001, 0xc004d78, 0x108042, 0x1600fff8, -0x0, 0xc004db9, 0x0, 0x8fbf0030, -0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, -0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, -0x0, 0x0, 0x0, 0x27bdffe8, -0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, -0x0, 0x3c020001, 0x8c426f1c, 0x14400005, -0x0, 0xc003daf, 0x8f840224, 0x100001d8, -0x0, 0x8f820220, 0x3c030008, 0x431024, -0x10400026, 0x24020001, 0x8f840224, 0x8f820220, -0x3c030400, 0x431024, 0x10400006, 0x0, -0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b, -0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000, -0x24420001, 0xac620000, 0x2c420002, 0x14400003, -0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002, -0x8c428fc0, 0x10400006, 0x30820040, 0x10400004, -0x24020001, 0x3c010002, 0x10000003, 0xac228fc4, -0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c, -0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002, -0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002, -0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002, -0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002, -0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002, -0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194, -0x31080, 0x3c010001, 0x220821, 0x8c226c00, -0x400008, 0x0, 0x24020002, 0x3c010002, -0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002, -0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002, -0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224, -0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0, -0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf, -0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, -0x431024, 0xaf820200, 0x3c010002, 0xac208fe0, -0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001, -0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002, -0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4, -0x14400006, 0x24020003, 0x3c010001, 0xac246d9c, -0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002, -0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002, -0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400003, 0x24020004, 0x3c010002, 0xac228f90, -0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff, -0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, -0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8, -0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002, -0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204, -0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, -0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002, -0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0, -0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff, -0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001, -0xac226e3c, 0x2c420002, 0x14400125, 0x24020001, -0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c, -0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002, -0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024, -0x3c020002, 0x8c428f9c, 0x10400115, 0x0, -0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002, -0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002, -0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204, -0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002, -0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0, -0x3c020002, 0x8c428fc0, 0x10400005, 0x0, -0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002, -0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21, -0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4, -0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c, -0x3c030002, 0x8c638fc8, 0x441024, 0x641824, -0x10430004, 0x24020001, 0x3c010002, 0x100000e4, -0xac228f90, 0x24020003, 0xaca20000, 0x24020008, -0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc, -0x1040000c, 0x24020001, 0x3c040002, 0xc005091, -0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005, -0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006, -0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002, -0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0, -0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0, -0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002, -0xac238fac, 0x8f830054, 0x24020009, 0x3c010002, -0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4, -0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0, -0x431023, 0x2c422710, 0x1440009f, 0x0, -0x3c020002, 0x8c428fc0, 0x10400005, 0x0, -0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002, -0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21, -0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc, -0x1040000e, 0x0, 0x3c020002, 0x8c428f9c, -0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f, -0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, -0x24020003, 0x10000029, 0x2402000c, 0x3c020002, -0x8c428f9c, 0x30420080, 0x14400005, 0x24020003, -0x8f820204, 0x30420080, 0x1040001f, 0x24020003, -0xac620000, 0x2402000a, 0x3c010002, 0xac228f90, -0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002, -0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000, -0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002, -0xac228f90, 0x641825, 0x3c010002, 0xac238fe0, -0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21, -0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0, -0x10400005, 0x0, 0x2402000c, 0x3c010002, -0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0, -0x10400063, 0x0, 0x3c040002, 0x8c848f9c, -0x10800055, 0x30820008, 0x3c030002, 0x8c638fac, -0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8, -0xaca20000, 0x24020006, 0x3c010002, 0x10000054, -0xac228f90, 0x8f820200, 0x34420002, 0xaf820200, -0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90, -0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002, -0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710, -0x14400031, 0x0, 0x3c020002, 0x8c428fd0, -0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4, -0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d, -0x0, 0x3c050001, 0x8ca56d98, 0xc00529b, -0x2021, 0x3c030001, 0x8c636d98, 0x24020004, -0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94, -0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94, -0x431024, 0x3c010001, 0xac226d94, 0x8f830224, -0x3c020200, 0x3c010002, 0xac238fec, 0x10000020, -0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005, -0x0, 0x3c020002, 0x8c428f9c, 0x1040000f, -0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21, -0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0, -0x1040000f, 0x0, 0x3c020002, 0x8c428f9c, -0x1440000b, 0x0, 0x24020002, 0x3c010002, -0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0, -0x10400003, 0x0, 0xc003daf, 0x0, -0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, -0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002, -0x24638fe8, 0x8c620000, 0x10400005, 0x34422000, -0x3c010002, 0xac228fdc, 0x10000003, 0xac600000, -0x3c010002, 0xac248fdc, 0x3e00008, 0x0, -0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002, -0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e, -0x821024, 0x14400061, 0x24020030, 0x30822000, -0x1040005d, 0x30838000, 0x31a02, 0x30820001, -0x21200, 0x3c040001, 0x8c846f20, 0x621825, -0x331c2, 0x3c030001, 0x24636e48, 0x30828000, -0x21202, 0x30840001, 0x42200, 0x441025, -0x239c2, 0x61080, 0x431021, 0x471021, -0x90430000, 0x24020001, 0x10620025, 0x0, -0x10600007, 0x24020002, 0x10620013, 0x24020003, -0x1062002c, 0x3c05000f, 0x10000037, 0x0, -0x8f820200, 0x2403feff, 0x431024, 0xaf820200, -0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x3c010002, 0xac209004, 0x3c010002, -0x10000034, 0xac20900c, 0x8f820200, 0x34420100, -0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, -0x431024, 0xaf820220, 0x24020100, 0x3c010002, -0xac229004, 0x3c010002, 0x10000026, 0xac20900c, -0x8f820200, 0x2403feff, 0x431024, 0xaf820200, -0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x3c010002, 0xac209004, 0x3c010002, 0x10000019, -0xac23900c, 0x8f820200, 0x34420100, 0xaf820200, -0x8f820220, 0x3c030001, 0x431025, 0xaf820220, -0x24020100, 0x3c010002, 0xac229004, 0x3c010002, -0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001, -0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014, -0x10000004, 0x0, 0x24020030, 0x3c010002, -0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020, -0x0, 0x0, 0x0, 0x27bdffc8, -0xafb20028, 0x809021, 0xafb3002c, 0xa09821, -0xafb00020, 0xc08021, 0x3c040001, 0x24846c50, -0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001, -0x2403021, 0x2603821, 0xafbf0030, 0xafb10024, -0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010, -0x24020002, 0x12620083, 0x2e620003, 0x10400005, -0x24020001, 0x1262000a, 0x0, 0x10000173, -0x0, 0x24020004, 0x126200f8, 0x24020008, -0x126200f7, 0x3c02ffec, 0x1000016c, 0x0, -0x3c020001, 0x8c426d94, 0x30420002, 0x14400004, -0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024, -0x3c010002, 0x310821, 0xac308ffc, 0x3c024000, -0x2021024, 0x1040004e, 0x1023c2, 0x30840030, -0x101382, 0x3042001c, 0x3c030001, 0x24636dd8, -0x431021, 0x823821, 0x3c020020, 0x2021024, -0x10400006, 0x24020100, 0x3c010002, 0x310821, -0xac229000, 0x10000005, 0x3c020080, 0x3c010002, -0x310821, 0xac209000, 0x3c020080, 0x2021024, -0x10400006, 0x121940, 0x3c020001, 0x3c010002, -0x230821, 0x10000005, 0xac229008, 0x121140, -0x3c010002, 0x220821, 0xac209008, 0x94e40000, -0x3c030001, 0x8c636f40, 0x24020005, 0x10620010, -0xa7a40018, 0x32024000, 0x10400002, 0x34824000, -0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, -0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002, -0x24040001, 0x2821, 0xc0045be, 0x27a60018, -0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001, -0xac316da4, 0x14530004, 0x32028000, 0xc003daf, -0x0, 0x32028000, 0x1040011c, 0x0, -0xc003daf, 0x0, 0x3c030001, 0x8c636f40, -0x24020005, 0x10620115, 0x24020002, 0x3c010001, -0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98, -0x24040001, 0x24050004, 0x27b0001a, 0xc0045be, -0x2003021, 0x24040001, 0x2821, 0xc0045be, -0x2003021, 0x3c020002, 0x511021, 0x8c428ff4, -0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff, -0x3c010001, 0xac336da4, 0x431024, 0x3c010002, -0x310821, 0x109300f7, 0xac228ff4, 0x100000f7, -0x0, 0x3c022000, 0x2021024, 0x10400005, -0x24020001, 0x3c010001, 0xac226f1c, 0x10000004, -0x128940, 0x3c010001, 0xac206f1c, 0x128940, -0x3c010002, 0x310821, 0xac308ff8, 0x3c024000, -0x2021024, 0x14400014, 0x0, 0x3c020001, -0x8c426f1c, 0x10400006, 0x24040004, 0x24050001, -0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8, -0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff, -0x3463ffff, 0x431024, 0x3c010002, 0x310821, -0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c, -0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d, -0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100, -0x3c010002, 0x310821, 0xac239004, 0x3c030001, -0x3c010002, 0x310821, 0xac23900c, 0x10000015, -0x34420400, 0x2021024, 0x10400008, 0x24030100, -0x3c020001, 0x8c426f20, 0x3c010002, 0x310821, -0xac239004, 0x1000000b, 0x34420800, 0x3c020080, -0x2021024, 0x1040002e, 0x3c030001, 0x3c020001, -0x8c426f20, 0x3c010002, 0x310821, 0xac23900c, -0x34420c00, 0x3c010001, 0xac226f20, 0x10000025, -0x24040001, 0x3c020020, 0x2021024, 0x10400006, -0x24020100, 0x3c010002, 0x310821, 0xac229004, -0x10000005, 0x3c020080, 0x3c010002, 0x310821, -0xac209004, 0x3c020080, 0x2021024, 0x10400007, -0x121940, 0x3c020001, 0x3c010002, 0x230821, -0xac22900c, 0x10000006, 0x24040001, 0x121140, -0x3c010002, 0x220821, 0xac20900c, 0x24040001, -0x2821, 0x27b0001e, 0xc00457c, 0x2003021, -0x24040001, 0x2821, 0xc00457c, 0x2003021, -0x24040001, 0x24050001, 0x27b0001c, 0xc00457c, -0x2003021, 0x24040001, 0x24050001, 0xc00457c, -0x2003021, 0x10000077, 0x0, 0x3c02ffec, -0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, -0x121140, 0x3c010002, 0x220821, 0xac308ff8, -0x3c022000, 0x2021024, 0x10400009, 0x0, -0x3c020001, 0x8c426e44, 0x14400005, 0x24020001, -0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000, -0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024, -0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c, -0xaf820238, 0x3c010001, 0xac206db0, 0x10600005, -0x24022020, 0x3c010001, 0xac226f20, 0x24020001, -0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002, -0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98, -0x3484ffff, 0x441024, 0x3c010002, 0x230821, -0xac228ff0, 0x24020001, 0x10a20044, 0x0, -0x10000040, 0x0, 0x3c020001, 0x8c426f1c, -0x1040001c, 0x24022000, 0x3c010001, 0xac226f20, -0x3c0300a0, 0x2031024, 0x14430005, 0x121140, -0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20, -0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020, -0x621024, 0x10400004, 0x24022001, 0x3c010001, -0x10000023, 0xac226f20, 0x3c020080, 0x621024, -0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c, -0xac226f20, 0x3c020020, 0x2021024, 0x10400007, -0x121940, 0x24020100, 0x3c010002, 0x230821, -0xac229004, 0x10000006, 0x3c020080, 0x121140, -0x3c010002, 0x220821, 0xac209004, 0x3c020080, -0x2021024, 0x10400006, 0x121940, 0x3c020001, -0x3c010002, 0x230821, 0x10000005, 0xac22900c, -0x121140, 0x3c010002, 0x220821, 0xac20900c, -0x3c030001, 0x8c636d98, 0x24020001, 0x10620003, -0x0, 0xc003daf, 0x0, 0x8fbf0030, -0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, -0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c, -0x9821, 0xafb50040, 0xa821, 0xafb10034, -0x8821, 0x24020002, 0xafbf0048, 0xafbe0044, -0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a, -0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022, -0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005, -0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d, -0x2201021, 0x24020004, 0x10a2020a, 0x24020008, -0x10a20208, 0x2201021, 0x10000256, 0x0, -0x8fa8002c, 0x88140, 0x3c030002, 0x701821, -0x8c638ffc, 0x621024, 0x14400009, 0x24040001, -0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002, -0x300821, 0xac318ff4, 0x10000246, 0x2201021, -0x24050001, 0xc00457c, 0x27a60018, 0x24040001, -0x24050001, 0xc00457c, 0x27a60018, 0x97a20018, -0x30420004, 0x104000d9, 0x3c114000, 0x3c020001, -0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9, -0x31080, 0x3c010001, 0x220821, 0x8c226c68, -0x400008, 0x0, 0x24040001, 0x24050011, -0x27b0001a, 0xc00457c, 0x2003021, 0x24040001, -0x24050011, 0xc00457c, 0x2003021, 0x97a3001a, -0x30624000, 0x10400002, 0x3c150010, 0x3c150008, -0x30628000, 0x104000aa, 0x3c130001, 0x100000a8, -0x3c130002, 0x24040001, 0x24050014, 0x27b0001a, -0xc00457c, 0x2003021, 0x24040001, 0x24050014, -0xc00457c, 0x2003021, 0x97a3001a, 0x30621000, -0x10400002, 0x3c150010, 0x3c150008, 0x30620800, -0x10400097, 0x3c130001, 0x10000095, 0x3c130002, -0x24040001, 0x24050019, 0x27b0001c, 0xc00457c, -0x2003021, 0x24040001, 0x24050019, 0xc00457c, -0x2003021, 0x97a2001c, 0x30430700, 0x24020400, -0x10620027, 0x28620401, 0x1040000e, 0x24020200, -0x1062001f, 0x28620201, 0x10400005, 0x24020100, -0x5062001e, 0x3c130001, 0x1000001e, 0x24040001, -0x24020300, 0x50620019, 0x3c130002, 0x10000019, -0x24040001, 0x24020600, 0x1062000d, 0x28620601, -0x10400005, 0x24020500, 0x5062000b, 0x3c130002, -0x10000010, 0x24040001, 0x24020700, 0x1462000d, -0x24040001, 0x3c130004, 0x1000000a, 0x3c150008, -0x10000006, 0x3c130004, 0x10000005, 0x3c150008, -0x3c130001, 0x10000002, 0x3c150008, 0x3c150010, -0x24040001, 0x24050018, 0x27b0001e, 0xc00457c, -0x2003021, 0x24040001, 0x24050018, 0xc00457c, -0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140, -0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022, -0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010, -0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b, -0xafa20014, 0x3c020004, 0x16620010, 0x3c020001, -0x8f840054, 0x24030001, 0x24020002, 0x3c010001, -0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001, -0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001, -0xac246f30, 0x1000004f, 0x2b38825, 0x16620039, -0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e, -0x24040018, 0x2021, 0x2821, 0xc004ddb, -0x34068000, 0x8f830054, 0x8f820054, 0x2b38825, -0x10000002, 0x24630032, 0x8f820054, 0x621023, -0x2c420033, 0x1440fffc, 0x0, 0x8f830054, -0x24020001, 0x3c010001, 0xac226e20, 0x3c010001, -0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001, -0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001, -0x1000002c, 0xac236f30, 0x2821, 0xc004ddb, -0x24060404, 0x2021, 0x2405001e, 0x27a60018, -0x24020002, 0xc0045be, 0xa7a20018, 0x2021, -0x2821, 0x27a60018, 0xc0045be, 0xa7a00018, -0x24040018, 0x24050002, 0xc004ddb, 0x24060004, -0x3c028000, 0x2221025, 0x2b31825, 0x10000015, -0x438825, 0x2221025, 0x2751825, 0x438825, -0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98, -0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b, -0xafb10014, 0x10000007, 0x0, 0x3c110002, -0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff, -0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e, -0x0, 0x3c020001, 0x8c426f1c, 0x10400002, -0x3c022000, 0x2228825, 0x8fa8002c, 0x81140, -0x3c010002, 0x220821, 0x8c229000, 0x10400003, -0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf, -0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140, -0x3c010002, 0x220821, 0x8c229008, 0x10400003, -0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f, -0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140, -0x3c010002, 0x220821, 0xac318ff4, 0x10000135, -0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002, -0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024, -0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, -0x628824, 0x3c010002, 0x3e0821, 0xac318ff0, -0x10000124, 0x2201021, 0x2821, 0xc00457c, -0x27a60018, 0x24040001, 0x2821, 0xc00457c, -0x27a60018, 0x24040001, 0x24050001, 0x27b20020, -0xc00457c, 0x2403021, 0x24040001, 0x24050001, -0xc00457c, 0x2403021, 0x24040001, 0x24050004, -0x27b1001e, 0xc00457c, 0x2203021, 0x24040001, -0x24050004, 0xc00457c, 0x2203021, 0x24040001, -0x24050005, 0x27b00022, 0xc00457c, 0x2003021, -0x24040001, 0x24050005, 0xc00457c, 0x2003021, -0x24040001, 0x24050010, 0xc00457c, 0x27a60018, -0x24040001, 0x24050010, 0xc00457c, 0x27a60018, -0x24040001, 0x2405000a, 0xc00457c, 0x2403021, -0x24040001, 0x2405000a, 0xc00457c, 0x2403021, -0x24040001, 0x24050018, 0xc00457c, 0x2203021, -0x24040001, 0x24050018, 0xc00457c, 0x2203021, -0x24040001, 0x24050001, 0xc00457c, 0x27a60018, -0x24040001, 0x24050001, 0xc00457c, 0x27a60018, -0x97a20018, 0x30420004, 0x10400066, 0x3c114000, -0x3c030001, 0x8c636f34, 0x24020005, 0x14620067, -0x24040001, 0x24050019, 0x27b0001c, 0xc00457c, -0x2003021, 0x24040001, 0x24050019, 0xc00457c, -0x2003021, 0x97a2001c, 0x30430700, 0x24020400, -0x10620027, 0x28620401, 0x1040000e, 0x24020200, -0x1062001f, 0x28620201, 0x10400005, 0x24020100, -0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004, -0x24020300, 0x50620019, 0x3c130002, 0x10000019, -0x3c020004, 0x24020600, 0x1062000d, 0x28620601, -0x10400005, 0x24020500, 0x5062000b, 0x3c130002, -0x10000010, 0x3c020004, 0x24020700, 0x1462000d, -0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008, -0x10000006, 0x3c130004, 0x10000005, 0x3c150008, -0x3c130001, 0x10000002, 0x3c150008, 0x3c150010, -0x3c020004, 0x12620017, 0x3c028000, 0x8f820054, -0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001, -0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001, -0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001, -0x16620022, 0x2758825, 0x2021, 0x2821, -0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b, -0xac306e20, 0x2221025, 0x2b31825, 0x438825, -0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001, -0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010, -0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001, -0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007, -0x0, 0x3c110002, 0x23e8821, 0x8e318ff0, -0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001, -0x8c426da8, 0x10400069, 0x0, 0x3c020001, -0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825, -0x8fa8002c, 0x81140, 0x3c010002, 0x220821, -0x8c229004, 0x10400003, 0x3c020020, 0x10000005, -0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x8fa8002c, 0x81140, 0x3c010002, 0x220821, -0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f, -0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b, -0x2228824, 0x8fa8002c, 0x82940, 0x3c030002, -0x651821, 0x8c638ff8, 0x3c024000, 0x621024, -0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, -0x3c010002, 0x250821, 0xac318ff0, 0x10000041, -0x2201021, 0x3c020001, 0x8c426da8, 0x10400034, -0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c, -0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b, -0x21023, 0x441024, 0x10600003, 0x518825, -0x3c022000, 0x2228825, 0x3c020002, 0x451021, -0x8c429004, 0x10400003, 0x3c020020, 0x10000004, -0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, -0x8fa8002c, 0x81140, 0x3c010002, 0x220821, -0x8c22900c, 0x10400003, 0x3c020080, 0x10000004, -0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, -0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800, -0x2228825, 0x3c020001, 0x8c426e34, 0x10400002, -0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38, -0x10400006, 0x3c020100, 0x10000004, 0x2228825, -0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c, -0x81140, 0x3c010002, 0x220821, 0xac318ff0, -0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, -0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, -0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028, -0x809021, 0xafbf002c, 0xafb10024, 0xafb00020, -0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220, -0x24020002, 0x1202005c, 0x2e020003, 0x10400005, -0x24020001, 0x1202000a, 0x121940, 0x1000010c, -0x0, 0x24020004, 0x120200bf, 0x24020008, -0x120200be, 0x128940, 0x10000105, 0x0, -0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002, -0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024, -0x10400038, 0x3c020008, 0x2021024, 0x10400020, -0x34840002, 0x3c020002, 0x431021, 0x8c429000, -0x10400005, 0x34840020, 0x34840100, 0x3c020020, -0x10000006, 0x2028025, 0x2402feff, 0x822024, -0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140, -0x3c010002, 0x220821, 0x8c229008, 0x10400005, -0x3c020001, 0xc23025, 0x3c020080, 0x10000016, -0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024, -0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024, -0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff, -0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024, -0x3c010002, 0x230821, 0xac209000, 0x3c010002, -0x230821, 0xac209008, 0xaf840200, 0xaf860220, -0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, -0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200, -0x2028024, 0x2402fffd, 0x621824, 0xc003daf, -0xaf830200, 0x121140, 0x3c010002, 0x220821, -0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c, -0x10400069, 0x24050004, 0x24040001, 0xc00457c, -0x27a60018, 0x24040001, 0x24050005, 0xc00457c, -0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001, -0x24846e48, 0x30630c00, 0x31a82, 0x30420c00, -0x21282, 0xa7a2001a, 0x21080, 0x441021, -0x431021, 0xa7a30018, 0x90480000, 0x24020001, -0x3103ffff, 0x10620029, 0x28620002, 0x10400005, -0x0, 0x10600009, 0x0, 0x1000003d, -0x0, 0x10700013, 0x24020003, 0x1062002c, -0x0, 0x10000037, 0x0, 0x8f820200, -0x2403feff, 0x431024, 0xaf820200, 0x8f820220, -0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, -0x3c010002, 0xac209004, 0x3c010002, 0x10000032, -0xac20900c, 0x8f820200, 0x34420100, 0xaf820200, -0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, -0xaf820220, 0x24020100, 0x3c010002, 0xac229004, -0x3c010002, 0x10000024, 0xac20900c, 0x8f820200, -0x2403feff, 0x431024, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x3c010002, -0xac209004, 0x3c010002, 0x10000017, 0xac23900c, -0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, -0x3c030001, 0x431025, 0xaf820220, 0x24020100, -0x3c010002, 0xac229004, 0x3c010002, 0x1000000a, -0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a, -0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010, -0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002, -0x1000004b, 0xaf820200, 0x128940, 0x3c050002, -0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021, -0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010, -0x0, 0x3c020001, 0x8c426f1c, 0x14400005, -0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200, -0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024, -0x3c010002, 0x310821, 0x10000031, 0xac308ff0, -0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020, -0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020, -0xa21024, 0x10400007, 0x34840020, 0x24020100, -0x3c010002, 0x310821, 0xac229004, 0x10000006, -0x34840100, 0x3c010002, 0x310821, 0xac209004, -0x2402feff, 0x822024, 0x3c020080, 0xa21024, -0x10400007, 0x121940, 0x3c020001, 0x3c010002, -0x230821, 0xac22900c, 0x10000008, 0xc23025, -0x121140, 0x3c010002, 0x220821, 0xac20900c, -0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, -0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, -0x121140, 0x3c010002, 0x220821, 0xac308ff0, -0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, -0x3e00008, 0x27bd0030, 0x0, 0x1821, -0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, -0x30420001, 0x10400004, 0x0, 0x8f820044, -0x10000003, 0x34420040, 0x8f820044, 0x461024, -0xaf820044, 0x8f820044, 0x34420020, 0xaf820044, -0x8f820044, 0x451024, 0xaf820044, 0x24630001, -0x28620008, 0x5440ffee, 0x641007, 0x3e00008, -0x0, 0x2c820008, 0x1040001b, 0x0, -0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001, -0x24426e60, 0x621821, 0x24640004, 0x90620000, -0x10400004, 0x0, 0x8f820044, 0x10000003, -0x34420040, 0x8f820044, 0x461024, 0xaf820044, -0x8f820044, 0x34420020, 0xaf820044, 0x8f820044, -0x451024, 0xaf820044, 0x24630001, 0x64102b, -0x1440ffee, 0x0, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x8f8400c4, -0x8f8600e0, 0x8f8700e4, 0x2402fff8, 0xc22824, -0x10e5001a, 0x27623ff8, 0x14e20002, 0x24e80008, -0x27683000, 0x55050004, 0x8d0a0000, 0x30c20004, -0x14400012, 0x805021, 0x8ce90000, 0x8f42013c, -0x1494823, 0x49182b, 0x94eb0006, 0x10600002, -0x25630050, 0x494821, 0x123182b, 0x50400003, -0x8f4201fc, 0x3e00008, 0xe01021, 0xaf8800e8, -0x24420001, 0xaf4201fc, 0xaf8800e4, 0x3e00008, -0x1021, 0x3e00008, 0x0, 0x8f8300e4, -0x27623ff8, 0x10620004, 0x24620008, 0xaf8200e8, -0x3e00008, 0xaf8200e4, 0x27623000, 0xaf8200e8, -0x3e00008, 0xaf8200e4, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x8f880120, -0x27624fe0, 0x8f830128, 0x15020002, 0x25090020, -0x27694800, 0x11230012, 0x8fa20010, 0xad040000, -0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, -0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, -0xad020010, 0xad030014, 0xaf890120, 0x8f4300fc, -0x24020001, 0x2463ffff, 0x3e00008, 0xaf4300fc, -0x8f430324, 0x1021, 0x24630001, 0x3e00008, -0xaf430324, 0x3e00008, 0x0, 0x8f880100, -0x276247e0, 0x8f830108, 0x15020002, 0x25090020, -0x27694000, 0x1123000f, 0x8fa20010, 0xad040000, -0xad050004, 0xad060008, 0xa507000e, 0x8fa30014, -0xad020018, 0x8fa20018, 0xad03001c, 0x25030016, -0xad020010, 0xad030014, 0xaf890100, 0x3e00008, -0x24020001, 0x8f430328, 0x1021, 0x24630001, -0x3e00008, 0xaf430328, 0x3e00008, 0x0, -0x0, 0x0, 0x0, 0x0 }; -static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { -0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f6677, 0x6d61696e, 0x2e632c76, 0x20312e31, -0x2e322e34, 0x35203139, 0x39392f30, 0x312f3234, -0x2030303a, 0x31303a35, 0x35207368, 0x75616e67, -0x20457870, 0x20240000, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x6261644d, 0x656d537a, -0x0, 0x68775665, 0x72000000, 0x62616448, -0x77566572, 0x0, 0x2a2a4441, 0x574e5f41, -0x0, 0x74785278, 0x4266537a, 0x0, -0x62664174, 0x6e4d726b, 0x0, 0x7265645a, -0x6f6e6531, 0x0, 0x70636943, 0x6f6e6600, -0x67656e43, 0x6f6e6600, 0x2a646d61, 0x5244666c, -0x0, 0x2a50414e, 0x49432a00, 0x2e2e2f2e, -0x2e2f2e2e, 0x2f2e2e2f, 0x2e2e2f73, 0x72632f6e, -0x69632f66, 0x77322f63, 0x6f6d6d6f, 0x6e2f6677, -0x6d61696e, 0x2e630000, 0x72636246, 0x6c616773, -0x0, 0x62616452, 0x78526362, 0x0, -0x676c6f62, 0x466c6773, 0x0, 0x2b5f6469, -0x73705f6c, 0x6f6f7000, 0x2b65765f, 0x68616e64, -0x6c657200, 0x63616e74, 0x31446d61, 0x0, -0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x635f636b, -0x73756d00, 0x2b685f73, 0x656e645f, 0x64617461, -0x5f726561, 0x64795f63, 0x6b73756d, 0x0, -0x2b685f64, 0x6d615f72, 0x645f6173, 0x73697374, -0x5f636b73, 0x756d0000, 0x74436b73, 0x6d4f6e00, -0x2b715f64, 0x6d615f74, 0x6f5f6e69, 0x63000000, -0x2b685f73, 0x656e645f, 0x64617461, 0x5f726561, -0x64790000, 0x2b685f64, 0x6d615f72, 0x645f6173, -0x73697374, 0x0, 0x74436b73, 0x6d4f6666, -0x0, 0x2b685f73, 0x656e645f, 0x62645f72, -0x65616479, 0x0, 0x68737453, 0x52696e67, -0x0, 0x62616453, 0x52696e67, 0x0, -0x6e696353, 0x52696e67, 0x0, 0x77446d61, -0x416c6c41, 0x0, 0x2b715f64, 0x6d615f74, -0x6f5f686f, 0x73745f63, 0x6b73756d, 0x0, -0x2b685f6d, 0x61635f72, 0x785f636f, 0x6d705f63, -0x6b73756d, 0x0, 0x2b685f64, 0x6d615f77, -0x725f6173, 0x73697374, 0x5f636b73, 0x756d0000, -0x72436b73, 0x6d4f6e00, 0x2b715f64, 0x6d615f74, -0x6f5f686f, 0x73740000, 0x2b685f6d, 0x61635f72, -0x785f636f, 0x6d700000, 0x2b685f64, 0x6d615f77, -0x725f6173, 0x73697374, 0x0, 0x72436b73, -0x6d4f6666, 0x0, 0x2b685f72, 0x6563765f, -0x62645f72, 0x65616479, 0x0, 0x2b685f72, -0x6563765f, 0x6a756d62, 0x6f5f6264, 0x5f726561, -0x64790000, 0x2b685f72, 0x6563765f, 0x6d696e69, -0x5f62645f, 0x72656164, 0x79000000, 0x2b6d685f, -0x636f6d6d, 0x616e6400, 0x2b685f74, 0x696d6572, -0x0, 0x2b685f64, 0x6f5f7570, 0x64617465, -0x5f74785f, 0x636f6e73, 0x0, 0x2b685f64, -0x6f5f7570, 0x64617465, 0x5f72785f, 0x70726f64, -0x0, 0x2b636b73, 0x756d3136, 0x0, -0x2b706565, 0x6b5f6d61, 0x635f7278, 0x5f776100, -0x2b706565, 0x6b5f6d61, 0x635f7278, 0x0, -0x2b646571, 0x5f6d6163, 0x5f727800, 0x2b685f6d, -0x61635f72, 0x785f6174, 0x746e0000, 0x62616452, -0x6574537a, 0x0, 0x72784264, 0x4266537a, -0x0, 0x2b6e756c, 0x6c5f6861, 0x6e646c65, -0x72000000, 0x66774f70, 0x4661696c, 0x0, -0x2b685f75, 0x70646174, 0x655f6c65, 0x64340000, -0x2b685f75, 0x70646174, 0x655f6c65, 0x64360000, -0x2b685f75, 0x70646174, 0x655f6c65, 0x64320000, -0x696e7453, 0x74617465, 0x0, 0x2a2a696e, -0x69744370, 0x0, 0x23736372, 0x65616d00, -0x69537461, 0x636b4572, 0x0, 0x70726f62, -0x654d656d, 0x0, 0x2a2a4441, 0x574e5f42, -0x0, 0x2b73775f, 0x646d615f, 0x61737369, -0x73745f70, 0x6c75735f, 0x74696d65, 0x72000000, -0x2b267072, 0x656c6f61, 0x645f7772, 0x5f646573, -0x63720000, 0x2b267072, 0x656c6f61, 0x645f7264, -0x5f646573, 0x63720000, 0x2b685f68, 0x665f7469, -0x6d657200, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f7469, 0x6d65722e, 0x632c7620, 0x312e312e, -0x322e3335, 0x20313939, 0x392f3031, 0x2f323720, -0x31393a30, 0x393a3530, 0x20686179, 0x65732045, -0x78702024, 0x0, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x542d446d, 0x61526432, -0x0, 0x542d446d, 0x61526431, 0x0, -0x542d446d, 0x61526442, 0x0, 0x542d446d, -0x61577232, 0x0, 0x542d446d, 0x61577231, -0x0, 0x542d446d, 0x61577242, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f636f, 0x6d6d616e, 0x642e632c, 0x7620312e, -0x312e322e, 0x32382031, 0x3939392f, 0x30312f32, -0x30203139, 0x3a34393a, 0x34392073, 0x6875616e, -0x67204578, 0x70202400, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x3f48636d, 0x644d6278, -0x0, 0x3f636d64, 0x48737453, 0x0, -0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64, -0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b, -0x0, 0x3f636d64, 0x45727200, 0x86ac, -0x8e5c, 0x8e5c, 0x8de4, 0x8b78, -0x8e30, 0x8e5c, 0x8790, 0x8800, -0x8990, 0x8a68, 0x8a34, 0x8e5c, -0x8870, 0x8b24, 0x8e5c, 0x8b34, -0x87b4, 0x8824, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f6d63, 0x6173742e, 0x632c7620, 0x312e312e, -0x322e3820, 0x31393938, 0x2f31322f, 0x30382030, -0x323a3336, 0x3a333620, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x6164644d, 0x63447570, -0x0, 0x6164644d, 0x6346756c, 0x0, -0x64656c4d, 0x634e6f45, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f646d, 0x612e632c, 0x7620312e, 0x312e322e, -0x32342031, 0x3939382f, 0x31322f32, 0x31203030, -0x3a33333a, 0x30392073, 0x6875616e, 0x67204578, -0x70202400, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x7377446d, 0x614f6666, 0x0, -0x31446d61, 0x4f6e0000, 0x7377446d, 0x614f6e00, -0x2372446d, 0x6141544e, 0x0, 0x72446d61, -0x41544e30, 0x0, 0x72446d61, 0x41544e31, -0x0, 0x72446d61, 0x34476200, 0x2a50414e, -0x49432a00, 0x2e2e2f2e, 0x2e2f2e2e, 0x2f2e2e2f, -0x2e2e2f73, 0x72632f6e, 0x69632f66, 0x77322f63, -0x6f6d6d6f, 0x6e2f646d, 0x612e6300, 0x2377446d, -0x6141544e, 0x0, 0x77446d61, 0x41544e30, -0x0, 0x77446d61, 0x41544e31, 0x0, -0x77446d61, 0x34476200, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f7472, 0x6163652e, 0x632c7620, 0x312e312e, -0x322e3520, 0x31393938, 0x2f30392f, 0x33302031, -0x383a3530, 0x3a323820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f6461, 0x74612e63, 0x2c762031, 0x2e312e32, -0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, -0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x46575f56, 0x45525349, -0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037, -0x2031373a, 0x35373a35, 0x32205044, 0x54203230, -0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54, -0x494d453a, 0x2031373a, 0x35373a35, 0x32000000, -0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, -0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, -0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, -0x0, 0x46575f43, 0x4f4d5049, 0x4c455f44, -0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f, -0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, -0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e, -0x20322e37, 0x2e320000, 0x0, 0x12041100, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f6d65, 0x6d2e632c, 0x7620312e, 0x312e322e, -0x35203139, 0x39382f30, 0x392f3330, 0x2031383a, -0x35303a30, 0x38207368, 0x75616e67, 0x20457870, -0x20240000, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f7365, 0x6e642e63, 0x2c762031, 0x2e312e32, -0x2e343420, 0x31393938, 0x2f31322f, 0x32312030, -0x303a3333, 0x3a313820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x69736e74, 0x54637055, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f7265, 0x63762e63, 0x2c762031, 0x2e312e32, -0x2e353320, 0x31393939, 0x2f30312f, 0x31362030, -0x323a3535, 0x3a343320, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x724d6163, 0x43686b30, -0x0, 0x72784672, 0x6d324c67, 0x0, -0x72784e6f, 0x53744264, 0x0, 0x72784e6f, -0x4d694264, 0x0, 0x72784e6f, 0x4a6d4264, -0x0, 0x7278436b, 0x446d6146, 0x0, -0x72785144, 0x6d457846, 0x0, 0x72785144, -0x6d614600, 0x72785144, 0x4c426446, 0x0, -0x72785144, 0x6d426446, 0x0, 0x72784372, -0x63506164, 0x0, 0x72536d51, 0x446d6146, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f6d61, 0x632e632c, 0x7620312e, 0x312e322e, -0x32322031, 0x3939382f, 0x31322f30, 0x38203032, -0x3a33363a, 0x33302073, 0x6875616e, 0x67204578, -0x70202400, 0x65767452, 0x6e674600, 0x51657674, -0x46000000, 0x51657674, 0x505f4600, 0x4d657674, -0x526e6746, 0x0, 0x4d516576, 0x74460000, -0x4d516576, 0x505f4600, 0x5173436f, 0x6e495f46, -0x0, 0x5173436f, 0x6e734600, 0x51725072, -0x6f644600, 0x6d616354, 0x68726573, 0x0, -0x23744d61, 0x6341544e, 0x0, 0x23724d61, -0x6341544e, 0x0, 0x72656d41, 0x73737274, -0x0, 0x6c696e6b, 0x444f574e, 0x0, -0x6c696e6b, 0x55500000, 0x0, 0x0, -0x0, 0x24486561, 0x6465723a, 0x202f7072, -0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, -0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, -0x6e2f636b, 0x73756d2e, 0x632c7620, 0x312e312e, -0x322e3920, 0x31393939, 0x2f30312f, 0x31342030, -0x303a3033, 0x3a343820, 0x73687561, 0x6e672045, -0x78702024, 0x0, 0x65767452, 0x6e674600, -0x51657674, 0x46000000, 0x51657674, 0x505f4600, -0x4d657674, 0x526e6746, 0x0, 0x4d516576, -0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, -0x6e495f46, 0x0, 0x5173436f, 0x6e734600, -0x51725072, 0x6f644600, 0x0, 0x0, -0x0, 0x50726f62, 0x65506879, 0x0, -0x6c6e6b41, 0x53535254, 0x0, 0x109a4, -0x10a1c, 0x10a50, 0x10a7c, 0x11050, -0x10aa8, 0x10b10, 0x111fc, 0x10dc0, -0x10c68, 0x10c80, 0x10cc4, 0x10cec, -0x10d0c, 0x10d34, 0x111fc, 0x10dc0, -0x10df8, 0x10e10, 0x10e40, 0x10e68, -0x10e88, 0x10eb0, 0x0, 0x10fdc, -0x11008, 0x1102c, 0x111fc, 0x11050, -0x11078, 0x11108, 0x0, 0x0, -0x0, 0x1186c, 0x1193c, 0x11a14, -0x11ae4, 0x11b40, 0x11c1c, 0x11c44, -0x11d20, 0x11d48, 0x11ef0, 0x11f18, -0x120c0, 0x122b8, 0x1254c, 0x12460, -0x1254c, 0x12578, 0x120e8, 0x12290, -0x7273745f, 0x676d6969, 0x0, 0x12608, -0x12640, 0x12728, 0x13374, 0x133b4, -0x133cc, 0x7365746c, 0x6f6f7000, 0x0, -0x0, 0x13bbc, 0x13bfc, 0x13c8c, -0x13cd0, 0x13d34, 0x13dc0, 0x13df4, -0x13e7c, 0x13f14, 0x13fe4, 0x14024, -0x140a8, 0x140cc, 0x141dc, 0x646f4261, -0x73655067, 0x0, 0x0, 0x0, -0x0, 0x73746d61, 0x634c4e4b, 0x0, -0x6765746d, 0x636c6e6b, 0x0, 0x14ed8, -0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, -0x14ed8, 0x7365746d, 0x61636163, 0x74000000, -0x0, 0x0 }; -static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { -0x1, -0x1, 0x1, 0xc001fc, 0x3ffc, -0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, -0x43205600, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x416c7465, -0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, -0x0, 0x0, 0x0, 0x1ffffc, -0x1fff7c, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x60cf00, -0x60, 0xcf000000, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x0, -0x0, 0x0, 0x3, 0x0, -0x1, 0x0, 0x0, 0x0, -0x1, 0x0, 0x1, 0x0, -0x0, 0x0, 0x0, 0x1, -0x1, 0x0, 0x0, 0x0, -0x0, 0x0, 0x1000000, 0x21000000, -0x12000140, 0x0, 0x0, 0x20000000, -0x120000a0, 0x0, 0x12000060, 0x12000180, -0x120001e0, 0x0, 0x0, 0x0, -0x1, 0x0, 0x0, 0x0, -0x0, 0x0, 0x0, 0x2, -0x0, 0x0, 0x30001, 0x1, -0x30201, 0x0, 0x0, 0x1010101, -0x1010100, 0x10100, 0x1010001, 0x10001, -0x1000101, 0x101, 0x0, 0x0 }; diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 187ac6eb6e9..7709992bb6b 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -1813,6 +1813,25 @@ static void __devinit amd8111e_probe_ext_phy(struct net_device* dev) lp->ext_phy_addr = 1; } +static const struct net_device_ops amd8111e_netdev_ops = { + .ndo_open = amd8111e_open, + .ndo_stop = amd8111e_close, + .ndo_start_xmit = amd8111e_start_xmit, + .ndo_tx_timeout = amd8111e_tx_timeout, + .ndo_get_stats = amd8111e_get_stats, + .ndo_set_multicast_list = amd8111e_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = amd8111e_set_mac_address, + .ndo_do_ioctl = amd8111e_ioctl, + .ndo_change_mtu = amd8111e_change_mtu, +#if AMD8111E_VLAN_TAG_USED + .ndo_vlan_rx_register = amd8111e_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = amd8111e_poll, +#endif +}; + static int __devinit amd8111e_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1872,7 +1891,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ; - dev->vlan_rx_register =amd8111e_vlan_rx_register; #endif lp = netdev_priv(dev); @@ -1901,27 +1919,16 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, if(dynamic_ipg[card_idx++]) lp->options |= OPTION_DYN_IPG_ENABLE; + /* Initialize driver entry points */ - dev->open = amd8111e_open; - dev->hard_start_xmit = amd8111e_start_xmit; - dev->stop = amd8111e_close; - dev->get_stats = amd8111e_get_stats; - dev->set_multicast_list = amd8111e_set_multicast_list; - dev->set_mac_address = amd8111e_set_mac_address; - dev->do_ioctl = amd8111e_ioctl; - dev->change_mtu = amd8111e_change_mtu; + dev->netdev_ops = &amd8111e_netdev_ops; SET_ETHTOOL_OPS(dev, &ops); dev->irq =pdev->irq; - dev->tx_timeout = amd8111e_tx_timeout; dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; netif_napi_add(dev, &lp->napi, amd8111e_rx_poll, 32); -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = amd8111e_poll; -#endif #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register =amd8111e_vlan_rx_register; #endif /* Probe the external PHY */ amd8111e_probe_ext_phy(dev); diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 9a0be9b2eaa..da64ba88d7f 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -48,12 +48,18 @@ static int ipddp_mode = IPDDP_DECAP; /* Index to functions, as function prototypes. */ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev); -static struct net_device_stats *ipddp_get_stats(struct net_device *dev); static int ipddp_create(struct ipddp_route *new_rt); static int ipddp_delete(struct ipddp_route *rt); static struct ipddp_route* ipddp_find_route(struct ipddp_route *rt); static int ipddp_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); +static const struct net_device_ops ipddp_netdev_ops = { + .ndo_start_xmit = ipddp_xmit, + .ndo_do_ioctl = ipddp_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; static struct net_device * __init ipddp_init(void) { @@ -61,7 +67,7 @@ static struct net_device * __init ipddp_init(void) struct net_device *dev; int err; - dev = alloc_etherdev(sizeof(struct net_device_stats)); + dev = alloc_etherdev(0); if (!dev) return ERR_PTR(-ENOMEM); @@ -71,9 +77,7 @@ static struct net_device * __init ipddp_init(void) printk(version); /* Initalize the device structure. */ - dev->hard_start_xmit = ipddp_xmit; - dev->get_stats = ipddp_get_stats; - dev->do_ioctl = ipddp_ioctl; + dev->netdev_ops = &ipddp_netdev_ops; dev->type = ARPHRD_IPDDP; /* IP over DDP tunnel */ dev->mtu = 585; @@ -103,13 +107,6 @@ static struct net_device * __init ipddp_init(void) return dev; } -/* - * Get the current statistics. This may be called with the card open or closed. - */ -static struct net_device_stats *ipddp_get_stats(struct net_device *dev) -{ - return netdev_priv(dev); -} /* * Transmit LLAP/ELAP frame using aarp_send_ddp. @@ -170,8 +167,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - ((struct net_device_stats *) netdev_priv(dev))->tx_packets++; - ((struct net_device_stats *) netdev_priv(dev))->tx_bytes += skb->len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 6278606d104..745ac188bab 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -646,6 +646,7 @@ static const struct net_device_ops etherh_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_addr = eth_set_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index 9ad22d1b00f..1cf2f949c0b 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -1357,6 +1357,7 @@ static const struct net_device_ops ks8695_netdev_ops = { .ndo_start_xmit = ks8695_start_xmit, .ndo_tx_timeout = ks8695_timeout, .ndo_set_mac_address = ks8695_set_mac, + .ndo_validate_addr = eth_validate_addr, .ndo_set_multicast_list = ks8695_set_multicast, }; diff --git a/drivers/net/atp.c b/drivers/net/atp.c index ea493ce2398..4317b3edb3d 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -204,8 +204,7 @@ static irqreturn_t atp_interrupt(int irq, void *dev_id); static void net_rx(struct net_device *dev); static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode); static int net_close(struct net_device *dev); -static void set_rx_mode_8002(struct net_device *dev); -static void set_rx_mode_8012(struct net_device *dev); +static void set_rx_mode(struct net_device *dev); static void tx_timeout(struct net_device *dev); @@ -242,6 +241,17 @@ static int __init atp_init(void) return -ENODEV; } +static const struct net_device_ops atp_netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = atp_send_packet, + .ndo_set_multicast_list = set_rx_mode, + .ndo_tx_timeout = tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __init atp_probe1(long ioaddr) { struct net_device *dev = NULL; @@ -342,12 +352,7 @@ static int __init atp_probe1(long ioaddr) if (dev->mem_end & 0xf) net_debug = dev->mem_end & 7; - dev->open = net_open; - dev->stop = net_close; - dev->hard_start_xmit = atp_send_packet; - dev->set_multicast_list = - lp->chip_type == RTL8002 ? &set_rx_mode_8002 : &set_rx_mode_8012; - dev->tx_timeout = tx_timeout; + dev->netdev_ops = &atp_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; res = register_netdev(dev); @@ -903,6 +908,17 @@ static void set_rx_mode_8012(struct net_device *dev) write_reg(ioaddr, CMR2, CMR2_IRQOUT); /* Switch back to page 0 */ } +static void set_rx_mode(struct net_device *dev) +{ + struct net_local *lp = netdev_priv(dev); + + if (lp->chip_type == RTL8002) + return set_rx_mode_8002(dev); + else + return set_rx_mode_8012(dev); +} + + static int __init atp_init_module(void) { if (debug) /* Emit version even if no cards detected. */ printk(KERN_INFO "%s", version); diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 0e7470a201f..5ae131c147f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -73,8 +73,8 @@ (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP)) #define NEXT_TX(N) (((N) + 1) & (B44_TX_RING_SIZE - 1)) -#define RX_PKT_OFFSET 30 -#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET + 64) +#define RX_PKT_OFFSET (RX_HEADER_LEN + 2) +#define RX_PKT_BUF_SZ (1536 + RX_PKT_OFFSET) /* minimum number of free TX descriptors required to wake up TX process */ #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) @@ -682,7 +682,6 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) } rh = (struct rx_header *) skb->data; - skb_reserve(skb, RX_PKT_OFFSET); rh->len = 0; rh->flags = 0; @@ -693,13 +692,13 @@ static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked) if (src_map != NULL) src_map->skb = NULL; - ctrl = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - RX_PKT_OFFSET)); + ctrl = (DESC_CTRL_LEN & RX_PKT_BUF_SZ); if (dest_idx == (B44_RX_RING_SIZE - 1)) ctrl |= DESC_CTRL_EOT; dp = &bp->rx_ring[dest_idx]; dp->ctrl = cpu_to_le32(ctrl); - dp->addr = cpu_to_le32((u32) mapping + RX_PKT_OFFSET + bp->dma_offset); + dp->addr = cpu_to_le32((u32) mapping + bp->dma_offset); if (bp->flags & B44_FLAG_RX_RING_HACK) b44_sync_dma_desc_for_device(bp->sdev, bp->rx_ring_dma, @@ -809,8 +808,8 @@ static int b44_rx(struct b44 *bp, int budget) ssb_dma_unmap_single(bp->sdev, map, skb_size, DMA_FROM_DEVICE); /* Leave out rx_header */ - skb_put(skb, len + RX_PKT_OFFSET); - skb_pull(skb, RX_PKT_OFFSET); + skb_put(skb, len + RX_PKT_OFFSET); + skb_pull(skb, RX_PKT_OFFSET); } else { struct sk_buff *copy_skb; @@ -2108,6 +2107,22 @@ static int __devinit b44_get_invariants(struct b44 *bp) return err; } +static const struct net_device_ops b44_netdev_ops = { + .ndo_open = b44_open, + .ndo_stop = b44_close, + .ndo_start_xmit = b44_start_xmit, + .ndo_get_stats = b44_get_stats, + .ndo_set_multicast_list = b44_set_rx_mode, + .ndo_set_mac_address = b44_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = b44_ioctl, + .ndo_tx_timeout = b44_tx_timeout, + .ndo_change_mtu = b44_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = b44_poll_controller, +#endif +}; + static int __devinit b44_init_one(struct ssb_device *sdev, const struct ssb_device_id *ent) { @@ -2145,20 +2160,9 @@ static int __devinit b44_init_one(struct ssb_device *sdev, bp->rx_pending = B44_DEF_RX_RING_PENDING; bp->tx_pending = B44_DEF_TX_RING_PENDING; - dev->open = b44_open; - dev->stop = b44_close; - dev->hard_start_xmit = b44_start_xmit; - dev->get_stats = b44_get_stats; - dev->set_multicast_list = b44_set_rx_mode; - dev->set_mac_address = b44_set_mac_addr; - dev->do_ioctl = b44_ioctl; - dev->tx_timeout = b44_tx_timeout; + dev->netdev_ops = &b44_netdev_ops; netif_napi_add(dev, &bp->napi, b44_poll, 64); dev->watchdog_timeo = B44_TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = b44_poll_controller; -#endif - dev->change_mtu = b44_change_mtu; dev->irq = sdev->irq; SET_ETHTOOL_OPS(dev, &b44_ethtool_ops); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ef8103b3523..4be05847f86 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -8243,6 +8243,9 @@ static int bnx2x_set_eeprom(struct net_device *dev, struct bnx2x *bp = netdev_priv(dev); int rc; + if (!netif_running(dev)) + return -EAGAIN; + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 460c2cad275..9fb388388fb 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4148,7 +4148,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) bond_for_each_slave(bond, slave, i) { pr_debug("s %p s->p %p c_m %p\n", slave, - slave->prev, slave->dev->change_mtu); + slave->prev, slave->dev->netdev_ops->ndo_change_mtu); res = dev_set_mtu(slave->dev, new_mtu); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 321f43d9f0e..840b3d1a22f 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -4977,6 +4977,22 @@ static void __devinit cas_program_bridge(struct pci_dev *cas_pdev) pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xff); } +static const struct net_device_ops cas_netdev_ops = { + .ndo_open = cas_open, + .ndo_stop = cas_close, + .ndo_start_xmit = cas_start_xmit, + .ndo_get_stats = cas_get_stats, + .ndo_set_multicast_list = cas_set_multicast, + .ndo_do_ioctl = cas_ioctl, + .ndo_tx_timeout = cas_tx_timeout, + .ndo_change_mtu = cas_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cas_netpoll, +#endif +}; + static int __devinit cas_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -5166,22 +5182,13 @@ static int __devinit cas_init_one(struct pci_dev *pdev, for (i = 0; i < N_RX_FLOWS; i++) skb_queue_head_init(&cp->rx_flows[i]); - dev->open = cas_open; - dev->stop = cas_close; - dev->hard_start_xmit = cas_start_xmit; - dev->get_stats = cas_get_stats; - dev->set_multicast_list = cas_set_multicast; - dev->do_ioctl = cas_ioctl; + dev->netdev_ops = &cas_netdev_ops; dev->ethtool_ops = &cas_ethtool_ops; - dev->tx_timeout = cas_tx_timeout; dev->watchdog_timeo = CAS_TX_TIMEOUT; - dev->change_mtu = cas_change_mtu; + #ifdef USE_NAPI netif_napi_add(dev, &cp->napi, cas_poll, 64); #endif -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = cas_netpoll; -#endif dev->irq = pdev->irq; dev->dma = 0; diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index 5b346f9eaa8..a89d8cc5120 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -50,12 +50,17 @@ struct vlan_group; struct adapter; struct sge_qset; +enum { /* rx_offload flags */ + T3_RX_CSUM = 1 << 0, + T3_LRO = 1 << 1, +}; + struct port_info { struct adapter *adapter; struct vlan_group *vlan_grp; struct sge_qset *qs; u8 port_id; - u8 rx_csum_offload; + u8 rx_offload; u8 nqsets; u8 first_qset; struct cphy phy; diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 2847f947499..0089746b8d0 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -546,7 +546,7 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; ++j, ++qset_idx) { - set_qset_lro(dev, qset_idx, pi->rx_csum_offload); + set_qset_lro(dev, qset_idx, pi->rx_offload & T3_LRO); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, @@ -1657,17 +1657,19 @@ static u32 get_rx_csum(struct net_device *dev) { struct port_info *p = netdev_priv(dev); - return p->rx_csum_offload; + return p->rx_offload & T3_RX_CSUM; } static int set_rx_csum(struct net_device *dev, u32 data) { struct port_info *p = netdev_priv(dev); - p->rx_csum_offload = data; - if (!data) { + if (data) { + p->rx_offload |= T3_RX_CSUM; + } else { int i; + p->rx_offload &= ~(T3_RX_CSUM | T3_LRO); for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) set_qset_lro(dev, i, 0); } @@ -1830,15 +1832,18 @@ static int cxgb3_set_flags(struct net_device *dev, u32 data) int i; if (data & ETH_FLAG_LRO) { - if (!pi->rx_csum_offload) + if (!(pi->rx_offload & T3_RX_CSUM)) return -EINVAL; + pi->rx_offload |= T3_LRO; for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) set_qset_lro(dev, i, 1); - } else + } else { + pi->rx_offload &= ~T3_LRO; for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) set_qset_lro(dev, i, 0); + } return 0; } @@ -1926,7 +1931,7 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) pi = adap2pinfo(adapter, i); if (t.qset_idx >= pi->first_qset && t.qset_idx < pi->first_qset + pi->nqsets && - !pi->rx_csum_offload) + !(pi->rx_offload & T3_RX_CSUM)) return -EINVAL; } @@ -2946,7 +2951,7 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->port[i] = netdev; pi = netdev_priv(netdev); pi->adapter = adapter; - pi->rx_csum_offload = 1; + pi->rx_offload = T3_RX_CSUM | T3_LRO; pi->port_id = i; netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); @@ -2955,6 +2960,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->mem_end = mmio_start + mmio_len - 1; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; netdev->features |= NETIF_F_LLTX; + netdev->features |= NETIF_F_LRO; if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 6c641a88947..14f9fb3e879 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1932,7 +1932,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); pi = netdev_priv(skb->dev); - if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) && + if ((pi->rx_offload & T3_RX_CSUM) && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; diff --git a/drivers/net/de600.c b/drivers/net/de600.c index 970f820ba81..de63f1d41d3 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -378,6 +378,16 @@ static void de600_rx_intr(struct net_device *dev) */ } +static const struct net_device_ops de600_netdev_ops = { + .ndo_open = de600_open, + .ndo_stop = de600_close, + .ndo_start_xmit = de600_start_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + + static struct net_device * __init de600_probe(void) { int i; @@ -439,9 +449,7 @@ static struct net_device * __init de600_probe(void) printk(", Ethernet Address: %pM\n", dev->dev_addr); - dev->open = de600_open; - dev->stop = de600_close; - dev->hard_start_xmit = &de600_start_xmit; + dev->netdev_ops = &de600_netdev_ops; dev->flags&=~IFF_MULTICAST; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index bdfa8940338..d52f34cc952 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -784,6 +784,17 @@ static int adapter_init(struct net_device *dev) return 0; /* all ok */ } +static const struct net_device_ops de620_netdev_ops = { + .ndo_open = de620_open, + .ndo_stop = de620_close, + .ndo_start_xmit = de620_start_xmit, + .ndo_tx_timeout = de620_timeout, + .ndo_set_multicast_list = de620_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + /****************************************************************************** * * Only start-up code below @@ -861,12 +872,8 @@ struct net_device * __init de620_probe(int unit) else printk(" UTP)\n"); - dev->open = de620_open; - dev->stop = de620_close; - dev->hard_start_xmit = de620_start_xmit; - dev->tx_timeout = de620_timeout; + dev->netdev_ops = &de620_netdev_ops; dev->watchdog_timeo = HZ*2; - dev->set_multicast_list = de620_set_multicast_list; /* base_addr and irq are already set, see above! */ diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 134b2d60b47..86bb876fb12 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -161,6 +161,7 @@ #include <linux/skbuff.h> #include <linux/ethtool.h> #include <linux/string.h> +#include <linux/firmware.h> #include <asm/unaligned.h> @@ -174,10 +175,17 @@ #define E100_WATCHDOG_PERIOD (2 * HZ) #define E100_NAPI_WEIGHT 16 +#define FIRMWARE_D101M "e100/d101m_ucode.bin" +#define FIRMWARE_D101S "e100/d101s_ucode.bin" +#define FIRMWARE_D102E "e100/d102e_ucode.bin" + MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR(DRV_COPYRIGHT); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +MODULE_FIRMWARE(FIRMWARE_D101M); +MODULE_FIRMWARE(FIRMWARE_D101S); +MODULE_FIRMWARE(FIRMWARE_D102E); static int debug = 3; static int eeprom_bad_csum_allow = 0; @@ -1049,178 +1057,6 @@ static void e100_configure(struct nic *nic, struct cb *cb, struct sk_buff *skb) c[16], c[17], c[18], c[19], c[20], c[21], c[22], c[23]); } -/********************************************************/ -/* Micro code for 8086:1229 Rev 8 */ -/********************************************************/ - -/* Parameter values for the D101M B-step */ -#define D101M_CPUSAVER_TIMER_DWORD 78 -#define D101M_CPUSAVER_BUNDLE_DWORD 65 -#define D101M_CPUSAVER_MIN_SIZE_DWORD 126 - -#define D101M_B_RCVBUNDLE_UCODE \ -{\ -0x00550215, 0xFFFF0437, 0xFFFFFFFF, 0x06A70789, 0xFFFFFFFF, 0x0558FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380216, \ -0x0010009C, 0x00204056, 0x002380CC, 0x00380056, \ -0x0010009C, 0x00244C0B, 0x00000800, 0x00124818, \ -0x00380438, 0x00000000, 0x00140000, 0x00380555, \ -0x00308000, 0x00100662, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222C21, 0x000C0002, 0x00103093, \ -0x00380C7A, 0x00080000, 0x00103090, 0x00380C7A, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244C2D, 0x00010004, 0x00041000, \ -0x003A0437, 0x00044010, 0x0038078A, 0x00000000, \ -0x00100099, 0x00206C7A, 0x0010009C, 0x00244C48, \ -0x00130824, 0x000C0001, 0x00101213, 0x00260C75, \ -0x00041000, 0x00010004, 0x00130826, 0x000C0006, \ -0x002206A8, 0x0013C926, 0x00101313, 0x003806A8, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380C34, 0x00000000, 0x00000000, \ -0x0021155B, 0x00100099, 0x00206559, 0x0010009C, \ -0x00244559, 0x00130836, 0x000C0000, 0x00220C62, \ -0x000C0001, 0x00101B13, 0x00229C0E, 0x00210C0E, \ -0x00226C0E, 0x00216C0E, 0x0022FC0E, 0x00215C0E, \ -0x00214C0E, 0x00380555, 0x00010004, 0x00041000, \ -0x00278C67, 0x00040800, 0x00018100, 0x003A0437, \ -0x00130826, 0x000C0001, 0x00220559, 0x00101313, \ -0x00380559, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00130831, 0x0010090B, 0x00124813, \ -0x000CFF80, 0x002606AB, 0x00041000, 0x00010004, \ -0x003806A8, 0x00000000, 0x00000000, 0x00000000, \ -} - -/********************************************************/ -/* Micro code for 8086:1229 Rev 9 */ -/********************************************************/ - -/* Parameter values for the D101S */ -#define D101S_CPUSAVER_TIMER_DWORD 78 -#define D101S_CPUSAVER_BUNDLE_DWORD 67 -#define D101S_CPUSAVER_MIN_SIZE_DWORD 128 - -#define D101S_RCVBUNDLE_UCODE \ -{\ -0x00550242, 0xFFFF047E, 0xFFFFFFFF, 0x06FF0818, 0xFFFFFFFF, 0x05A6FFFF, \ -0x000C0001, 0x00101312, 0x000C0008, 0x00380243, \ -0x0010009C, 0x00204056, 0x002380D0, 0x00380056, \ -0x0010009C, 0x00244F8B, 0x00000800, 0x00124818, \ -0x0038047F, 0x00000000, 0x00140000, 0x003805A3, \ -0x00308000, 0x00100610, 0x00100561, 0x000E0408, \ -0x00134861, 0x000C0002, 0x00103093, 0x00308000, \ -0x00100624, 0x00100561, 0x000E0408, 0x00100861, \ -0x000C007E, 0x00222FA1, 0x000C0002, 0x00103093, \ -0x00380F90, 0x00080000, 0x00103090, 0x00380F90, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x0010009C, 0x00244FAD, 0x00010004, 0x00041000, \ -0x003A047E, 0x00044010, 0x00380819, 0x00000000, \ -0x00100099, 0x00206FFD, 0x0010009A, 0x0020AFFD, \ -0x0010009C, 0x00244FC8, 0x00130824, 0x000C0001, \ -0x00101213, 0x00260FF7, 0x00041000, 0x00010004, \ -0x00130826, 0x000C0006, 0x00220700, 0x0013C926, \ -0x00101313, 0x00380700, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00080600, 0x00101B10, 0x00050004, 0x00100826, \ -0x00101210, 0x00380FB6, 0x00000000, 0x00000000, \ -0x002115A9, 0x00100099, 0x002065A7, 0x0010009A, \ -0x0020A5A7, 0x0010009C, 0x002445A7, 0x00130836, \ -0x000C0000, 0x00220FE4, 0x000C0001, 0x00101B13, \ -0x00229F8E, 0x00210F8E, 0x00226F8E, 0x00216F8E, \ -0x0022FF8E, 0x00215F8E, 0x00214F8E, 0x003805A3, \ -0x00010004, 0x00041000, 0x00278FE9, 0x00040800, \ -0x00018100, 0x003A047E, 0x00130826, 0x000C0001, \ -0x002205A7, 0x00101313, 0x003805A7, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00130831, \ -0x0010090B, 0x00124813, 0x000CFF80, 0x00260703, \ -0x00041000, 0x00010004, 0x00380700 \ -} - -/********************************************************/ -/* Micro code for the 8086:1229 Rev F/10 */ -/********************************************************/ - -/* Parameter values for the D102 E-step */ -#define D102_E_CPUSAVER_TIMER_DWORD 42 -#define D102_E_CPUSAVER_BUNDLE_DWORD 54 -#define D102_E_CPUSAVER_MIN_SIZE_DWORD 46 - -#define D102_E_RCVBUNDLE_UCODE \ -{\ -0x007D028F, 0x0E4204F9, 0x14ED0C85, 0x14FA14E9, 0x0EF70E36, 0x1FFF1FFF, \ -0x00E014B9, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014BD, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014D5, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C1, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00E014C8, 0x00000000, 0x00000000, 0x00000000, \ -0x00200600, 0x00E014EE, 0x00000000, 0x00000000, \ -0x0030FF80, 0x00940E46, 0x00038200, 0x00102000, \ -0x00E00E43, 0x00000000, 0x00000000, 0x00000000, \ -0x00300006, 0x00E014FB, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00906E41, 0x00800E3C, 0x00E00E39, 0x00000000, \ -0x00906EFD, 0x00900EFD, 0x00E00EF8, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -0x00000000, 0x00000000, 0x00000000, 0x00000000, \ -} - -static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb) -{ -/* *INDENT-OFF* */ - static struct { - u32 ucode[UCODE_SIZE + 1]; - u8 mac; - u8 timer_dword; - u8 bundle_dword; - u8 min_size_dword; - } ucode_opts[] = { - { D101M_B_RCVBUNDLE_UCODE, - mac_82559_D101M, - D101M_CPUSAVER_TIMER_DWORD, - D101M_CPUSAVER_BUNDLE_DWORD, - D101M_CPUSAVER_MIN_SIZE_DWORD }, - { D101S_RCVBUNDLE_UCODE, - mac_82559_D101S, - D101S_CPUSAVER_TIMER_DWORD, - D101S_CPUSAVER_BUNDLE_DWORD, - D101S_CPUSAVER_MIN_SIZE_DWORD }, - { D102_E_RCVBUNDLE_UCODE, - mac_82551_F, - D102_E_CPUSAVER_TIMER_DWORD, - D102_E_CPUSAVER_BUNDLE_DWORD, - D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { D102_E_RCVBUNDLE_UCODE, - mac_82551_10, - D102_E_CPUSAVER_TIMER_DWORD, - D102_E_CPUSAVER_BUNDLE_DWORD, - D102_E_CPUSAVER_MIN_SIZE_DWORD }, - { {0}, 0, 0, 0, 0} - }, *opts; -/* *INDENT-ON* */ - /************************************************************************* * CPUSaver parameters * @@ -1280,42 +1116,101 @@ static void e100_setup_ucode(struct nic *nic, struct cb *cb, struct sk_buff *skb #define BUNDLEMAX (u16)6 #define INTDELAY (u16)1536 /* 0x600 */ +/* Initialize firmware */ +static const struct firmware *e100_request_firmware(struct nic *nic) +{ + const char *fw_name; + const struct firmware *fw; + u8 timer, bundle, min_size; + int err; + /* do not load u-code for ICH devices */ if (nic->flags & ich) - goto noloaducode; + return NULL; /* Search for ucode match against h/w revision */ - for (opts = ucode_opts; opts->mac; opts++) { - int i; - u32 *ucode = opts->ucode; - if (nic->mac != opts->mac) - continue; - - /* Insert user-tunable settings */ - ucode[opts->timer_dword] &= 0xFFFF0000; - ucode[opts->timer_dword] |= INTDELAY; - ucode[opts->bundle_dword] &= 0xFFFF0000; - ucode[opts->bundle_dword] |= BUNDLEMAX; - ucode[opts->min_size_dword] &= 0xFFFF0000; - ucode[opts->min_size_dword] |= (BUNDLESMALL) ? 0xFFFF : 0xFF80; - - for (i = 0; i < UCODE_SIZE; i++) - cb->u.ucode[i] = cpu_to_le32(ucode[i]); - cb->command = cpu_to_le16(cb_ucode | cb_el); - return; - } - -noloaducode: - cb->command = cpu_to_le16(cb_nop | cb_el); -} - -static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, - void (*cb_prepare)(struct nic *, struct cb *, struct sk_buff *)) -{ + if (nic->mac == mac_82559_D101M) + fw_name = FIRMWARE_D101M; + else if (nic->mac == mac_82559_D101S) + fw_name = FIRMWARE_D101S; + else if (nic->mac == mac_82551_F || nic->mac == mac_82551_10) + fw_name = FIRMWARE_D102E; + else /* No ucode on other devices */ + return NULL; + + err = request_firmware(&fw, fw_name, &nic->pdev->dev); + if (err) { + DPRINTK(PROBE, ERR, "Failed to load firmware \"%s\": %d\n", + fw_name, err); + return ERR_PTR(err); + } + /* Firmware should be precisely UCODE_SIZE (words) plus three bytes + indicating the offsets for BUNDLESMALL, BUNDLEMAX, INTDELAY */ + if (fw->size != UCODE_SIZE * 4 + 3) { + DPRINTK(PROBE, ERR, "Firmware \"%s\" has wrong size %zu\n", + fw_name, fw->size); + release_firmware(fw); + return ERR_PTR(-EINVAL); + } + + /* Read timer, bundle and min_size from end of firmware blob */ + timer = fw->data[UCODE_SIZE * 4]; + bundle = fw->data[UCODE_SIZE * 4 + 1]; + min_size = fw->data[UCODE_SIZE * 4 + 2]; + + if (timer >= UCODE_SIZE || bundle >= UCODE_SIZE || + min_size >= UCODE_SIZE) { + DPRINTK(PROBE, ERR, + "\"%s\" has bogus offset values (0x%x,0x%x,0x%x)\n", + fw_name, timer, bundle, min_size); + release_firmware(fw); + return ERR_PTR(-EINVAL); + } + /* OK, firmware is validated and ready to use... */ + return fw; +} + +static void e100_setup_ucode(struct nic *nic, struct cb *cb, + struct sk_buff *skb) +{ + const struct firmware *fw = (void *)skb; + u8 timer, bundle, min_size; + + /* It's not a real skb; we just abused the fact that e100_exec_cb + will pass it through to here... */ + cb->skb = NULL; + + /* firmware is stored as little endian already */ + memcpy(cb->u.ucode, fw->data, UCODE_SIZE * 4); + + /* Read timer, bundle and min_size from end of firmware blob */ + timer = fw->data[UCODE_SIZE * 4]; + bundle = fw->data[UCODE_SIZE * 4 + 1]; + min_size = fw->data[UCODE_SIZE * 4 + 2]; + + /* Insert user-tunable settings in cb->u.ucode */ + cb->u.ucode[timer] &= cpu_to_le32(0xFFFF0000); + cb->u.ucode[timer] |= cpu_to_le32(INTDELAY); + cb->u.ucode[bundle] &= cpu_to_le32(0xFFFF0000); + cb->u.ucode[bundle] |= cpu_to_le32(BUNDLEMAX); + cb->u.ucode[min_size] &= cpu_to_le32(0xFFFF0000); + cb->u.ucode[min_size] |= cpu_to_le32((BUNDLESMALL) ? 0xFFFF : 0xFF80); + + cb->command = cpu_to_le16(cb_ucode | cb_el); +} + +static inline int e100_load_ucode_wait(struct nic *nic) +{ + const struct firmware *fw; int err = 0, counter = 50; struct cb *cb = nic->cb_to_clean; - if ((err = e100_exec_cb(nic, NULL, e100_setup_ucode))) + fw = e100_request_firmware(nic); + /* If it's NULL, then no ucode is required */ + if (!fw || IS_ERR(fw)) + return PTR_ERR(fw); + + if ((err = e100_exec_cb(nic, (void *)fw, e100_setup_ucode))) DPRINTK(PROBE,ERR, "ucode cmd failed with error %d\n", err); /* must restart cuc */ @@ -1435,7 +1330,7 @@ static int e100_hw_init(struct nic *nic) return err; if ((err = e100_exec_cmd(nic, ruc_load_base, 0))) return err; - if ((err = e100_exec_cb_wait(nic, NULL, e100_setup_ucode))) + if ((err = e100_load_ucode_wait(nic))) return err; if ((err = e100_exec_cb(nic, NULL, e100_configure))) return err; diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index f2a5963b5a9..e415e81ecd3 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -390,7 +390,8 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) } static DEFINE_MUTEX(nvm_mutex); -static pid_t nvm_owner = -1; +static pid_t nvm_owner_pid = -1; +static char nvm_owner_name[TASK_COMM_LEN] = ""; /** * e1000_acquire_swflag_ich8lan - Acquire software control flag @@ -408,11 +409,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) might_sleep(); if (!mutex_trylock(&nvm_mutex)) { - WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n", - nvm_owner); + WARN(1, KERN_ERR "e1000e mutex contention. Owned by process " + "%s (pid %d), required by process %s (pid %d)\n", + nvm_owner_name, nvm_owner_pid, + current->comm, current->pid); + mutex_lock(&nvm_mutex); } - nvm_owner = current->pid; + nvm_owner_pid = current->pid; + strncpy(nvm_owner_name, current->comm, TASK_COMM_LEN); while (timeout) { extcnf_ctrl = er32(EXTCNF_CTRL); @@ -430,7 +435,8 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) hw_dbg(hw, "FW or HW has locked the resource for too long.\n"); extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ew32(EXTCNF_CTRL, extcnf_ctrl); - nvm_owner = -1; + nvm_owner_pid = -1; + strcpy(nvm_owner_name, ""); mutex_unlock(&nvm_mutex); return -E1000_ERR_CONFIG; } @@ -454,7 +460,8 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw) extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; ew32(EXTCNF_CTRL, extcnf_ctrl); - nvm_owner = -1; + nvm_owner_pid = -1; + strcpy(nvm_owner_name, ""); mutex_unlock(&nvm_mutex); } diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index 20eb05cddb8..b07ba1924de 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -169,6 +169,7 @@ static const struct net_device_ops e21_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 2a33a613d9e..8fe9dcaa753 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -214,7 +214,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, u64 *qp_handle, struct h_epas *h_epas) { u64 hret; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; u64 allocate_controls = EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0) @@ -312,7 +312,7 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, u64 *cq_handle, struct h_epas *epas) { u64 hret; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, outs, @@ -374,7 +374,7 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, struct ehea_eq_attr *eq_attr, u64 *eq_handle) { u64 hret, allocate_controls; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; /* resource type */ allocate_controls = @@ -407,7 +407,7 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat, u16 *out_swr, u16 *out_rwr) { u64 hret; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP, outs, @@ -449,7 +449,7 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle, struct ehea_mr *mr) { u64 hret; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; hret = ehea_plpar_hcall9(H_REGISTER_SMR, outs, @@ -468,7 +468,7 @@ u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle, u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) { - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA, outs, @@ -493,7 +493,7 @@ u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u32 pd, u64 *mr_handle, u32 *lkey) { u64 hret; - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, outs, @@ -564,7 +564,7 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 outs[PLPAR_HCALL9_BUFSIZE]; + unsigned long outs[PLPAR_HCALL9_BUFSIZE]; u64 port_info; u64 arr_index = 0; u64 cb_logaddr = virt_to_abs(cb_addr); diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index cefe1d98f93..fc6cc038c7b 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -1531,6 +1531,17 @@ static int enc28j60_chipset_init(struct net_device *dev) return enc28j60_hw_init(priv); } +static const struct net_device_ops enc28j60_netdev_ops = { + .ndo_open = enc28j60_net_open, + .ndo_stop = enc28j60_net_close, + .ndo_start_xmit = enc28j60_send_packet, + .ndo_set_multicast_list = enc28j60_set_multicast_list, + .ndo_set_mac_address = enc28j60_set_mac_address, + .ndo_tx_timeout = enc28j60_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit enc28j60_probe(struct spi_device *spi) { struct net_device *dev; @@ -1585,12 +1596,7 @@ static int __devinit enc28j60_probe(struct spi_device *spi) dev->if_port = IF_PORT_10BASET; dev->irq = spi->irq; - dev->open = enc28j60_net_open; - dev->stop = enc28j60_net_close; - dev->hard_start_xmit = enc28j60_send_packet; - dev->set_multicast_list = &enc28j60_set_multicast_list; - dev->set_mac_address = enc28j60_set_mac_address; - dev->tx_timeout = &enc28j60_tx_timeout; + dev->netdev_ops = &enc28j60_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; SET_ETHTOOL_OPS(dev, &enc28j60_ethtool_ops); diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index d039e16f276..7d60551d538 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -1599,6 +1599,7 @@ static const struct net_device_ops enic_netdev_ops = { .ndo_start_xmit = enic_hard_start_xmit, .ndo_get_stats = enic_get_stats, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_set_multicast_list = enic_set_multicast_list, .ndo_change_mtu = enic_change_mtu, .ndo_vlan_rx_register = enic_vlan_rx_register, diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f9b37c80dda..a539bc3163c 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -308,7 +308,18 @@ static int epic_close(struct net_device *dev); static struct net_device_stats *epic_get_stats(struct net_device *dev); static void set_rx_mode(struct net_device *dev); - +static const struct net_device_ops epic_netdev_ops = { + .ndo_open = epic_open, + .ndo_stop = epic_close, + .ndo_start_xmit = epic_start_xmit, + .ndo_tx_timeout = epic_tx_timeout, + .ndo_get_stats = epic_get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; static int __devinit epic_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -483,15 +494,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, dev->if_port = ep->default_port = option; /* The Epic-specific entries in the device structure. */ - dev->open = &epic_open; - dev->hard_start_xmit = &epic_start_xmit; - dev->stop = &epic_close; - dev->get_stats = &epic_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &epic_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->tx_timeout = &epic_tx_timeout; netif_napi_add(dev, &ep->napi, epic_poll, 64); ret = register_netdev(dev); diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 31ab1ff623f..daf7272c335 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -467,6 +467,18 @@ static void stop_nic_rxtx(void __iomem *ioaddr, long crvalue) } } +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_do_ioctl = mii_ioctl, + .ndo_tx_timeout = fealnx_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; static int __devinit fealnx_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -649,15 +661,8 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, np->mii.force_media = 1; } - /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &mii_ioctl; + dev->netdev_ops = &netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &fealnx_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; err = register_netdev(dev); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 5b68dc20168..5b910cf6374 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -13,7 +13,7 @@ * Copyright (C) 2004 Andrew de Quincey (wol support) * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane * IRQ rate fixes, bigendian fixes, cleanups, verification) - * Copyright (c) 2004,2005,2006,2007,2008 NVIDIA Corporation + * Copyright (c) 2004,2005,2006,2007,2008,2009 NVIDIA 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 @@ -39,7 +39,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.61" +#define FORCEDETH_VERSION "0.62" #define DRV_NAME "forcedeth" #include <linux/module.h> @@ -2096,14 +2096,15 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } + spin_lock_irqsave(&np->lock, flags); empty_slots = nv_get_empty_tx_slots(np); if (unlikely(empty_slots <= entries)) { - spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); np->tx_stop = 1; spin_unlock_irqrestore(&np->lock, flags); return NETDEV_TX_BUSY; } + spin_unlock_irqrestore(&np->lock, flags); start_tx = put_tx = np->put_tx.orig; @@ -2214,14 +2215,15 @@ static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev) ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } + spin_lock_irqsave(&np->lock, flags); empty_slots = nv_get_empty_tx_slots(np); if (unlikely(empty_slots <= entries)) { - spin_lock_irqsave(&np->lock, flags); netif_stop_queue(dev); np->tx_stop = 1; spin_unlock_irqrestore(&np->lock, flags); return NETDEV_TX_BUSY; } + spin_unlock_irqrestore(&np->lock, flags); start_tx = put_tx = np->put_tx.ex; start_tx_ctx = np->put_tx_ctx; @@ -3403,10 +3405,10 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { + spin_lock(&np->lock); netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ - spin_lock(&np->lock); np->irqmask &= ~NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) @@ -3520,10 +3522,10 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { + spin_lock(&np->lock); netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ - spin_lock(&np->lock); np->irqmask &= ~NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) @@ -6167,19 +6169,19 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, {0,}, }; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c672ecfc959..efcbeb6c867 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -238,8 +238,8 @@ static int gfar_of_init(struct net_device *dev) goto err_out; } - snprintf(priv->phy_bus_id, BUS_ID_SIZE, PHY_ID_FMT, "0", - fixed_link[0]); + snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), + PHY_ID_FMT, "0", fixed_link[0]); } else { phy = of_find_node_by_phandle(*ph); @@ -256,7 +256,7 @@ static int gfar_of_init(struct net_device *dev) of_node_put(mdio); gfar_mdio_bus_name(bus_name, mdio); - snprintf(priv->phy_bus_id, BUS_ID_SIZE, "%s:%02x", + snprintf(priv->phy_bus_id, sizeof(priv->phy_bus_id), "%s:%02x", bus_name, *id); } @@ -296,6 +296,20 @@ err_out: return err; } +/* Ioctl MII Interface */ +static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct gfar_private *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!priv->phydev) + return -ENODEV; + + return phy_mii_ioctl(priv->phydev, if_mii(rq), cmd); +} + /* Set up the ethernet device structure, private data, * and anything else we need before we start */ static int gfar_probe(struct of_device *ofdev, @@ -366,6 +380,7 @@ static int gfar_probe(struct of_device *ofdev, dev->set_multicast_list = gfar_set_multi; dev->ethtool_ops = &gfar_ethtool_ops; + dev->do_ioctl = gfar_ioctl; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; @@ -1973,6 +1988,8 @@ static void adjust_link(struct net_device *dev) case 1000: tempval = ((tempval & ~(MACCFG2_IF)) | MACCFG2_GMII); + + ecntrl &= ~(ECNTRL_R100); break; case 100: case 10: diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 32200227c92..7e8b3c59a7d 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -576,6 +576,7 @@ static const struct net_device_ops hamachi_netdev_ops = { .ndo_set_multicast_list = set_rx_mode, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_tx_timeout = hamachi_tx_timeout, .ndo_do_ioctl = netdev_ioctl, }; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 50f1e172ee8..2d4089894ec 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -717,11 +717,12 @@ static int sixpack_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct sixpack *sp = sp_get(tty); - struct net_device *dev = sp->dev; + struct net_device *dev; unsigned int tmp, err; if (!sp) return -ENXIO; + dev = sp->dev; switch(cmd) { case SIOCGIFNAME: diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index b507dbc16e6..5e070f44663 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -166,6 +166,7 @@ static const struct net_device_ops hpp_netdev_ops = { .ndo_get_stats = eip_get_stats, .ndo_set_multicast_list = eip_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = eip_poll, diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index ebe7651fcb8..ad8be7e7829 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -425,6 +425,28 @@ struct net_device * __init hp100_probe(int unit) } #endif /* !MODULE && CONFIG_ISA */ +static const struct net_device_ops hp100_bm_netdev_ops = { + .ndo_open = hp100_open, + .ndo_stop = hp100_close, + .ndo_start_xmit = hp100_start_xmit_bm, + .ndo_get_stats = hp100_get_stats, + .ndo_set_multicast_list = hp100_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + +static const struct net_device_ops hp100_netdev_ops = { + .ndo_open = hp100_open, + .ndo_stop = hp100_close, + .ndo_start_xmit = hp100_start_xmit, + .ndo_get_stats = hp100_get_stats, + .ndo_set_multicast_list = hp100_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit hp100_probe1(struct net_device *dev, int ioaddr, u_char bus, struct pci_dev *pci_dev) { @@ -657,16 +679,10 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr, lp->virt_memory_size = virt_memory_size; lp->rx_ratio = hp100_rx_ratio; /* can be conf'd with insmod */ - dev->open = hp100_open; - dev->stop = hp100_close; - if (lp->mode == 1) /* busmaster */ - dev->hard_start_xmit = hp100_start_xmit_bm; + dev->netdev_ops = &hp100_bm_netdev_ops; else - dev->hard_start_xmit = hp100_start_xmit; - - dev->get_stats = hp100_get_stats; - dev->set_multicast_list = &hp100_set_multicast_list; + dev->netdev_ops = &hp100_netdev_ops; /* Ask the card for which IRQ line it is configured */ if (bus == HP100_BUS_PCI) { diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 9cb38a8d438..8ac0930c183 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -103,6 +103,7 @@ static const struct net_device_ops hydra_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 9bc0f178f24..ca3bb9f7321 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -754,7 +754,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, void (*done) (struct net_device *, u32)) { struct ibmveth_adapter *adapter = netdev_priv(dev); - u64 set_attr, clr_attr, ret_attr; + unsigned long set_attr, clr_attr, ret_attr; long ret; int rc1 = 0, rc2 = 0; int restart = 0; @@ -1209,7 +1209,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ long ret; struct net_device *netdev; struct ibmveth_adapter *adapter; - u64 set_attr, ret_attr; + unsigned long set_attr, ret_attr; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; diff --git a/drivers/net/ibmveth.h b/drivers/net/ibmveth.h index d2818694875..ec76ace66c6 100644 --- a/drivers/net/ibmveth.h +++ b/drivers/net/ibmveth.h @@ -39,11 +39,11 @@ #define IbmVethMcastRemoveFilter 0x2UL #define IbmVethMcastClearFilterTable 0x3UL -#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000ULL -#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00ULL -#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004ULL -#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002ULL -#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001ULL +#define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL +#define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL +#define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL +#define IBMVETH_ILLAN_IPV4_TCP_CSUM 0x0000000000000002UL +#define IBMVETH_ILLAN_ACTIVE_TRUNK 0x0000000000000001UL /* hcall macros */ #define h_register_logical_lan(ua, buflst, rxq, fltlst, mac) \ diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 7b6d435a846..360aa5e35fd 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -2210,6 +2210,19 @@ static void __devexit ipg_remove(struct pci_dev *pdev) pci_set_drvdata(pdev, NULL); } +static const struct net_device_ops ipg_netdev_ops = { + .ndo_open = ipg_nic_open, + .ndo_stop = ipg_nic_stop, + .ndo_start_xmit = ipg_nic_hard_start_xmit, + .ndo_get_stats = ipg_nic_get_stats, + .ndo_set_multicast_list = ipg_nic_set_multicast_list, + .ndo_do_ioctl = ipg_ioctl, + .ndo_tx_timeout = ipg_tx_timeout, + .ndo_change_mtu = ipg_nic_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit ipg_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -2258,15 +2271,7 @@ static int __devinit ipg_probe(struct pci_dev *pdev, /* Declare IPG NIC functions for Ethernet device methods. */ - dev->open = &ipg_nic_open; - dev->stop = &ipg_nic_stop; - dev->hard_start_xmit = &ipg_nic_hard_start_xmit; - dev->get_stats = &ipg_nic_get_stats; - dev->set_multicast_list = &ipg_nic_set_multicast_list; - dev->do_ioctl = ipg_ioctl; - dev->tx_timeout = ipg_tx_timeout; - dev->change_mtu = &ipg_nic_change_mtu; - + dev->netdev_ops = &ipg_netdev_ops; SET_NETDEV_DEV(dev, &pdev->dev); SET_ETHTOOL_OPS(dev, &ipg_ethtool_ops); diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 3c58e67ef1e..17779f9bffc 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -109,7 +109,6 @@ static int ali_ircc_net_open(struct net_device *dev); static int ali_ircc_net_close(struct net_device *dev); static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud); -static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev); /* SIR function */ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev); @@ -366,7 +365,6 @@ static int ali_ircc_open(int i, chipio_t *info) dev->open = ali_ircc_net_open; dev->stop = ali_ircc_net_close; dev->do_ioctl = ali_ircc_net_ioctl; - dev->get_stats = ali_ircc_net_get_stats; err = register_netdev(dev); if (err) { @@ -876,7 +874,7 @@ static void ali_ircc_sir_receive(struct ali_ircc_cb *self) * async_unwrap_char will deliver all found frames */ do { - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, inb(iobase+UART_RX)); /* Make sure we don't stay here too long */ @@ -943,7 +941,7 @@ static void ali_ircc_sir_write_wakeup(struct ali_ircc_cb *self) netif_wake_queue(self->netdev); } - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; /* Turn on receive interrupts */ outb(UART_IER_RDI, iobase+UART_IER); @@ -1467,7 +1465,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; self->tx_fifo.tail += skb->len; - self->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); @@ -1661,12 +1659,12 @@ static int ali_ircc_dma_xmit_complete(struct ali_ircc_cb *self) { IRDA_ERROR("%s(), ********* LSR_FRAME_ABORT *********\n", __func__); - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; } else { - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; } /* Check if we need to change the speed */ @@ -1831,35 +1829,35 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) IRDA_DEBUG(0,"%s(), ************* RX Errors ************ \n", __func__ ); /* Skip frame */ - self->stats.rx_errors++; + self->netdev->stats.rx_errors++; self->rx_buff.data += len; if (status & LSR_FIFO_UR) { - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* FIFO Errors ************ \n", __func__ ); } if (status & LSR_FRAME_ERROR) { - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* FRAME Errors ************ \n", __func__ ); } if (status & LSR_CRC_ERROR) { - self->stats.rx_crc_errors++; + self->netdev->stats.rx_crc_errors++; IRDA_DEBUG(0,"%s(), ************* CRC Errors ************ \n", __func__ ); } if(self->rcvFramesOverflow) { - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ************* Overran DMA buffer ************ \n", __func__ ); } if(len == 0) { - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; IRDA_DEBUG(0,"%s(), ********** Receive Frame Size = 0 ********* \n", __func__ ); } } @@ -1910,7 +1908,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) IRDA_WARNING("%s(), memory squeeze, " "dropping frame.\n", __func__); - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; return FALSE; } @@ -1924,8 +1922,8 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) /* Move to next frame */ self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); @@ -1994,7 +1992,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->stats.tx_bytes += self->tx_buff.len; + self->netdev->stats.tx_bytes += self->tx_buff.len; /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); @@ -2111,17 +2109,6 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) return status; } -static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev) -{ - struct ali_ircc_cb *self = netdev_priv(dev); - - IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); - - IRDA_DEBUG(2, "%s(), ----------------- End ------------------\n", __func__ ); - - return &self->stats; -} - static int ali_ircc_suspend(struct platform_device *dev, pm_message_t state) { struct ali_ircc_cb *self = platform_get_drvdata(dev); diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h index ed35d99763d..0c8edb41bd0 100644 --- a/drivers/net/irda/ali-ircc.h +++ b/drivers/net/irda/ali-ircc.h @@ -191,7 +191,6 @@ struct ali_ircc_cb { struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; /* QoS capabilities for this device */ diff --git a/drivers/net/irda/au1000_ircc.h b/drivers/net/irda/au1000_ircc.h index b4763f24dde..c072c09a8d9 100644 --- a/drivers/net/irda/au1000_ircc.h +++ b/drivers/net/irda/au1000_ircc.h @@ -107,7 +107,6 @@ struct au1k_private { iobuff_t rx_buff; struct net_device *netdev; - struct net_device_stats stats; struct timeval stamp; struct timeval now; diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index 6c4b53ffbca..941164076a2 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -53,7 +53,6 @@ static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *); static int au1k_irda_rx(struct net_device *); static void au1k_irda_interrupt(int, void *); static void au1k_tx_timeout(struct net_device *); -static struct net_device_stats *au1k_irda_stats(struct net_device *); static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int); static int au1k_irda_set_speed(struct net_device *dev, int speed); @@ -213,7 +212,6 @@ static int au1k_irda_net_init(struct net_device *dev) dev->open = au1k_irda_start; dev->hard_start_xmit = au1k_irda_hard_xmit; dev->stop = au1k_irda_stop; - dev->get_stats = au1k_irda_stats; dev->do_ioctl = au1k_irda_ioctl; dev->tx_timeout = au1k_tx_timeout; @@ -596,7 +594,7 @@ static int au1k_irda_rx(struct net_device *dev) update_rx_stats(dev, flags, count); skb=alloc_skb(count+1,GFP_ATOMIC); if (skb == NULL) { - aup->stats.rx_dropped++; + aup->netdev->stats.rx_dropped++; continue; } skb_reserve(skb, 1); @@ -832,13 +830,6 @@ au1k_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } - -static struct net_device_stats *au1k_irda_stats(struct net_device *dev) -{ - struct au1k_private *aup = netdev_priv(dev); - return &aup->stats; -} - MODULE_AUTHOR("Pete Popov <ppopov@mvista.com>"); MODULE_DESCRIPTION("Au1000 IrDA Device Driver"); diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 687c2d53d4d..6f3e7f71658 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1194,13 +1194,13 @@ toshoboe_interrupt (int irq, void *dev_id) txp = txpc; txpc++; txpc %= TX_SLOTS; - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; if (self->ring->tx[txpc].control & OBOE_CTL_TX_HW_OWNS) self->ring->tx[txp].control &= ~OBOE_CTL_TX_RTCENTX; } - self->stats.tx_packets--; + self->netdev->stats.tx_packets--; #else - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; #endif toshoboe_start_DMA(self, OBOE_CONFIG0H_ENTX); } @@ -1280,7 +1280,7 @@ dumpbufs(self->rx_bufs[self->rxs],len,'<'); skb_put (skb, len); skb_copy_to_linear_data(skb, self->rx_bufs[self->rxs], len); - self->stats.rx_packets++; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); skb->protocol = htons (ETH_P_IRDA); diff --git a/drivers/net/irda/donauboe.h b/drivers/net/irda/donauboe.h index 1e67720f106..0dbd1932b72 100644 --- a/drivers/net/irda/donauboe.h +++ b/drivers/net/irda/donauboe.h @@ -308,7 +308,6 @@ struct OboeRing struct toshoboe_cb { struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct tty_driver ttydev; struct irlap_cb *irlap; /* The link layer we are binded to */ diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 205e4e825a9..29118f58a14 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -122,7 +122,6 @@ static int irda_usb_net_open(struct net_device *dev); static int irda_usb_net_close(struct net_device *dev); static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static void irda_usb_net_timeout(struct net_device *dev); -static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev); /************************ TRANSMIT ROUTINES ************************/ /* @@ -525,13 +524,13 @@ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) /* Ask USB to send the packet - Irq disabled -> GFP_ATOMIC */ if ((res = usb_submit_urb(urb, GFP_ATOMIC))) { IRDA_WARNING("%s(), failed Tx URB\n", __func__); - self->stats.tx_errors++; + netdev->stats.tx_errors++; /* Let USB recover : We will catch that in the watchdog */ /*netif_start_queue(netdev);*/ } else { /* Increment packet stats */ - self->stats.tx_packets++; - self->stats.tx_bytes += skb->len; + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; netdev->trans_start = jiffies; } @@ -677,7 +676,7 @@ static void irda_usb_net_timeout(struct net_device *netdev) IRDA_DEBUG(0, "%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, urb->status, urb->transfer_flags); /* Increase error count */ - self->stats.tx_errors++; + netdev->stats.tx_errors++; #ifdef IU_BUG_KICK_TIMEOUT /* Can't be a bad idea to reset the speed ;-) - Jean II */ @@ -826,7 +825,7 @@ static void irda_usb_receive(struct urb *urb) if (urb->status != 0) { switch (urb->status) { case -EILSEQ: - self->stats.rx_crc_errors++; + self->netdev->stats.rx_crc_errors++; /* Also precursor to a hot-unplug on UHCI. */ /* Fallthrough... */ case -ECONNRESET: @@ -839,7 +838,7 @@ static void irda_usb_receive(struct urb *urb) case -ETIME: /* Usually precursor to a hot-unplug on OHCI. */ default: - self->stats.rx_errors++; + self->netdev->stats.rx_errors++; IRDA_DEBUG(0, "%s(), RX status %d, transfer_flags 0x%04X \n", __func__, urb->status, urb->transfer_flags); break; } @@ -890,7 +889,7 @@ static void irda_usb_receive(struct urb *urb) IRDA_SKB_MAX_MTU); if (!newskb) { - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; /* We could deliver the current skb, but this would stall * the Rx path. Better drop the packet... Jean II */ goto done; @@ -927,8 +926,8 @@ static void irda_usb_receive(struct urb *urb) netif_rx(dataskb); /* Keep stats up to date */ - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; done: /* Note : at this point, the URB we've just received (urb) @@ -1342,14 +1341,6 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) } /*------------------------------------------------------------------*/ -/* - * Get device stats (for /proc/net/dev and ifconfig) - */ -static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) -{ - struct irda_usb_cb *self = netdev_priv(dev); - return &self->stats; -} /********************* IRDA CONFIG SUBROUTINES *********************/ /* @@ -1428,7 +1419,6 @@ static inline int irda_usb_open(struct irda_usb_cb *self) netdev->watchdog_timeo = 250*HZ/1000; /* 250 ms > USB timeout */ netdev->open = irda_usb_net_open; netdev->stop = irda_usb_net_close; - netdev->get_stats = irda_usb_net_get_stats; netdev->do_ioctl = irda_usb_net_ioctl; return register_netdev(netdev); diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h index a0ca9c1fe19..ac0443d52e5 100644 --- a/drivers/net/irda/irda-usb.h +++ b/drivers/net/irda/irda-usb.h @@ -152,7 +152,6 @@ struct irda_usb_cb { struct urb *speed_urb; /* URB used to send speed commands */ struct net_device *netdev; /* Yes! we are some kind of netdev. */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; char *speed_buff; /* Buffer for speed changes */ diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index c747c874d44..b4a61717254 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -105,7 +105,7 @@ struct kingsun_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ - struct net_device_stats stats; /* network statistics */ + struct qos_info qos; __u8 *in_buf; /* receive buffer */ @@ -186,12 +186,12 @@ static int kingsun_hard_xmit(struct sk_buff *skb, struct net_device *netdev) case -EPIPE: break; default: - kingsun->stats.tx_errors++; + netdev->stats.tx_errors++; netif_start_queue(netdev); } } else { - kingsun->stats.tx_packets++; - kingsun->stats.tx_bytes += skb->len; + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; } dev_kfree_skb(skb); @@ -232,7 +232,7 @@ static void kingsun_rcv_irq(struct urb *urb) if (bytes[0] >= 1 && bytes[0] < kingsun->max_rx) { for (i = 1; i <= bytes[0]; i++) { async_unwrap_char(kingsun->netdev, - &kingsun->stats, + &kingsun->netdev->stats, &kingsun->rx_buff, bytes[i]); } do_gettimeofday(&kingsun->rx_time); @@ -418,15 +418,6 @@ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq, return ret; } -/* - * Get device stats (for /proc/net/dev and ifconfig) - */ -static struct net_device_stats * -kingsun_net_get_stats(struct net_device *netdev) -{ - struct kingsun_cb *kingsun = netdev_priv(netdev); - return &kingsun->stats; -} /* * This routine is called by the USB subsystem for each new device @@ -532,7 +523,6 @@ static int kingsun_probe(struct usb_interface *intf, net->hard_start_xmit = kingsun_hard_xmit; net->open = kingsun_net_open; net->stop = kingsun_net_close; - net->get_stats = kingsun_net_get_stats; net->do_ioctl = kingsun_net_ioctl; ret = register_netdev(net); diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 600d96f9cdb..55322fb92cf 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -174,7 +174,7 @@ struct ks959_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ - struct net_device_stats stats; /* network statistics */ + struct qos_info qos; struct usb_ctrlrequest *tx_setuprequest; @@ -366,7 +366,7 @@ static void ks959_send_irq(struct urb *urb) case -EPIPE: break; default: - kingsun->stats.tx_errors++; + netdev->stats.tx_errors++; netif_start_queue(netdev); } } @@ -416,12 +416,12 @@ static int ks959_hard_xmit(struct sk_buff *skb, struct net_device *netdev) case -EPIPE: break; default: - kingsun->stats.tx_errors++; + netdev->stats.tx_errors++; netif_start_queue(netdev); } } else { - kingsun->stats.tx_packets++; - kingsun->stats.tx_bytes += skb->len; + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; } @@ -469,7 +469,7 @@ static void ks959_rcv_irq(struct urb *urb) */ if (kingsun->rx_variable_xormask != 0) { async_unwrap_char(kingsun->netdev, - &kingsun->stats, + &kingsun->netdev->stats, &kingsun->rx_unwrap_buff, bytes[i]); } @@ -669,15 +669,6 @@ static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) } /* - * Get device stats (for /proc/net/dev and ifconfig) - */ -static struct net_device_stats *ks959_net_get_stats(struct net_device *netdev) -{ - struct ks959_cb *kingsun = netdev_priv(netdev); - return &kingsun->stats; -} - -/* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. @@ -792,7 +783,6 @@ static int ks959_probe(struct usb_interface *intf, net->hard_start_xmit = ks959_hard_xmit; net->open = ks959_net_open; net->stop = ks959_net_close; - net->get_stats = ks959_net_get_stats; net->do_ioctl = ks959_net_ioctl; ret = register_netdev(net); diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 0e7f89337b2..5b327b09acd 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -140,7 +140,7 @@ struct ksdazzle_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ - struct net_device_stats stats; /* network statistics */ + struct qos_info qos; struct urb *tx_urb; @@ -278,7 +278,7 @@ static void ksdazzle_send_irq(struct urb *urb) case -EPIPE: break; default: - kingsun->stats.tx_errors++; + netdev->stats.tx_errors++; netif_start_queue(netdev); } } @@ -329,12 +329,12 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) case -EPIPE: break; default: - kingsun->stats.tx_errors++; + netdev->stats.tx_errors++; netif_start_queue(netdev); } } else { - kingsun->stats.tx_packets++; - kingsun->stats.tx_bytes += skb->len; + netdev->stats.tx_packets++; + netdev->stats.tx_bytes += skb->len; } @@ -348,9 +348,10 @@ static int ksdazzle_hard_xmit(struct sk_buff *skb, struct net_device *netdev) static void ksdazzle_rcv_irq(struct urb *urb) { struct ksdazzle_cb *kingsun = urb->context; + struct net_device *netdev = kingsun->netdev; /* in process of stopping, just drop data */ - if (!netif_running(kingsun->netdev)) { + if (!netif_running(netdev)) { kingsun->receiving = 0; return; } @@ -368,7 +369,7 @@ static void ksdazzle_rcv_irq(struct urb *urb) unsigned int i; for (i = 0; i < urb->actual_length; i++) { - async_unwrap_char(kingsun->netdev, &kingsun->stats, + async_unwrap_char(netdev, &netdev->stats, &kingsun->rx_unwrap_buff, bytes[i]); } kingsun->receiving = @@ -562,16 +563,6 @@ static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq, } /* - * Get device stats (for /proc/net/dev and ifconfig) - */ -static struct net_device_stats *ksdazzle_net_get_stats(struct net_device - *netdev) -{ - struct ksdazzle_cb *kingsun = netdev_priv(netdev); - return &kingsun->stats; -} - -/* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. @@ -696,7 +687,6 @@ static int ksdazzle_probe(struct usb_interface *intf, net->hard_start_xmit = ksdazzle_hard_xmit; net->open = ksdazzle_net_open; net->stop = ksdazzle_net_close; - net->get_stats = ksdazzle_net_get_stats; net->do_ioctl = ksdazzle_net_ioctl; ret = register_netdev(net); diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index 904c9610c0d..7eafdca19f3 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -403,8 +403,8 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) if(unlikely(new_len <= 0)) { IRDA_ERROR("%s short frame length %d\n", mcs->netdev->name, new_len); - ++mcs->stats.rx_errors; - ++mcs->stats.rx_length_errors; + ++mcs->netdev->stats.rx_errors; + ++mcs->netdev->stats.rx_length_errors; return; } fcs = 0; @@ -413,14 +413,14 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) if(fcs != GOOD_FCS) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); - mcs->stats.rx_errors++; - mcs->stats.rx_crc_errors++; + mcs->netdev->stats.rx_errors++; + mcs->netdev->stats.rx_crc_errors++; return; } skb = dev_alloc_skb(new_len + 1); if(unlikely(!skb)) { - ++mcs->stats.rx_dropped; + ++mcs->netdev->stats.rx_dropped; return; } @@ -433,8 +433,8 @@ static void mcs_unwrap_mir(struct mcs_cb *mcs, __u8 *buf, int len) netif_rx(skb); - mcs->stats.rx_packets++; - mcs->stats.rx_bytes += new_len; + mcs->netdev->stats.rx_packets++; + mcs->netdev->stats.rx_bytes += new_len; return; } @@ -458,22 +458,22 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) if(unlikely(new_len <= 0)) { IRDA_ERROR("%s short frame length %d\n", mcs->netdev->name, new_len); - ++mcs->stats.rx_errors; - ++mcs->stats.rx_length_errors; + ++mcs->netdev->stats.rx_errors; + ++mcs->netdev->stats.rx_length_errors; return; } fcs = ~(crc32_le(~0, buf, new_len)); if(fcs != get_unaligned_le32(buf + new_len)) { IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len); - mcs->stats.rx_errors++; - mcs->stats.rx_crc_errors++; + mcs->netdev->stats.rx_errors++; + mcs->netdev->stats.rx_crc_errors++; return; } skb = dev_alloc_skb(new_len + 1); if(unlikely(!skb)) { - ++mcs->stats.rx_dropped; + ++mcs->netdev->stats.rx_dropped; return; } @@ -486,8 +486,8 @@ static void mcs_unwrap_fir(struct mcs_cb *mcs, __u8 *buf, int len) netif_rx(skb); - mcs->stats.rx_packets++; - mcs->stats.rx_bytes += new_len; + mcs->netdev->stats.rx_packets++; + mcs->netdev->stats.rx_bytes += new_len; return; } @@ -756,14 +756,6 @@ static int mcs_net_open(struct net_device *netdev) return ret; } - -/* Get device stats for /proc/net/dev and ifconfig */ -static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev) -{ - struct mcs_cb *mcs = netdev_priv(netdev); - return &mcs->stats; -} - /* Receive callback function. */ static void mcs_receive_irq(struct urb *urb) { @@ -786,14 +778,14 @@ static void mcs_receive_irq(struct urb *urb) */ /* SIR speed */ if(mcs->speed < 576000) { - async_unwrap_char(mcs->netdev, &mcs->stats, + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, &mcs->rx_buff, 0xc0); for (i = 0; i < urb->actual_length; i++) - async_unwrap_char(mcs->netdev, &mcs->stats, + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, &mcs->rx_buff, bytes[i]); - async_unwrap_char(mcs->netdev, &mcs->stats, + async_unwrap_char(mcs->netdev, &mcs->netdev->stats, &mcs->rx_buff, 0xc1); } /* MIR speed */ @@ -868,12 +860,12 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev) case -EPIPE: break; default: - mcs->stats.tx_errors++; + mcs->netdev->stats.tx_errors++; netif_start_queue(ndev); } } else { - mcs->stats.tx_packets++; - mcs->stats.tx_bytes += skb->len; + mcs->netdev->stats.tx_packets++; + mcs->netdev->stats.tx_bytes += skb->len; } dev_kfree_skb(skb); @@ -931,7 +923,6 @@ static int mcs_probe(struct usb_interface *intf, ndev->hard_start_xmit = mcs_hard_xmit; ndev->open = mcs_net_open; ndev->stop = mcs_net_close; - ndev->get_stats = mcs_net_get_stats; ndev->do_ioctl = mcs_net_ioctl; if (!intf->cur_altsetting) diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h index b18148cee63..6bdc621e67c 100644 --- a/drivers/net/irda/mcs7780.h +++ b/drivers/net/irda/mcs7780.h @@ -104,7 +104,6 @@ struct mcs_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ - struct net_device_stats stats; /* network statistics */ struct qos_info qos; unsigned int speed; /* Current speed */ unsigned int new_speed; /* new speed */ @@ -154,7 +153,6 @@ static int mcs_speed_change(struct mcs_cb *mcs); static int mcs_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd); static int mcs_net_close(struct net_device *netdev); static int mcs_net_open(struct net_device *netdev); -static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev); static void mcs_receive_irq(struct urb *urb); static void mcs_send_irq(struct urb *urb); diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 2c6bf2d11bb..61e509cb712 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -185,7 +185,6 @@ static void nsc_ircc_init_dongle_interface (int iobase, int dongle_id); static int nsc_ircc_net_open(struct net_device *dev); static int nsc_ircc_net_close(struct net_device *dev); static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); /* Globals */ static int pnp_registered; @@ -446,7 +445,6 @@ static int __init nsc_ircc_open(chipio_t *info) dev->open = nsc_ircc_net_open; dev->stop = nsc_ircc_net_close; dev->do_ioctl = nsc_ircc_net_ioctl; - dev->get_stats = nsc_ircc_net_get_stats; err = register_netdev(dev); if (err) { @@ -1401,7 +1399,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->stats.tx_bytes += self->tx_buff.len; + dev->stats.tx_bytes += self->tx_buff.len; /* Add interrupt on tx low level (will fire immediately) */ switch_bank(iobase, BANK0); @@ -1473,7 +1471,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; self->tx_fifo.tail += skb->len; - self->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); @@ -1652,13 +1650,13 @@ static int nsc_ircc_dma_xmit_complete(struct nsc_ircc_cb *self) /* Check for underrrun! */ if (inb(iobase+ASCR) & ASCR_TXUR) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; /* Clear bit, by writing 1 into it */ outb(ASCR_TXUR, iobase+ASCR); } else { - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; } /* Finished with this frame, so prepare for next */ @@ -1793,28 +1791,28 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) if (status & FRM_ST_ERR_MSK) { if (status & FRM_ST_LOST_FR) { /* Add number of lost frames to stats */ - self->stats.rx_errors += len; + self->netdev->stats.rx_errors += len; } else { /* Skip frame */ - self->stats.rx_errors++; + self->netdev->stats.rx_errors++; self->rx_buff.data += len; if (status & FRM_ST_MAX_LEN) - self->stats.rx_length_errors++; + self->netdev->stats.rx_length_errors++; if (status & FRM_ST_PHY_ERR) - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; if (status & FRM_ST_BAD_CRC) - self->stats.rx_crc_errors++; + self->netdev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ if (status & FRM_ST_OVR1) - self->stats.rx_fifo_errors++; + self->netdev->stats.rx_fifo_errors++; if (status & FRM_ST_OVR2) - self->stats.rx_fifo_errors++; + self->netdev->stats.rx_fifo_errors++; } else { /* * First we must make sure that the frame we @@ -1863,7 +1861,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) IRDA_WARNING("%s(), memory squeeze, " "dropping frame.\n", __func__); - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; /* Restore bank register */ outb(bank, iobase+BSR); @@ -1889,8 +1887,8 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) /* Move to next frame */ self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); @@ -1920,8 +1918,8 @@ static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self) /* Receive all characters in Rx FIFO */ do { byte = inb(iobase+RXD); - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, - byte); + async_unwrap_char(self->netdev, &self->netdev->stats, + &self->rx_buff, byte); } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ } @@ -1952,7 +1950,7 @@ static void nsc_ircc_sir_interrupt(struct nsc_ircc_cb *self, int eir) self->ier = IER_TXLDL_IE; else { - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; netif_wake_queue(self->netdev); self->ier = IER_TXEMP_IE; } @@ -2307,13 +2305,6 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return ret; } -static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) -{ - struct nsc_ircc_cb *self = netdev_priv(dev); - - return &self->stats; -} - static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state) { struct nsc_ircc_cb *self = platform_get_drvdata(dev); diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 71cd3c5a076..7ba7738759b 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -251,7 +251,6 @@ struct nsc_ircc_cb { struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; /* QoS capabilities for this device */ diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 004a9aab3a5..31794c2363e 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -108,7 +108,6 @@ struct pxa_irda { int txdma; int rxdma; - struct net_device_stats stats; struct irlap_cb *irlap; struct qos_info qos; @@ -258,14 +257,15 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) data = STRBR; if (lsr & (LSR_OE | LSR_PE | LSR_FE | LSR_BI)) { printk(KERN_DEBUG "pxa_ir: sir receiving error\n"); - si->stats.rx_errors++; + dev->stats.rx_errors++; if (lsr & LSR_FE) - si->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (lsr & LSR_OE) - si->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else { - si->stats.rx_bytes++; - async_unwrap_char(dev, &si->stats, &si->rx_buff, data); + dev->stats.rx_bytes++; + async_unwrap_char(dev, &dev->stats, + &si->rx_buff, data); } lsr = STLSR; } @@ -277,8 +277,8 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) case 0x0C: /* Character Timeout Indication */ do { - si->stats.rx_bytes++; - async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); + dev->stats.rx_bytes++; + async_unwrap_char(dev, &dev->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); si->last_oscr = OSCR; break; @@ -290,9 +290,8 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) } if (si->tx_buff.len == 0) { - si->stats.tx_packets++; - si->stats.tx_bytes += si->tx_buff.data - - si->tx_buff.head; + dev->stats.tx_packets++; + dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; /* We need to ensure that the transmitter has finished. */ while ((STLSR & LSR_TEMT) == 0) @@ -343,10 +342,10 @@ static void pxa_irda_fir_dma_tx_irq(int channel, void *data) DCSR(channel) = dcsr & ~DCSR_RUN; if (dcsr & DCSR_ENDINTR) { - si->stats.tx_packets++; - si->stats.tx_bytes += si->dma_tx_buff_len; + dev->stats.tx_packets++; + dev->stats.tx_bytes += si->dma_tx_buff_len; } else { - si->stats.tx_errors++; + dev->stats.tx_errors++; } while (ICSR1 & ICSR1_TBY) @@ -392,14 +391,14 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in data = ICDR; if (stat & (ICSR1_CRE | ICSR1_ROR)) { - si->stats.rx_errors++; + dev->stats.rx_errors++; if (stat & ICSR1_CRE) { printk(KERN_DEBUG "pxa_ir: fir receive CRC error\n"); - si->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; } if (stat & ICSR1_ROR) { printk(KERN_DEBUG "pxa_ir: fir receive overrun\n"); - si->stats.rx_over_errors++; + dev->stats.rx_over_errors++; } } else { si->dma_rx_buff[len++] = data; @@ -415,14 +414,14 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in if (icsr0 & ICSR0_FRE) { printk(KERN_ERR "pxa_ir: dropping erroneous frame\n"); - si->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } skb = alloc_skb(len+1,GFP_ATOMIC); if (!skb) { printk(KERN_ERR "pxa_ir: fir out of memory for receive skb\n"); - si->stats.rx_dropped++; + dev->stats.rx_dropped++; return; } @@ -437,8 +436,8 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - si->stats.rx_packets++; - si->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; } } @@ -457,10 +456,10 @@ static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id) if (icsr0 & (ICSR0_FRE | ICSR0_RAB)) { if (icsr0 & ICSR0_FRE) { printk(KERN_DEBUG "pxa_ir: fir receive frame error\n"); - si->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; } else { printk(KERN_DEBUG "pxa_ir: fir receive abort\n"); - si->stats.rx_errors++; + dev->stats.rx_errors++; } ICSR0 = icsr0 & (ICSR0_FRE | ICSR0_RAB); } @@ -589,12 +588,6 @@ static int pxa_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } -static struct net_device_stats *pxa_irda_stats(struct net_device *dev) -{ - struct pxa_irda *si = netdev_priv(dev); - return &si->stats; -} - static void pxa_irda_startup(struct pxa_irda *si) { /* Disable STUART interrupts */ @@ -857,7 +850,6 @@ static int pxa_irda_probe(struct platform_device *pdev) dev->open = pxa_irda_start; dev->stop = pxa_irda_stop; dev->do_ioctl = pxa_irda_ioctl; - dev->get_stats = pxa_irda_stats; irda_init_max_qos_capabilies(&si->qos); diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index d302bcf4c14..7a2b003954c 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -60,7 +60,6 @@ struct sa1100_irda { dma_regs_t *txdma; dma_regs_t *rxdma; - struct net_device_stats stats; struct device *dev; struct irda_platform_data *pdata; struct irlap_cb *irlap; @@ -375,13 +374,13 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) data = Ser2UTDR; if (stat & (UTSR1_FRE | UTSR1_ROR)) { - si->stats.rx_errors++; + dev->stats.rx_errors++; if (stat & UTSR1_FRE) - si->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; if (stat & UTSR1_ROR) - si->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; } else - async_unwrap_char(dev, &si->stats, &si->rx_buff, data); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, data); status = Ser2UTSR0; } @@ -396,9 +395,9 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) * There are at least 4 bytes in the FIFO. Read 3 bytes * and leave the rest to the block below. */ - async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR); - async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR); - async_unwrap_char(dev, &si->stats, &si->rx_buff, Ser2UTDR); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); } if (status & (UTSR0_RFS | UTSR0_RID)) { @@ -406,7 +405,7 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) * Fifo contains more than 1 character. */ do { - async_unwrap_char(dev, &si->stats, &si->rx_buff, + async_unwrap_char(dev, &dev->stats, &si->rx_buff, Ser2UTDR); } while (Ser2UTSR1 & UTSR1_RNE); @@ -422,8 +421,8 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) } while (Ser2UTSR1 & UTSR1_TNF && si->tx_buff.len); if (si->tx_buff.len == 0) { - si->stats.tx_packets++; - si->stats.tx_bytes += si->tx_buff.data - + dev->stats.tx_packets++; + dev->stats.tx_bytes += si->tx_buff.data - si->tx_buff.head; /* @@ -482,11 +481,11 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev data = Ser2HSDR; if (stat & (HSSR1_CRE | HSSR1_ROR)) { - si->stats.rx_errors++; + dev->stats.rx_errors++; if (stat & HSSR1_CRE) - si->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (stat & HSSR1_ROR) - si->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; } else skb->data[len++] = data; @@ -505,8 +504,8 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev skb->dev = dev; skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); - si->stats.rx_packets++; - si->stats.rx_bytes += len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; /* * Before we pass the buffer up, allocate a new one. @@ -545,10 +544,10 @@ static void sa1100_irda_fir_irq(struct net_device *dev) * from the fifo. */ if (Ser2HSSR0 & (HSSR0_FRE | HSSR0_RAB)) { - si->stats.rx_errors++; + dev->stats.rx_errors++; if (Ser2HSSR0 & HSSR0_FRE) - si->stats.rx_frame_errors++; + dev->stats.rx_frame_errors++; /* * Clear out the DMA... @@ -633,8 +632,8 @@ static void sa1100_irda_txdma_irq(void *id) */ if (skb) { dma_unmap_single(si->dev, si->txbuf_dma, skb->len, DMA_TO_DEVICE); - si->stats.tx_packets ++; - si->stats.tx_bytes += skb->len; + dev->stats.tx_packets ++; + dev->stats.tx_bytes += skb->len; dev_kfree_skb_irq(skb); } @@ -762,12 +761,6 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) return ret; } -static struct net_device_stats *sa1100_irda_stats(struct net_device *dev) -{ - struct sa1100_irda *si = netdev_priv(dev); - return &si->stats; -} - static int sa1100_irda_start(struct net_device *dev) { struct sa1100_irda *si = netdev_priv(dev); @@ -924,7 +917,6 @@ static int sa1100_irda_probe(struct platform_device *pdev) dev->open = sa1100_irda_start; dev->stop = sa1100_irda_stop; dev->do_ioctl = sa1100_irda_ioctl; - dev->get_stats = sa1100_irda_stats; dev->irq = IRQ_Ser2ICP; irda_init_max_qos_capabilies(&si->qos); diff --git a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h index 2a57bc67ce3..6d5b1e2b128 100644 --- a/drivers/net/irda/sir-dev.h +++ b/drivers/net/irda/sir-dev.h @@ -160,7 +160,6 @@ static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode) struct sir_dev { struct net_device *netdev; - struct net_device_stats stats; struct irlap_cb *irlap; diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index ceef040aa76..5b5862499de 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -455,8 +455,8 @@ void sirdev_write_complete(struct sir_dev *dev) if ((skb=dev->tx_skb) != NULL) { dev->tx_skb = NULL; dev_kfree_skb_any(skb); - dev->stats.tx_errors++; - dev->stats.tx_dropped++; + dev->netdev->stats.tx_errors++; + dev->netdev->stats.tx_dropped++; } dev->tx_buff.len = 0; } @@ -493,8 +493,8 @@ void sirdev_write_complete(struct sir_dev *dev) if ((skb=dev->tx_skb) != NULL) { dev->tx_skb = NULL; - dev->stats.tx_packets++; - dev->stats.tx_bytes += skb->len; + dev->netdev->stats.tx_packets++; + dev->netdev->stats.tx_bytes += skb->len; dev_kfree_skb_any(skb); } @@ -548,7 +548,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) * just update stats and set media busy */ irda_device_set_media_busy(dev->netdev, TRUE); - dev->stats.rx_dropped++; + dev->netdev->stats.rx_dropped++; IRDA_DEBUG(0, "%s; rx-drop: %zd\n", __func__, count); return 0; } @@ -557,7 +557,7 @@ int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) if (likely(atomic_read(&dev->enable_rx))) { while (count--) /* Unwrap and destuff one byte */ - async_unwrap_char(dev->netdev, &dev->stats, + async_unwrap_char(dev->netdev, &dev->netdev->stats, &dev->rx_buff, *cp++); } else { while (count--) { @@ -582,13 +582,6 @@ EXPORT_SYMBOL(sirdev_receive); /* callbacks from network layer */ -static struct net_device_stats *sirdev_get_stats(struct net_device *ndev) -{ - struct sir_dev *dev = netdev_priv(ndev); - - return (dev) ? &dev->stats : NULL; -} - static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) { struct sir_dev *dev = netdev_priv(ndev); @@ -654,7 +647,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) */ atomic_set(&dev->enable_rx, 0); if (unlikely(sirdev_is_receiving(dev))) - dev->stats.collisions++; + dev->netdev->stats.collisions++; actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len); @@ -669,8 +662,8 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) IRDA_ERROR("%s: drv->do_write failed (%d)\n", __func__, actual); dev_kfree_skb_any(skb); - dev->stats.tx_errors++; - dev->stats.tx_dropped++; + dev->netdev->stats.tx_errors++; + dev->netdev->stats.tx_dropped++; netif_wake_queue(ndev); } spin_unlock_irqrestore(&dev->tx_lock, flags); @@ -918,7 +911,6 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n ndev->hard_start_xmit = sirdev_hard_xmit; ndev->open = sirdev_open; ndev->stop = sirdev_close; - ndev->get_stats = sirdev_get_stats; ndev->do_ioctl = sirdev_ioctl; if (register_netdev(ndev)) { diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index 5d09e157e15..dd73cce1099 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -150,7 +150,6 @@ struct smsc_chip_address { /* Private data for each instance */ struct smsc_ircc_cb { struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ chipio_t io; /* IrDA controller information */ @@ -215,7 +214,6 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cm #if SMSC_IRCC2_C_NET_TIMEOUT static void smsc_ircc_timeout(struct net_device *dev); #endif -static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev); static int smsc_ircc_is_receiving(struct smsc_ircc_cb *self); static void smsc_ircc_probe_transceiver(struct smsc_ircc_cb *self); static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 speed); @@ -529,7 +527,6 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u dev->open = smsc_ircc_net_open; dev->stop = smsc_ircc_net_close; dev->do_ioctl = smsc_ircc_net_ioctl; - dev->get_stats = smsc_ircc_net_get_stats; self = netdev_priv(dev); self->netdev = dev; @@ -834,13 +831,6 @@ static int smsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd return ret; } -static struct net_device_stats *smsc_ircc_net_get_stats(struct net_device *dev) -{ - struct smsc_ircc_cb *self = netdev_priv(dev); - - return &self->stats; -} - #if SMSC_IRCC2_C_NET_TIMEOUT /* * Function smsc_ircc_timeout (struct net_device *dev) @@ -920,7 +910,7 @@ static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->stats.tx_bytes += self->tx_buff.len; + dev->stats.tx_bytes += self->tx_buff.len; /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, self->io.sir_base + UART_IER); @@ -1320,16 +1310,16 @@ static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self) /* Check for underrun! */ register_bank(iobase, 0); if (inb(iobase + IRCC_LSR) & IRCC_LSR_UNDERRUN) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; /* Reset error condition */ register_bank(iobase, 0); outb(IRCC_MASTER_ERROR_RESET, iobase + IRCC_MASTER); outb(0x00, iobase + IRCC_MASTER); } else { - self->stats.tx_packets++; - self->stats.tx_bytes += self->tx_buff.len; + self->netdev->stats.tx_packets++; + self->netdev->stats.tx_bytes += self->tx_buff.len; } /* Check if it's time to change the speed */ @@ -1429,15 +1419,15 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) /* Look for errors */ if (lsr & (IRCC_LSR_FRAME_ERROR | IRCC_LSR_CRC_ERROR | IRCC_LSR_SIZE_ERROR)) { - self->stats.rx_errors++; + self->netdev->stats.rx_errors++; if (lsr & IRCC_LSR_FRAME_ERROR) - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; if (lsr & IRCC_LSR_CRC_ERROR) - self->stats.rx_crc_errors++; + self->netdev->stats.rx_crc_errors++; if (lsr & IRCC_LSR_SIZE_ERROR) - self->stats.rx_length_errors++; + self->netdev->stats.rx_length_errors++; if (lsr & (IRCC_LSR_UNDERRUN | IRCC_LSR_OVERRUN)) - self->stats.rx_length_errors++; + self->netdev->stats.rx_length_errors++; return; } @@ -1460,8 +1450,8 @@ static void smsc_ircc_dma_receive_complete(struct smsc_ircc_cb *self) skb_reserve(skb, 1); memcpy(skb_put(skb, len), self->rx_buff.data, len); - self->stats.rx_packets++; - self->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; skb->dev = self->netdev; skb_reset_mac_header(skb); @@ -1489,7 +1479,7 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self) * async_unwrap_char will deliver all found frames */ do { - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, inb(iobase + UART_RX)); /* Make sure we don't stay here to long */ @@ -1992,7 +1982,7 @@ static void smsc_ircc_sir_write_wakeup(struct smsc_ircc_cb *self) /* Tell network layer that we want more frames */ netif_wake_queue(self->netdev); } - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; if (self->io.speed <= 115200) { /* diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index ca4cd9266e5..8b1658c6c92 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -164,7 +164,7 @@ struct stir_cb { struct usb_device *usbdev; /* init: probe_irda */ struct net_device *netdev; /* network layer */ struct irlap_cb *irlap; /* The link layer we are binded to */ - struct net_device_stats stats; /* network statistics */ + struct qos_info qos; unsigned speed; /* Current speed */ @@ -323,16 +323,16 @@ static void fir_eof(struct stir_cb *stir) pr_debug("%s: short frame len %d\n", stir->netdev->name, len); - ++stir->stats.rx_errors; - ++stir->stats.rx_length_errors; + ++stir->netdev->stats.rx_errors; + ++stir->netdev->stats.rx_length_errors; return; } fcs = ~(crc32_le(~0, rx_buff->data, len)); if (fcs != get_unaligned_le32(rx_buff->data + len)) { pr_debug("crc error calc 0x%x len %d\n", fcs, len); - stir->stats.rx_errors++; - stir->stats.rx_crc_errors++; + stir->netdev->stats.rx_errors++; + stir->netdev->stats.rx_crc_errors++; return; } @@ -340,7 +340,7 @@ static void fir_eof(struct stir_cb *stir) if (len < IRDA_RX_COPY_THRESHOLD) { nskb = dev_alloc_skb(len + 1); if (unlikely(!nskb)) { - ++stir->stats.rx_dropped; + ++stir->netdev->stats.rx_dropped; return; } skb_reserve(nskb, 1); @@ -349,7 +349,7 @@ static void fir_eof(struct stir_cb *stir) } else { nskb = dev_alloc_skb(rx_buff->truesize); if (unlikely(!nskb)) { - ++stir->stats.rx_dropped; + ++stir->netdev->stats.rx_dropped; return; } skb_reserve(nskb, 1); @@ -366,8 +366,8 @@ static void fir_eof(struct stir_cb *stir) netif_rx(skb); - stir->stats.rx_packets++; - stir->stats.rx_bytes += len; + stir->netdev->stats.rx_packets++; + stir->netdev->stats.rx_bytes += len; rx_buff->data = rx_buff->head; rx_buff->len = 0; @@ -437,7 +437,7 @@ static void stir_fir_chars(struct stir_cb *stir, if (unlikely(rx_buff->len >= rx_buff->truesize)) { pr_debug("%s: fir frame exceeds %d\n", stir->netdev->name, rx_buff->truesize); - ++stir->stats.rx_over_errors; + ++stir->netdev->stats.rx_over_errors; goto error_recovery; } @@ -445,10 +445,10 @@ static void stir_fir_chars(struct stir_cb *stir, continue; frame_error: - ++stir->stats.rx_frame_errors; + ++stir->netdev->stats.rx_frame_errors; error_recovery: - ++stir->stats.rx_errors; + ++stir->netdev->stats.rx_errors; rx_buff->state = OUTSIDE_FRAME; rx_buff->in_frame = FALSE; } @@ -461,7 +461,7 @@ static void stir_sir_chars(struct stir_cb *stir, int i; for (i = 0; i < len; i++) - async_unwrap_char(stir->netdev, &stir->stats, + async_unwrap_char(stir->netdev, &stir->netdev->stats, &stir->rx_buff, bytes[i]); } @@ -692,7 +692,7 @@ static void receive_stop(struct stir_cb *stir) usb_kill_urb(stir->rx_urb); if (stir->rx_buff.in_frame) - stir->stats.collisions++; + stir->netdev->stats.collisions++; } /* * Wrap data in socket buffer and send it. @@ -718,15 +718,15 @@ static void stir_send(struct stir_cb *stir, struct sk_buff *skb) if (!first_frame) fifo_txwait(stir, wraplen); - stir->stats.tx_packets++; - stir->stats.tx_bytes += skb->len; + stir->netdev->stats.tx_packets++; + stir->netdev->stats.tx_bytes += skb->len; stir->netdev->trans_start = jiffies; pr_debug("send %d (%d)\n", skb->len, wraplen); if (usb_bulk_msg(stir->usbdev, usb_sndbulkpipe(stir->usbdev, 1), stir->io_buf, wraplen, NULL, TRANSMIT_TIMEOUT)) - stir->stats.tx_errors++; + stir->netdev->stats.tx_errors++; } /* @@ -1008,15 +1008,6 @@ static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) } /* - * Get device stats (for /proc/net/dev and ifconfig) - */ -static struct net_device_stats *stir_net_get_stats(struct net_device *netdev) -{ - struct stir_cb *stir = netdev_priv(netdev); - return &stir->stats; -} - -/* * This routine is called by the USB subsystem for each new device * in the system. We need to check if the device is ours, and in * this case start handling it. @@ -1066,7 +1057,6 @@ static int stir_probe(struct usb_interface *intf, net->hard_start_xmit = stir_hard_xmit; net->open = stir_net_open; net->stop = stir_net_close; - net->get_stats = stir_net_get_stats; net->do_ioctl = stir_net_ioctl; ret = register_netdev(net); diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 74c78cf7a33..8b3e545924c 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -101,8 +101,6 @@ static int via_ircc_net_open(struct net_device *dev); static int via_ircc_net_close(struct net_device *dev); static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *via_ircc_net_get_stats(struct net_device - *dev); static void via_ircc_change_dongle_speed(int iobase, int speed, int dongle_id); static int RxTimerHandler(struct via_ircc_cb *self, int iobase); @@ -434,7 +432,6 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) dev->open = via_ircc_net_open; dev->stop = via_ircc_net_close; dev->do_ioctl = via_ircc_net_ioctl; - dev->get_stats = via_ircc_net_get_stats; err = register_netdev(dev); if (err) @@ -855,7 +852,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, async_wrap_skb(skb, self->tx_buff.data, self->tx_buff.truesize); - self->stats.tx_bytes += self->tx_buff.len; + dev->stats.tx_bytes += self->tx_buff.len; /* Send this frame with old speed */ SetBaudRate(iobase, self->io.speed); SetPulseWidth(iobase, 12); @@ -921,7 +918,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, self->tx_fifo.queue[self->tx_fifo.free].len = skb->len; self->tx_fifo.tail += skb->len; - self->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; skb_copy_from_linear_data(skb, self->tx_fifo.queue[self->tx_fifo.free].start, skb->len); self->tx_fifo.len++; @@ -990,12 +987,12 @@ static int via_ircc_dma_xmit_complete(struct via_ircc_cb *self) /* Clear bit, by writing 1 into it */ Tx_status = GetTXStatus(iobase); if (Tx_status & 0x08) { - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; hwreset(self); // how to clear underrrun ? } else { - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; ResetChip(iobase, 3); ResetChip(iobase, 4); } @@ -1119,8 +1116,8 @@ static int via_ircc_dma_receive_complete(struct via_ircc_cb *self, } // Move to next frame self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); @@ -1180,7 +1177,7 @@ F01_E */ */ if ((skb == NULL) || (skb->data == NULL) || (self->rx_buff.data == NULL) || (len < 6)) { - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; return TRUE; } skb_reserve(skb, 1); @@ -1192,8 +1189,8 @@ F01_E */ // Move to next frame self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); @@ -1220,13 +1217,13 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase) IRDA_DEBUG(2, "%s(): len=%x\n", __func__, len); if ((len - 4) < 2) { - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; return FALSE; } skb = dev_alloc_skb(len + 1); if (skb == NULL) { - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; return FALSE; } skb_reserve(skb, 1); @@ -1238,8 +1235,8 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase) st_fifo->tail = 0; // Move to next frame self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); @@ -1295,7 +1292,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) */ if ((skb == NULL) || (skb->data == NULL) || (self->rx_buff.data == NULL) || (len < 6)) { - self->stats.rx_dropped++; + self->netdev->stats.rx_dropped++; continue; } skb_reserve(skb, 1); @@ -1307,8 +1304,8 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) // Move to next frame self->rx_buff.data += len; - self->stats.rx_bytes += len; - self->stats.rx_packets++; + self->netdev->stats.rx_bytes += len; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); @@ -1523,7 +1520,7 @@ static int via_ircc_net_open(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); self = netdev_priv(dev); - self->stats.rx_packets = 0; + dev->stats.rx_packets = 0; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; if (request_irq(self->io.irq, via_ircc_interrupt, 0, dev->name, dev)) { @@ -1660,14 +1657,6 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, return ret; } -static struct net_device_stats *via_ircc_net_get_stats(struct net_device - *dev) -{ - struct via_ircc_cb *self = netdev_priv(dev); - - return &self->stats; -} - MODULE_AUTHOR("VIA Technologies,inc"); MODULE_DESCRIPTION("VIA IrDA Device Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h index 403c3f77634..d9d1db03fa2 100644 --- a/drivers/net/irda/via-ircc.h +++ b/drivers/net/irda/via-ircc.h @@ -95,7 +95,6 @@ struct via_ircc_cb { struct tx_fifo tx_fifo; /* Info about frames to be transmitted */ struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; /* QoS capabilities for this device */ diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 0d30f8d659a..723c4588c80 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -291,14 +291,14 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) now.tv_sec - idev->last_rx.tv_sec - delta1, delta2); seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu", - idev->stats.rx_packets, idev->stats.rx_bytes, idev->stats.rx_errors, - idev->stats.rx_dropped); + ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors, + ndev->stats.rx_dropped); seq_printf(seq, " / overrun=%lu / length=%lu / frame=%lu / crc=%lu\n", - idev->stats.rx_over_errors, idev->stats.rx_length_errors, - idev->stats.rx_frame_errors, idev->stats.rx_crc_errors); + ndev->stats.rx_over_errors, ndev->stats.rx_length_errors, + ndev->stats.rx_frame_errors, ndev->stats.rx_crc_errors); seq_printf(seq, "TX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu / fifo=%lu\n", - idev->stats.tx_packets, idev->stats.tx_bytes, idev->stats.tx_errors, - idev->stats.tx_dropped, idev->stats.tx_fifo_errors); + ndev->stats.tx_packets, ndev->stats.tx_bytes, ndev->stats.tx_errors, + ndev->stats.tx_dropped, ndev->stats.tx_fifo_errors); } @@ -651,21 +651,21 @@ static void vlsi_rx_interrupt(struct net_device *ndev) if (ret < 0) { ret = -ret; - idev->stats.rx_errors++; + ndev->stats.rx_errors++; if (ret & VLSI_RX_DROP) - idev->stats.rx_dropped++; + ndev->stats.rx_dropped++; if (ret & VLSI_RX_OVER) - idev->stats.rx_over_errors++; + ndev->stats.rx_over_errors++; if (ret & VLSI_RX_LENGTH) - idev->stats.rx_length_errors++; + ndev->stats.rx_length_errors++; if (ret & VLSI_RX_FRAME) - idev->stats.rx_frame_errors++; + ndev->stats.rx_frame_errors++; if (ret & VLSI_RX_CRC) - idev->stats.rx_crc_errors++; + ndev->stats.rx_crc_errors++; } else if (ret > 0) { - idev->stats.rx_packets++; - idev->stats.rx_bytes += ret; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += ret; } } @@ -686,6 +686,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev) static void vlsi_unarm_rx(vlsi_irda_dev_t *idev) { + struct net_device *ndev = pci_get_drvdata(idev->pdev); struct vlsi_ring *r = idev->rx_ring; struct ring_descr *rd; int ret; @@ -711,21 +712,21 @@ static void vlsi_unarm_rx(vlsi_irda_dev_t *idev) if (ret < 0) { ret = -ret; - idev->stats.rx_errors++; + ndev->stats.rx_errors++; if (ret & VLSI_RX_DROP) - idev->stats.rx_dropped++; + ndev->stats.rx_dropped++; if (ret & VLSI_RX_OVER) - idev->stats.rx_over_errors++; + ndev->stats.rx_over_errors++; if (ret & VLSI_RX_LENGTH) - idev->stats.rx_length_errors++; + ndev->stats.rx_length_errors++; if (ret & VLSI_RX_FRAME) - idev->stats.rx_frame_errors++; + ndev->stats.rx_frame_errors++; if (ret & VLSI_RX_CRC) - idev->stats.rx_crc_errors++; + ndev->stats.rx_crc_errors++; } else if (ret > 0) { - idev->stats.rx_packets++; - idev->stats.rx_bytes += ret; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += ret; } } } @@ -1050,8 +1051,8 @@ drop_unlock: drop: IRDA_WARNING("%s: dropping packet - %s\n", __func__, msg); dev_kfree_skb_any(skb); - idev->stats.tx_errors++; - idev->stats.tx_dropped++; + ndev->stats.tx_errors++; + ndev->stats.tx_dropped++; /* Don't even think about returning NET_XMIT_DROP (=1) here! * In fact any retval!=0 causes the packet scheduler to requeue the * packet for later retry of transmission - which isn't exactly @@ -1078,15 +1079,15 @@ static void vlsi_tx_interrupt(struct net_device *ndev) if (ret < 0) { ret = -ret; - idev->stats.tx_errors++; + ndev->stats.tx_errors++; if (ret & VLSI_TX_DROP) - idev->stats.tx_dropped++; + ndev->stats.tx_dropped++; if (ret & VLSI_TX_FIFO) - idev->stats.tx_fifo_errors++; + ndev->stats.tx_fifo_errors++; } else if (ret > 0){ - idev->stats.tx_packets++; - idev->stats.tx_bytes += ret; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ret; } } @@ -1122,6 +1123,7 @@ static void vlsi_tx_interrupt(struct net_device *ndev) static void vlsi_unarm_tx(vlsi_irda_dev_t *idev) { + struct net_device *ndev = pci_get_drvdata(idev->pdev); struct vlsi_ring *r = idev->tx_ring; struct ring_descr *rd; int ret; @@ -1145,15 +1147,15 @@ static void vlsi_unarm_tx(vlsi_irda_dev_t *idev) if (ret < 0) { ret = -ret; - idev->stats.tx_errors++; + ndev->stats.tx_errors++; if (ret & VLSI_TX_DROP) - idev->stats.tx_dropped++; + ndev->stats.tx_dropped++; if (ret & VLSI_TX_FIFO) - idev->stats.tx_fifo_errors++; + ndev->stats.tx_fifo_errors++; } else if (ret > 0){ - idev->stats.tx_packets++; - idev->stats.tx_bytes += ret; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ret; } } @@ -1373,13 +1375,6 @@ static int vlsi_stop_hw(vlsi_irda_dev_t *idev) /**************************************************************/ -static struct net_device_stats * vlsi_get_stats(struct net_device *ndev) -{ - vlsi_irda_dev_t *idev = netdev_priv(ndev); - - return &idev->stats; -} - static void vlsi_tx_timeout(struct net_device *ndev) { vlsi_irda_dev_t *idev = netdev_priv(ndev); @@ -1615,7 +1610,6 @@ static int vlsi_irda_init(struct net_device *ndev) ndev->open = vlsi_open; ndev->stop = vlsi_close; - ndev->get_stats = vlsi_get_stats; ndev->hard_start_xmit = vlsi_hard_start_xmit; ndev->do_ioctl = vlsi_ioctl; ndev->tx_timeout = vlsi_tx_timeout; diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h index 9b1884329fb..3050d1a0ccc 100644 --- a/drivers/net/irda/vlsi_ir.h +++ b/drivers/net/irda/vlsi_ir.h @@ -712,7 +712,6 @@ static inline struct ring_descr *ring_get(struct vlsi_ring *r) typedef struct vlsi_irda_dev { struct pci_dev *pdev; - struct net_device_stats stats; struct irlap_cb *irlap; diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 30ec9131c5c..dc0a2e4d830 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -102,7 +102,6 @@ static int w83977af_is_receiving(struct w83977af_ir *self); static int w83977af_net_open(struct net_device *dev); static int w83977af_net_close(struct net_device *dev); static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev); /* * Function w83977af_init () @@ -237,7 +236,6 @@ static int w83977af_open(int i, unsigned int iobase, unsigned int irq, dev->open = w83977af_net_open; dev->stop = w83977af_net_close; dev->do_ioctl = w83977af_net_ioctl; - dev->get_stats = w83977af_net_get_stats; err = register_netdev(dev); if (err) { @@ -702,13 +700,13 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self) if (inb(iobase+AUDR) & AUDR_UNDR) { IRDA_DEBUG(0, "%s(), Transmit underrun!\n", __func__ ); - self->stats.tx_errors++; - self->stats.tx_fifo_errors++; + self->netdev->stats.tx_errors++; + self->netdev->stats.tx_fifo_errors++; /* Clear bit, by writing 1 to it */ outb(AUDR_UNDR, iobase+AUDR); } else - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; if (self->new_speed) { @@ -846,28 +844,28 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self) if (status & FS_FO_ERR_MSK) { if (status & FS_FO_LST_FR) { /* Add number of lost frames to stats */ - self->stats.rx_errors += len; + self->netdev->stats.rx_errors += len; } else { /* Skip frame */ - self->stats.rx_errors++; + self->netdev->stats.rx_errors++; self->rx_buff.data += len; if (status & FS_FO_MX_LEX) - self->stats.rx_length_errors++; + self->netdev->stats.rx_length_errors++; if (status & FS_FO_PHY_ERR) - self->stats.rx_frame_errors++; + self->netdev->stats.rx_frame_errors++; if (status & FS_FO_CRC_ERR) - self->stats.rx_crc_errors++; + self->netdev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ if (status & FS_FO_RX_OV) - self->stats.rx_fifo_errors++; + self->netdev->stats.rx_fifo_errors++; if (status & FS_FO_FSF_OV) - self->stats.rx_fifo_errors++; + self->netdev->stats.rx_fifo_errors++; } else { /* Check if we have transferred all data to memory */ @@ -917,7 +915,7 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self) /* Move to next frame */ self->rx_buff.data += len; - self->stats.rx_packets++; + self->netdev->stats.rx_packets++; skb->dev = self->netdev; skb_reset_mac_header(skb); @@ -951,7 +949,7 @@ static void w83977af_pio_receive(struct w83977af_ir *self) /* Receive all characters in Rx FIFO */ do { byte = inb(iobase+RBR); - async_unwrap_char(self->netdev, &self->stats, &self->rx_buff, + async_unwrap_char(self->netdev, &self->netdev->stats, &self->rx_buff, byte); } while (inb(iobase+USR) & USR_RDR); /* Data available */ } @@ -994,7 +992,7 @@ static __u8 w83977af_sir_interrupt(struct w83977af_ir *self, int isr) outb(AUDR_SFEND, iobase+AUDR); outb(set, iobase+SSR); - self->stats.tx_packets++; + self->netdev->stats.tx_packets++; /* Feed me more packets */ netif_wake_queue(self->netdev); @@ -1336,13 +1334,6 @@ out: return ret; } -static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev) -{ - struct w83977af_ir *self = netdev_priv(dev); - - return &self->stats; -} - MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>"); MODULE_DESCRIPTION("Winbond W83977AF IrDA Device Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/irda/w83977af_ir.h b/drivers/net/irda/w83977af_ir.h index 87c3975baf6..fefe9b11e20 100644 --- a/drivers/net/irda/w83977af_ir.h +++ b/drivers/net/irda/w83977af_ir.h @@ -172,7 +172,6 @@ struct w83977af_ir { int tx_len; /* Number of frames in tx_buff */ struct net_device *netdev; /* Yes! we are some kind of netdevice */ - struct net_device_stats stats; struct irlap_cb *irlap; /* The link layer we are binded to */ struct qos_info qos; /* QoS capabilities for this device */ diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 57716e22660..8e884869a05 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -486,6 +486,7 @@ static const struct net_device_ops mac8390_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 15bb38d9930..9f6644a4403 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -952,6 +952,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_get_stats = mlx4_en_get_stats, .ndo_set_multicast_list = mlx4_en_set_multicast, .ndo_set_mac_address = mlx4_en_set_mac, + .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = mlx4_en_change_mtu, .ndo_tx_timeout = mlx4_en_tx_timeout, .ndo_vlan_rx_register = mlx4_en_vlan_rx_register, diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c index cfeef0f1bac..c1bd040b9e0 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_params.c @@ -399,8 +399,10 @@ static int mlx4_en_set_ringparam(struct net_device *dev, rx_size = roundup_pow_of_two(param->rx_pending); rx_size = max_t(u32, rx_size, MLX4_EN_MIN_RX_SIZE); + rx_size = min_t(u32, rx_size, MLX4_EN_MAX_RX_SIZE); tx_size = roundup_pow_of_two(param->tx_pending); tx_size = max_t(u32, tx_size, MLX4_EN_MIN_TX_SIZE); + tx_size = min_t(u32, tx_size, MLX4_EN_MAX_TX_SIZE); if (rx_size == priv->prof->rx_ring_size && tx_size == priv->prof->tx_ring_size) @@ -440,8 +442,8 @@ static void mlx4_en_get_ringparam(struct net_device *dev, struct mlx4_en_dev *mdev = priv->mdev; memset(param, 0, sizeof(*param)); - param->rx_max_pending = mdev->dev->caps.max_rq_sg; - param->tx_max_pending = mdev->dev->caps.max_sq_sg; + param->rx_max_pending = MLX4_EN_MAX_RX_SIZE; + param->tx_max_pending = MLX4_EN_MAX_TX_SIZE; param->rx_pending = mdev->profile.prof[priv->port].rx_ring_size; param->tx_pending = mdev->profile.prof[priv->port].tx_ring_size; } diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index ff4d75205c2..4afd5993e31 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -203,19 +203,21 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, /* Optimize the common case when there are no wraparounds */ if (likely((void *) tx_desc + tx_info->nr_txbb * TXBB_SIZE <= end)) { - if (tx_info->linear) { - pci_unmap_single(mdev->pdev, - (dma_addr_t) be64_to_cpu(data->addr), + if (!tx_info->inl) { + if (tx_info->linear) { + pci_unmap_single(mdev->pdev, + (dma_addr_t) be64_to_cpu(data->addr), be32_to_cpu(data->byte_count), PCI_DMA_TODEVICE); - ++data; - } + ++data; + } - for (i = 0; i < frags; i++) { - frag = &skb_shinfo(skb)->frags[i]; - pci_unmap_page(mdev->pdev, - (dma_addr_t) be64_to_cpu(data[i].addr), - frag->size, PCI_DMA_TODEVICE); + for (i = 0; i < frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + pci_unmap_page(mdev->pdev, + (dma_addr_t) be64_to_cpu(data[i].addr), + frag->size, PCI_DMA_TODEVICE); + } } /* Stamp the freed descriptor */ for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { @@ -224,27 +226,29 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, } } else { - if ((void *) data >= end) { - data = (struct mlx4_wqe_data_seg *) - (ring->buf + ((void *) data - end)); - } + if (!tx_info->inl) { + if ((void *) data >= end) { + data = (struct mlx4_wqe_data_seg *) + (ring->buf + ((void *) data - end)); + } - if (tx_info->linear) { - pci_unmap_single(mdev->pdev, - (dma_addr_t) be64_to_cpu(data->addr), + if (tx_info->linear) { + pci_unmap_single(mdev->pdev, + (dma_addr_t) be64_to_cpu(data->addr), be32_to_cpu(data->byte_count), PCI_DMA_TODEVICE); - ++data; - } + ++data; + } - for (i = 0; i < frags; i++) { - /* Check for wraparound before unmapping */ - if ((void *) data >= end) - data = (struct mlx4_wqe_data_seg *) ring->buf; - frag = &skb_shinfo(skb)->frags[i]; - pci_unmap_page(mdev->pdev, + for (i = 0; i < frags; i++) { + /* Check for wraparound before unmapping */ + if ((void *) data >= end) + data = (struct mlx4_wqe_data_seg *) ring->buf; + frag = &skb_shinfo(skb)->frags[i]; + pci_unmap_page(mdev->pdev, (dma_addr_t) be64_to_cpu(data->addr), frag->size, PCI_DMA_TODEVICE); + } } /* Stamp the freed descriptor */ for (i = 0; i < tx_info->nr_txbb * TXBB_SIZE; i += STAMP_STRIDE) { @@ -790,8 +794,11 @@ int mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) wmb(); data->byte_count = cpu_to_be32(skb_headlen(skb) - lso_header_size); } - } else + tx_info->inl = 0; + } else { build_inline_wqe(tx_desc, skb, real_size, &vlan_tag, tx_ind, fragptr); + tx_info->inl = 1; + } ring->prod += nr_txbb; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 710c79e7a2d..6ef2490d5c3 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -912,8 +912,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) int i; if (msi_x) { - nreq = min(dev->caps.num_eqs - dev->caps.reserved_eqs, - num_possible_cpus() + 1); + nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, + num_possible_cpus() + 1); entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); if (!entries) goto no_msi; diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 2e96c7b2180..e9af32d41ca 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -115,6 +115,10 @@ enum { }; #define MLX4_EN_MAX_RX_FRAGS 4 +/* Maximum ring sizes */ +#define MLX4_EN_MAX_TX_SIZE 8192 +#define MLX4_EN_MAX_RX_SIZE 8192 + /* Minimum ring size for our page-allocation sceme to work */ #define MLX4_EN_MIN_RX_SIZE (MLX4_EN_ALLOC_SIZE / SMP_CACHE_BYTES) #define MLX4_EN_MIN_TX_SIZE (4096 / TXBB_SIZE) @@ -202,6 +206,7 @@ struct mlx4_en_tx_info { u32 nr_txbb; u8 linear; u8 data_offset; + u8 inl; }; diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 478edb92bca..c5dec54251b 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -779,6 +779,22 @@ static void __devinit natsemi_init_media (struct net_device *dev) } +static const struct net_device_ops natsemi_netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = natsemi_change_mtu, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = ns_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = natsemi_poll_controller, +#endif +}; + static int __devinit natsemi_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -911,20 +927,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (find_cnt < MAX_UNITS && full_duplex[find_cnt]) np->full_duplex = 1; - /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->change_mtu = &natsemi_change_mtu; - dev->do_ioctl = &netdev_ioctl; - dev->tx_timeout = &ns_tx_timeout; + dev->netdev_ops = &natsemi_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &natsemi_poll_controller; -#endif SET_ETHTOOL_OPS(dev, ðtool_ops); if (mtu) diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index b5723917104..7bd6662d5b0 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -202,6 +202,7 @@ static const struct net_device_ops ne_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index 62f20ba211c..f090d3b9ec9 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -208,6 +208,7 @@ static const struct net_device_ops ne2k_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 46b0772489e..e80294d8cc1 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1956,7 +1956,11 @@ static const struct net_device_ops netdev_ops = { .ndo_change_mtu = ns83820_change_mtu, .ndo_set_multicast_list = ns83820_set_multicast, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_tx_timeout = ns83820_tx_timeout, +#ifdef NS83820_VLAN_ACCEL_SUPPORT + .ndo_vlan_rx_register = ns83820_vlan_rx_register, +#endif }; static int __devinit ns83820_init_one(struct pci_dev *pci_dev, @@ -2216,7 +2220,6 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, #ifdef NS83820_VLAN_ACCEL_SUPPORT /* We also support hardware vlan acceleration */ ndev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - ndev->vlan_rx_register = ns83820_vlan_rx_register; #endif if (using_dac) { diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 044b7b07f5f..665a4286da3 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1568,6 +1568,22 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) return err; } +static const struct net_device_ops pcnet32_netdev_ops = { + .ndo_open = pcnet32_open, + .ndo_stop = pcnet32_close, + .ndo_start_xmit = pcnet32_start_xmit, + .ndo_tx_timeout = pcnet32_tx_timeout, + .ndo_get_stats = pcnet32_get_stats, + .ndo_set_multicast_list = pcnet32_set_multicast_list, + .ndo_do_ioctl = pcnet32_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = pcnet32_poll_controller, +#endif +}; + /* pcnet32_probe1 * Called from both pcnet32_probe_vlbus and pcnet_probe_pci. * pdev will be NULL when called from pcnet32_probe_vlbus. @@ -1934,20 +1950,10 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) lp->watchdog_timer.function = (void *)&pcnet32_watchdog; /* The PCNET32-specific entries in the device structure. */ - dev->open = &pcnet32_open; - dev->hard_start_xmit = &pcnet32_start_xmit; - dev->stop = &pcnet32_close; - dev->get_stats = &pcnet32_get_stats; - dev->set_multicast_list = &pcnet32_set_multicast_list; - dev->do_ioctl = &pcnet32_ioctl; + dev->netdev_ops = &pcnet32_netdev_ops; dev->ethtool_ops = &pcnet32_ethtool_ops; - dev->tx_timeout = pcnet32_tx_timeout; dev->watchdog_timeo = (5 * HZ); -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = pcnet32_poll_controller; -#endif - /* Fill in the generic fields of the device structure. */ if (register_netdev(dev)) goto err_free_ring; @@ -2276,7 +2282,7 @@ static int pcnet32_open(struct net_device *dev) if (lp->chip_version >= PCNET32_79C970A) { /* Print the link status and start the watchdog */ pcnet32_check_media(dev, 1); - mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + mod_timer(&lp->watchdog_timer, PCNET32_WATCHDOG_TIMEOUT); } i = 0; @@ -2911,7 +2917,7 @@ static void pcnet32_watchdog(struct net_device *dev) pcnet32_check_media(dev, 0); spin_unlock_irqrestore(&lp->lock, flags); - mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + mod_timer(&lp->watchdog_timer, round_jiffies(PCNET32_WATCHDOG_TIMEOUT)); } static int pcnet32_pm_suspend(struct pci_dev *pdev, pm_message_t state) diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 0c46d603b8f..0be0f0b164f 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -265,6 +265,13 @@ static const struct header_ops plip_header_ops = { .cache = plip_hard_header_cache, }; +static const struct net_device_ops plip_netdev_ops = { + .ndo_open = plip_open, + .ndo_stop = plip_close, + .ndo_start_xmit = plip_tx_packet, + .ndo_do_ioctl = plip_ioctl, +}; + /* Entry point of PLIP driver. Probe the hardware, and register/initialize the driver. @@ -280,15 +287,11 @@ plip_init_netdev(struct net_device *dev) struct net_local *nl = netdev_priv(dev); /* Then, override parts of it */ - dev->hard_start_xmit = plip_tx_packet; - dev->open = plip_open; - dev->stop = plip_close; - dev->do_ioctl = plip_ioctl; - dev->tx_queue_len = 10; dev->flags = IFF_POINTOPOINT|IFF_NOARP; memset(dev->dev_addr, 0xfc, ETH_ALEN); + dev->netdev_ops = &plip_netdev_ops; dev->header_ops = &plip_header_ops; diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 459663a4023..c1dadadfab1 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -28,11 +28,11 @@ } while (0) #define QLGE_VENDOR_ID 0x1077 -#define QLGE_DEVICE_ID1 0x8012 -#define QLGE_DEVICE_ID 0x8000 +#define QLGE_DEVICE_ID 0x8012 -#define MAX_RX_RINGS 128 -#define MAX_TX_RINGS 128 +#define MAX_CPUS 8 +#define MAX_TX_RINGS MAX_CPUS +#define MAX_RX_RINGS ((MAX_CPUS * 2) + 1) #define NUM_TX_RING_ENTRIES 256 #define NUM_RX_RING_ENTRIES 256 @@ -45,6 +45,7 @@ #define MAX_SPLIT_SIZE 1023 #define QLGE_SB_PAD 32 +#define MAX_CQ 128 #define DFLT_COALESCE_WAIT 100 /* 100 usec wait for coalescing */ #define MAX_INTER_FRAME_WAIT 10 /* 10 usec max interframe-wait for coalescing */ #define DFLT_INTER_FRAME_WAIT (MAX_INTER_FRAME_WAIT/2) @@ -961,8 +962,7 @@ struct ib_mac_iocb_rsp { #define IB_MAC_IOCB_RSP_DS 0x40 /* data is in small buffer */ #define IB_MAC_IOCB_RSP_DL 0x80 /* data is in large buffer */ __le32 data_len; /* */ - __le32 data_addr_lo; /* */ - __le32 data_addr_hi; /* */ + __le64 data_addr; /* */ __le32 rss; /* */ __le16 vlan_id; /* 12 bits */ #define IB_MAC_IOCB_RSP_C 0x1000 /* VLAN CFI bit */ @@ -976,8 +976,7 @@ struct ib_mac_iocb_rsp { #define IB_MAC_IOCB_RSP_HS 0x40 #define IB_MAC_IOCB_RSP_HL 0x80 __le32 hdr_len; /* */ - __le32 hdr_addr_lo; /* */ - __le32 hdr_addr_hi; /* */ + __le64 hdr_addr; /* */ } __attribute((packed)); struct ib_ae_iocb_rsp { @@ -1042,10 +1041,8 @@ struct wqicb { __le16 cq_id_rss; #define Q_CQ_ID_RSS_RV 0x8000 __le16 rid; - __le32 addr_lo; - __le32 addr_hi; - __le32 cnsmr_idx_addr_lo; - __le32 cnsmr_idx_addr_hi; + __le64 addr; + __le64 cnsmr_idx_addr; } __attribute((packed)); /* @@ -1070,18 +1067,14 @@ struct cqicb { #define LEN_CPP_64 0x0002 #define LEN_CPP_128 0x0003 __le16 rid; - __le32 addr_lo; - __le32 addr_hi; - __le32 prod_idx_addr_lo; - __le32 prod_idx_addr_hi; + __le64 addr; + __le64 prod_idx_addr; __le16 pkt_delay; __le16 irq_delay; - __le32 lbq_addr_lo; - __le32 lbq_addr_hi; + __le64 lbq_addr; __le16 lbq_buf_size; __le16 lbq_len; /* entry count */ - __le32 sbq_addr_lo; - __le32 sbq_addr_hi; + __le64 sbq_addr; __le16 sbq_buf_size; __le16 sbq_len; /* entry count */ } __attribute((packed)); @@ -1145,7 +1138,7 @@ struct tx_ring { struct wqicb wqicb; /* structure used to inform chip of new queue */ void *wq_base; /* pci_alloc:virtual addr for tx */ dma_addr_t wq_base_dma; /* pci_alloc:dma addr for tx */ - u32 *cnsmr_idx_sh_reg; /* shadow copy of consumer idx */ + __le32 *cnsmr_idx_sh_reg; /* shadow copy of consumer idx */ dma_addr_t cnsmr_idx_sh_reg_dma; /* dma-shadow copy of consumer */ u32 wq_size; /* size in bytes of queue area */ u32 wq_len; /* number of entries in queue */ @@ -1181,7 +1174,7 @@ struct rx_ring { u32 cq_size; u32 cq_len; u16 cq_id; - volatile __le32 *prod_idx_sh_reg; /* Shadowed producer register. */ + __le32 *prod_idx_sh_reg; /* Shadowed producer register. */ dma_addr_t prod_idx_sh_reg_dma; void __iomem *cnsmr_idx_db_reg; /* PCI doorbell mem area + 0 */ u32 cnsmr_idx; /* current sw idx */ @@ -1402,9 +1395,11 @@ struct ql_adapter { int rx_ring_count; int ring_mem_size; void *ring_mem; - struct rx_ring *rx_ring; + + struct rx_ring rx_ring[MAX_RX_RINGS]; + struct tx_ring tx_ring[MAX_TX_RINGS]; + int rx_csum; - struct tx_ring *tx_ring; u32 default_rx_queue; u16 rx_coalesce_usecs; /* cqicb->int_delay */ @@ -1459,6 +1454,24 @@ static inline void ql_write_db_reg(u32 val, void __iomem *addr) mmiowb(); } +/* + * Shadow Registers: + * Outbound queues have a consumer index that is maintained by the chip. + * Inbound queues have a producer index that is maintained by the chip. + * For lower overhead, these registers are "shadowed" to host memory + * which allows the device driver to track the queue progress without + * PCI reads. When an entry is placed on an inbound queue, the chip will + * update the relevant index register and then copy the value to the + * shadow register in host memory. + */ +static inline u32 ql_read_sh_reg(__le32 *addr) +{ + u32 reg; + reg = le32_to_cpu(*addr); + rmb(); + return reg; +} + extern char qlge_driver_name[]; extern const char qlge_driver_version[]; extern const struct ethtool_ops qlge_ethtool_ops; diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 3f5e02d2e4a..379b895ed6e 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -435,14 +435,10 @@ void ql_dump_wqicb(struct wqicb *wqicb) printk(KERN_ERR PFX "wqicb->cq_id_rss = %d.\n", le16_to_cpu(wqicb->cq_id_rss)); printk(KERN_ERR PFX "wqicb->rid = 0x%x.\n", le16_to_cpu(wqicb->rid)); - printk(KERN_ERR PFX "wqicb->wq_addr_lo = 0x%.08x.\n", - le32_to_cpu(wqicb->addr_lo)); - printk(KERN_ERR PFX "wqicb->wq_addr_hi = 0x%.08x.\n", - le32_to_cpu(wqicb->addr_hi)); - printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_lo = 0x%.08x.\n", - le32_to_cpu(wqicb->cnsmr_idx_addr_lo)); - printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr_hi = 0x%.08x.\n", - le32_to_cpu(wqicb->cnsmr_idx_addr_hi)); + printk(KERN_ERR PFX "wqicb->wq_addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(wqicb->addr)); + printk(KERN_ERR PFX "wqicb->wq_cnsmr_idx_addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(wqicb->cnsmr_idx_addr)); } void ql_dump_tx_ring(struct tx_ring *tx_ring) @@ -455,10 +451,11 @@ void ql_dump_tx_ring(struct tx_ring *tx_ring) printk(KERN_ERR PFX "tx_ring->base = %p.\n", tx_ring->wq_base); printk(KERN_ERR PFX "tx_ring->base_dma = 0x%llx.\n", (unsigned long long) tx_ring->wq_base_dma); - printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg = %p.\n", - tx_ring->cnsmr_idx_sh_reg); - printk(KERN_ERR PFX "tx_ring->cnsmr_idx_sh_reg_dma = 0x%llx.\n", - (unsigned long long) tx_ring->cnsmr_idx_sh_reg_dma); + printk(KERN_ERR PFX + "tx_ring->cnsmr_idx_sh_reg, addr = 0x%p, value = %d.\n", + tx_ring->cnsmr_idx_sh_reg, + tx_ring->cnsmr_idx_sh_reg + ? ql_read_sh_reg(tx_ring->cnsmr_idx_sh_reg) : 0); printk(KERN_ERR PFX "tx_ring->size = %d.\n", tx_ring->wq_size); printk(KERN_ERR PFX "tx_ring->len = %d.\n", tx_ring->wq_len); printk(KERN_ERR PFX "tx_ring->prod_idx_db_reg = %p.\n", @@ -510,30 +507,22 @@ void ql_dump_cqicb(struct cqicb *cqicb) printk(KERN_ERR PFX "cqicb->msix_vect = %d.\n", cqicb->msix_vect); printk(KERN_ERR PFX "cqicb->flags = %x.\n", cqicb->flags); printk(KERN_ERR PFX "cqicb->len = %d.\n", le16_to_cpu(cqicb->len)); - printk(KERN_ERR PFX "cqicb->addr_lo = %x.\n", - le32_to_cpu(cqicb->addr_lo)); - printk(KERN_ERR PFX "cqicb->addr_hi = %x.\n", - le32_to_cpu(cqicb->addr_hi)); - printk(KERN_ERR PFX "cqicb->prod_idx_addr_lo = %x.\n", - le32_to_cpu(cqicb->prod_idx_addr_lo)); - printk(KERN_ERR PFX "cqicb->prod_idx_addr_hi = %x.\n", - le32_to_cpu(cqicb->prod_idx_addr_hi)); + printk(KERN_ERR PFX "cqicb->addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(cqicb->addr)); + printk(KERN_ERR PFX "cqicb->prod_idx_addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(cqicb->prod_idx_addr)); printk(KERN_ERR PFX "cqicb->pkt_delay = 0x%.04x.\n", le16_to_cpu(cqicb->pkt_delay)); printk(KERN_ERR PFX "cqicb->irq_delay = 0x%.04x.\n", le16_to_cpu(cqicb->irq_delay)); - printk(KERN_ERR PFX "cqicb->lbq_addr_lo = %x.\n", - le32_to_cpu(cqicb->lbq_addr_lo)); - printk(KERN_ERR PFX "cqicb->lbq_addr_hi = %x.\n", - le32_to_cpu(cqicb->lbq_addr_hi)); + printk(KERN_ERR PFX "cqicb->lbq_addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(cqicb->lbq_addr)); printk(KERN_ERR PFX "cqicb->lbq_buf_size = 0x%.04x.\n", le16_to_cpu(cqicb->lbq_buf_size)); printk(KERN_ERR PFX "cqicb->lbq_len = 0x%.04x.\n", le16_to_cpu(cqicb->lbq_len)); - printk(KERN_ERR PFX "cqicb->sbq_addr_lo = %x.\n", - le32_to_cpu(cqicb->sbq_addr_lo)); - printk(KERN_ERR PFX "cqicb->sbq_addr_hi = %x.\n", - le32_to_cpu(cqicb->sbq_addr_hi)); + printk(KERN_ERR PFX "cqicb->sbq_addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(cqicb->sbq_addr)); printk(KERN_ERR PFX "cqicb->sbq_buf_size = 0x%.04x.\n", le16_to_cpu(cqicb->sbq_buf_size)); printk(KERN_ERR PFX "cqicb->sbq_len = 0x%.04x.\n", @@ -558,9 +547,10 @@ void ql_dump_rx_ring(struct rx_ring *rx_ring) printk(KERN_ERR PFX "rx_ring->cq_size = %d.\n", rx_ring->cq_size); printk(KERN_ERR PFX "rx_ring->cq_len = %d.\n", rx_ring->cq_len); printk(KERN_ERR PFX - "rx_ring->prod_idx_sh_reg, addr = %p, value = %d.\n", + "rx_ring->prod_idx_sh_reg, addr = 0x%p, value = %d.\n", rx_ring->prod_idx_sh_reg, - rx_ring->prod_idx_sh_reg ? *(rx_ring->prod_idx_sh_reg) : 0); + rx_ring->prod_idx_sh_reg + ? ql_read_sh_reg(rx_ring->prod_idx_sh_reg) : 0); printk(KERN_ERR PFX "rx_ring->prod_idx_sh_reg_dma = %llx.\n", (unsigned long long) rx_ring->prod_idx_sh_reg_dma); printk(KERN_ERR PFX "rx_ring->cnsmr_idx_db_reg = %p.\n", @@ -809,10 +799,8 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp) printk(KERN_ERR PFX "data_len = %d\n", le32_to_cpu(ib_mac_rsp->data_len)); - printk(KERN_ERR PFX "data_addr_hi = 0x%x\n", - le32_to_cpu(ib_mac_rsp->data_addr_hi)); - printk(KERN_ERR PFX "data_addr_lo = 0x%x\n", - le32_to_cpu(ib_mac_rsp->data_addr_lo)); + printk(KERN_ERR PFX "data_addr = 0x%llx\n", + (unsigned long long) le64_to_cpu(ib_mac_rsp->data_addr)); if (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_RSS_MASK) printk(KERN_ERR PFX "rss = %x\n", le32_to_cpu(ib_mac_rsp->rss)); @@ -828,10 +816,8 @@ void ql_dump_ib_mac_rsp(struct ib_mac_iocb_rsp *ib_mac_rsp) if (ib_mac_rsp->flags4 & IB_MAC_IOCB_RSP_HV) { printk(KERN_ERR PFX "hdr length = %d.\n", le32_to_cpu(ib_mac_rsp->hdr_len)); - printk(KERN_ERR PFX "hdr addr_hi = 0x%x.\n", - le32_to_cpu(ib_mac_rsp->hdr_addr_hi)); - printk(KERN_ERR PFX "hdr addr_lo = 0x%x.\n", - le32_to_cpu(ib_mac_rsp->hdr_addr_lo)); + printk(KERN_ERR PFX "hdr addr = 0x%llx.\n", + (unsigned long long) le64_to_cpu(ib_mac_rsp->hdr_addr)); } } #endif diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index f4c016012f1..45421c8b601 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -76,7 +76,6 @@ MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); static struct pci_device_id qlge_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)}, - {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID1)}, /* required last entry */ {0,} }; @@ -127,12 +126,12 @@ static int ql_sem_trylock(struct ql_adapter *qdev, u32 sem_mask) int ql_sem_spinlock(struct ql_adapter *qdev, u32 sem_mask) { - unsigned int seconds = 3; + unsigned int wait_count = 30; do { if (!ql_sem_trylock(qdev, sem_mask)) return 0; - ssleep(1); - } while (--seconds); + udelay(100); + } while (--wait_count); return -ETIMEDOUT; } @@ -1545,7 +1544,7 @@ static void ql_process_chip_ae_intr(struct ql_adapter *qdev, static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) { struct ql_adapter *qdev = rx_ring->qdev; - u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg); + u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); struct ob_mac_iocb_rsp *net_rsp = NULL; int count = 0; @@ -1571,7 +1570,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) } count++; ql_update_cq(rx_ring); - prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg); + prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); } ql_write_cq_idx(rx_ring); if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) { @@ -1591,7 +1590,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) { struct ql_adapter *qdev = rx_ring->qdev; - u32 prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg); + u32 prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); struct ql_net_rsp_iocb *net_rsp; int count = 0; @@ -1624,7 +1623,7 @@ static int ql_clean_inbound_rx_ring(struct rx_ring *rx_ring, int budget) } count++; ql_update_cq(rx_ring); - prod = le32_to_cpu(*rx_ring->prod_idx_sh_reg); + prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); if (count == budget) break; } @@ -1787,7 +1786,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) * Check the default queue and wake handler if active. */ rx_ring = &qdev->rx_ring[0]; - if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[0].\n"); ql_disable_completion_interrupt(qdev, intr_context->intr); queue_delayed_work_on(smp_processor_id(), qdev->q_workqueue, @@ -1801,7 +1800,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) */ for (i = 1; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; - if (le32_to_cpu(*rx_ring->prod_idx_sh_reg) != + if (ql_read_sh_reg(rx_ring->prod_idx_sh_reg) != rx_ring->cnsmr_idx) { QPRINTK(qdev, INTR, INFO, "Waking handler for rx_ring[%d].\n", i); @@ -2356,28 +2355,6 @@ static void ql_tx_ring_clean(struct ql_adapter *qdev) } } -static void ql_free_ring_cb(struct ql_adapter *qdev) -{ - kfree(qdev->ring_mem); -} - -static int ql_alloc_ring_cb(struct ql_adapter *qdev) -{ - /* Allocate space for tx/rx ring control blocks. */ - qdev->ring_mem_size = - (qdev->tx_ring_count * sizeof(struct tx_ring)) + - (qdev->rx_ring_count * sizeof(struct rx_ring)); - qdev->ring_mem = kmalloc(qdev->ring_mem_size, GFP_KERNEL); - if (qdev->ring_mem == NULL) { - return -ENOMEM; - } else { - qdev->rx_ring = qdev->ring_mem; - qdev->tx_ring = qdev->ring_mem + - (qdev->rx_ring_count * sizeof(struct rx_ring)); - } - return 0; -} - static void ql_free_mem_resources(struct ql_adapter *qdev) { int i; @@ -2467,12 +2444,9 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) bq_len = (rx_ring->cq_len == 65536) ? 0 : (u16) rx_ring->cq_len; cqicb->len = cpu_to_le16(bq_len | LEN_V | LEN_CPP_CONT); - cqicb->addr_lo = cpu_to_le32(rx_ring->cq_base_dma); - cqicb->addr_hi = cpu_to_le32((u64) rx_ring->cq_base_dma >> 32); + cqicb->addr = cpu_to_le64(rx_ring->cq_base_dma); - cqicb->prod_idx_addr_lo = cpu_to_le32(rx_ring->prod_idx_sh_reg_dma); - cqicb->prod_idx_addr_hi = - cpu_to_le32((u64) rx_ring->prod_idx_sh_reg_dma >> 32); + cqicb->prod_idx_addr = cpu_to_le64(rx_ring->prod_idx_sh_reg_dma); /* * Set up the control block load flags. @@ -2483,10 +2457,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma; - cqicb->lbq_addr_lo = - cpu_to_le32(rx_ring->lbq_base_indirect_dma); - cqicb->lbq_addr_hi = - cpu_to_le32((u64) rx_ring->lbq_base_indirect_dma >> 32); + cqicb->lbq_addr = + cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : (u16) rx_ring->lbq_buf_size; cqicb->lbq_buf_size = cpu_to_le16(bq_len); @@ -2501,10 +2473,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma; - cqicb->sbq_addr_lo = - cpu_to_le32(rx_ring->sbq_base_indirect_dma); - cqicb->sbq_addr_hi = - cpu_to_le32((u64) rx_ring->sbq_base_indirect_dma >> 32); + cqicb->sbq_addr = + cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8); bq_len = (rx_ring->sbq_len == 65536) ? 0 : @@ -2611,12 +2581,9 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) Q_FLAGS_LB | Q_FLAGS_LI | Q_FLAGS_LO); wqicb->cq_id_rss = cpu_to_le16(tx_ring->cq_id); wqicb->rid = 0; - wqicb->addr_lo = cpu_to_le32(tx_ring->wq_base_dma); - wqicb->addr_hi = cpu_to_le32((u64) tx_ring->wq_base_dma >> 32); + wqicb->addr = cpu_to_le64(tx_ring->wq_base_dma); - wqicb->cnsmr_idx_addr_lo = cpu_to_le32(tx_ring->cnsmr_idx_sh_reg_dma); - wqicb->cnsmr_idx_addr_hi = - cpu_to_le32((u64) tx_ring->cnsmr_idx_sh_reg_dma >> 32); + wqicb->cnsmr_idx_addr = cpu_to_le64(tx_ring->cnsmr_idx_sh_reg_dma); ql_init_tx_ring(qdev, tx_ring); @@ -2746,14 +2713,14 @@ static void ql_resolve_queues_to_irqs(struct ql_adapter *qdev) * Outbound queue is for outbound completions only. */ intr_context->handler = qlge_msix_tx_isr; - sprintf(intr_context->name, "%s-txq-%d", + sprintf(intr_context->name, "%s-tx-%d", qdev->ndev->name, i); } else { /* * Inbound queues handle unicast frames only. */ intr_context->handler = qlge_msix_rx_isr; - sprintf(intr_context->name, "%s-rxq-%d", + sprintf(intr_context->name, "%s-rx-%d", qdev->ndev->name, i); } } @@ -3247,7 +3214,6 @@ static int qlge_close(struct net_device *ndev) msleep(1); ql_adapter_down(qdev); ql_release_adapter_resources(qdev); - ql_free_ring_cb(qdev); return 0; } @@ -3273,8 +3239,8 @@ static int ql_configure_rings(struct ql_adapter *qdev) * This limitation can be removed when requested. */ - if (cpu_cnt > 8) - cpu_cnt = 8; + if (cpu_cnt > MAX_CPUS) + cpu_cnt = MAX_CPUS; /* * rx_ring[0] is always the default queue. @@ -3294,9 +3260,6 @@ static int ql_configure_rings(struct ql_adapter *qdev) */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; - if (ql_alloc_ring_cb(qdev)) - return -ENOMEM; - for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; memset((void *)tx_ring, 0, sizeof(tx_ring)); @@ -3393,7 +3356,6 @@ static int qlge_open(struct net_device *ndev) error_up: ql_release_adapter_resources(qdev); - ql_free_ring_cb(qdev); return err; } diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 53bbddfc8c9..72fd9e97c19 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include <asm/processor.h> #define DRV_NAME "r6040" -#define DRV_VERSION "0.19" -#define DRV_RELDATE "18Dec2008" +#define DRV_VERSION "0.21" +#define DRV_RELDATE "09Jan2009" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ @@ -200,7 +200,7 @@ struct r6040_private { static char version[] __devinitdata = KERN_INFO DRV_NAME ": RDC R6040 NAPI net driver," - "version "DRV_VERSION " (" DRV_RELDATE ")\n"; + "version "DRV_VERSION " (" DRV_RELDATE ")"; static int phy_table[] = { PHY1_ADDR, PHY2_ADDR }; @@ -330,7 +330,7 @@ static int r6040_alloc_rxbufs(struct net_device *dev) do { skb = netdev_alloc_skb(dev, MAX_BUF_SIZE); if (!skb) { - printk(KERN_ERR "%s: failed to alloc skb for rx\n", dev->name); + printk(KERN_ERR DRV_NAME "%s: failed to alloc skb for rx\n", dev->name); rc = -ENOMEM; goto err_exit; } @@ -457,22 +457,12 @@ static void r6040_down(struct net_device *dev) iowrite16(adrp[0], ioaddr + MID_0L); iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); - free_irq(dev->irq, dev); - - /* Free RX buffer */ - r6040_free_rxbufs(dev); - - /* Free TX buffer */ - r6040_free_txbufs(dev); - - /* Free Descriptor memory */ - pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); - pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma); } static int r6040_close(struct net_device *dev) { struct r6040_private *lp = netdev_priv(dev); + struct pci_dev *pdev = lp->pdev; /* deleted timer */ del_timer_sync(&lp->timer); @@ -481,8 +471,28 @@ static int r6040_close(struct net_device *dev) napi_disable(&lp->napi); netif_stop_queue(dev); r6040_down(dev); + + free_irq(dev->irq, dev); + + /* Free RX buffer */ + r6040_free_rxbufs(dev); + + /* Free TX buffer */ + r6040_free_txbufs(dev); + spin_unlock_irq(&lp->lock); + /* Free Descriptor memory */ + if (lp->rx_ring) { + pci_free_consistent(pdev, RX_DESC_SIZE, lp->rx_ring, lp->rx_ring_dma); + lp->rx_ring = 0; + } + + if (lp->tx_ring) { + pci_free_consistent(pdev, TX_DESC_SIZE, lp->tx_ring, lp->tx_ring_dma); + lp->tx_ring = 0; + } + return 0; } @@ -1049,6 +1059,7 @@ static const struct net_device_ops r6040_netdev_ops = { .ndo_set_multicast_list = r6040_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = r6040_ioctl, .ndo_tx_timeout = r6040_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1077,20 +1088,20 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, /* this should always be supported */ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses" "not supported by the card\n"); goto err_out; } err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); if (err) { - printk(KERN_ERR DRV_NAME "32-bit PCI DMA addresses" + printk(KERN_ERR DRV_NAME ": 32-bit PCI DMA addresses" "not supported by the card\n"); goto err_out; } /* IO Size check */ if (pci_resource_len(pdev, 0) < io_size) { - printk(KERN_ERR DRV_NAME "Insufficient PCI resources, aborting\n"); + printk(KERN_ERR DRV_NAME ": Insufficient PCI resources, aborting\n"); err = -EIO; goto err_out; } @@ -1100,7 +1111,7 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, dev = alloc_etherdev(sizeof(struct r6040_private)); if (!dev) { - printk(KERN_ERR DRV_NAME "Failed to allocate etherdev\n"); + printk(KERN_ERR DRV_NAME ": Failed to allocate etherdev\n"); err = -ENOMEM; goto err_out; } @@ -1116,11 +1127,15 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, ioaddr = pci_iomap(pdev, bar, io_size); if (!ioaddr) { - printk(KERN_ERR "ioremap failed for device %s\n", + printk(KERN_ERR DRV_NAME ": ioremap failed for device %s\n", pci_name(pdev)); err = -EIO; goto err_out_free_res; } + /* If PHY status change register is still set to zero it means the + * bootloader didn't initialize it */ + if (ioread16(ioaddr + PHY_CC) == 0) + iowrite16(0x9f07, ioaddr + PHY_CC); /* Init system & device */ lp->base = ioaddr; @@ -1137,6 +1152,13 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, adrp[1] = ioread16(ioaddr + MID_0M); adrp[2] = ioread16(ioaddr + MID_0H); + /* Some bootloader/BIOSes do not initialize + * MAC address, warn about that */ + if (!(adrp[0] || adrp[1] || adrp[2])) { + printk(KERN_WARNING DRV_NAME ": MAC address not initialized, generating random\n"); + random_ether_addr(dev->dev_addr); + } + /* Link new device into r6040_root_dev */ lp->pdev = pdev; lp->dev = dev; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index be3025310e9..fc0e38bddee 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -134,6 +134,16 @@ static const struct pnp_device_id sb1000_pnp_ids[] = { }; MODULE_DEVICE_TABLE(pnp, sb1000_pnp_ids); +static const struct net_device_ops sb1000_netdev_ops = { + .ndo_open = sb1000_open, + .ndo_start_xmit = sb1000_start_xmit, + .ndo_do_ioctl = sb1000_dev_ioctl, + .ndo_stop = sb1000_close, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) { @@ -192,11 +202,7 @@ sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id) if (sb1000_debug > 0) printk(KERN_NOTICE "%s", version); - /* The SB1000-specific entries in the device structure. */ - dev->open = sb1000_open; - dev->do_ioctl = sb1000_dev_ioctl; - dev->hard_start_xmit = sb1000_start_xmit; - dev->stop = sb1000_close; + dev->netdev_ops = &sb1000_netdev_ops; /* hardware address is 0:0:serial_number */ dev->dev_addr[2] = serial_number >> 24 & 0xff; diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 42fd3127660..8b75bef4a84 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -1408,6 +1408,7 @@ static const struct net_device_ops sc92031_netdev_ops = { .ndo_set_multicast_list = sc92031_set_multicast_list, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_tx_timeout = sc92031_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = sc92031_poll_controller, diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index b9768760fae..9ecb77da954 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -636,10 +636,11 @@ static void tenxpress_phy_fini(struct efx_nic *efx) { int reg; - if (efx->phy_type == PHY_TYPE_SFT9001B) { + if (efx->phy_type == PHY_TYPE_SFT9001B) device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_short_reach); - } else { + + if (efx->phy_type == PHY_TYPE_SFX7101) { /* Power down the LNPGA */ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index 83cc3c5f794..a9732686134 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -1782,6 +1782,21 @@ static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL); } +static const struct net_device_ops sis190_netdev_ops = { + .ndo_open = sis190_open, + .ndo_stop = sis190_close, + .ndo_do_ioctl = sis190_ioctl, + .ndo_start_xmit = sis190_start_xmit, + .ndo_tx_timeout = sis190_tx_timeout, + .ndo_set_multicast_list = sis190_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sis190_netpoll, +#endif +}; + static int __devinit sis190_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1815,19 +1830,12 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, INIT_WORK(&tp->phy_task, sis190_phy_task); - dev->open = sis190_open; - dev->stop = sis190_close; - dev->do_ioctl = sis190_ioctl; - dev->tx_timeout = sis190_tx_timeout; - dev->watchdog_timeo = SIS190_TX_TIMEOUT; - dev->hard_start_xmit = sis190_start_xmit; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sis190_netpoll; -#endif - dev->set_multicast_list = sis190_set_rx_mode; + dev->netdev_ops = &sis190_netdev_ops; + SET_ETHTOOL_OPS(dev, &sis190_ethtool_ops); dev->irq = pdev->irq; dev->base_addr = (unsigned long) 0xdead; + dev->watchdog_timeo = SIS190_TX_TIMEOUT; spin_lock_init(&tp->lock); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 4acd41a093a..6cbefcae9ac 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -389,6 +389,7 @@ static const struct net_device_ops sis900_netdev_ops = { .ndo_set_multicast_list = set_rx_mode, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = mii_ioctl, .ndo_tx_timeout = sis900_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 8e1c0baf695..5c61d5fad90 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -603,7 +603,6 @@ static int sl_init(struct net_device *dev) dev->mtu = sl->mtu; dev->type = ARPHRD_SLIP + sl->mode; #ifdef SL_CHECK_TRANSMIT - dev->tx_timeout = sl_tx_timeout; dev->watchdog_timeo = 20*HZ; #endif return 0; @@ -617,19 +616,26 @@ static void sl_uninit(struct net_device *dev) sl_free_bufs(sl); } +static const struct net_device_ops sl_netdev_ops = { + .ndo_init = sl_init, + .ndo_uninit = sl_uninit, + .ndo_open = sl_open, + .ndo_stop = sl_close, + .ndo_start_xmit = sl_xmit, + .ndo_get_stats = sl_get_stats, + .ndo_change_mtu = sl_change_mtu, + .ndo_tx_timeout = sl_tx_timeout, +#ifdef CONFIG_SLIP_SMART + .ndo_do_ioctl = sl_ioctl, +#endif +}; + + static void sl_setup(struct net_device *dev) { - dev->init = sl_init; - dev->uninit = sl_uninit; - dev->open = sl_open; + dev->netdev_ops = &sl_netdev_ops; dev->destructor = free_netdev; - dev->stop = sl_close; - dev->get_stats = sl_get_stats; - dev->change_mtu = sl_change_mtu; - dev->hard_start_xmit = sl_xmit; -#ifdef CONFIG_SLIP_SMART - dev->do_ioctl = sl_ioctl; -#endif + dev->hard_header_len = 0; dev->addr_len = 0; dev->tx_queue_len = 10; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index 404b80e5ba1..8d36d40649e 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -192,6 +192,7 @@ static const struct net_device_ops ultramca_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index b3866089a20..2033fee3143 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -196,6 +196,7 @@ static const struct net_device_ops ultra_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index dc3f1108884..f513bdf1c88 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -144,6 +144,7 @@ static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) } BUG(); + return 0; } static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, @@ -1740,6 +1741,7 @@ static const struct net_device_ops smsc911x_netdev_ops = { .ndo_set_multicast_list = smsc911x_set_multicast_list, .ndo_do_ioctl = smsc911x_do_ioctl, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = smsc911x_poll_controller, #endif @@ -1967,7 +1969,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev) smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED, - SMSC_CHIPNAME, dev); + dev->name, dev); if (retval) { SMSC_WARNING(PROBE, "Unable to claim requested irq: %d", dev->irq); diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c index 27e017d9696..c14a4c6452c 100644 --- a/drivers/net/smsc9420.c +++ b/drivers/net/smsc9420.c @@ -1551,6 +1551,7 @@ static const struct net_device_ops smsc9420_netdev_ops = { .ndo_set_multicast_list = smsc9420_set_multicast_list, .ndo_do_ioctl = smsc9420_do_ioctl, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = smsc9420_poll_controller, #endif /* CONFIG_NET_POLL_CONTROLLER */ diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 57fb1f71c47..da3a76b18ef 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -648,6 +648,24 @@ static void netdev_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) #endif /* VLAN_SUPPORT */ +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_tx_timeout = tx_timeout, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = &set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef VLAN_SUPPORT + .ndo_vlan_rx_register = netdev_vlan_rx_register, + .ndo_vlan_rx_add_vid = netdev_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = netdev_vlan_rx_kill_vid, +#endif +}; + static int __devinit starfire_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -710,11 +728,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, if (enable_hw_cksum) dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; #endif /* ZEROCOPY */ + #ifdef VLAN_SUPPORT dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER; - dev->vlan_rx_register = netdev_vlan_rx_register; - dev->vlan_rx_add_vid = netdev_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = netdev_vlan_rx_kill_vid; #endif /* VLAN_RX_KILL_VID */ #ifdef ADDR_64BITS dev->features |= NETIF_F_HIGHDMA; @@ -810,18 +826,12 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, } } - /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->tx_timeout = tx_timeout; + dev->netdev_ops = &netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work); - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; SET_ETHTOOL_OPS(dev, ðtool_ops); + netif_napi_add(dev, &np->napi, netdev_poll, max_interrupt_work); + if (mtu) dev->mtu = mtu; diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 698893b9200..feaf0e0577d 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -449,6 +449,19 @@ static void sundance_reset(struct net_device *dev, unsigned long reset_cmd) } } +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = tx_timeout, + .ndo_change_mtu = change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit sundance_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -530,16 +543,10 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, np->mii_if.reg_num_mask = 0x1f; /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); - dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->change_mtu = &change_mtu; + pci_set_drvdata(pdev, dev); i = register_netdev(dev); diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 8a746041248..86c765d83de 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -2989,6 +2989,19 @@ static void gem_remove_one(struct pci_dev *pdev) } } +static const struct net_device_ops gem_netdev_ops = { + .ndo_open = gem_open, + .ndo_stop = gem_close, + .ndo_start_xmit = gem_start_xmit, + .ndo_get_stats = gem_get_stats, + .ndo_set_multicast_list = gem_set_multicast, + .ndo_do_ioctl = gem_ioctl, + .ndo_tx_timeout = gem_tx_timeout, + .ndo_change_mtu = gem_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit gem_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3142,17 +3155,10 @@ static int __devinit gem_init_one(struct pci_dev *pdev, if (gem_get_device_address(gp)) goto err_out_free_consistent; - dev->open = gem_open; - dev->stop = gem_close; - dev->hard_start_xmit = gem_start_xmit; - dev->get_stats = gem_get_stats; - dev->set_multicast_list = gem_set_multicast; - dev->do_ioctl = gem_ioctl; + dev->netdev_ops = &gem_netdev_ops; netif_napi_add(dev, &gp->napi, gem_poll, 64); dev->ethtool_ops = &gem_ethtool_ops; - dev->tx_timeout = gem_tx_timeout; dev->watchdog_timeo = 5 * HZ; - dev->change_mtu = gem_change_mtu; dev->irq = pdev->irq; dev->dma = 0; dev->set_mac_address = gem_set_mac_address; diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index b22d3355fb4..7a72a3112f0 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2607,6 +2607,18 @@ static struct quattro * __devinit quattro_pci_find(struct pci_dev *pdev) } #endif /* CONFIG_PCI */ +static const struct net_device_ops hme_netdev_ops = { + .ndo_open = happy_meal_open, + .ndo_stop = happy_meal_close, + .ndo_start_xmit = happy_meal_start_xmit, + .ndo_tx_timeout = happy_meal_tx_timeout, + .ndo_get_stats = happy_meal_get_stats, + .ndo_set_multicast_list = happy_meal_set_multicast, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + #ifdef CONFIG_SBUS static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) { @@ -2750,12 +2762,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) init_timer(&hp->happy_timer); hp->dev = dev; - dev->open = &happy_meal_open; - dev->stop = &happy_meal_close; - dev->hard_start_xmit = &happy_meal_start_xmit; - dev->get_stats = &happy_meal_get_stats; - dev->set_multicast_list = &happy_meal_set_multicast; - dev->tx_timeout = &happy_meal_tx_timeout; + dev->netdev_ops = &hme_netdev_ops; dev->watchdog_timeo = 5*HZ; dev->ethtool_ops = &hme_ethtool_ops; @@ -3076,12 +3083,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, init_timer(&hp->happy_timer); hp->dev = dev; - dev->open = &happy_meal_open; - dev->stop = &happy_meal_close; - dev->hard_start_xmit = &happy_meal_start_xmit; - dev->get_stats = &happy_meal_get_stats; - dev->set_multicast_list = &happy_meal_set_multicast; - dev->tx_timeout = &happy_meal_tx_timeout; + dev->netdev_ops = &hme_netdev_ops; dev->watchdog_timeo = 5*HZ; dev->ethtool_ops = &hme_ethtool_ops; dev->irq = pdev->irq; diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 85ef8b74455..68b967b585a 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -831,6 +831,21 @@ static void TLan_Poll(struct net_device *dev) } #endif +static const struct net_device_ops TLan_netdev_ops = { + .ndo_open = TLan_Open, + .ndo_stop = TLan_Close, + .ndo_start_xmit = TLan_StartTx, + .ndo_tx_timeout = TLan_tx_timeout, + .ndo_get_stats = TLan_GetStats, + .ndo_set_multicast_list = TLan_SetMulticastList, + .ndo_do_ioctl = TLan_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = TLan_Poll, +#endif +}; @@ -892,16 +907,7 @@ static int TLan_Init( struct net_device *dev ) netif_carrier_off(dev); /* Device methods */ - dev->open = &TLan_Open; - dev->hard_start_xmit = &TLan_StartTx; - dev->stop = &TLan_Close; - dev->get_stats = &TLan_GetStats; - dev->set_multicast_list = &TLan_SetMulticastList; - dev->do_ioctl = &TLan_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &TLan_Poll; -#endif - dev->tx_timeout = &TLan_tx_timeout; + dev->netdev_ops = &TLan_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; return 0; diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 5166be930a5..d5d53b633cf 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1922,6 +1922,18 @@ bad_srom: goto fill_defaults; } +static const struct net_device_ops de_netdev_ops = { + .ndo_open = de_open, + .ndo_stop = de_close, + .ndo_set_multicast_list = de_set_rx_mode, + .ndo_start_xmit = de_start_xmit, + .ndo_get_stats = de_get_stats, + .ndo_tx_timeout = de_tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit de_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1944,14 +1956,9 @@ static int __devinit de_init_one (struct pci_dev *pdev, if (!dev) return -ENOMEM; + dev->netdev_ops = &de_netdev_ops; SET_NETDEV_DEV(dev, &pdev->dev); - dev->open = de_open; - dev->stop = de_close; - dev->set_multicast_list = de_set_rx_mode; - dev->hard_start_xmit = de_start_xmit; - dev->get_stats = de_get_stats; dev->ethtool_ops = &de_ethtool_ops; - dev->tx_timeout = de_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; de = netdev_priv(dev); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 67bfd6f4336..6418f74415d 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1077,6 +1077,18 @@ static int (*dc_infoblock[])(struct net_device *dev, u_char, u_char *) = { mdelay(2); /* Wait for 2ms */\ } +static const struct net_device_ops de4x5_netdev_ops = { + .ndo_open = de4x5_open, + .ndo_stop = de4x5_close, + .ndo_start_xmit = de4x5_queue_pkt, + .ndo_get_stats = de4x5_get_stats, + .ndo_set_multicast_list = set_multicast_list, + .ndo_do_ioctl = de4x5_ioctl, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address= eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static int __devinit de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) @@ -1258,13 +1270,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) /* The DE4X5-specific entries in the device structure. */ SET_NETDEV_DEV(dev, gendev); - dev->open = &de4x5_open; - dev->hard_start_xmit = &de4x5_queue_pkt; - dev->stop = &de4x5_close; - dev->get_stats = &de4x5_get_stats; - dev->set_multicast_list = &set_multicast_list; - dev->do_ioctl = &de4x5_ioctl; - + dev->netdev_ops = &de4x5_netdev_ops; dev->mem_start = 0; /* Fill in the generic fields of the device structure. */ diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index 28a5c51b43a..2e5c99941f3 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -257,9 +257,6 @@ struct dmfe_board_info { u8 wol_mode; /* user WOL settings */ struct timer_list timer; - /* System defined statistic counter */ - struct net_device_stats stats; - /* Driver defined statistic counter */ unsigned long tx_fifo_underrun; unsigned long tx_loss_carrier; @@ -316,7 +313,6 @@ static u8 SF_mode; /* Special Function: 1:VLAN, 2:RX Flow Control static int dmfe_open(struct DEVICE *); static int dmfe_start_xmit(struct sk_buff *, struct DEVICE *); static int dmfe_stop(struct DEVICE *); -static struct net_device_stats * dmfe_get_stats(struct DEVICE *); static void dmfe_set_filter_mode(struct DEVICE *); static const struct ethtool_ops netdev_ethtool_ops; static u16 read_srom_word(long ,int); @@ -351,6 +347,19 @@ static void dmfe_set_phyxcer(struct dmfe_board_info *); /* DM910X network board routine ---------------------------- */ +static const struct net_device_ops netdev_ops = { + .ndo_open = dmfe_open, + .ndo_stop = dmfe_stop, + .ndo_start_xmit = dmfe_start_xmit, + .ndo_set_multicast_list = dmfe_set_filter_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = poll_dmfe, +#endif +}; + /* * Search DM910X board ,allocate space and register it */ @@ -442,14 +451,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, dev->base_addr = db->ioaddr; dev->irq = pdev->irq; pci_set_drvdata(pdev, dev); - dev->open = &dmfe_open; - dev->hard_start_xmit = &dmfe_start_xmit; - dev->stop = &dmfe_stop; - dev->get_stats = &dmfe_get_stats; - dev->set_multicast_list = &dmfe_set_filter_mode; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &poll_dmfe; -#endif + dev->netdev_ops = &netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; netif_carrier_off(dev); spin_lock_init(&db->lock); @@ -867,15 +869,15 @@ static void dmfe_free_tx_pkt(struct DEVICE *dev, struct dmfe_board_info * db) /* A packet sent completed */ db->tx_packet_cnt--; - db->stats.tx_packets++; + dev->stats.tx_packets++; /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ - db->stats.collisions += (tdes0 >> 3) & 0xf; - db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; + dev->stats.collisions += (tdes0 >> 3) & 0xf; + dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { - db->stats.tx_errors++; + dev->stats.tx_errors++; if (tdes0 & 0x0002) { /* UnderRun */ db->tx_fifo_underrun++; @@ -969,13 +971,13 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) if (rdes0 & 0x8000) { /* This is a error packet */ //printk(DRV_NAME ": rdes0: %lx\n", rdes0); - db->stats.rx_errors++; + dev->stats.rx_errors++; if (rdes0 & 1) - db->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rdes0 & 2) - db->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rdes0 & 0x80) - db->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } if ( !(rdes0 & 0x8000) || @@ -1008,8 +1010,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - db->stats.rx_packets++; - db->stats.rx_bytes += rxlen; + dev->stats.rx_packets++; + dev->stats.rx_bytes += rxlen; } } else { /* Reuse SKB buffer when the packet is error */ @@ -1024,20 +1026,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) db->rx_ready_ptr = rxptr; } - -/* - * Get statistics from driver. - */ - -static struct net_device_stats * dmfe_get_stats(struct DEVICE *dev) -{ - struct dmfe_board_info *db = netdev_priv(dev); - - DMFE_DBUG(0, "dmfe_get_stats", 0); - return &db->stats; -} - - /* * Set DM910X multicast address */ @@ -1161,7 +1149,7 @@ static void dmfe_timer(unsigned long data) /* Operating Mode Check */ if ( (db->dm910x_chk_mode & 0x1) && - (db->stats.rx_packets > MAX_CHECK_PACKET) ) + (dev->stats.rx_packets > MAX_CHECK_PACKET) ) db->dm910x_chk_mode = 0x4; /* Dynamic reset DM910X : system error or transmit time-out */ diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index ff84babb3ff..bee75fa87a9 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1225,6 +1225,22 @@ static int tulip_uli_dm_quirk(struct pci_dev *pdev) return 0; } +static const struct net_device_ops tulip_netdev_ops = { + .ndo_open = tulip_open, + .ndo_start_xmit = tulip_start_xmit, + .ndo_tx_timeout = tulip_tx_timeout, + .ndo_stop = tulip_close, + .ndo_get_stats = tulip_get_stats, + .ndo_do_ioctl = private_ioctl, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = poll_tulip, +#endif +}; + static int __devinit tulip_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1601,20 +1617,11 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, } /* The Tulip-specific entries in the device structure. */ - dev->open = tulip_open; - dev->hard_start_xmit = tulip_start_xmit; - dev->tx_timeout = tulip_tx_timeout; + dev->netdev_ops = &tulip_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; #ifdef CONFIG_TULIP_NAPI netif_napi_add(dev, &tp->napi, tulip_poll, 16); #endif - dev->stop = tulip_close; - dev->get_stats = tulip_get_stats; - dev->do_ioctl = private_ioctl; - dev->set_multicast_list = set_rx_mode; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &poll_tulip; -#endif SET_ETHTOOL_OPS(dev, &ops); if (register_netdev(dev)) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index 00cbc5251dc..030e02e6302 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -168,9 +168,6 @@ struct uli526x_board_info { u8 wait_reset; /* Hardware failed, need to reset */ struct timer_list timer; - /* System defined statistic counter */ - struct net_device_stats stats; - /* Driver defined statistic counter */ unsigned long tx_fifo_underrun; unsigned long tx_loss_carrier; @@ -220,7 +217,6 @@ static int mode = 8; static int uli526x_open(struct net_device *); static int uli526x_start_xmit(struct sk_buff *, struct net_device *); static int uli526x_stop(struct net_device *); -static struct net_device_stats * uli526x_get_stats(struct net_device *); static void uli526x_set_filter_mode(struct net_device *); static const struct ethtool_ops netdev_ethtool_ops; static u16 read_srom_word(long, int); @@ -251,6 +247,19 @@ static void uli526x_set_phyxcer(struct uli526x_board_info *); /* ULI526X network board routine ---------------------------- */ +static const struct net_device_ops netdev_ops = { + .ndo_open = uli526x_open, + .ndo_stop = uli526x_stop, + .ndo_start_xmit = uli526x_start_xmit, + .ndo_set_multicast_list = uli526x_set_filter_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = uli526x_poll, +#endif +}; + /* * Search ULI526X board, allocate space and register it */ @@ -335,15 +344,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, pci_set_drvdata(pdev, dev); /* Register some necessary functions */ - dev->open = &uli526x_open; - dev->hard_start_xmit = &uli526x_start_xmit; - dev->stop = &uli526x_stop; - dev->get_stats = &uli526x_get_stats; - dev->set_multicast_list = &uli526x_set_filter_mode; + dev->netdev_ops = &netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &uli526x_poll; -#endif + spin_lock_init(&db->lock); @@ -733,7 +736,8 @@ static void uli526x_poll(struct net_device *dev) * Free TX resource after TX complete */ -static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_info * db) +static void uli526x_free_tx_pkt(struct net_device *dev, + struct uli526x_board_info * db) { struct tx_desc *txptr; u32 tdes0; @@ -747,15 +751,15 @@ static void uli526x_free_tx_pkt(struct net_device *dev, struct uli526x_board_inf /* A packet sent completed */ db->tx_packet_cnt--; - db->stats.tx_packets++; + dev->stats.tx_packets++; /* Transmit statistic counter */ if ( tdes0 != 0x7fffffff ) { /* printk(DRV_NAME ": tdes0=%x\n", tdes0); */ - db->stats.collisions += (tdes0 >> 3) & 0xf; - db->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; + dev->stats.collisions += (tdes0 >> 3) & 0xf; + dev->stats.tx_bytes += le32_to_cpu(txptr->tdes1) & 0x7ff; if (tdes0 & TDES0_ERR_MASK) { - db->stats.tx_errors++; + dev->stats.tx_errors++; if (tdes0 & 0x0002) { /* UnderRun */ db->tx_fifo_underrun++; if ( !(db->cr6_data & CR6_SFT) ) { @@ -825,13 +829,13 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info if (rdes0 & 0x8000) { /* This is a error packet */ //printk(DRV_NAME ": rdes0: %lx\n", rdes0); - db->stats.rx_errors++; + dev->stats.rx_errors++; if (rdes0 & 1) - db->stats.rx_fifo_errors++; + dev->stats.rx_fifo_errors++; if (rdes0 & 2) - db->stats.rx_crc_errors++; + dev->stats.rx_crc_errors++; if (rdes0 & 0x80) - db->stats.rx_length_errors++; + dev->stats.rx_length_errors++; } if ( !(rdes0 & 0x8000) || @@ -854,8 +858,8 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - db->stats.rx_packets++; - db->stats.rx_bytes += rxlen; + dev->stats.rx_packets++; + dev->stats.rx_bytes += rxlen; } else { /* Reuse SKB buffer when the packet is error */ @@ -872,19 +876,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info /* - * Get statistics from driver. - */ - -static struct net_device_stats * uli526x_get_stats(struct net_device *dev) -{ - struct uli526x_board_info *db = netdev_priv(dev); - - ULI526X_DBUG(0, "uli526x_get_stats", 0); - return &db->stats; -} - - -/* * Set ULI526X multicast address */ diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 022d99af864..f467bf87817 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -343,7 +343,18 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static const struct ethtool_ops netdev_ethtool_ops; static int netdev_close(struct net_device *dev); - +static const struct net_device_ops netdev_ops = { + .ndo_open = netdev_open, + .ndo_stop = netdev_close, + .ndo_start_xmit = start_tx, + .ndo_get_stats = get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = tx_timeout, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; static int __devinit w840_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -420,14 +431,8 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, np->mii_if.force_media = 1; /* The chip-specific entries in the device structure. */ - dev->open = &netdev_open; - dev->hard_start_xmit = &start_tx; - dev->stop = &netdev_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; i = register_netdev(dev); @@ -1555,7 +1560,7 @@ static void __devexit w840_remove1 (struct pci_dev *pdev) * rtnl_lock, & netif_device_detach after the rtnl_unlock. * - get_stats: * spin_lock_irq(np->lock), doesn't touch hw if not present - * - hard_start_xmit: + * - start_xmit: * synchronize_irq + netif_tx_disable; * - tx_timeout: * netif_device_detach + netif_tx_disable; diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 13c8703ecb9..c2ca9f40e40 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -104,10 +104,8 @@ struct xircom_private { */ spinlock_t lock; - struct pci_dev *pdev; struct net_device *dev; - struct net_device_stats stats; }; @@ -119,7 +117,6 @@ static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev); static int xircom_open(struct net_device *dev); static int xircom_close(struct net_device *dev); static void xircom_up(struct xircom_private *card); -static struct net_device_stats *xircom_get_stats(struct net_device *dev); #ifdef CONFIG_NET_POLL_CONTROLLER static void xircom_poll_controller(struct net_device *dev); #endif @@ -194,6 +191,18 @@ static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, }; +static const struct net_device_ops netdev_ops = { + .ndo_open = xircom_open, + .ndo_stop = xircom_close, + .ndo_start_xmit = xircom_start_xmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = xircom_poll_controller, +#endif +}; + /* xircom_probe is the code that gets called on device insertion. it sets up the hardware and registers the device to the networklayer. @@ -266,13 +275,7 @@ static int __devinit xircom_probe(struct pci_dev *pdev, const struct pci_device_ read_mac_address(private); setup_descriptors(private); - dev->open = &xircom_open; - dev->hard_start_xmit = &xircom_start_xmit; - dev->stop = &xircom_close; - dev->get_stats = &xircom_get_stats; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &xircom_poll_controller; -#endif + dev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); pci_set_drvdata(pdev, dev); @@ -497,14 +500,6 @@ static int xircom_close(struct net_device *dev) } - -static struct net_device_stats *xircom_get_stats(struct net_device *dev) -{ - struct xircom_private *card = netdev_priv(dev); - return &card->stats; -} - - #ifdef CONFIG_NET_POLL_CONTROLLER static void xircom_poll_controller(struct net_device *dev) { @@ -1193,7 +1188,7 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri skb = dev_alloc_skb(pkt_len + 2); if (skb == NULL) { - card->stats.rx_dropped++; + dev->stats.rx_dropped++; goto out; } skb_reserve(skb, 2); @@ -1201,8 +1196,8 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - card->stats.rx_packets++; - card->stats.rx_bytes += pkt_len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; out: /* give the buffer back to the card */ @@ -1232,16 +1227,16 @@ static void investigate_write_descriptor(struct net_device *dev, struct xircom_p #endif if (status > 0) { /* bit 31 is 0 when done */ if (card->tx_skb[descnr]!=NULL) { - card->stats.tx_bytes += card->tx_skb[descnr]->len; + dev->stats.tx_bytes += card->tx_skb[descnr]->len; dev_kfree_skb_irq(card->tx_skb[descnr]); } card->tx_skb[descnr] = NULL; /* Bit 8 in the status field is 1 if there was a collision */ if (status&(1<<8)) - card->stats.collisions++; + dev->stats.collisions++; card->tx_buffer[4*descnr] = 0; /* descriptor is free again */ netif_wake_queue (dev); - card->stats.tx_packets++; + dev->stats.tx_packets++; } leave("investigate_write_descriptor"); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 0009f4e3443..3af9a9516cc 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -2296,6 +2296,19 @@ out: return mode; } +static const struct net_device_ops typhoon_netdev_ops = { + .ndo_open = typhoon_open, + .ndo_stop = typhoon_close, + .ndo_start_xmit = typhoon_start_tx, + .ndo_set_multicast_list = typhoon_set_rx_mode, + .ndo_tx_timeout = typhoon_tx_timeout, + .ndo_get_stats = typhoon_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = typhoon_set_mac_address, + .ndo_change_mtu = eth_change_mtu, + .ndo_vlan_rx_register = typhoon_vlan_rx_register, +}; + static int __devinit typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2495,16 +2508,9 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } /* The chip-specific entries in the device structure. */ - dev->open = typhoon_open; - dev->hard_start_xmit = typhoon_start_tx; - dev->stop = typhoon_close; - dev->set_multicast_list = typhoon_set_rx_mode; - dev->tx_timeout = typhoon_tx_timeout; + dev->netdev_ops = &typhoon_netdev_ops; netif_napi_add(dev, &tp->napi, typhoon_poll, 16); dev->watchdog_timeo = TX_TIMEOUT; - dev->get_stats = typhoon_get_stats; - dev->set_mac_address = typhoon_set_mac_address; - dev->vlan_rx_register = typhoon_vlan_rx_register; SET_ETHTOOL_OPS(dev, &typhoon_ethtool_ops); diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 7d5a1303e30..11441225bf4 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -442,40 +442,30 @@ static void magic_packet_detection_enable(struct ucc_geth_private *ugeth) { struct ucc_fast_private *uccf; struct ucc_geth __iomem *ug_regs; - u32 maccfg2, uccm; uccf = ugeth->uccf; ug_regs = ugeth->ug_regs; /* Enable interrupts for magic packet detection */ - uccm = in_be32(uccf->p_uccm); - uccm |= UCCE_MPD; - out_be32(uccf->p_uccm, uccm); + setbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); /* Enable magic packet detection */ - maccfg2 = in_be32(&ug_regs->maccfg2); - maccfg2 |= MACCFG2_MPE; - out_be32(&ug_regs->maccfg2, maccfg2); + setbits32(&ug_regs->maccfg2, MACCFG2_MPE); } static void magic_packet_detection_disable(struct ucc_geth_private *ugeth) { struct ucc_fast_private *uccf; struct ucc_geth __iomem *ug_regs; - u32 maccfg2, uccm; uccf = ugeth->uccf; ug_regs = ugeth->ug_regs; /* Disable interrupts for magic packet detection */ - uccm = in_be32(uccf->p_uccm); - uccm &= ~UCCE_MPD; - out_be32(uccf->p_uccm, uccm); + clrbits32(uccf->p_uccm, UCC_GETH_UCCE_MPD); /* Disable magic packet detection */ - maccfg2 = in_be32(&ug_regs->maccfg2); - maccfg2 &= ~MACCFG2_MPE; - out_be32(&ug_regs->maccfg2, maccfg2); + clrbits32(&ug_regs->maccfg2, MACCFG2_MPE); } #endif /* MAGIC_PACKET */ @@ -585,7 +575,8 @@ static void get_statistics(struct ucc_geth_private *ugeth, /* Hardware only if user handed pointer and driver actually gathers hardware statistics */ - if (hardware_statistics && (in_be32(&uf_regs->upsmr) & UPSMR_HSE)) { + if (hardware_statistics && + (in_be32(&uf_regs->upsmr) & UCC_GETH_UPSMR_HSE)) { hardware_statistics->tx64 = in_be32(&ug_regs->tx64); hardware_statistics->tx127 = in_be32(&ug_regs->tx127); hardware_statistics->tx255 = in_be32(&ug_regs->tx255); @@ -1181,9 +1172,7 @@ int init_flow_control_params(u32 automatic_flow_control_mode, out_be32(uempr_register, value); /* Set UPSMR register */ - value = in_be32(upsmr_register); - value |= automatic_flow_control_mode; - out_be32(upsmr_register, value); + setbits32(upsmr_register, automatic_flow_control_mode); value = in_be32(maccfg1_register); if (rx_flow_control_enable) @@ -1200,14 +1189,11 @@ static int init_hw_statistics_gathering_mode(int enable_hardware_statistics, u32 __iomem *upsmr_register, u16 __iomem *uescr_register) { - u32 upsmr_value = 0; u16 uescr_value = 0; + /* Enable hardware statistics gathering if requested */ - if (enable_hardware_statistics) { - upsmr_value = in_be32(upsmr_register); - upsmr_value |= UPSMR_HSE; - out_be32(upsmr_register, upsmr_value); - } + if (enable_hardware_statistics) + setbits32(upsmr_register, UCC_GETH_UPSMR_HSE); /* Clear hardware statistics counters */ uescr_value = in_be16(uescr_register); @@ -1233,23 +1219,17 @@ static int init_firmware_statistics_gathering_mode(int { /* Note: this function does not check if */ /* the parameters it receives are NULL */ - u16 temoder_value; - u32 remoder_value; if (enable_tx_firmware_statistics) { out_be32(tx_rmon_base_ptr, tx_firmware_statistics_structure_address); - temoder_value = in_be16(temoder_register); - temoder_value |= TEMODER_TX_RMON_STATISTICS_ENABLE; - out_be16(temoder_register, temoder_value); + setbits16(temoder_register, TEMODER_TX_RMON_STATISTICS_ENABLE); } if (enable_rx_firmware_statistics) { out_be32(rx_rmon_base_ptr, rx_firmware_statistics_structure_address); - remoder_value = in_be32(remoder_register); - remoder_value |= REMODER_RX_RMON_STATISTICS_ENABLE; - out_be32(remoder_register, remoder_value); + setbits32(remoder_register, REMODER_RX_RMON_STATISTICS_ENABLE); } return 0; @@ -1316,15 +1296,12 @@ static int init_check_frame_length_mode(int length_check, static int init_preamble_length(u8 preamble_length, u32 __iomem *maccfg2_register) { - u32 value = 0; - if ((preamble_length < 3) || (preamble_length > 7)) return -EINVAL; - value = in_be32(maccfg2_register); - value &= ~MACCFG2_PREL_MASK; - value |= (preamble_length << MACCFG2_PREL_SHIFT); - out_be32(maccfg2_register, value); + clrsetbits_be32(maccfg2_register, MACCFG2_PREL_MASK, + preamble_length << MACCFG2_PREL_SHIFT); + return 0; } @@ -1337,19 +1314,19 @@ static int init_rx_parameters(int reject_broadcast, value = in_be32(upsmr_register); if (reject_broadcast) - value |= UPSMR_BRO; + value |= UCC_GETH_UPSMR_BRO; else - value &= ~UPSMR_BRO; + value &= ~UCC_GETH_UPSMR_BRO; if (receive_short_frames) - value |= UPSMR_RSH; + value |= UCC_GETH_UPSMR_RSH; else - value &= ~UPSMR_RSH; + value &= ~UCC_GETH_UPSMR_RSH; if (promiscuous) - value |= UPSMR_PRO; + value |= UCC_GETH_UPSMR_PRO; else - value &= ~UPSMR_PRO; + value &= ~UCC_GETH_UPSMR_PRO; out_be32(upsmr_register, value); @@ -1410,26 +1387,27 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) /* Set UPSMR */ upsmr = in_be32(&uf_regs->upsmr); - upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); + upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M | + UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM); if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_RXID) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { - upsmr |= UPSMR_RPM; + upsmr |= UCC_GETH_UPSMR_RPM; switch (ugeth->max_speed) { case SPEED_10: - upsmr |= UPSMR_R10M; + upsmr |= UCC_GETH_UPSMR_R10M; /* FALLTHROUGH */ case SPEED_100: if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) - upsmr |= UPSMR_RMM; + upsmr |= UCC_GETH_UPSMR_RMM; } } if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { - upsmr |= UPSMR_TBIM; + upsmr |= UCC_GETH_UPSMR_TBIM; } out_be32(&uf_regs->upsmr, upsmr); @@ -1517,9 +1495,9 @@ static void adjust_link(struct net_device *dev) (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_TXID) || (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { if (phydev->speed == SPEED_10) - upsmr |= UPSMR_R10M; + upsmr |= UCC_GETH_UPSMR_R10M; else - upsmr &= ~(UPSMR_R10M); + upsmr &= ~UCC_GETH_UPSMR_R10M; } break; default: @@ -1602,10 +1580,8 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) uccf = ugeth->uccf; /* Mask GRACEFUL STOP TX interrupt bit and clear it */ - temp = in_be32(uccf->p_uccm); - temp &= ~UCCE_GRA; - out_be32(uccf->p_uccm, temp); - out_be32(uccf->p_ucce, UCCE_GRA); /* clear by writing 1 */ + clrbits32(uccf->p_uccm, UCC_GETH_UCCE_GRA); + out_be32(uccf->p_ucce, UCC_GETH_UCCE_GRA); /* clear by writing 1 */ /* Issue host command */ cecr_subblock = @@ -1617,7 +1593,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) do { msleep(10); temp = in_be32(uccf->p_ucce); - } while (!(temp & UCCE_GRA) && --i); + } while (!(temp & UCC_GETH_UCCE_GRA) && --i); uccf->stopped_tx = 1; @@ -1975,12 +1951,9 @@ static void ucc_geth_set_multi(struct net_device *dev) uf_regs = ugeth->uccf->uf_regs; if (dev->flags & IFF_PROMISC) { - - out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr) | UPSMR_PRO); - + setbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO); } else { - - out_be32(&uf_regs->upsmr, in_be32(&uf_regs->upsmr)&~UPSMR_PRO); + clrbits32(&uf_regs->upsmr, UCC_GETH_UPSMR_PRO); p_82xx_addr_filt = (struct ucc_geth_82xx_address_filtering_pram __iomem *) ugeth-> @@ -2020,7 +1993,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) { struct ucc_geth __iomem *ug_regs = ugeth->ug_regs; struct phy_device *phydev = ugeth->phydev; - u32 tempval; ugeth_vdbg("%s: IN", __func__); @@ -2037,9 +2009,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) out_be32(ugeth->uccf->p_ucce, 0xffffffff); /* Disable Rx and Tx */ - tempval = in_be32(&ug_regs->maccfg1); - tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); - out_be32(&ug_regs->maccfg1, tempval); + clrbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); ucc_geth_memclean(ugeth); } @@ -2153,10 +2123,10 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) /* Generate uccm_mask for receive */ uf_info->uccm_mask = ug_info->eventRegMask & UCCE_OTHER;/* Errors */ for (i = 0; i < ug_info->numQueuesRx; i++) - uf_info->uccm_mask |= (UCCE_RXBF_SINGLE_MASK << i); + uf_info->uccm_mask |= (UCC_GETH_UCCE_RXF0 << i); for (i = 0; i < ug_info->numQueuesTx; i++) - uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); + uf_info->uccm_mask |= (UCC_GETH_UCCE_TXB0 << i); /* Initialize the general fast UCC block. */ if (ucc_fast_init(uf_info, &ugeth->uccf)) { if (netif_msg_probe(ugeth)) @@ -2185,7 +2155,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) struct ucc_geth __iomem *ug_regs; int ret_val = -EINVAL; u32 remoder = UCC_GETH_REMODER_INIT; - u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; + u32 init_enet_pram_offset, cecr_subblock, command; u32 ifstat, i, j, size, l2qt, l3qt, length; u16 temoder = UCC_GETH_TEMODER_INIT; u16 test; @@ -2281,10 +2251,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) &uf_regs->upsmr, &ug_regs->uempr, &ug_regs->maccfg1); - maccfg1 = in_be32(&ug_regs->maccfg1); - maccfg1 |= MACCFG1_ENABLE_RX; - maccfg1 |= MACCFG1_ENABLE_TX; - out_be32(&ug_regs->maccfg1, maccfg1); + setbits32(&ug_regs->maccfg1, MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); /* Set IPGIFG */ /* For more details see the hardware spec. */ @@ -3274,7 +3241,6 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) static int ucc_geth_poll(struct napi_struct *napi, int budget) { struct ucc_geth_private *ugeth = container_of(napi, struct ucc_geth_private, napi); - struct net_device *dev = ugeth->dev; struct ucc_geth_info *ug_info; int howmany, i; @@ -3285,14 +3251,8 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) howmany += ucc_geth_rx(ugeth, i, budget - howmany); if (howmany < budget) { - struct ucc_fast_private *uccf; - u32 uccm; - netif_rx_complete(napi); - uccf = ugeth->uccf; - uccm = in_be32(uccf->p_uccm); - uccm |= UCCE_RX_EVENTS; - out_be32(uccf->p_uccm, uccm); + setbits32(ugeth->uccf->p_uccm, UCCE_RX_EVENTS); } return howmany; @@ -3332,7 +3292,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* Tx event processing */ if (ucce & UCCE_TX_EVENTS) { spin_lock(&ugeth->lock); - tx_mask = UCCE_TXBF_SINGLE_MASK; + tx_mask = UCC_GETH_UCCE_TXB0; for (i = 0; i < ug_info->numQueuesTx; i++) { if (ucce & tx_mask) ucc_geth_tx(dev, i); @@ -3344,12 +3304,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* Errors and other events */ if (ucce & UCCE_OTHER) { - if (ucce & UCCE_BSY) { + if (ucce & UCC_GETH_UCCE_BSY) dev->stats.rx_errors++; - } - if (ucce & UCCE_TXE) { + if (ucce & UCC_GETH_UCCE_TXE) dev->stats.tx_errors++; - } } return IRQ_HANDLED; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index d74d2f7cb73..8f699cb773e 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -162,92 +162,27 @@ struct ucc_geth { boundary */ /* UCC GETH Event Register */ -#define UCCE_MPD 0x80000000 /* Magic packet - detection */ -#define UCCE_SCAR 0x40000000 -#define UCCE_GRA 0x20000000 /* Tx graceful - stop - complete */ -#define UCCE_CBPR 0x10000000 -#define UCCE_BSY 0x08000000 -#define UCCE_RXC 0x04000000 -#define UCCE_TXC 0x02000000 -#define UCCE_TXE 0x01000000 -#define UCCE_TXB7 0x00800000 -#define UCCE_TXB6 0x00400000 -#define UCCE_TXB5 0x00200000 -#define UCCE_TXB4 0x00100000 -#define UCCE_TXB3 0x00080000 -#define UCCE_TXB2 0x00040000 -#define UCCE_TXB1 0x00020000 -#define UCCE_TXB0 0x00010000 -#define UCCE_RXB7 0x00008000 -#define UCCE_RXB6 0x00004000 -#define UCCE_RXB5 0x00002000 -#define UCCE_RXB4 0x00001000 -#define UCCE_RXB3 0x00000800 -#define UCCE_RXB2 0x00000400 -#define UCCE_RXB1 0x00000200 -#define UCCE_RXB0 0x00000100 -#define UCCE_RXF7 0x00000080 -#define UCCE_RXF6 0x00000040 -#define UCCE_RXF5 0x00000020 -#define UCCE_RXF4 0x00000010 -#define UCCE_RXF3 0x00000008 -#define UCCE_RXF2 0x00000004 -#define UCCE_RXF1 0x00000002 -#define UCCE_RXF0 0x00000001 - -#define UCCE_RXBF_SINGLE_MASK (UCCE_RXF0) -#define UCCE_TXBF_SINGLE_MASK (UCCE_TXB0) - -#define UCCE_TXB (UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 |\ - UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0) -#define UCCE_RXB (UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 |\ - UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0) -#define UCCE_RXF (UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 |\ - UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0) -#define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ - UCCE_RXC | UCCE_TXC | UCCE_TXE) - -#define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY) -#define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE) - -/* UCC GETH UPSMR (Protocol Specific Mode Register) */ -#define UPSMR_ECM 0x04000000 /* Enable CAM - Miss or - Enable - Filtering - Miss */ -#define UPSMR_HSE 0x02000000 /* Hardware - Statistics - Enable */ -#define UPSMR_PRO 0x00400000 /* Promiscuous*/ -#define UPSMR_CAP 0x00200000 /* CAM polarity - */ -#define UPSMR_RSH 0x00100000 /* Receive - Short Frames - */ -#define UPSMR_RPM 0x00080000 /* Reduced Pin - Mode - interfaces */ -#define UPSMR_R10M 0x00040000 /* RGMII/RMII - 10 Mode */ -#define UPSMR_RLPB 0x00020000 /* RMII - Loopback - Mode */ -#define UPSMR_TBIM 0x00010000 /* Ten-bit - Interface - Mode */ -#define UPSMR_RMM 0x00001000 /* RMII/RGMII - Mode */ -#define UPSMR_CAM 0x00000400 /* CAM Address - Matching */ -#define UPSMR_BRO 0x00000200 /* Broadcast - Address */ -#define UPSMR_RES1 0x00002000 /* Reserved - feild - must - be 1 */ +#define UCCE_TXB (UCC_GETH_UCCE_TXB7 | UCC_GETH_UCCE_TXB6 | \ + UCC_GETH_UCCE_TXB5 | UCC_GETH_UCCE_TXB4 | \ + UCC_GETH_UCCE_TXB3 | UCC_GETH_UCCE_TXB2 | \ + UCC_GETH_UCCE_TXB1 | UCC_GETH_UCCE_TXB0) + +#define UCCE_RXB (UCC_GETH_UCCE_RXB7 | UCC_GETH_UCCE_RXB6 | \ + UCC_GETH_UCCE_RXB5 | UCC_GETH_UCCE_RXB4 | \ + UCC_GETH_UCCE_RXB3 | UCC_GETH_UCCE_RXB2 | \ + UCC_GETH_UCCE_RXB1 | UCC_GETH_UCCE_RXB0) + +#define UCCE_RXF (UCC_GETH_UCCE_RXF7 | UCC_GETH_UCCE_RXF6 | \ + UCC_GETH_UCCE_RXF5 | UCC_GETH_UCCE_RXF4 | \ + UCC_GETH_UCCE_RXF3 | UCC_GETH_UCCE_RXF2 | \ + UCC_GETH_UCCE_RXF1 | UCC_GETH_UCCE_RXF0) + +#define UCCE_OTHER (UCC_GETH_UCCE_SCAR | UCC_GETH_UCCE_GRA | \ + UCC_GETH_UCCE_CBPR | UCC_GETH_UCCE_BSY | \ + UCC_GETH_UCCE_RXC | UCC_GETH_UCCE_TXC | UCC_GETH_UCCE_TXE) + +#define UCCE_RX_EVENTS (UCCE_RXF | UCC_GETH_UCCE_BSY) +#define UCCE_TX_EVENTS (UCCE_TXB | UCC_GETH_UCCE_TXE) /* UCC GETH MACCFG1 (MAC Configuration 1 Register) */ #define MACCFG1_FLOW_RX 0x00000020 /* Flow Control @@ -945,9 +880,10 @@ struct ucc_geth_hardware_statistics { #define UCC_GETH_REMODER_INIT 0 /* bits that must be set */ #define UCC_GETH_TEMODER_INIT 0xC000 /* bits that must */ -#define UCC_GETH_UPSMR_INIT (UPSMR_RES1) /* Start value - for this - register */ + +/* Initial value for UPSMR */ +#define UCC_GETH_UPSMR_INIT UCC_GETH_UPSMR_RES1 + #define UCC_GETH_MACCFG1_INIT 0 #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index edd244f3acb..5b67bbf1987 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -23,7 +23,7 @@ #include <linux/usb/usbnet.h> /* datasheet: - http://www.davicom.com.tw/big5/download/Data%20Sheet/DM9601-DS-P01-930914.pdf + http://ptm2.cc.utu.fi/ftp/network/cards/DM9601/From_NET/DM9601-DS-P01-930914.pdf */ /* control requests */ @@ -397,16 +397,24 @@ static void dm9601_set_multicast(struct net_device *net) dm_write_reg_async(dev, DM_RX_CTRL, rx_ctl); } +static void __dm9601_set_mac_address(struct usbnet *dev) +{ + dm_write_async(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr); +} + static int dm9601_set_mac_address(struct net_device *net, void *p) { struct sockaddr *addr = p; struct usbnet *dev = netdev_priv(net); - if (!is_valid_ether_addr(addr->sa_data)) + if (!is_valid_ether_addr(addr->sa_data)) { + dev_err(&net->dev, "not setting invalid mac address %pM\n", + addr->sa_data); return -EINVAL; + } memcpy(net->dev_addr, addr->sa_data, net->addr_len); - dm_write_async(dev, DM_PHY_ADDR, net->addr_len, net->dev_addr); + __dm9601_set_mac_address(dev); return 0; } @@ -414,6 +422,7 @@ static int dm9601_set_mac_address(struct net_device *net, void *p) static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) { int ret; + u8 mac[ETH_ALEN]; ret = usbnet_get_endpoints(dev, intf); if (ret) @@ -438,12 +447,24 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) udelay(20); /* read MAC */ - if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, dev->net->dev_addr) < 0) { + if (dm_read(dev, DM_PHY_ADDR, ETH_ALEN, mac) < 0) { printk(KERN_ERR "Error reading MAC address\n"); ret = -ENODEV; goto out; } + /* + * Overwrite the auto-generated address only with good ones. + */ + if (is_valid_ether_addr(mac)) + memcpy(dev->net->dev_addr, mac, ETH_ALEN); + else { + printk(KERN_WARNING + "dm9601: No valid MAC address in EEPROM, using %pM\n", + dev->net->dev_addr); + __dm9601_set_mac_address(dev); + } + /* power up phy */ dm_write_reg(dev, DM_GPR_CTRL, 1); dm_write_reg(dev, DM_GPR_DATA, 0); diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 3073ca25a0b..7cb10a0a531 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -251,7 +251,6 @@ struct kaweth_device struct net_device_stats stats; }; - /**************************************************************** * kaweth_control ****************************************************************/ @@ -975,6 +974,17 @@ static int kaweth_resume(struct usb_interface *intf) /**************************************************************** * kaweth_probe ****************************************************************/ + + +static const struct net_device_ops kaweth_netdev_ops = { + .ndo_open = kaweth_open, + .ndo_stop = kaweth_close, + .ndo_start_xmit = kaweth_start_xmit, + .ndo_tx_timeout = kaweth_tx_timeout, + .ndo_set_multicast_list = kaweth_set_rx_mode, + .ndo_get_stats = kaweth_netdev_stats, +}; + static int kaweth_probe( struct usb_interface *intf, const struct usb_device_id *id /* from id_table */ @@ -1147,22 +1157,13 @@ err_fw: memcpy(netdev->dev_addr, &kaweth->configuration.hw_addr, sizeof(kaweth->configuration.hw_addr)); - netdev->open = kaweth_open; - netdev->stop = kaweth_close; - + netdev->netdev_ops = &kaweth_netdev_ops; netdev->watchdog_timeo = KAWETH_TX_TIMEOUT; - netdev->tx_timeout = kaweth_tx_timeout; - - netdev->hard_start_xmit = kaweth_start_xmit; - netdev->set_multicast_list = kaweth_set_rx_mode; - netdev->get_stats = kaweth_netdev_stats; netdev->mtu = le16_to_cpu(kaweth->configuration.segment_size); SET_ETHTOOL_OPS(netdev, &ops); /* kaweth is zeroed as part of alloc_netdev */ - INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); - usb_set_intfdata(intf, kaweth); #if 0 diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index d9241f1c080..a8228d87c8c 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -93,6 +93,7 @@ module_param (msg_level, int, 0); MODULE_PARM_DESC (msg_level, "Override default message level"); MODULE_DEVICE_TABLE(usb, pegasus_ids); +static const struct net_device_ops pegasus_netdev_ops; static int update_eth_regs_async(pegasus_t *); /* Aargh!!! I _really_ hate such tweaks */ @@ -1360,14 +1361,10 @@ static int pegasus_probe(struct usb_interface *intf, pegasus->intf = intf; pegasus->usb = dev; pegasus->net = net; - net->open = pegasus_open; - net->stop = pegasus_close; + + net->watchdog_timeo = PEGASUS_TX_TIMEOUT; - net->tx_timeout = pegasus_tx_timeout; - net->do_ioctl = pegasus_ioctl; - net->hard_start_xmit = pegasus_start_xmit; - net->set_multicast_list = pegasus_set_multicast; - net->get_stats = pegasus_netdev_stats; + net->netdev_ops = &pegasus_netdev_ops; SET_ETHTOOL_OPS(net, &ops); pegasus->mii.dev = net; pegasus->mii.mdio_read = mdio_read; @@ -1482,6 +1479,16 @@ static int pegasus_resume (struct usb_interface *intf) return 0; } +static const struct net_device_ops pegasus_netdev_ops = { + .ndo_open = pegasus_open, + .ndo_stop = pegasus_close, + .ndo_do_ioctl = pegasus_ioctl, + .ndo_start_xmit = pegasus_start_xmit, + .ndo_set_multicast_list = pegasus_set_multicast, + .ndo_get_stats = pegasus_netdev_stats, + .ndo_tx_timeout = pegasus_tx_timeout, +}; + static struct usb_driver pegasus_driver = { .name = driver_name, .probe = pegasus_probe, diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index ac07cc6e3cb..3b8e6325427 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -622,6 +622,7 @@ static const struct net_device_ops rhine_netdev_ops = { .ndo_get_stats = rhine_get_stats, .ndo_set_multicast_list = rhine_set_rx_mode, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = netdev_ioctl, .ndo_tx_timeout = rhine_tx_timeout, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 58e25d090ae..a75f91dc315 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -855,6 +855,7 @@ static const struct net_device_ops velocity_netdev_ops = { .ndo_start_xmit = velocity_xmit, .ndo_get_stats = velocity_get_stats, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_set_multicast_list = velocity_set_multi, .ndo_change_mtu = velocity_change_mtu, .ndo_do_ioctl = velocity_ioctl, diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b7004ff3645..43f6523c40b 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -624,6 +624,18 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops virtnet_netdev = { + .ndo_open = virtnet_open, + .ndo_stop = virtnet_close, + .ndo_start_xmit = start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_change_mtu = virtnet_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = virtnet_netpoll, +#endif +}; + static int virtnet_probe(struct virtio_device *vdev) { int err; @@ -636,14 +648,8 @@ static int virtnet_probe(struct virtio_device *vdev) return -ENOMEM; /* Set up network device as normal. */ - dev->open = virtnet_open; - dev->stop = virtnet_close; - dev->hard_start_xmit = start_xmit; - dev->change_mtu = virtnet_change_mtu; + dev->netdev_ops = &virtnet_netdev; dev->features = NETIF_F_HIGHDMA; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = virtnet_netpoll; -#endif SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops); SET_NETDEV_DEV(dev, &vdev->dev); diff --git a/drivers/net/wd.c b/drivers/net/wd.c index 3c1edda08d3..d8322d2d1e2 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -155,6 +155,7 @@ static const struct net_device_ops wd_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index 6d4b65fd9c1..c6d93465c7e 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c @@ -397,11 +397,13 @@ int i2400mu_probe(struct usb_interface *iface, i2400m->bus_fw_name = I2400MU_FW_FILE_NAME; i2400m->bus_bm_mac_addr_impaired = 0; +#ifdef CONFIG_PM iface->needs_remote_wakeup = 1; /* autosuspend (15s delay) */ device_init_wakeup(dev, 1); usb_autopm_enable(i2400mu->usb_iface); usb_dev->autosuspend_delay = 15 * HZ; usb_dev->autosuspend_disabled = 0; +#endif result = i2400m_setup(i2400m, I2400M_BRI_MAC_REINIT); if (result < 0) { @@ -493,7 +495,9 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) int result = 0; struct device *dev = &iface->dev; struct i2400mu *i2400mu = usb_get_intfdata(iface); +#ifdef CONFIG_PM struct usb_device *usb_dev = i2400mu->usb_dev; +#endif struct i2400m *i2400m = &i2400mu->i2400m; d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); @@ -503,11 +507,13 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) atomic_dec(&i2400mu->do_autopm); result = i2400m_cmd_enter_powersave(i2400m); atomic_inc(&i2400mu->do_autopm); +#ifdef CONFIG_PM if (result < 0 && usb_dev->auto_pm == 0) { /* System suspend, can't fail */ dev_err(dev, "failed to suspend, will reset on resume\n"); result = 0; } +#endif if (result < 0) goto error_enter_powersave; i2400mu_notification_release(i2400mu); diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index 7e2b1a67e5d..b65b4feb2d2 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath5k/dma.c @@ -594,7 +594,7 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) * XXX: BMISS interrupts may occur after association. * I found this on 5210 code but it needs testing. If this is * true we should disable them before assoc and re-enable them - * after a successfull assoc + some jiffies. + * after a successful assoc + some jiffies. interrupt_mask &= ~AR5K_INT_BMISS; */ } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 3dba8367944..4e0007d2003 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -1369,7 +1369,7 @@ EXPORT_SYMBOL_GPL(lbs_start_card); void lbs_stop_card(struct lbs_private *priv) { - struct net_device *dev = priv->dev; + struct net_device *dev; struct cmd_ctrl_node *cmdnode; unsigned long flags; @@ -1377,9 +1377,10 @@ void lbs_stop_card(struct lbs_private *priv) if (!priv) goto out; + dev = priv->dev; - netif_stop_queue(priv->dev); - netif_carrier_off(priv->dev); + netif_stop_queue(dev); + netif_carrier_off(dev); lbs_debugfs_remove_one(priv); if (priv->mesh_tlv) { diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 9caa96a1358..a611ad85798 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -287,7 +287,7 @@ static void zd_op_stop(struct ieee80211_hw *hw) * @skb - a sk-buffer * @flags: extra flags to set in the TX status info * @ackssi: ACK signal strength - * @success - True for successfull transmission of the frame + * @success - True for successful transmission of the frame * * This information calls ieee80211_tx_status_irqsafe() if required by the * control information. It copies the control information into the status diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 761635be910..cd6184ee08e 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1105,6 +1105,16 @@ static void xennet_uninit(struct net_device *dev) gnttab_free_grant_references(np->gref_rx_head); } +static const struct net_device_ops xennet_netdev_ops = { + .ndo_open = xennet_open, + .ndo_uninit = xennet_uninit, + .ndo_stop = xennet_close, + .ndo_start_xmit = xennet_start_xmit, + .ndo_change_mtu = xennet_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev) { int i, err; @@ -1161,12 +1171,9 @@ static struct net_device * __devinit xennet_create_dev(struct xenbus_device *dev goto exit_free_tx; } - netdev->open = xennet_open; - netdev->hard_start_xmit = xennet_start_xmit; - netdev->stop = xennet_close; + netdev->netdev_ops = &xennet_netdev_ops; + netif_napi_add(netdev, &np->napi, xennet_poll, 64); - netdev->uninit = xennet_uninit; - netdev->change_mtu = xennet_change_mtu; netdev->features = NETIF_F_IP_CSUM; SET_ETHTOOL_OPS(netdev, &xennet_ethtool_ops); diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index cf971292277..2f1645dcb8c 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -362,6 +362,7 @@ static const struct net_device_ops netdev_ops = { .ndo_set_multicast_list = set_rx_mode, .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = netdev_ioctl, .ndo_tx_timeout = yellowfin_tx_timeout, }; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index affd904deaf..37c84e3b8be 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -147,6 +147,7 @@ static const struct net_device_ops zorro8390_netdev_ops = { .ndo_get_stats = ei_get_stats, .ndo_set_multicast_list = ei_set_multicast_list, .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = eth_change_mtu, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = ei_poll, diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 65e8294a9e2..9da5a4b8113 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -1,11 +1,12 @@ /** * @file buffer_sync.c * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> * @author Barry Kasindorf + * @author Robert Richter <robert.richter@amd.com> * * This is the core of the buffer management. Each * CPU buffer is processed and entered into the @@ -315,88 +316,73 @@ static void add_trace_begin(void) add_event_entry(TRACE_BEGIN_CODE); } -#ifdef CONFIG_OPROFILE_IBS - -#define IBS_FETCH_CODE_SIZE 2 -#define IBS_OP_CODE_SIZE 5 - -/* - * Add IBS fetch and op entries to event buffer - */ -static void add_ibs_begin(int cpu, int code, struct mm_struct *mm) +static void add_data(struct op_entry *entry, struct mm_struct *mm) { - unsigned long rip; - int i, count; - unsigned long ibs_cookie = 0; + unsigned long code, pc, val; + unsigned long cookie; off_t offset; - struct op_sample *sample; - - sample = cpu_buffer_read_entry(cpu); - if (!sample) - goto Error; - rip = sample->eip; -#ifdef __LP64__ - rip += sample->event << 32; -#endif + if (!op_cpu_buffer_get_data(entry, &code)) + return; + if (!op_cpu_buffer_get_data(entry, &pc)) + return; + if (!op_cpu_buffer_get_size(entry)) + return; if (mm) { - ibs_cookie = lookup_dcookie(mm, rip, &offset); + cookie = lookup_dcookie(mm, pc, &offset); - if (ibs_cookie == NO_COOKIE) - offset = rip; - if (ibs_cookie == INVALID_COOKIE) { + if (cookie == NO_COOKIE) + offset = pc; + if (cookie == INVALID_COOKIE) { atomic_inc(&oprofile_stats.sample_lost_no_mapping); - offset = rip; + offset = pc; } - if (ibs_cookie != last_cookie) { - add_cookie_switch(ibs_cookie); - last_cookie = ibs_cookie; + if (cookie != last_cookie) { + add_cookie_switch(cookie); + last_cookie = cookie; } } else - offset = rip; + offset = pc; add_event_entry(ESCAPE_CODE); add_event_entry(code); add_event_entry(offset); /* Offset from Dcookie */ - /* we send the Dcookie offset, but send the raw Linear Add also*/ - add_event_entry(sample->eip); - add_event_entry(sample->event); - - if (code == IBS_FETCH_CODE) - count = IBS_FETCH_CODE_SIZE; /*IBS FETCH is 2 int64s*/ - else - count = IBS_OP_CODE_SIZE; /*IBS OP is 5 int64s*/ - - for (i = 0; i < count; i++) { - sample = cpu_buffer_read_entry(cpu); - if (!sample) - goto Error; - add_event_entry(sample->eip); - add_event_entry(sample->event); - } - - return; - -Error: - return; + while (op_cpu_buffer_get_data(entry, &val)) + add_event_entry(val); } -#endif - -static void add_sample_entry(unsigned long offset, unsigned long event) +static inline void add_sample_entry(unsigned long offset, unsigned long event) { add_event_entry(offset); add_event_entry(event); } -static int add_us_sample(struct mm_struct *mm, struct op_sample *s) +/* + * Add a sample to the global event buffer. If possible the + * sample is converted into a persistent dentry/offset pair + * for later lookup from userspace. Return 0 on failure. + */ +static int +add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) { unsigned long cookie; off_t offset; + if (in_kernel) { + add_sample_entry(s->eip, s->event); + return 1; + } + + /* add userspace sample */ + + if (!mm) { + atomic_inc(&oprofile_stats.sample_lost_no_mm); + return 0; + } + cookie = lookup_dcookie(mm, s->eip, &offset); if (cookie == INVALID_COOKIE) { @@ -415,25 +401,6 @@ static int add_us_sample(struct mm_struct *mm, struct op_sample *s) } -/* Add a sample to the global event buffer. If possible the - * sample is converted into a persistent dentry/offset pair - * for later lookup from userspace. - */ -static int -add_sample(struct mm_struct *mm, struct op_sample *s, int in_kernel) -{ - if (in_kernel) { - add_sample_entry(s->eip, s->event); - return 1; - } else if (mm) { - return add_us_sample(mm, s); - } else { - atomic_inc(&oprofile_stats.sample_lost_no_mm); - } - return 0; -} - - static void release_mm(struct mm_struct *mm) { if (!mm) @@ -526,66 +493,69 @@ void sync_buffer(int cpu) { struct mm_struct *mm = NULL; struct mm_struct *oldmm; + unsigned long val; struct task_struct *new; unsigned long cookie = 0; int in_kernel = 1; sync_buffer_state state = sb_buffer_start; unsigned int i; unsigned long available; + unsigned long flags; + struct op_entry entry; + struct op_sample *sample; mutex_lock(&buffer_mutex); add_cpu_switch(cpu); - cpu_buffer_reset(cpu); - available = cpu_buffer_entries(cpu); + op_cpu_buffer_reset(cpu); + available = op_cpu_buffer_entries(cpu); for (i = 0; i < available; ++i) { - struct op_sample *s = cpu_buffer_read_entry(cpu); - if (!s) + sample = op_cpu_buffer_read_entry(&entry, cpu); + if (!sample) break; - if (is_code(s->eip)) { - switch (s->event) { - case 0: - case CPU_IS_KERNEL: + if (is_code(sample->eip)) { + flags = sample->event; + if (flags & TRACE_BEGIN) { + state = sb_bt_start; + add_trace_begin(); + } + if (flags & KERNEL_CTX_SWITCH) { /* kernel/userspace switch */ - in_kernel = s->event; + in_kernel = flags & IS_KERNEL; if (state == sb_buffer_start) state = sb_sample_start; - add_kernel_ctx_switch(s->event); - break; - case CPU_TRACE_BEGIN: - state = sb_bt_start; - add_trace_begin(); - break; -#ifdef CONFIG_OPROFILE_IBS - case IBS_FETCH_BEGIN: - state = sb_bt_start; - add_ibs_begin(cpu, IBS_FETCH_CODE, mm); - break; - case IBS_OP_BEGIN: - state = sb_bt_start; - add_ibs_begin(cpu, IBS_OP_CODE, mm); - break; -#endif - default: + add_kernel_ctx_switch(flags & IS_KERNEL); + } + if (flags & USER_CTX_SWITCH + && op_cpu_buffer_get_data(&entry, &val)) { /* userspace context switch */ + new = (struct task_struct *)val; oldmm = mm; - new = (struct task_struct *)s->event; release_mm(oldmm); mm = take_tasks_mm(new); if (mm != oldmm) cookie = get_exec_dcookie(mm); add_user_ctx_switch(new, cookie); - break; - } - } else if (state >= sb_bt_start && - !add_sample(mm, s, in_kernel)) { - if (state == sb_bt_start) { - state = sb_bt_ignore; - atomic_inc(&oprofile_stats.bt_lost_no_mapping); } + if (op_cpu_buffer_get_size(&entry)) + add_data(&entry, mm); + continue; + } + + if (state < sb_bt_start) + /* ignore sample */ + continue; + + if (add_sample(mm, sample, in_kernel)) + continue; + + /* ignore backtraces if failed to add a sample */ + if (state == sb_bt_start) { + state = sb_bt_ignore; + atomic_inc(&oprofile_stats.bt_lost_no_mapping); } } release_mm(mm); diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index 61090969158..2e03b6d796d 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c @@ -1,11 +1,12 @@ /** * @file cpu_buffer.c * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> * @author Barry Kasindorf <barry.kasindorf@amd.com> + * @author Robert Richter <robert.richter@amd.com> * * Each CPU has a local buffer that stores PC value/event * pairs. We also log context switches when we notice them. @@ -45,8 +46,8 @@ * can be changed to a single buffer solution when the ring buffer * access is implemented as non-locking atomic code. */ -struct ring_buffer *op_ring_buffer_read; -struct ring_buffer *op_ring_buffer_write; +static struct ring_buffer *op_ring_buffer_read; +static struct ring_buffer *op_ring_buffer_write; DEFINE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); static void wq_sync_buffer(struct work_struct *work); @@ -54,19 +55,9 @@ static void wq_sync_buffer(struct work_struct *work); #define DEFAULT_TIMER_EXPIRE (HZ / 10) static int work_enabled; -void free_cpu_buffers(void) -{ - if (op_ring_buffer_read) - ring_buffer_free(op_ring_buffer_read); - op_ring_buffer_read = NULL; - if (op_ring_buffer_write) - ring_buffer_free(op_ring_buffer_write); - op_ring_buffer_write = NULL; -} - unsigned long oprofile_get_cpu_buffer_size(void) { - return fs_cpu_buffer_size; + return oprofile_cpu_buffer_size; } void oprofile_cpu_buffer_inc_smpl_lost(void) @@ -77,11 +68,21 @@ void oprofile_cpu_buffer_inc_smpl_lost(void) cpu_buf->sample_lost_overflow++; } +void free_cpu_buffers(void) +{ + if (op_ring_buffer_read) + ring_buffer_free(op_ring_buffer_read); + op_ring_buffer_read = NULL; + if (op_ring_buffer_write) + ring_buffer_free(op_ring_buffer_write); + op_ring_buffer_write = NULL; +} + int alloc_cpu_buffers(void) { int i; - unsigned long buffer_size = fs_cpu_buffer_size; + unsigned long buffer_size = oprofile_cpu_buffer_size; op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); if (!op_ring_buffer_read) @@ -97,8 +98,6 @@ int alloc_cpu_buffers(void) b->last_is_kernel = -1; b->tracing = 0; b->buffer_size = buffer_size; - b->tail_pos = 0; - b->head_pos = 0; b->sample_received = 0; b->sample_lost_overflow = 0; b->backtrace_aborted = 0; @@ -145,47 +144,156 @@ void end_cpu_work(void) flush_scheduled_work(); } -static inline int -add_sample(struct oprofile_cpu_buffer *cpu_buf, - unsigned long pc, unsigned long event) +/* + * This function prepares the cpu buffer to write a sample. + * + * Struct op_entry is used during operations on the ring buffer while + * struct op_sample contains the data that is stored in the ring + * buffer. Struct entry can be uninitialized. The function reserves a + * data array that is specified by size. Use + * op_cpu_buffer_write_commit() after preparing the sample. In case of + * errors a null pointer is returned, otherwise the pointer to the + * sample. + * + */ +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size) +{ + entry->event = ring_buffer_lock_reserve + (op_ring_buffer_write, sizeof(struct op_sample) + + size * sizeof(entry->sample->data[0]), &entry->irq_flags); + if (entry->event) + entry->sample = ring_buffer_event_data(entry->event); + else + entry->sample = NULL; + + if (!entry->sample) + return NULL; + + entry->size = size; + entry->data = entry->sample->data; + + return entry->sample; +} + +int op_cpu_buffer_write_commit(struct op_entry *entry) +{ + return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, + entry->irq_flags); +} + +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu) +{ + struct ring_buffer_event *e; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + goto event; + if (ring_buffer_swap_cpu(op_ring_buffer_read, + op_ring_buffer_write, + cpu)) + return NULL; + e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); + if (e) + goto event; + return NULL; + +event: + entry->event = e; + entry->sample = ring_buffer_event_data(e); + entry->size = (ring_buffer_event_length(e) - sizeof(struct op_sample)) + / sizeof(entry->sample->data[0]); + entry->data = entry->sample->data; + return entry->sample; +} + +unsigned long op_cpu_buffer_entries(int cpu) +{ + return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) + + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); +} + +static int +op_add_code(struct oprofile_cpu_buffer *cpu_buf, unsigned long backtrace, + int is_kernel, struct task_struct *task) { struct op_entry entry; - int ret; + struct op_sample *sample; + unsigned long flags; + int size; + + flags = 0; + + if (backtrace) + flags |= TRACE_BEGIN; + + /* notice a switch from user->kernel or vice versa */ + is_kernel = !!is_kernel; + if (cpu_buf->last_is_kernel != is_kernel) { + cpu_buf->last_is_kernel = is_kernel; + flags |= KERNEL_CTX_SWITCH; + if (is_kernel) + flags |= IS_KERNEL; + } + + /* notice a task switch */ + if (cpu_buf->last_task != task) { + cpu_buf->last_task = task; + flags |= USER_CTX_SWITCH; + } + + if (!flags) + /* nothing to do */ + return 0; + + if (flags & USER_CTX_SWITCH) + size = 1; + else + size = 0; + + sample = op_cpu_buffer_write_reserve(&entry, size); + if (!sample) + return -ENOMEM; - ret = cpu_buffer_write_entry(&entry); - if (ret) - return ret; + sample->eip = ESCAPE_CODE; + sample->event = flags; - entry.sample->eip = pc; - entry.sample->event = event; + if (size) + op_cpu_buffer_add_data(&entry, (unsigned long)task); - ret = cpu_buffer_write_commit(&entry); - if (ret) - return ret; + op_cpu_buffer_write_commit(&entry); return 0; } static inline int -add_code(struct oprofile_cpu_buffer *buffer, unsigned long value) +op_add_sample(struct oprofile_cpu_buffer *cpu_buf, + unsigned long pc, unsigned long event) { - return add_sample(buffer, ESCAPE_CODE, value); + struct op_entry entry; + struct op_sample *sample; + + sample = op_cpu_buffer_write_reserve(&entry, 0); + if (!sample) + return -ENOMEM; + + sample->eip = pc; + sample->event = event; + + return op_cpu_buffer_write_commit(&entry); } -/* This must be safe from any context. It's safe writing here - * because of the head/tail separation of the writer and reader - * of the CPU buffer. +/* + * This must be safe from any context. * * is_kernel is needed because on some architectures you cannot * tell if you are in kernel or user space simply by looking at * pc. We tag this in the buffer by generating kernel enter/exit * events whenever is_kernel changes */ -static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, - int is_kernel, unsigned long event) +static int +log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, + unsigned long backtrace, int is_kernel, unsigned long event) { - struct task_struct *task; - cpu_buf->sample_received++; if (pc == ESCAPE_CODE) { @@ -193,25 +301,10 @@ static int log_sample(struct oprofile_cpu_buffer *cpu_buf, unsigned long pc, return 0; } - is_kernel = !!is_kernel; - - task = current; - - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - cpu_buf->last_is_kernel = is_kernel; - if (add_code(cpu_buf, is_kernel)) - goto fail; - } - - /* notice a task switch */ - if (cpu_buf->last_task != task) { - cpu_buf->last_task = task; - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - } + if (op_add_code(cpu_buf, backtrace, is_kernel, current)) + goto fail; - if (add_sample(cpu_buf, pc, event)) + if (op_add_sample(cpu_buf, pc, event)) goto fail; return 1; @@ -221,109 +314,102 @@ fail: return 0; } -static int oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_begin_trace(struct oprofile_cpu_buffer *cpu_buf) { - add_code(cpu_buf, CPU_TRACE_BEGIN); cpu_buf->tracing = 1; - return 1; } -static void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) +static inline void oprofile_end_trace(struct oprofile_cpu_buffer *cpu_buf) { cpu_buf->tracing = 0; } -void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, - unsigned long event, int is_kernel) +static inline void +__oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - - if (!backtrace_depth) { - log_sample(cpu_buf, pc, is_kernel, event); - return; - } - - if (!oprofile_begin_trace(cpu_buf)) - return; + unsigned long backtrace = oprofile_backtrace_depth; /* * if log_sample() fail we can't backtrace since we lost the * source of this event */ - if (log_sample(cpu_buf, pc, is_kernel, event)) - oprofile_ops.backtrace(regs, backtrace_depth); + if (!log_sample(cpu_buf, pc, backtrace, is_kernel, event)) + /* failed */ + return; + + if (!backtrace) + return; + + oprofile_begin_trace(cpu_buf); + oprofile_ops.backtrace(regs, backtrace); oprofile_end_trace(cpu_buf); } +void oprofile_add_ext_sample(unsigned long pc, struct pt_regs * const regs, + unsigned long event, int is_kernel) +{ + __oprofile_add_ext_sample(pc, regs, event, is_kernel); +} + void oprofile_add_sample(struct pt_regs * const regs, unsigned long event) { int is_kernel = !user_mode(regs); unsigned long pc = profile_pc(regs); - oprofile_add_ext_sample(pc, regs, event, is_kernel); + __oprofile_add_ext_sample(pc, regs, event, is_kernel); } -#ifdef CONFIG_OPROFILE_IBS - -#define MAX_IBS_SAMPLE_SIZE 14 - -void oprofile_add_ibs_sample(struct pt_regs * const regs, - unsigned int * const ibs_sample, int ibs_code) +/* + * Add samples with data to the ring buffer. + * + * Use oprofile_add_data(&entry, val) to add data and + * oprofile_write_commit(&entry) to commit the sample. + */ +void +oprofile_write_reserve(struct op_entry *entry, struct pt_regs * const regs, + unsigned long pc, int code, int size) { + struct op_sample *sample; int is_kernel = !user_mode(regs); struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - struct task_struct *task; - int fail = 0; cpu_buf->sample_received++; - /* notice a switch from user->kernel or vice versa */ - if (cpu_buf->last_is_kernel != is_kernel) { - if (add_code(cpu_buf, is_kernel)) - goto fail; - cpu_buf->last_is_kernel = is_kernel; - } - - /* notice a task switch */ - if (!is_kernel) { - task = current; - if (cpu_buf->last_task != task) { - if (add_code(cpu_buf, (unsigned long)task)) - goto fail; - cpu_buf->last_task = task; - } - } - - fail = fail || add_code(cpu_buf, ibs_code); - fail = fail || add_sample(cpu_buf, ibs_sample[0], ibs_sample[1]); - fail = fail || add_sample(cpu_buf, ibs_sample[2], ibs_sample[3]); - fail = fail || add_sample(cpu_buf, ibs_sample[4], ibs_sample[5]); - - if (ibs_code == IBS_OP_BEGIN) { - fail = fail || add_sample(cpu_buf, ibs_sample[6], ibs_sample[7]); - fail = fail || add_sample(cpu_buf, ibs_sample[8], ibs_sample[9]); - fail = fail || add_sample(cpu_buf, ibs_sample[10], ibs_sample[11]); - } + /* no backtraces for samples with data */ + if (op_add_code(cpu_buf, 0, is_kernel, current)) + goto fail; - if (fail) + sample = op_cpu_buffer_write_reserve(entry, size + 2); + if (!sample) goto fail; + sample->eip = ESCAPE_CODE; + sample->event = 0; /* no flags */ - if (backtrace_depth) - oprofile_ops.backtrace(regs, backtrace_depth); + op_cpu_buffer_add_data(entry, code); + op_cpu_buffer_add_data(entry, pc); return; fail: cpu_buf->sample_lost_overflow++; - return; } -#endif +int oprofile_add_data(struct op_entry *entry, unsigned long val) +{ + return op_cpu_buffer_add_data(entry, val); +} + +int oprofile_write_commit(struct op_entry *entry) +{ + return op_cpu_buffer_write_commit(entry); +} void oprofile_add_pc(unsigned long pc, int is_kernel, unsigned long event) { struct oprofile_cpu_buffer *cpu_buf = &__get_cpu_var(cpu_buffer); - log_sample(cpu_buf, pc, is_kernel, event); + log_sample(cpu_buf, pc, 0, is_kernel, event); } void oprofile_add_trace(unsigned long pc) @@ -340,7 +426,7 @@ void oprofile_add_trace(unsigned long pc) if (pc == ESCAPE_CODE) goto fail; - if (add_sample(cpu_buf, pc, 0)) + if (op_add_sample(cpu_buf, pc, 0)) goto fail; return; diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h index aacb0f0bc56..63f81c44846 100644 --- a/drivers/oprofile/cpu_buffer.h +++ b/drivers/oprofile/cpu_buffer.h @@ -1,10 +1,11 @@ /** * @file cpu_buffer.h * - * @remark Copyright 2002 OProfile authors + * @remark Copyright 2002-2009 OProfile authors * @remark Read the file COPYING * * @author John Levon <levon@movementarian.org> + * @author Robert Richter <robert.richter@amd.com> */ #ifndef OPROFILE_CPU_BUFFER_H @@ -31,17 +32,12 @@ void end_cpu_work(void); struct op_sample { unsigned long eip; unsigned long event; + unsigned long data[0]; }; -struct op_entry { - struct ring_buffer_event *event; - struct op_sample *sample; - unsigned long irq_flags; -}; +struct op_entry; struct oprofile_cpu_buffer { - volatile unsigned long head_pos; - volatile unsigned long tail_pos; unsigned long buffer_size; struct task_struct *last_task; int last_is_kernel; @@ -54,8 +50,6 @@ struct oprofile_cpu_buffer { struct delayed_work work; }; -extern struct ring_buffer *op_ring_buffer_read; -extern struct ring_buffer *op_ring_buffer_write; DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); /* @@ -64,7 +58,7 @@ DECLARE_PER_CPU(struct oprofile_cpu_buffer, cpu_buffer); * reset these to invalid values; the next sample collected will * populate the buffer with proper values to initialize the buffer */ -static inline void cpu_buffer_reset(int cpu) +static inline void op_cpu_buffer_reset(int cpu) { struct oprofile_cpu_buffer *cpu_buf = &per_cpu(cpu_buffer, cpu); @@ -72,55 +66,48 @@ static inline void cpu_buffer_reset(int cpu) cpu_buf->last_task = NULL; } -static inline int cpu_buffer_write_entry(struct op_entry *entry) -{ - entry->event = ring_buffer_lock_reserve(op_ring_buffer_write, - sizeof(struct op_sample), - &entry->irq_flags); - if (entry->event) - entry->sample = ring_buffer_event_data(entry->event); - else - entry->sample = NULL; - - if (!entry->sample) - return -ENOMEM; - - return 0; -} +struct op_sample +*op_cpu_buffer_write_reserve(struct op_entry *entry, unsigned long size); +int op_cpu_buffer_write_commit(struct op_entry *entry); +struct op_sample *op_cpu_buffer_read_entry(struct op_entry *entry, int cpu); +unsigned long op_cpu_buffer_entries(int cpu); -static inline int cpu_buffer_write_commit(struct op_entry *entry) +/* returns the remaining free size of data in the entry */ +static inline +int op_cpu_buffer_add_data(struct op_entry *entry, unsigned long val) { - return ring_buffer_unlock_commit(op_ring_buffer_write, entry->event, - entry->irq_flags); + if (!entry->size) + return 0; + *entry->data = val; + entry->size--; + entry->data++; + return entry->size; } -static inline struct op_sample *cpu_buffer_read_entry(int cpu) +/* returns the size of data in the entry */ +static inline +int op_cpu_buffer_get_size(struct op_entry *entry) { - struct ring_buffer_event *e; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - if (ring_buffer_swap_cpu(op_ring_buffer_read, - op_ring_buffer_write, - cpu)) - return NULL; - e = ring_buffer_consume(op_ring_buffer_read, cpu, NULL); - if (e) - return ring_buffer_event_data(e); - return NULL; + return entry->size; } -/* "acquire" as many cpu buffer slots as we can */ -static inline unsigned long cpu_buffer_entries(int cpu) +/* returns 0 if empty or the size of data including the current value */ +static inline +int op_cpu_buffer_get_data(struct op_entry *entry, unsigned long *val) { - return ring_buffer_entries_cpu(op_ring_buffer_read, cpu) - + ring_buffer_entries_cpu(op_ring_buffer_write, cpu); + int size = entry->size; + if (!size) + return 0; + *val = *entry->data; + entry->size--; + entry->data++; + return size; } -/* transient events for the CPU buffer -> event buffer */ -#define CPU_IS_KERNEL 1 -#define CPU_TRACE_BEGIN 2 -#define IBS_FETCH_BEGIN 3 -#define IBS_OP_BEGIN 4 +/* extra data flags */ +#define KERNEL_CTX_SWITCH (1UL << 0) +#define IS_KERNEL (1UL << 1) +#define TRACE_BEGIN (1UL << 2) +#define USER_CTX_SWITCH (1UL << 3) #endif /* OPROFILE_CPU_BUFFER_H */ diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index 191a3202cec..2b7ae366ceb 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -73,8 +73,8 @@ int alloc_event_buffer(void) unsigned long flags; spin_lock_irqsave(&oprofilefs_lock, flags); - buffer_size = fs_buffer_size; - buffer_watershed = fs_buffer_watershed; + buffer_size = oprofile_buffer_size; + buffer_watershed = oprofile_buffer_watershed; spin_unlock_irqrestore(&oprofilefs_lock, flags); if (buffer_watershed >= buffer_size) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index cd375907f26..3cffce90f82 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -23,7 +23,7 @@ struct oprofile_operations oprofile_ops; unsigned long oprofile_started; -unsigned long backtrace_depth; +unsigned long oprofile_backtrace_depth; static unsigned long is_setup; static DEFINE_MUTEX(start_mutex); @@ -172,7 +172,7 @@ int oprofile_set_backtrace(unsigned long val) goto out; } - backtrace_depth = val; + oprofile_backtrace_depth = val; out: mutex_unlock(&start_mutex); diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h index 5df0c21a608..c288d3c24b5 100644 --- a/drivers/oprofile/oprof.h +++ b/drivers/oprofile/oprof.h @@ -21,12 +21,12 @@ void oprofile_stop(void); struct oprofile_operations; -extern unsigned long fs_buffer_size; -extern unsigned long fs_cpu_buffer_size; -extern unsigned long fs_buffer_watershed; +extern unsigned long oprofile_buffer_size; +extern unsigned long oprofile_cpu_buffer_size; +extern unsigned long oprofile_buffer_watershed; extern struct oprofile_operations oprofile_ops; extern unsigned long oprofile_started; -extern unsigned long backtrace_depth; +extern unsigned long oprofile_backtrace_depth; struct super_block; struct dentry; diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index d8201998b0b..5d36ffc30dd 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -14,17 +14,18 @@ #include "oprofile_stats.h" #include "oprof.h" -#define FS_BUFFER_SIZE_DEFAULT 131072 -#define FS_CPU_BUFFER_SIZE_DEFAULT 8192 -#define FS_BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ +#define BUFFER_SIZE_DEFAULT 131072 +#define CPU_BUFFER_SIZE_DEFAULT 8192 +#define BUFFER_WATERSHED_DEFAULT 32768 /* FIXME: tune */ -unsigned long fs_buffer_size; -unsigned long fs_cpu_buffer_size; -unsigned long fs_buffer_watershed; +unsigned long oprofile_buffer_size; +unsigned long oprofile_cpu_buffer_size; +unsigned long oprofile_buffer_watershed; static ssize_t depth_read(struct file *file, char __user *buf, size_t count, loff_t *offset) { - return oprofilefs_ulong_to_user(backtrace_depth, buf, count, offset); + return oprofilefs_ulong_to_user(oprofile_backtrace_depth, buf, count, + offset); } @@ -125,16 +126,16 @@ static const struct file_operations dump_fops = { void oprofile_create_files(struct super_block *sb, struct dentry *root) { /* reinitialize default values */ - fs_buffer_size = FS_BUFFER_SIZE_DEFAULT; - fs_cpu_buffer_size = FS_CPU_BUFFER_SIZE_DEFAULT; - fs_buffer_watershed = FS_BUFFER_WATERSHED_DEFAULT; + oprofile_buffer_size = BUFFER_SIZE_DEFAULT; + oprofile_cpu_buffer_size = CPU_BUFFER_SIZE_DEFAULT; + oprofile_buffer_watershed = BUFFER_WATERSHED_DEFAULT; oprofilefs_create_file(sb, root, "enable", &enable_fops); oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666); oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops); - oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size); - oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed); - oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_size", &oprofile_buffer_size); + oprofilefs_create_ulong(sb, root, "buffer_watershed", &oprofile_buffer_watershed); + oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &oprofile_cpu_buffer_size); oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops); oprofilefs_create_file(sb, root, "backtrace_depth", &depth_fops); oprofilefs_create_file(sb, root, "pointer_size", &pointer_size_fops); diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c index 82136913536..7931133526c 100644 --- a/drivers/parisc/asp.c +++ b/drivers/parisc/asp.c @@ -71,8 +71,7 @@ static void asp_choose_irq(struct parisc_device *dev, void *ctrl) */ #define ASP_INTERRUPT_ADDR 0xf0800000 -int __init -asp_init_chip(struct parisc_device *dev) +static int __init asp_init_chip(struct parisc_device *dev) { struct gsc_irq gsc_irq; int ret; diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index dcc1e9958d2..cd4dd7ed2c0 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -555,7 +555,7 @@ static u32 hint_lookup[] = { * (Load Coherence Index) instruction. The 8 bits used for the virtual * index are bits 12:19 of the value returned by LCI. */ -void CCIO_INLINE +static void CCIO_INLINE ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hints) { @@ -1578,8 +1578,6 @@ static int __init ccio_probe(struct parisc_device *dev) ioc_count++; - parisc_vmerge_boundary = IOVP_SIZE; - parisc_vmerge_max_size = BITS_PER_LONG * IOVP_SIZE; parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c index 77cc8bfef8c..d539d9df88e 100644 --- a/drivers/parisc/dino.c +++ b/drivers/parisc/dino.c @@ -287,7 +287,7 @@ DINO_PORT_OUT(b, 8, 3) DINO_PORT_OUT(w, 16, 2) DINO_PORT_OUT(l, 32, 0) -struct pci_port_ops dino_port_ops = { +static struct pci_port_ops dino_port_ops = { .inb = dino_in8, .inw = dino_in16, .inl = dino_in32, @@ -690,7 +690,7 @@ dino_fixup_bus(struct pci_bus *bus) } -struct pci_bios_ops dino_bios_ops = { +static struct pci_bios_ops dino_bios_ops = { .init = dino_bios_init, .fixup_bus = dino_fixup_bus }; diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c index 65eee67aa2a..13856415b43 100644 --- a/drivers/parisc/hppb.c +++ b/drivers/parisc/hppb.c @@ -29,7 +29,7 @@ struct hppb_card { struct hppb_card *next; }; -struct hppb_card hppb_card_head = { +static struct hppb_card hppb_card_head = { .hpa = 0, .next = NULL, }; diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c index bee510098ce..e65727ca9fc 100644 --- a/drivers/parisc/lasi.c +++ b/drivers/parisc/lasi.c @@ -107,7 +107,7 @@ lasi_init_irq(struct gsc_asic *this_lasi) #else -void __init lasi_led_init(unsigned long lasi_hpa) +static void __init lasi_led_init(unsigned long lasi_hpa) { unsigned long datareg; @@ -163,8 +163,7 @@ static void lasi_power_off(void) gsc_writel(0x02, datareg); } -int __init -lasi_init_chip(struct parisc_device *dev) +static int __init lasi_init_chip(struct parisc_device *dev) { extern void (*chassis_power_off)(void); struct gsc_asic *lasi; diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index a28c8946dea..d8233de8c75 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -824,7 +824,7 @@ lba_fixup_bus(struct pci_bus *bus) } -struct pci_bios_ops lba_bios_ops = { +static struct pci_bios_ops lba_bios_ops = { .init = lba_bios_init, .fixup_bus = lba_fixup_bus, }; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index bc73b96346f..3fac8f81d59 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -561,7 +561,7 @@ typedef unsigned long space_t; * IOMMU uses little endian for the pdir. */ -void SBA_INLINE +static void SBA_INLINE sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hint) { @@ -1874,7 +1874,7 @@ static struct parisc_device_id sba_tbl[] = { { 0, } }; -int sba_driver_callback(struct parisc_device *); +static int sba_driver_callback(struct parisc_device *); static struct parisc_driver sba_driver = { .name = MODULE_NAME, @@ -1887,8 +1887,7 @@ static struct parisc_driver sba_driver = { ** If so, initialize the chip and tell other partners in crime they ** have work to do. */ -int -sba_driver_callback(struct parisc_device *dev) +static int sba_driver_callback(struct parisc_device *dev) { struct sba_device *sba_dev; u32 func_class; @@ -1979,8 +1978,6 @@ sba_driver_callback(struct parisc_device *dev) proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops); #endif - parisc_vmerge_boundary = IOVP_SIZE; - parisc_vmerge_max_size = IOVP_SIZE * BITS_PER_LONG; parisc_has_iommu(); return 0; } diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c index 1e93c837514..4fa3bb2ddfe 100644 --- a/drivers/parisc/superio.c +++ b/drivers/parisc/superio.c @@ -405,7 +405,6 @@ static void __init superio_serial_init(void) serial_port.type = PORT_16550A; serial_port.uartclk = 115200*16; serial_port.fifosize = 16; - spin_lock_init(&serial_port.lock); /* serial port #1 */ serial_port.iobase = sio_dev.sp1_base; diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c index 892a83bbe73..da9d5ad1353 100644 --- a/drivers/parisc/wax.c +++ b/drivers/parisc/wax.c @@ -68,8 +68,7 @@ wax_init_irq(struct gsc_asic *wax) // gsc_writel(0xFFFFFFFF, base+0x2000); /* RS232-B on Wax */ } -int __init -wax_init_chip(struct parisc_device *dev) +static int __init wax_init_chip(struct parisc_device *dev) { struct gsc_asic *wax; struct parisc_device *parent; diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c index c62ab8d240a..1c114180106 100644 --- a/drivers/pci/hotplug/acpi_pcihp.c +++ b/drivers/pci/hotplug/acpi_pcihp.c @@ -33,7 +33,6 @@ #include <linux/pci-acpi.h> #include <acpi/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #define MY_NAME "acpi_pcihp" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 27fd18f019f..db85284ffb6 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -217,7 +217,6 @@ struct hpc_ops { #ifdef CONFIG_ACPI #include <acpi/acpi.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #include <linux/pci-acpi.h> extern void __init pciehp_acpi_slot_detection_init(void); diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 235fb7a5a8a..3dfecb20d5e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -438,7 +438,8 @@ static struct intel_iommu *device_to_iommu(u8 bus, u8 devfn) continue; for (i = 0; i < drhd->devices_cnt; i++) - if (drhd->devices[i]->bus->number == bus && + if (drhd->devices[i] && + drhd->devices[i]->bus->number == bus && drhd->devices[i]->devfn == devfn) return drhd->iommu; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 3582512e722..deea8a187eb 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -13,8 +13,6 @@ #include <linux/module.h> #include <linux/pci-aspm.h> #include <acpi/acpi.h> -#include <acpi/acnamesp.h> -#include <acpi/acresrc.h> #include <acpi/acpi_bus.h> #include <linux/pci-acpi.h> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index c23619fb6c4..db7ec14fa71 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -71,11 +71,11 @@ static ssize_t broken_parity_status_store(struct device *dev, static ssize_t local_cpus_show(struct device *dev, struct device_attribute *attr, char *buf) { - cpumask_t mask; + const struct cpumask *mask; int len; - mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); - len = cpumask_scnprintf(buf, PAGE_SIZE-2, &mask); + mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); + len = cpumask_scnprintf(buf, PAGE_SIZE-2, mask); buf[len++] = '\n'; buf[len] = '\0'; return len; @@ -85,11 +85,11 @@ static ssize_t local_cpus_show(struct device *dev, static ssize_t local_cpulist_show(struct device *dev, struct device_attribute *attr, char *buf) { - cpumask_t mask; + const struct cpumask *mask; int len; - mask = pcibus_to_cpumask(to_pci_dev(dev)->bus); - len = cpulist_scnprintf(buf, PAGE_SIZE-2, &mask); + mask = cpumask_of_pcibus(to_pci_dev(dev)->bus); + len = cpulist_scnprintf(buf, PAGE_SIZE-2, mask); buf[len++] = '\n'; buf[len] = '\0'; return len; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 303644614ee..55ec44a27e8 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -51,12 +51,12 @@ static ssize_t pci_bus_show_cpuaffinity(struct device *dev, char *buf) { int ret; - cpumask_t cpumask; + const struct cpumask *cpumask; - cpumask = pcibus_to_cpumask(to_pci_bus(dev)); + cpumask = cpumask_of_pcibus(to_pci_bus(dev)); ret = type? - cpulist_scnprintf(buf, PAGE_SIZE-2, &cpumask) : - cpumask_scnprintf(buf, PAGE_SIZE-2, &cpumask); + cpulist_scnprintf(buf, PAGE_SIZE-2, cpumask) : + cpumask_scnprintf(buf, PAGE_SIZE-2, cpumask); buf[ret++] = '\n'; buf[ret] = '\0'; return ret; diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig new file mode 100644 index 00000000000..9652c3fe7f5 --- /dev/null +++ b/drivers/platform/Kconfig @@ -0,0 +1,5 @@ +# drivers/platform/Kconfig + +if X86 +source "drivers/platform/x86/Kconfig" +endif diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile new file mode 100644 index 00000000000..782953ae4c0 --- /dev/null +++ b/drivers/platform/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for linux/drivers/platform +# + +obj-$(CONFIG_X86) += x86/ diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig new file mode 100644 index 00000000000..e65448e99b4 --- /dev/null +++ b/drivers/platform/x86/Kconfig @@ -0,0 +1,375 @@ +# +# X86 Platform Specific Drivers +# + +menuconfig X86_PLATFORM_DEVICES + bool "X86 Platform Specific Device Drivers" + default y + ---help--- + Say Y here to get to see options for device drivers for various + x86 platforms, including vendor-specific laptop extension drivers. + This option alone does not add any kernel code. + + If you say N, all options in this submenu will be skipped and disabled. + +if X86_PLATFORM_DEVICES + +config ACER_WMI + tristate "Acer WMI Laptop Extras (EXPERIMENTAL)" + depends on EXPERIMENTAL + depends on ACPI + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE + depends on SERIO_I8042 + depends on RFKILL + select ACPI_WMI + ---help--- + This is a driver for newer Acer (and Wistron) laptops. It adds + wireless radio and bluetooth control, and on some laptops, + exposes the mail LED and LCD backlight. + + For more information about this driver see + <file:Documentation/laptops/acer-wmi.txt> + + If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M + here. + +config ASUS_LAPTOP + tristate "Asus Laptop Extras (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL && !ACPI_ASUS + depends on LEDS_CLASS + depends on NEW_LEDS + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is the new Linux driver for Asus laptops. It may also support some + MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate + standard ACPI events that go through /proc/acpi/events. It also adds + support for video output switching, LCD backlight control, Bluetooth and + Wlan control, and most importantly, allows you to blink those fancy LEDs. + + For more information and a userspace daemon for handling the extra + buttons see <http://acpi4asus.sf.net/>. + + If you have an ACPI-compatible ASUS laptop, say Y or M here. + +config FUJITSU_LAPTOP + tristate "Fujitsu Laptop Extras" + depends on ACPI + depends on INPUT + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by Fujitsu: + + * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks + * Possibly other Fujitsu laptop models + * Tested with S6410 and S7020 + + It adds support for LCD brightness control and some hotkeys. + + If you have a Fujitsu laptop, say Y or M here. + +config FUJITSU_LAPTOP_DEBUG + bool "Verbose debug mode for Fujitsu Laptop Extras" + depends on FUJITSU_LAPTOP + default n + ---help--- + Enables extra debug output from the fujitsu extras driver, at the + expense of a slight increase in driver size. + + If you are not sure, say N here. + +config TC1100_WMI + tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)" + depends on !X86_64 + depends on EXPERIMENTAL + depends on ACPI + select ACPI_WMI + ---help--- + This is a driver for the WMI extensions (wireless and bluetooth power + control) of the HP Compaq TC1100 tablet. + +config HP_WMI + tristate "HP WMI extras" + depends on ACPI_WMI + depends on INPUT + depends on RFKILL + help + Say Y here if you want to support WMI-based hotkeys on HP laptops and + to read data from WMI such as docking or ambient light sensor state. + + To compile this driver as a module, choose M here: the module will + be called hp-wmi. + +config MSI_LAPTOP + tristate "MSI Laptop Extras" + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by MSI (MICRO-STAR + INTERNATIONAL): + + MSI MegaBook S270 (MS-1013) + Cytron/TCM/Medion/Tchibo MD96100/SAM2000 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + More information about this driver is available at + <http://0pointer.de/lennart/tchibo.html>. + + If you have an MSI S270 laptop, say Y or M here. + +config PANASONIC_LAPTOP + tristate "Panasonic Laptop Extras" + depends on INPUT && ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This driver adds support for access to backlight control and hotkeys + on Panasonic Let's Note laptops. + + If you have a Panasonic Let's note laptop (such as the R1(N variant), + R2, R3, R5, T2, W2 and Y2 series), say Y. + +config COMPAL_LAPTOP + tristate "Compal Laptop Extras" + depends on ACPI + depends on BACKLIGHT_CLASS_DEVICE + ---help--- + This is a driver for laptops built by Compal: + + Compal FL90/IFL90 + Compal FL91/IFL91 + Compal FL92/JFL92 + Compal FT00/IFT00 + + It adds support for Bluetooth, WLAN and LCD brightness control. + + If you have an Compal FL9x/IFL9x/FT00 laptop, say Y or M here. + +config SONY_LAPTOP + tristate "Sony Laptop Extras" + depends on ACPI + select BACKLIGHT_CLASS_DEVICE + depends on INPUT + ---help--- + This mini-driver drives the SNC and SPIC devices present in the ACPI + BIOS of the Sony Vaio laptops. + + It gives access to some extra laptop functionalities like Bluetooth, + screen brightness control, Fn keys and allows powering on/off some + devices. + + Read <file:Documentation/laptops/sony-laptop.txt> for more information. + +config SONYPI_COMPAT + bool "Sonypi compatibility" + depends on SONY_LAPTOP + ---help--- + Build the sonypi driver compatibility code into the sony-laptop driver. + +config THINKPAD_ACPI + tristate "ThinkPad ACPI Laptop Extras" + depends on ACPI + select BACKLIGHT_LCD_SUPPORT + select BACKLIGHT_CLASS_DEVICE + select HWMON + select NVRAM + select INPUT + select NEW_LEDS + select LEDS_CLASS + select NET + select RFKILL + ---help--- + This is a driver for the IBM and Lenovo ThinkPad laptops. It adds + support for Fn-Fx key combinations, Bluetooth control, video + output switching, ThinkLight control, UltraBay eject and more. + For more information about this driver see + <file:Documentation/laptops/thinkpad-acpi.txt> and + <http://ibm-acpi.sf.net/> . + + This driver was formerly known as ibm-acpi. + + If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. + +config THINKPAD_ACPI_DEBUG + bool "Verbose debug mode" + depends on THINKPAD_ACPI + default n + ---help--- + Enables extra debugging information, at the expense of a slightly + increase in driver size. + + If you are not sure, say N here. + +config THINKPAD_ACPI_DOCK + bool "Legacy Docking Station Support" + depends on THINKPAD_ACPI + depends on ACPI_DOCK=n + default n + ---help--- + Allows the thinkpad_acpi driver to handle docking station events. + This support was made obsolete by the generic ACPI docking station + support (CONFIG_ACPI_DOCK). It will allow locking and removing the + laptop from the docking station, but will not properly connect PCI + devices. + + If you are not sure, say N here. + +config THINKPAD_ACPI_BAY + bool "Legacy Removable Bay Support" + depends on THINKPAD_ACPI + default y + ---help--- + Allows the thinkpad_acpi driver to handle removable bays. It will + electrically disable the device in the bay, and also generate + notifications when the bay lever is ejected or inserted. + + If you are not sure, say Y here. + +config THINKPAD_ACPI_VIDEO + bool "Video output control support" + depends on THINKPAD_ACPI + default y + ---help--- + Allows the thinkpad_acpi driver to provide an interface to control + the various video output ports. + + This feature often won't work well, depending on ThinkPad model, + display state, video output devices in use, whether there is a X + server running, phase of the moon, and the current mood of + Schroedinger's cat. If you can use X.org's RandR to control + your ThinkPad's video output ports instead of this feature, + don't think twice: do it and say N here to save some memory. + + If you are not sure, say Y here. + +config THINKPAD_ACPI_HOTKEY_POLL + bool "Support NVRAM polling for hot keys" + depends on THINKPAD_ACPI + default y + ---help--- + Some thinkpad models benefit from NVRAM polling to detect a few of + the hot key press events. If you know your ThinkPad model does not + need to do NVRAM polling to support any of the hot keys you use, + unselecting this option will save about 1kB of memory. + + ThinkPads T40 and newer, R52 and newer, and X31 and newer are + unlikely to need NVRAM polling in their latest BIOS versions. + + NVRAM polling can detect at most the following keys: ThinkPad/Access + IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, + Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). + + If you are not sure, say Y here. The driver enables polling only if + it is strictly necessary to do so. + +config INTEL_MENLOW + tristate "Thermal Management driver for Intel menlow platform" + depends on ACPI_THERMAL + select THERMAL + ---help--- + ACPI thermal management enhancement driver on + Intel Menlow platform. + + If unsure, say N. + +config EEEPC_LAPTOP + tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL + select BACKLIGHT_CLASS_DEVICE + select HWMON + select RFKILL + ---help--- + This driver supports the Fn-Fx keys on Eee PC laptops. + It also adds the ability to switch camera/wlan on/off. + + If you have an Eee PC laptop, say Y or M here. + + +config ACPI_WMI + tristate "WMI (EXPERIMENTAL)" + depends on ACPI + depends on EXPERIMENTAL + help + This driver adds support for the ACPI-WMI (Windows Management + Instrumentation) mapper device (PNP0C14) found on some systems. + + ACPI-WMI is a proprietary extension to ACPI to expose parts of the + ACPI firmware to userspace - this is done through various vendor + defined methods and data blocks in a PNP0C14 device, which are then + made available for userspace to call. + + The implementation of this in Linux currently only exposes this to + other kernel space drivers. + + This driver is a required dependency to build the firmware specific + drivers needed on many machines, including Acer and HP laptops. + + It is safe to enable this driver even if your DSDT doesn't define + any ACPI-WMI devices. + +config ACPI_ASUS + tristate "ASUS/Medion Laptop Extras" + depends on ACPI + select BACKLIGHT_CLASS_DEVICE + ---help--- + This driver provides support for extra features of ACPI-compatible + ASUS laptops. As some of Medion laptops are made by ASUS, it may also + support some Medion laptops (such as 9675 for example). It makes all + the extra buttons generate standard ACPI events that go through + /proc/acpi/events, and (on some models) adds support for changing the + display brightness and output, switching the LCD backlight on and off, + and most importantly, allows you to blink those fancy LEDs intended + for reporting mail and wireless status. + + Note: display switching code is currently considered EXPERIMENTAL, + toying with these values may even lock your machine. + + All settings are changed via /proc/acpi/asus directory entries. Owner + and group for these entries can be set with asus_uid and asus_gid + parameters. + + More information and a userspace daemon for handling the extra buttons + at <http://sourceforge.net/projects/acpi4asus/>. + + If you have an ACPI-compatible ASUS laptop, say Y or M here. This + driver is still under development, so if your laptop is unsupported or + something works not quite as expected, please use the mailing list + available on the above page (acpi4asus-user@lists.sourceforge.net). + + NOTE: This driver is deprecated and will probably be removed soon, + use asus-laptop instead. + +config ACPI_TOSHIBA + tristate "Toshiba Laptop Extras" + depends on ACPI + depends on INPUT + select INPUT_POLLDEV + select NET + select RFKILL + select BACKLIGHT_CLASS_DEVICE + ---help--- + This driver adds support for access to certain system settings + on "legacy free" Toshiba laptops. These laptops can be recognized by + their lack of a BIOS setup menu and APM support. + + On these machines, all system configuration is handled through the + ACPI. This driver is required for access to controls not covered + by the general ACPI drivers, such as LCD brightness, video output, + etc. + + This driver differs from the non-ACPI Toshiba laptop driver (located + under "Processor type and features") in several aspects. + Configuration is accessed by reading and writing text files in the + /proc tree instead of by program interface to /dev. Furthermore, no + power management functions are exposed, as those are handled by the + general ACPI drivers. + + More information about this driver is available at + <http://memebeam.org/toys/ToshibaAcpiDriver>. + + If you have a legacy free Toshiba laptop (such as the Libretto L1 + series), say Y. +endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile new file mode 100644 index 00000000000..1e9de2ae0de --- /dev/null +++ b/drivers/platform/x86/Makefile @@ -0,0 +1,19 @@ +# +# Makefile for linux/drivers/platform/x86 +# x86 Platform-Specific Drivers +# +obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o +obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o +obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o +obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o +obj-$(CONFIG_ACER_WMI) += acer-wmi.o +obj-$(CONFIG_HP_WMI) += hp-wmi.o +obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o +obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o +obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o +obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o +obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o +obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o +obj-$(CONFIG_ACPI_WMI) += wmi.o +obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o +obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o diff --git a/drivers/misc/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 94c9f911824..94c9f911824 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c diff --git a/drivers/misc/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 8fb8b359104..8fb8b359104 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c diff --git a/drivers/acpi/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index 1e74988c7b2..1e74988c7b2 100644 --- a/drivers/acpi/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c diff --git a/drivers/misc/compal-laptop.c b/drivers/platform/x86/compal-laptop.c index 11003bba10d..11003bba10d 100644 --- a/drivers/misc/compal-laptop.c +++ b/drivers/platform/x86/compal-laptop.c diff --git a/drivers/misc/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index 02fe2b8b893..02fe2b8b893 100644 --- a/drivers/misc/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index a7dd3e9fb79..65dc41540c6 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -3,6 +3,7 @@ /* Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@physics.adelaide.edu.au> Copyright (C) 2008 Peter Gruber <nokos@gmx.net> + Copyright (C) 2008 Tony Vroon <tony@linx.net> Based on earlier work: Copyright (C) 2003 Shane Spencer <shane@bogomip.com> Adrian Yee <brewt-fujitsu@brewt.org> @@ -65,8 +66,11 @@ #include <linux/kfifo.h> #include <linux/video_output.h> #include <linux/platform_device.h> +#ifdef CONFIG_LEDS_CLASS +#include <linux/leds.h> +#endif -#define FUJITSU_DRIVER_VERSION "0.4.3" +#define FUJITSU_DRIVER_VERSION "0.5.0" #define FUJITSU_LCD_N_LEVELS 8 @@ -83,6 +87,24 @@ #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 +/* FUNC interface - command values */ +#define FUNC_RFKILL 0x1000 +#define FUNC_LEDS 0x1001 +#define FUNC_BUTTONS 0x1002 +#define FUNC_BACKLIGHT 0x1004 + +/* FUNC interface - responses */ +#define UNSUPPORTED_CMD 0x80000000 + +#ifdef CONFIG_LEDS_CLASS +/* FUNC interface - LED control */ +#define FUNC_LED_OFF 0x1 +#define FUNC_LED_ON 0x30001 +#define KEYBOARD_LAMPS 0x100 +#define LOGOLAMP_POWERON 0x2000 +#define LOGOLAMP_ALWAYS 0x4000 +#endif + /* Hotkey details */ #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ #define KEY2_CODE 0x411 @@ -133,7 +155,6 @@ struct fujitsu_t { static struct fujitsu_t *fujitsu; static int use_alt_lcd_levels = -1; -static int disable_brightness_keys = -1; static int disable_brightness_adjust = -1; /* Device used to access other hotkeys on the laptop */ @@ -145,8 +166,9 @@ struct fujitsu_hotkey_t { struct platform_device *pf_device; struct kfifo *fifo; spinlock_t fifo_lock; - - unsigned int irb; /* info about the pressed buttons */ + int rfkill_state; + int logolamp_registered; + int kblamps_registered; }; static struct fujitsu_hotkey_t *fujitsu_hotkey; @@ -154,12 +176,139 @@ static struct fujitsu_hotkey_t *fujitsu_hotkey; static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, void *data); +#ifdef CONFIG_LEDS_CLASS +static enum led_brightness logolamp_get(struct led_classdev *cdev); +static void logolamp_set(struct led_classdev *cdev, + enum led_brightness brightness); + +struct led_classdev logolamp_led = { + .name = "fujitsu::logolamp", + .brightness_get = logolamp_get, + .brightness_set = logolamp_set +}; + +static enum led_brightness kblamps_get(struct led_classdev *cdev); +static void kblamps_set(struct led_classdev *cdev, + enum led_brightness brightness); + +struct led_classdev kblamps_led = { + .name = "fujitsu::kblamps", + .brightness_get = kblamps_get, + .brightness_set = kblamps_set +}; +#endif + #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG static u32 dbg_level = 0x03; #endif static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data); +/* Fujitsu ACPI interface function */ + +static int call_fext_func(int cmd, int arg0, int arg1, int arg2) +{ + acpi_status status = AE_OK; + union acpi_object params[4] = { + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER }, + { .type = ACPI_TYPE_INTEGER } + }; + struct acpi_object_list arg_list = { 4, ¶ms[0] }; + struct acpi_buffer output; + union acpi_object out_obj; + acpi_handle handle = NULL; + + status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "FUNC interface is not present\n"); + return -ENODEV; + } + + params[0].integer.value = cmd; + params[1].integer.value = arg0; + params[2].integer.value = arg1; + params[3].integer.value = arg2; + + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + status = acpi_evaluate_object(handle, NULL, &arg_list, &output); + if (ACPI_FAILURE(status)) { + vdbg_printk(FUJLAPTOP_DBG_WARN, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + if (out_obj.type != ACPI_TYPE_INTEGER) { + vdbg_printk(FUJLAPTOP_DBG_WARN, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not " + "return an integer\n", + cmd, arg0, arg1, arg2); + return -ENODEV; + } + + vdbg_printk(FUJLAPTOP_DBG_TRACE, + "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", + cmd, arg0, arg1, arg2, (int)out_obj.integer.value); + return out_obj.integer.value; +} + +#ifdef CONFIG_LEDS_CLASS +/* LED class callbacks */ + +static void logolamp_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); + } else if (brightness >= LED_HALF) { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); + } else { + call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); + } +} + +static void kblamps_set(struct led_classdev *cdev, + enum led_brightness brightness) +{ + if (brightness >= LED_FULL) + call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); + else + call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); +} + +static enum led_brightness logolamp_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + int poweron, always; + + poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); + if (poweron == FUNC_LED_ON) { + brightness = LED_HALF; + always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); + if (always == FUNC_LED_ON) + brightness = LED_FULL; + } + return brightness; +} + +static enum led_brightness kblamps_get(struct led_classdev *cdev) +{ + enum led_brightness brightness = LED_OFF; + + if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) + brightness = LED_FULL; + + return brightness; +} +#endif + /* Hardware access for LCD brightness control */ static int set_lcd_level(int level) @@ -263,44 +412,34 @@ static int get_max_brightness(void) return fujitsu->max_brightness; } -static int get_lcd_level_alt(void) -{ - unsigned long long state = 0; - acpi_status status = AE_OK; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLS\n"); - - status = - acpi_evaluate_integer(fujitsu->acpi_handle, "GBLS", NULL, &state); - if (status < 0) - return status; - - fujitsu->brightness_level = state & 0x0fffffff; - - if (state & 0x80000000) - fujitsu->brightness_changed = 1; - else - fujitsu->brightness_changed = 0; - - return fujitsu->brightness_level; -} - /* Backlight device stuff */ static int bl_get_brightness(struct backlight_device *b) { - if (use_alt_lcd_levels) - return get_lcd_level_alt(); - else - return get_lcd_level(); + return get_lcd_level(); } static int bl_update_status(struct backlight_device *b) { + int ret; + if (b->props.power == 4) + ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); + else + ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); + if (ret != 0) + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "Unable to adjust backlight power, error code %i\n", + ret); + if (use_alt_lcd_levels) - return set_lcd_level_alt(b->props.brightness); + ret = set_lcd_level_alt(b->props.brightness); else - return set_lcd_level(b->props.brightness); + ret = set_lcd_level(b->props.brightness); + if (ret != 0) + vdbg_printk(FUJLAPTOP_DBG_ERROR, + "Unable to adjust LCD brightness, error code %i\n", + ret); + return ret; } static struct backlight_ops fujitsubl_ops = { @@ -344,10 +483,7 @@ static ssize_t show_lcd_level(struct device *dev, int ret; - if (use_alt_lcd_levels) - ret = get_lcd_level_alt(); - else - ret = get_lcd_level(); + ret = get_lcd_level(); if (ret < 0) return ret; @@ -372,52 +508,71 @@ static ssize_t store_lcd_level(struct device *dev, if (ret < 0) return ret; - if (use_alt_lcd_levels) - ret = get_lcd_level_alt(); - else - ret = get_lcd_level(); + ret = get_lcd_level(); if (ret < 0) return ret; return count; } -/* Hardware access for hotkey device */ - -static int get_irb(void) +static ssize_t +ignore_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { - unsigned long long state = 0; - acpi_status status = AE_OK; - - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n"); - - status = - acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL, - &state); - if (status < 0) - return status; + return count; +} - fujitsu_hotkey->irb = state; +static ssize_t +show_lid_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x100) + return sprintf(buf, "open\n"); + else + return sprintf(buf, "closed\n"); +} - return fujitsu_hotkey->irb; +static ssize_t +show_dock_state(struct device *dev, + struct device_attribute *attr, char *buf) +{ + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x200) + return sprintf(buf, "docked\n"); + else + return sprintf(buf, "undocked\n"); } static ssize_t -ignore_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +show_radios_state(struct device *dev, + struct device_attribute *attr, char *buf) { - return count; + if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD) + return sprintf(buf, "unknown\n"); + if (fujitsu_hotkey->rfkill_state & 0x20) + return sprintf(buf, "on\n"); + else + return sprintf(buf, "killed\n"); } static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, ignore_store); static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); +static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); +static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); +static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); static struct attribute *fujitsupf_attributes[] = { &dev_attr_brightness_changed.attr, &dev_attr_max_brightness.attr, &dev_attr_lcd_level.attr, + &dev_attr_lid.attr, + &dev_attr_dock.attr, + &dev_attr_radios.attr, NULL }; @@ -435,24 +590,16 @@ static struct platform_driver fujitsupf_driver = { static void dmi_check_cb_common(const struct dmi_system_id *id) { acpi_handle handle; - int have_blnf; printk(KERN_INFO "fujitsu-laptop: Identified laptop model '%s'.\n", id->ident); - have_blnf = ACPI_SUCCESS - (acpi_get_handle(NULL, "\\_SB.PCI0.GFX0.LCD.BLNF", &handle)); if (use_alt_lcd_levels == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detecting usealt\n"); - use_alt_lcd_levels = 1; - } - if (disable_brightness_keys == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "auto-detecting disable_keys\n"); - disable_brightness_keys = have_blnf ? 1 : 0; - } - if (disable_brightness_adjust == -1) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, - "auto-detecting disable_adjust\n"); - disable_brightness_adjust = have_blnf ? 0 : 1; + if (ACPI_SUCCESS(acpi_get_handle(NULL, + "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle))) + use_alt_lcd_levels = 1; + else + use_alt_lcd_levels = 0; + vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as " + "%i\n", use_alt_lcd_levels); } } @@ -581,19 +728,14 @@ static int acpi_fujitsu_add(struct acpi_device *device) /* do config (detect defaults) */ use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; - disable_brightness_keys = disable_brightness_keys == 1 ? 1 : 0; disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; vdbg_printk(FUJLAPTOP_DBG_INFO, - "config: [alt interface: %d], [key disable: %d], [adjust disable: %d]\n", - use_alt_lcd_levels, disable_brightness_keys, - disable_brightness_adjust); + "config: [alt interface: %d], [adjust disable: %d]\n", + use_alt_lcd_levels, disable_brightness_adjust); if (get_max_brightness() <= 0) fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; - if (use_alt_lcd_levels) - get_lcd_level_alt(); - else - get_lcd_level(); + get_lcd_level(); return result; @@ -644,43 +786,23 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) case ACPI_FUJITSU_NOTIFY_CODE1: keycode = 0; oldb = fujitsu->brightness_level; - get_lcd_level(); /* the alt version always yields changed */ + get_lcd_level(); newb = fujitsu->brightness_level; vdbg_printk(FUJLAPTOP_DBG_TRACE, "brightness button event [%i -> %i (%i)]\n", oldb, newb, fujitsu->brightness_changed); - if (oldb == newb && fujitsu->brightness_changed) { - keycode = 0; - if (disable_brightness_keys != 1) { - if (oldb == 0) { - acpi_bus_generate_proc_event - (fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, - 0); - keycode = KEY_BRIGHTNESSDOWN; - } else if (oldb == - (fujitsu->max_brightness) - 1) { - acpi_bus_generate_proc_event - (fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, - 0); - keycode = KEY_BRIGHTNESSUP; - } - } - } else if (oldb < newb) { + if (oldb < newb) { if (disable_brightness_adjust != 1) { if (use_alt_lcd_levels) set_lcd_level_alt(newb); else set_lcd_level(newb); } - if (disable_brightness_keys != 1) { - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); - keycode = KEY_BRIGHTNESSUP; - } + acpi_bus_generate_proc_event(fujitsu->dev, + ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS, 0); + keycode = KEY_BRIGHTNESSUP; } else if (oldb > newb) { if (disable_brightness_adjust != 1) { if (use_alt_lcd_levels) @@ -688,13 +810,9 @@ static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data) else set_lcd_level(newb); } - if (disable_brightness_keys != 1) { - acpi_bus_generate_proc_event(fujitsu->dev, - ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); - keycode = KEY_BRIGHTNESSDOWN; - } - } else { - keycode = KEY_UNKNOWN; + acpi_bus_generate_proc_event(fujitsu->dev, + ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS, 0); + keycode = KEY_BRIGHTNESSDOWN; } break; default: @@ -771,7 +889,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) input->id.bustype = BUS_HOST; input->id.product = 0x06; input->dev.parent = &device->dev; - input->evbit[0] = BIT(EV_KEY); + + set_bit(EV_KEY, input->evbit); set_bit(fujitsu->keycode1, input->keybit); set_bit(fujitsu->keycode2, input->keybit); set_bit(fujitsu->keycode3, input->keybit); @@ -803,10 +922,44 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) printk(KERN_ERR "_INI Method failed\n"); } - i = 0; /* Discard hotkey ringbuffer */ - while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ; + i = 0; + while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) + ; /* No action, result is discarded */ vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); + fujitsu_hotkey->rfkill_state = + call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); + + /* Suspect this is a keymap of the application panel, print it */ + printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n", + call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); + + #ifdef CONFIG_LEDS_CLASS + if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { + result = led_classdev_register(&fujitsu->pf_device->dev, + &logolamp_led); + if (result == 0) { + fujitsu_hotkey->logolamp_registered = 1; + } else { + printk(KERN_ERR "fujitsu-laptop: Could not register " + "LED handler for logo lamp, error %i\n", result); + } + } + + if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && + (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { + result = led_classdev_register(&fujitsu->pf_device->dev, + &kblamps_led); + if (result == 0) { + fujitsu_hotkey->kblamps_registered = 1; + } else { + printk(KERN_ERR "fujitsu-laptop: Could not register " + "LED handler for keyboard lamps, error %i\n", result); + } + } + #endif + return result; end: @@ -852,16 +1005,15 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event, input = fujitsu_hotkey->input; - vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n"); + fujitsu_hotkey->rfkill_state = + call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); switch (event) { case ACPI_FUJITSU_NOTIFY_CODE1: i = 0; - while ((irb = get_irb()) != 0 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { - vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n", - irb); - + while ((irb = + call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 + && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { switch (irb & 0x4ff) { case KEY1_CODE: keycode = fujitsu->keycode1; @@ -1035,6 +1187,15 @@ static int __init fujitsu_init(void) goto fail_hotkey1; } + /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ + + if (!acpi_video_backlight_support()) { + if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) + fujitsu->bl_device->props.power = 4; + else + fujitsu->bl_device->props.power = 0; + } + printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION " successfully loaded.\n"); @@ -1074,6 +1235,14 @@ fail_acpi: static void __exit fujitsu_cleanup(void) { + #ifdef CONFIG_LEDS_CLASS + if (fujitsu_hotkey->logolamp_registered != 0) + led_classdev_unregister(&logolamp_led); + + if (fujitsu_hotkey->kblamps_registered != 0) + led_classdev_unregister(&kblamps_led); + #endif + sysfs_remove_group(&fujitsu->pf_device->dev.kobj, &fujitsupf_attribute_group); platform_device_unregister(fujitsu->pf_device); @@ -1098,9 +1267,6 @@ module_exit(fujitsu_cleanup); module_param(use_alt_lcd_levels, uint, 0644); MODULE_PARM_DESC(use_alt_lcd_levels, "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); -module_param(disable_brightness_keys, uint, 0644); -MODULE_PARM_DESC(disable_brightness_keys, - "Disable brightness keys (eg. if they are already handled by the generic ACPI_VIDEO device)."); module_param(disable_brightness_adjust, uint, 0644); MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG @@ -1108,12 +1274,13 @@ module_param_named(debug, dbg_level, uint, 0644); MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); #endif -MODULE_AUTHOR("Jonathan Woithe, Peter Gruber"); +MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); MODULE_DESCRIPTION("Fujitsu laptop extras support"); MODULE_VERSION(FUJITSU_DRIVER_VERSION); MODULE_LICENSE("GPL"); MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); +MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); static struct pnp_device_id pnp_ids[] = { diff --git a/drivers/misc/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 4b7c24c519c..7c789f0a94d 100644 --- a/drivers/misc/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c @@ -428,7 +428,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wifi_rfkill->state = hp_wmi_wifi_state(); wifi_rfkill->toggle_radio = hp_wmi_wifi_set; wifi_rfkill->user_claim_unsupported = 1; - rfkill_register(wifi_rfkill); + err = rfkill_register(wifi_rfkill); + if (err) + goto add_sysfs_error; } if (wireless & 0x2) { @@ -438,7 +440,8 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) bluetooth_rfkill->state = hp_wmi_bluetooth_state(); bluetooth_rfkill->toggle_radio = hp_wmi_bluetooth_set; bluetooth_rfkill->user_claim_unsupported = 1; - rfkill_register(bluetooth_rfkill); + err = rfkill_register(bluetooth_rfkill); + goto register_bluetooth_error; } if (wireless & 0x4) { @@ -447,10 +450,16 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) wwan_rfkill->state = hp_wmi_wwan_state(); wwan_rfkill->toggle_radio = hp_wmi_wwan_set; wwan_rfkill->user_claim_unsupported = 1; - rfkill_register(wwan_rfkill); + err = rfkill_register(wwan_rfkill); + if (err) + goto register_wwan_err; } return 0; +register_wwan_err: + rfkill_unregister(bluetooth_rfkill); +register_bluetooth_error: + rfkill_unregister(wifi_rfkill); add_sysfs_error: cleanup_sysfs(device); return err; diff --git a/drivers/misc/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 27b7662955b..27b7662955b 100644 --- a/drivers/misc/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c diff --git a/drivers/misc/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index 759763d18e4..759763d18e4 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c diff --git a/drivers/misc/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 4a1bc64485d..f30db367c82 100644 --- a/drivers/misc/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -241,8 +241,6 @@ static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val) }; acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_pcc_write_sset"); - status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET, ¶ms, NULL); @@ -254,8 +252,6 @@ static inline int acpi_pcc_get_sqty(struct acpi_device *device) unsigned long long s; acpi_status status; - ACPI_FUNCTION_TRACE("acpi_pcc_get_sqty"); - status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY, NULL, &s); if (ACPI_SUCCESS(status)) @@ -274,8 +270,6 @@ static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc, u32 *sinf) union acpi_object *hkey = NULL; int i; - ACPI_FUNCTION_TRACE("acpi_pcc_retrieve_biosdata"); - status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, 0, &buffer); if (ACPI_FAILURE(status)) { @@ -501,8 +495,6 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) int key_code, hkey_num; unsigned long long result; - ACPI_FUNCTION_TRACE("acpi_pcc_generate_keyinput"); - rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, NULL, &result); if (!ACPI_SUCCESS(rc)) { @@ -538,8 +530,6 @@ static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data) { struct pcc_acpi *pcc = (struct pcc_acpi *) data; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_notify"); - switch (event) { case HKEY_NOTIFY: acpi_pcc_generate_keyinput(pcc); @@ -554,8 +544,6 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) { int i, rc; - ACPI_FUNCTION_TRACE("acpi_pcc_init_input"); - pcc->input_dev = input_allocate_device(); if (!pcc->input_dev) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, @@ -597,8 +585,6 @@ static int acpi_pcc_hotkey_resume(struct acpi_device *device) struct pcc_acpi *pcc = acpi_driver_data(device); acpi_status status = AE_OK; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_resume"); - if (device == NULL || pcc == NULL) return -EINVAL; @@ -616,8 +602,6 @@ static int acpi_pcc_hotkey_add(struct acpi_device *device) struct pcc_acpi *pcc; int num_sifr, result; - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_add"); - if (!device) return -EINVAL; @@ -714,8 +698,6 @@ static int __init acpi_pcc_init(void) { int result = 0; - ACPI_FUNCTION_TRACE("acpi_pcc_init"); - if (acpi_disabled) return -ENODEV; @@ -733,8 +715,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) { struct pcc_acpi *pcc = acpi_driver_data(device); - ACPI_FUNCTION_TRACE("acpi_pcc_hotkey_remove"); - if (!device || !pcc) return -EINVAL; @@ -757,8 +737,6 @@ static int acpi_pcc_hotkey_remove(struct acpi_device *device, int type) static void __exit acpi_pcc_exit(void) { - ACPI_FUNCTION_TRACE("acpi_pcc_exit"); - acpi_bus_unregister_driver(&acpi_pcc_driver); } diff --git a/drivers/misc/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 571b211608d..537959d0714 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -935,14 +935,17 @@ static void sony_acpi_notify(acpi_handle handle, u32 event, void *data) static acpi_status sony_walk_callback(acpi_handle handle, u32 level, void *context, void **return_value) { - struct acpi_namespace_node *node; - union acpi_operand_object *operand; + struct acpi_device_info *info; + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - node = (struct acpi_namespace_node *)handle; - operand = (union acpi_operand_object *)node->object; + if (ACPI_SUCCESS(acpi_get_object_info(handle, &buffer))) { + info = buffer.pointer; - printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, - (u32) operand->method.param_count); + printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", + (char *)&info->name, info->param_count); + + kfree(buffer.pointer); + } return AE_OK; } diff --git a/drivers/misc/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index f25e4c974dc..b4a4aa9ee48 100644 --- a/drivers/misc/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -30,7 +30,6 @@ #include <linux/init.h> #include <linux/types.h> #include <acpi/acpi.h> -#include <acpi/actypes.h> #include <acpi/acpi_bus.h> #include <acpi/acpi_drivers.h> #include <linux/platform_device.h> diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 899766e16fa..3478453eba7 100644 --- a/drivers/misc/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -76,7 +76,6 @@ #include <linux/workqueue.h> #include <acpi/acpi_drivers.h> -#include <acpi/acnamesp.h> #include <linux/pci_ids.h> diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 40e60fc2e59..40e60fc2e59 100644 --- a/drivers/acpi/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c diff --git a/drivers/acpi/wmi.c b/drivers/platform/x86/wmi.c index 8a8b377712c..8a8b377712c 100644 --- a/drivers/acpi/wmi.c +++ b/drivers/platform/x86/wmi.c diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 383e47c392a..2834846a185 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -23,7 +23,6 @@ #include <linux/pnp.h> #include <linux/mod_devicetable.h> #include <acpi/acpi_bus.h> -#include <acpi/actypes.h> #include "../base.h" #include "pnpacpi.h" diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 668472405a5..33da1127992 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -82,4 +82,10 @@ config BATTERY_DA9030 Say Y here to enable support for batteries charger integrated into DA9030 PMIC. +config CHARGER_PCF50633 + tristate "NXP PCF50633 MBC" + depends on MFD_PCF50633 + help + Say Y to include support for NXP PCF50633 Main Battery Charger. + endif # POWER_SUPPLY diff --git a/drivers/power/Makefile b/drivers/power/Makefile index eebb15505a4..2fcf41d13e5 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o +obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
\ No newline at end of file diff --git a/drivers/power/pcf50633-charger.c b/drivers/power/pcf50633-charger.c new file mode 100644 index 00000000000..e988ec130fc --- /dev/null +++ b/drivers/power/pcf50633-charger.c @@ -0,0 +1,358 @@ +/* NXP PCF50633 Main Battery Charger Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte, Andy Green and Werner Almesberger + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/types.h> +#include <linux/device.h> +#include <linux/sysfs.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> + +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/mbc.h> + +struct pcf50633_mbc { + struct pcf50633 *pcf; + + int adapter_active; + int adapter_online; + int usb_active; + int usb_online; + + struct power_supply usb; + struct power_supply adapter; +}; + +int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma) +{ + struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); + int ret = 0; + u8 bits; + + if (ma >= 1000) + bits = PCF50633_MBCC7_USB_1000mA; + else if (ma >= 500) + bits = PCF50633_MBCC7_USB_500mA; + else if (ma >= 100) + bits = PCF50633_MBCC7_USB_100mA; + else + bits = PCF50633_MBCC7_USB_SUSPEND; + + ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7, + PCF50633_MBCC7_USB_MASK, bits); + if (ret) + dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma); + else + dev_info(pcf->dev, "usb curlim to %d mA\n", ma); + + power_supply_changed(&mbc->usb); + + return ret; +} +EXPORT_SYMBOL_GPL(pcf50633_mbc_usb_curlim_set); + +int pcf50633_mbc_get_status(struct pcf50633 *pcf) +{ + struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); + int status = 0; + + if (mbc->usb_online) + status |= PCF50633_MBC_USB_ONLINE; + if (mbc->usb_active) + status |= PCF50633_MBC_USB_ACTIVE; + if (mbc->adapter_online) + status |= PCF50633_MBC_ADAPTER_ONLINE; + if (mbc->adapter_active) + status |= PCF50633_MBC_ADAPTER_ACTIVE; + + return status; +} +EXPORT_SYMBOL_GPL(pcf50633_mbc_get_status); + +void pcf50633_mbc_set_status(struct pcf50633 *pcf, int what, int status) +{ + struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev); + + if (what & PCF50633_MBC_USB_ONLINE) + mbc->usb_online = !!status; + if (what & PCF50633_MBC_USB_ACTIVE) + mbc->usb_active = !!status; + if (what & PCF50633_MBC_ADAPTER_ONLINE) + mbc->adapter_online = !!status; + if (what & PCF50633_MBC_ADAPTER_ACTIVE) + mbc->adapter_active = !!status; +} +EXPORT_SYMBOL_GPL(pcf50633_mbc_set_status); + +static ssize_t +show_chgmode(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pcf50633_mbc *mbc = dev_get_drvdata(dev); + + u8 mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2); + u8 chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK); + + return sprintf(buf, "%d\n", chgmod); +} +static DEVICE_ATTR(chgmode, S_IRUGO, show_chgmode, NULL); + +static ssize_t +show_usblim(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct pcf50633_mbc *mbc = dev_get_drvdata(dev); + u8 usblim = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCC7) & + PCF50633_MBCC7_USB_MASK; + unsigned int ma; + + if (usblim == PCF50633_MBCC7_USB_1000mA) + ma = 1000; + else if (usblim == PCF50633_MBCC7_USB_500mA) + ma = 500; + else if (usblim == PCF50633_MBCC7_USB_100mA) + ma = 100; + else + ma = 0; + + return sprintf(buf, "%u\n", ma); +} + +static ssize_t set_usblim(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct pcf50633_mbc *mbc = dev_get_drvdata(dev); + unsigned long ma; + int ret; + + ret = strict_strtoul(buf, 10, &ma); + if (ret) + return -EINVAL; + + pcf50633_mbc_usb_curlim_set(mbc->pcf, ma); + + return count; +} + +static DEVICE_ATTR(usb_curlim, S_IRUGO | S_IWUSR, show_usblim, set_usblim); + +static struct attribute *pcf50633_mbc_sysfs_entries[] = { + &dev_attr_chgmode.attr, + &dev_attr_usb_curlim.attr, + NULL, +}; + +static struct attribute_group mbc_attr_group = { + .name = NULL, /* put in device directory */ + .attrs = pcf50633_mbc_sysfs_entries, +}; + +static void +pcf50633_mbc_irq_handler(int irq, void *data) +{ + struct pcf50633_mbc *mbc = data; + + /* USB */ + if (irq == PCF50633_IRQ_USBINS) { + mbc->usb_online = 1; + } else if (irq == PCF50633_IRQ_USBREM) { + mbc->usb_online = 0; + mbc->usb_active = 0; + pcf50633_mbc_usb_curlim_set(mbc->pcf, 0); + } + + /* Adapter */ + if (irq == PCF50633_IRQ_ADPINS) { + mbc->adapter_online = 1; + mbc->adapter_active = 1; + } else if (irq == PCF50633_IRQ_ADPREM) { + mbc->adapter_online = 0; + mbc->adapter_active = 0; + } + + if (irq == PCF50633_IRQ_BATFULL) { + mbc->usb_active = 0; + mbc->adapter_active = 0; + } + + power_supply_changed(&mbc->usb); + power_supply_changed(&mbc->adapter); + + if (mbc->pcf->pdata->mbc_event_callback) + mbc->pcf->pdata->mbc_event_callback(mbc->pcf, irq); +} + +static int adapter_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = mbc->adapter_online; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static int usb_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct pcf50633_mbc *mbc = container_of(psy, struct pcf50633_mbc, usb); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = mbc->usb_online; + break; + default: + ret = -EINVAL; + break; + } + return ret; +} + +static enum power_supply_property power_props[] = { + POWER_SUPPLY_PROP_ONLINE, +}; + +static const u8 mbc_irq_handlers[] = { + PCF50633_IRQ_ADPINS, + PCF50633_IRQ_ADPREM, + PCF50633_IRQ_USBINS, + PCF50633_IRQ_USBREM, + PCF50633_IRQ_BATFULL, + PCF50633_IRQ_CHGHALT, + PCF50633_IRQ_THLIMON, + PCF50633_IRQ_THLIMOFF, + PCF50633_IRQ_USBLIMON, + PCF50633_IRQ_USBLIMOFF, + PCF50633_IRQ_LOWSYS, + PCF50633_IRQ_LOWBAT, +}; + +static int __devinit pcf50633_mbc_probe(struct platform_device *pdev) +{ + struct pcf50633_mbc *mbc; + struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data; + int ret; + int i; + u8 mbcs1; + + mbc = kzalloc(sizeof(*mbc), GFP_KERNEL); + if (!mbc) + return -ENOMEM; + + platform_set_drvdata(pdev, mbc); + mbc->pcf = pdata->pcf; + + /* Set up IRQ handlers */ + for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) + pcf50633_register_irq(mbc->pcf, mbc_irq_handlers[i], + pcf50633_mbc_irq_handler, mbc); + + /* Create power supplies */ + mbc->adapter.name = "adapter"; + mbc->adapter.type = POWER_SUPPLY_TYPE_MAINS; + mbc->adapter.properties = power_props; + mbc->adapter.num_properties = ARRAY_SIZE(power_props); + mbc->adapter.get_property = &adapter_get_property; + mbc->adapter.supplied_to = mbc->pcf->pdata->batteries; + mbc->adapter.num_supplicants = mbc->pcf->pdata->num_batteries; + + mbc->usb.name = "usb"; + mbc->usb.type = POWER_SUPPLY_TYPE_USB; + mbc->usb.properties = power_props; + mbc->usb.num_properties = ARRAY_SIZE(power_props); + mbc->usb.get_property = usb_get_property; + mbc->usb.supplied_to = mbc->pcf->pdata->batteries; + mbc->usb.num_supplicants = mbc->pcf->pdata->num_batteries; + + ret = power_supply_register(&pdev->dev, &mbc->adapter); + if (ret) { + dev_err(mbc->pcf->dev, "failed to register adapter\n"); + kfree(mbc); + return ret; + } + + ret = power_supply_register(&pdev->dev, &mbc->usb); + if (ret) { + dev_err(mbc->pcf->dev, "failed to register usb\n"); + power_supply_unregister(&mbc->adapter); + kfree(mbc); + return ret; + } + + ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group); + if (ret) + dev_err(mbc->pcf->dev, "failed to create sysfs entries\n"); + + mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1); + if (mbcs1 & PCF50633_MBCS1_USBPRES) + pcf50633_mbc_irq_handler(PCF50633_IRQ_USBINS, mbc); + if (mbcs1 & PCF50633_MBCS1_ADAPTPRES) + pcf50633_mbc_irq_handler(PCF50633_IRQ_ADPINS, mbc); + + return 0; +} + +static int __devexit pcf50633_mbc_remove(struct platform_device *pdev) +{ + struct pcf50633_mbc *mbc = platform_get_drvdata(pdev); + int i; + + /* Remove IRQ handlers */ + for (i = 0; i < ARRAY_SIZE(mbc_irq_handlers); i++) + pcf50633_free_irq(mbc->pcf, mbc_irq_handlers[i]); + + power_supply_unregister(&mbc->usb); + power_supply_unregister(&mbc->adapter); + + kfree(mbc); + + return 0; +} + +static struct platform_driver pcf50633_mbc_driver = { + .driver = { + .name = "pcf50633-mbc", + }, + .probe = pcf50633_mbc_probe, + .remove = __devexit_p(pcf50633_mbc_remove), +}; + +static int __init pcf50633_mbc_init(void) +{ + return platform_driver_register(&pcf50633_mbc_driver); +} +module_init(pcf50633_mbc_init); + +static void __exit pcf50633_mbc_exit(void) +{ + platform_driver_unregister(&pcf50633_mbc_driver); +} +module_exit(pcf50633_mbc_exit); + +MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); +MODULE_DESCRIPTION("PCF50633 mbc driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-mbc"); diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 39360e2a454..e7e0cf102d6 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -73,4 +73,11 @@ config REGULATOR_DA903X Say y here to support the BUCKs and LDOs regulators found on Dialog Semiconductor DA9030/DA9034 PMIC. +config REGULATOR_PCF50633 + tristate "PCF50633 regulator driver" + depends on MFD_PCF50633 + help + Say Y here to support the voltage regulators and convertors + on PCF50633 + endif diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 254d40c02ee..61b30c6ddec 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -11,5 +11,6 @@ obj-$(CONFIG_REGULATOR_BQ24022) += bq24022.o obj-$(CONFIG_REGULATOR_WM8350) += wm8350-regulator.o obj-$(CONFIG_REGULATOR_WM8400) += wm8400-regulator.o obj-$(CONFIG_REGULATOR_DA903X) += da903x.o +obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o ccflags-$(CONFIG_REGULATOR_DEBUG) += -DDEBUG diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 02a774424e8..f511a406fca 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -29,7 +29,7 @@ static DEFINE_MUTEX(regulator_list_mutex); static LIST_HEAD(regulator_list); static LIST_HEAD(regulator_map_list); -/** +/* * struct regulator_dev * * Voltage / Current regulator class device. One for each regulator. @@ -56,7 +56,7 @@ struct regulator_dev { void *reg_data; /* regulator_dev data */ }; -/** +/* * struct regulator_map * * Used to provide symbolic supply names to devices. @@ -79,7 +79,7 @@ struct regulator { int uA_load; int min_uV; int max_uV; - int enabled; /* client has called enabled */ + int enabled; /* count of client enables */ char *supply_name; struct device_attribute dev_attr; struct regulator_dev *rdev; @@ -174,6 +174,16 @@ static int regulator_check_current_limit(struct regulator_dev *rdev, /* operating mode constraint check */ static int regulator_check_mode(struct regulator_dev *rdev, int mode) { + switch (mode) { + case REGULATOR_MODE_FAST: + case REGULATOR_MODE_NORMAL: + case REGULATOR_MODE_IDLE: + case REGULATOR_MODE_STANDBY: + break; + default: + return -EINVAL; + } + if (!rdev->constraints) { printk(KERN_ERR "%s: no constraints for %s\n", __func__, rdev->desc->name); @@ -232,6 +242,7 @@ static ssize_t regulator_uV_show(struct device *dev, return ret; } +static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); static ssize_t regulator_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -240,6 +251,7 @@ static ssize_t regulator_uA_show(struct device *dev, return sprintf(buf, "%d\n", _regulator_get_current_limit(rdev)); } +static DEVICE_ATTR(microamps, 0444, regulator_uA_show, NULL); static ssize_t regulator_name_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -257,12 +269,8 @@ static ssize_t regulator_name_show(struct device *dev, return sprintf(buf, "%s\n", name); } -static ssize_t regulator_opmode_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t regulator_print_opmode(char *buf, int mode) { - struct regulator_dev *rdev = dev_get_drvdata(dev); - int mode = _regulator_get_mode(rdev); - switch (mode) { case REGULATOR_MODE_FAST: return sprintf(buf, "fast\n"); @@ -276,12 +284,17 @@ static ssize_t regulator_opmode_show(struct device *dev, return sprintf(buf, "unknown\n"); } -static ssize_t regulator_state_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t regulator_opmode_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - int state = _regulator_is_enabled(rdev); + return regulator_print_opmode(buf, _regulator_get_mode(rdev)); +} +static DEVICE_ATTR(opmode, 0444, regulator_opmode_show, NULL); + +static ssize_t regulator_print_state(char *buf, int state) +{ if (state > 0) return sprintf(buf, "enabled\n"); else if (state == 0) @@ -290,6 +303,15 @@ static ssize_t regulator_state_show(struct device *dev, return sprintf(buf, "unknown\n"); } +static ssize_t regulator_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct regulator_dev *rdev = dev_get_drvdata(dev); + + return regulator_print_state(buf, _regulator_is_enabled(rdev)); +} +static DEVICE_ATTR(state, 0444, regulator_state_show, NULL); + static ssize_t regulator_min_uA_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -300,6 +322,7 @@ static ssize_t regulator_min_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uA); } +static DEVICE_ATTR(min_microamps, 0444, regulator_min_uA_show, NULL); static ssize_t regulator_max_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -311,6 +334,7 @@ static ssize_t regulator_max_uA_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uA); } +static DEVICE_ATTR(max_microamps, 0444, regulator_max_uA_show, NULL); static ssize_t regulator_min_uV_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -322,6 +346,7 @@ static ssize_t regulator_min_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->min_uV); } +static DEVICE_ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL); static ssize_t regulator_max_uV_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -333,6 +358,7 @@ static ssize_t regulator_max_uV_show(struct device *dev, return sprintf(buf, "%d\n", rdev->constraints->max_uV); } +static DEVICE_ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL); static ssize_t regulator_total_uA_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -347,6 +373,7 @@ static ssize_t regulator_total_uA_show(struct device *dev, mutex_unlock(&rdev->mutex); return sprintf(buf, "%d\n", uA); } +static DEVICE_ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL); static ssize_t regulator_num_users_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -374,153 +401,106 @@ static ssize_t regulator_suspend_mem_uV_show(struct device *dev, { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_mem.uV); } +static DEVICE_ATTR(suspend_mem_microvolts, 0444, + regulator_suspend_mem_uV_show, NULL); static ssize_t regulator_suspend_disk_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_disk.uV); } +static DEVICE_ATTR(suspend_disk_microvolts, 0444, + regulator_suspend_disk_uV_show, NULL); static ssize_t regulator_suspend_standby_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); return sprintf(buf, "%d\n", rdev->constraints->state_standby.uV); } - -static ssize_t suspend_opmode_show(struct regulator_dev *rdev, - unsigned int mode, char *buf) -{ - switch (mode) { - case REGULATOR_MODE_FAST: - return sprintf(buf, "fast\n"); - case REGULATOR_MODE_NORMAL: - return sprintf(buf, "normal\n"); - case REGULATOR_MODE_IDLE: - return sprintf(buf, "idle\n"); - case REGULATOR_MODE_STANDBY: - return sprintf(buf, "standby\n"); - } - return sprintf(buf, "unknown\n"); -} +static DEVICE_ATTR(suspend_standby_microvolts, 0444, + regulator_suspend_standby_uV_show, NULL); static ssize_t regulator_suspend_mem_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_mem.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_mem.mode); } +static DEVICE_ATTR(suspend_mem_mode, 0444, + regulator_suspend_mem_mode_show, NULL); static ssize_t regulator_suspend_disk_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_disk.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_disk.mode); } +static DEVICE_ATTR(suspend_disk_mode, 0444, + regulator_suspend_disk_mode_show, NULL); static ssize_t regulator_suspend_standby_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - return suspend_opmode_show(rdev, - rdev->constraints->state_standby.mode, buf); + return regulator_print_opmode(buf, + rdev->constraints->state_standby.mode); } +static DEVICE_ATTR(suspend_standby_mode, 0444, + regulator_suspend_standby_mode_show, NULL); static ssize_t regulator_suspend_mem_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - - if (rdev->constraints->state_mem.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_mem.enabled); } +static DEVICE_ATTR(suspend_mem_state, 0444, + regulator_suspend_mem_state_show, NULL); static ssize_t regulator_suspend_disk_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - - if (rdev->constraints->state_disk.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_disk.enabled); } +static DEVICE_ATTR(suspend_disk_state, 0444, + regulator_suspend_disk_state_show, NULL); static ssize_t regulator_suspend_standby_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - if (!rdev->constraints) - return sprintf(buf, "not defined\n"); - - if (rdev->constraints->state_standby.enabled) - return sprintf(buf, "enabled\n"); - else - return sprintf(buf, "disabled\n"); + return regulator_print_state(buf, + rdev->constraints->state_standby.enabled); } +static DEVICE_ATTR(suspend_standby_state, 0444, + regulator_suspend_standby_state_show, NULL); + +/* + * These are the only attributes are present for all regulators. + * Other attributes are a function of regulator functionality. + */ static struct device_attribute regulator_dev_attrs[] = { __ATTR(name, 0444, regulator_name_show, NULL), - __ATTR(microvolts, 0444, regulator_uV_show, NULL), - __ATTR(microamps, 0444, regulator_uA_show, NULL), - __ATTR(opmode, 0444, regulator_opmode_show, NULL), - __ATTR(state, 0444, regulator_state_show, NULL), - __ATTR(min_microvolts, 0444, regulator_min_uV_show, NULL), - __ATTR(min_microamps, 0444, regulator_min_uA_show, NULL), - __ATTR(max_microvolts, 0444, regulator_max_uV_show, NULL), - __ATTR(max_microamps, 0444, regulator_max_uA_show, NULL), - __ATTR(requested_microamps, 0444, regulator_total_uA_show, NULL), __ATTR(num_users, 0444, regulator_num_users_show, NULL), __ATTR(type, 0444, regulator_type_show, NULL), - __ATTR(suspend_mem_microvolts, 0444, - regulator_suspend_mem_uV_show, NULL), - __ATTR(suspend_disk_microvolts, 0444, - regulator_suspend_disk_uV_show, NULL), - __ATTR(suspend_standby_microvolts, 0444, - regulator_suspend_standby_uV_show, NULL), - __ATTR(suspend_mem_mode, 0444, - regulator_suspend_mem_mode_show, NULL), - __ATTR(suspend_disk_mode, 0444, - regulator_suspend_disk_mode_show, NULL), - __ATTR(suspend_standby_mode, 0444, - regulator_suspend_standby_mode_show, NULL), - __ATTR(suspend_mem_state, 0444, - regulator_suspend_mem_state_show, NULL), - __ATTR(suspend_disk_state, 0444, - regulator_suspend_disk_state_show, NULL), - __ATTR(suspend_standby_state, 0444, - regulator_suspend_standby_state_show, NULL), __ATTR_NULL, }; @@ -675,7 +655,8 @@ static void print_constraints(struct regulator_dev *rdev) /** * set_machine_constraints - sets regulator constraints - * @regulator: regulator source + * @rdev: regulator source + * @constraints: constraints to apply * * Allows platform initialisation code to define and constrain * regulator circuits e.g. valid voltage/current ranges, etc. NOTE: @@ -750,8 +731,8 @@ out: /** * set_supply - set regulator supply regulator - * @regulator: regulator name - * @supply: supply regulator name + * @rdev: regulator name + * @supply_rdev: supply regulator name * * Called by platform initialisation code to set the supply regulator for this * regulator. This ensures that a regulators supply will also be enabled by the @@ -778,9 +759,9 @@ out: /** * set_consumer_device_supply: Bind a regulator to a symbolic supply - * @regulator: regulator source - * @dev: device the supply applies to - * @supply: symbolic name for supply + * @rdev: regulator source + * @consumer_dev: device the supply applies to + * @supply: symbolic name for supply * * Allows platform initialisation code to map physical regulator * sources to symbolic names for supplies for use by devices. Devices @@ -795,6 +776,20 @@ static int set_consumer_device_supply(struct regulator_dev *rdev, if (supply == NULL) return -EINVAL; + list_for_each_entry(node, ®ulator_map_list, list) { + if (consumer_dev != node->dev) + continue; + if (strcmp(node->supply, supply) != 0) + continue; + + dev_dbg(consumer_dev, "%s/%s is '%s' supply; fail %s/%s\n", + dev_name(&node->regulator->dev), + node->regulator->desc->name, + supply, + dev_name(&rdev->dev), rdev->desc->name); + return -EBUSY; + } + node = kmalloc(sizeof(struct regulator_map), GFP_KERNEL); if (node == NULL) return -ENOMEM; @@ -963,16 +958,13 @@ void regulator_put(struct regulator *regulator) if (regulator == NULL || IS_ERR(regulator)) return; - if (regulator->enabled) { - printk(KERN_WARNING "Releasing supply %s while enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - regulator_disable(regulator); - } - mutex_lock(®ulator_list_mutex); rdev = regulator->rdev; + if (WARN(regulator->enabled, "Releasing supply %s while enabled\n", + regulator->supply_name)) + _regulator_disable(rdev); + /* remove any sysfs entries */ if (regulator->dev) { sysfs_remove_link(&rdev->dev.kobj, regulator->supply_name); @@ -1034,29 +1026,26 @@ static int _regulator_enable(struct regulator_dev *rdev) * regulator_enable - enable regulator output * @regulator: regulator source * - * Enable the regulator output at the predefined voltage or current value. + * Request that the regulator be enabled with the regulator output at + * the predefined voltage or current value. Calls to regulator_enable() + * must be balanced with calls to regulator_disable(). + * * NOTE: the output value can be set by other drivers, boot loader or may be * hardwired in the regulator. - * NOTE: calls to regulator_enable() must be balanced with calls to - * regulator_disable(). */ int regulator_enable(struct regulator *regulator) { - int ret; - - if (regulator->enabled) { - printk(KERN_CRIT "Regulator %s already enabled\n", - regulator->supply_name); - WARN_ON(regulator->enabled); - return 0; - } + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 1; - ret = _regulator_enable(regulator->rdev); - if (ret != 0) - regulator->enabled = 0; - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 0) + ret = _regulator_enable(rdev); + else if (regulator->enabled < 0) + ret = -EIO; + if (ret == 0) + regulator->enabled++; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_enable); @@ -1100,27 +1089,31 @@ static int _regulator_disable(struct regulator_dev *rdev) * regulator_disable - disable regulator output * @regulator: regulator source * - * Disable the regulator output voltage or current. - * NOTE: this will only disable the regulator output if no other consumer - * devices have it enabled. - * NOTE: calls to regulator_enable() must be balanced with calls to + * Disable the regulator output voltage or current. Calls to + * regulator_enable() must be balanced with calls to * regulator_disable(). + * + * NOTE: this will only disable the regulator output if no other consumer + * devices have it enabled, the regulator device supports disabling and + * machine constraints permit this operation. */ int regulator_disable(struct regulator *regulator) { - int ret; - - if (!regulator->enabled) { - printk(KERN_ERR "%s: not in use by this consumer\n", - __func__); - return 0; - } + struct regulator_dev *rdev = regulator->rdev; + int ret = 0; - mutex_lock(®ulator->rdev->mutex); - regulator->enabled = 0; - regulator->uA_load = 0; - ret = _regulator_disable(regulator->rdev); - mutex_unlock(®ulator->rdev->mutex); + mutex_lock(&rdev->mutex); + if (regulator->enabled == 1) { + ret = _regulator_disable(rdev); + if (ret == 0) + regulator->uA_load = 0; + } else if (WARN(regulator->enabled <= 0, + "unbalanced disables for supply %s\n", + regulator->supply_name)) + ret = -EIO; + if (ret == 0) + regulator->enabled--; + mutex_unlock(&rdev->mutex); return ret; } EXPORT_SYMBOL_GPL(regulator_disable); @@ -1196,7 +1189,13 @@ out: * regulator_is_enabled - is the regulator output enabled * @regulator: regulator source * - * Returns zero for disabled otherwise return number of enable requests. + * Returns positive if the regulator driver backing the source/client + * has requested that the device be enabled, zero if it hasn't, else a + * negative errno code. + * + * Note that the device backing this regulator handle can have multiple + * users, so it might be enabled even if regulator_enable() was never + * called for this particular source. */ int regulator_is_enabled(struct regulator *regulator) { @@ -1219,7 +1218,7 @@ EXPORT_SYMBOL_GPL(regulator_is_enabled); * * NOTE: If the regulator is shared between several devices then the lowest * request voltage that meets the system constraints will be used. - * NOTE: Regulator system constraints must be set for this regulator before + * Regulator system constraints must be set for this regulator before * calling this function otherwise this call will fail. */ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) @@ -1493,7 +1492,8 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) mode = rdev->desc->ops->get_optimum_mode(rdev, input_uV, output_uV, total_uA_load); - if (ret <= 0) { + ret = regulator_check_mode(rdev, mode); + if (ret < 0) { printk(KERN_ERR "%s: failed to get optimum mode for %s @" " %d uA %d -> %d uV\n", __func__, rdev->desc->name, total_uA_load, input_uV, output_uV); @@ -1501,7 +1501,7 @@ int regulator_set_optimum_mode(struct regulator *regulator, int uA_load) } ret = rdev->desc->ops->set_mode(rdev, mode); - if (ret <= 0) { + if (ret < 0) { printk(KERN_ERR "%s: failed to set optimum mode %x for %s\n", __func__, mode, rdev->desc->name); goto out; @@ -1516,7 +1516,7 @@ EXPORT_SYMBOL_GPL(regulator_set_optimum_mode); /** * regulator_register_notifier - register regulator event notifier * @regulator: regulator source - * @notifier_block: notifier block + * @nb: notifier block * * Register notifier block to receive regulator events. */ @@ -1531,7 +1531,7 @@ EXPORT_SYMBOL_GPL(regulator_register_notifier); /** * regulator_unregister_notifier - unregister regulator event notifier * @regulator: regulator source - * @notifier_block: notifier block + * @nb: notifier block * * Unregister regulator event notifier block. */ @@ -1697,9 +1697,9 @@ EXPORT_SYMBOL_GPL(regulator_bulk_free); /** * regulator_notifier_call_chain - call regulator event notifier - * @regulator: regulator source + * @rdev: regulator source * @event: notifier block - * @data: + * @data: callback-specific data. * * Called by regulator drivers to notify clients a regulator event has * occurred. We also notify regulator clients downstream. @@ -1713,10 +1713,122 @@ int regulator_notifier_call_chain(struct regulator_dev *rdev, } EXPORT_SYMBOL_GPL(regulator_notifier_call_chain); +/* + * To avoid cluttering sysfs (and memory) with useless state, only + * create attributes that can be meaningfully displayed. + */ +static int add_regulator_attributes(struct regulator_dev *rdev) +{ + struct device *dev = &rdev->dev; + struct regulator_ops *ops = rdev->desc->ops; + int status = 0; + + /* some attributes need specific methods to be displayed */ + if (ops->get_voltage) { + status = device_create_file(dev, &dev_attr_microvolts); + if (status < 0) + return status; + } + if (ops->get_current_limit) { + status = device_create_file(dev, &dev_attr_microamps); + if (status < 0) + return status; + } + if (ops->get_mode) { + status = device_create_file(dev, &dev_attr_opmode); + if (status < 0) + return status; + } + if (ops->is_enabled) { + status = device_create_file(dev, &dev_attr_state); + if (status < 0) + return status; + } + + /* some attributes are type-specific */ + if (rdev->desc->type == REGULATOR_CURRENT) { + status = device_create_file(dev, &dev_attr_requested_microamps); + if (status < 0) + return status; + } + + /* all the other attributes exist to support constraints; + * don't show them if there are no constraints, or if the + * relevant supporting methods are missing. + */ + if (!rdev->constraints) + return status; + + /* constraints need specific supporting methods */ + if (ops->set_voltage) { + status = device_create_file(dev, &dev_attr_min_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_max_microvolts); + if (status < 0) + return status; + } + if (ops->set_current_limit) { + status = device_create_file(dev, &dev_attr_min_microamps); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_max_microamps); + if (status < 0) + return status; + } + + /* suspend mode constraints need multiple supporting methods */ + if (!(ops->set_suspend_enable && ops->set_suspend_disable)) + return status; + + status = device_create_file(dev, &dev_attr_suspend_standby_state); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_suspend_mem_state); + if (status < 0) + return status; + status = device_create_file(dev, &dev_attr_suspend_disk_state); + if (status < 0) + return status; + + if (ops->set_suspend_voltage) { + status = device_create_file(dev, + &dev_attr_suspend_standby_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_mem_microvolts); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_disk_microvolts); + if (status < 0) + return status; + } + + if (ops->set_suspend_mode) { + status = device_create_file(dev, + &dev_attr_suspend_standby_mode); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_mem_mode); + if (status < 0) + return status; + status = device_create_file(dev, + &dev_attr_suspend_disk_mode); + if (status < 0) + return status; + } + + return status; +} + /** * regulator_register - register regulator - * @regulator: regulator source - * @reg_data: private regulator data + * @regulator_desc: regulator to register + * @dev: struct device for the regulator + * @driver_data: private regulator data * * Called by regulator drivers to register a regulator. * Returns 0 on success. @@ -1761,45 +1873,37 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, /* preform any regulator specific init */ if (init_data->regulator_init) { ret = init_data->regulator_init(rdev->reg_data); - if (ret < 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } - } - - /* set regulator constraints */ - ret = set_machine_constraints(rdev, &init_data->constraints); - if (ret < 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; + if (ret < 0) + goto clean; } /* register with sysfs */ rdev->dev.class = ®ulator_class; rdev->dev.parent = dev; - snprintf(rdev->dev.bus_id, sizeof(rdev->dev.bus_id), - "regulator.%d", atomic_inc_return(®ulator_no) - 1); + dev_set_name(&rdev->dev, "regulator.%d", + atomic_inc_return(®ulator_no) - 1); ret = device_register(&rdev->dev); - if (ret != 0) { - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret != 0) + goto clean; dev_set_drvdata(&rdev->dev, rdev); + /* set regulator constraints */ + ret = set_machine_constraints(rdev, &init_data->constraints); + if (ret < 0) + goto scrub; + + /* add attributes supported by this regulator */ + ret = add_regulator_attributes(rdev); + if (ret < 0) + goto scrub; + /* set supply regulator if it exists */ if (init_data->supply_regulator_dev) { ret = set_supply(rdev, dev_get_drvdata(init_data->supply_regulator_dev)); - if (ret < 0) { - device_unregister(&rdev->dev); - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; - } + if (ret < 0) + goto scrub; } /* add consumers devices */ @@ -1811,10 +1915,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, for (--i; i >= 0; i--) unset_consumer_device_supply(rdev, init_data->consumer_supplies[i].dev); - device_unregister(&rdev->dev); - kfree(rdev); - rdev = ERR_PTR(ret); - goto out; + goto scrub; } } @@ -1822,12 +1923,19 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc, out: mutex_unlock(®ulator_list_mutex); return rdev; + +scrub: + device_unregister(&rdev->dev); +clean: + kfree(rdev); + rdev = ERR_PTR(ret); + goto out; } EXPORT_SYMBOL_GPL(regulator_register); /** * regulator_unregister - unregister regulator - * @regulator: regulator source + * @rdev: regulator to unregister * * Called by regulator drivers to unregister a regulator. */ @@ -1846,7 +1954,7 @@ void regulator_unregister(struct regulator_dev *rdev) EXPORT_SYMBOL_GPL(regulator_unregister); /** - * regulator_suspend_prepare: prepare regulators for system wide suspend + * regulator_suspend_prepare - prepare regulators for system wide suspend * @state: system suspend state * * Configure each regulator with it's suspend operating parameters for state. @@ -1882,7 +1990,7 @@ EXPORT_SYMBOL_GPL(regulator_suspend_prepare); /** * rdev_get_drvdata - get rdev regulator driver data - * @regulator: regulator + * @rdev: regulator * * Get rdev regulator driver private data. This call can be used in the * regulator driver context. @@ -1919,7 +2027,7 @@ EXPORT_SYMBOL_GPL(regulator_set_drvdata); /** * regulator_get_id - get regulator ID - * @regulator: regulator + * @rdev: regulator */ int rdev_get_id(struct regulator_dev *rdev) { diff --git a/drivers/regulator/da903x.c b/drivers/regulator/da903x.c index 773b29cec8b..fe77730a7ed 100644 --- a/drivers/regulator/da903x.c +++ b/drivers/regulator/da903x.c @@ -102,7 +102,7 @@ static int da903x_set_ldo_voltage(struct regulator_dev *rdev, uint8_t val, mask; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -159,7 +159,7 @@ static int da903x_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - return reg_val & (1 << info->enable_bit); + return !!(reg_val & (1 << info->enable_bit)); } /* DA9030 specific operations */ @@ -172,7 +172,7 @@ static int da9030_set_ldo1_15_voltage(struct regulator_dev *rdev, int ret; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -199,7 +199,7 @@ static int da9030_set_ldo14_voltage(struct regulator_dev *rdev, int thresh; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -248,7 +248,7 @@ static int da9034_set_dvc_voltage(struct regulator_dev *rdev, int ret; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } @@ -273,7 +273,7 @@ static int da9034_set_ldo12_voltage(struct regulator_dev *rdev, uint8_t val, mask; if (check_range(info, min_uV, max_uV)) { - pr_err("invalid voltage range (%d, %d) uV", min_uV, max_uV); + pr_err("invalid voltage range (%d, %d) uV\n", min_uV, max_uV); return -EINVAL; } diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c new file mode 100644 index 00000000000..4cc85ec6e12 --- /dev/null +++ b/drivers/regulator/pcf50633-regulator.c @@ -0,0 +1,329 @@ +/* NXP PCF50633 PMIC Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte and Andy Green and Werner Almesberger + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/platform_device.h> + +#include <linux/mfd/pcf50633/core.h> +#include <linux/mfd/pcf50633/pmic.h> + +#define PCF50633_REGULATOR(_name, _id) \ + { \ + .name = _name, \ + .id = _id, \ + .ops = &pcf50633_regulator_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + } + +static const u8 pcf50633_regulator_registers[PCF50633_NUM_REGULATORS] = { + [PCF50633_REGULATOR_AUTO] = PCF50633_REG_AUTOOUT, + [PCF50633_REGULATOR_DOWN1] = PCF50633_REG_DOWN1OUT, + [PCF50633_REGULATOR_DOWN2] = PCF50633_REG_DOWN2OUT, + [PCF50633_REGULATOR_MEMLDO] = PCF50633_REG_MEMLDOOUT, + [PCF50633_REGULATOR_LDO1] = PCF50633_REG_LDO1OUT, + [PCF50633_REGULATOR_LDO2] = PCF50633_REG_LDO2OUT, + [PCF50633_REGULATOR_LDO3] = PCF50633_REG_LDO3OUT, + [PCF50633_REGULATOR_LDO4] = PCF50633_REG_LDO4OUT, + [PCF50633_REGULATOR_LDO5] = PCF50633_REG_LDO5OUT, + [PCF50633_REGULATOR_LDO6] = PCF50633_REG_LDO6OUT, + [PCF50633_REGULATOR_HCLDO] = PCF50633_REG_HCLDOOUT, +}; + +/* Bits from voltage value */ +static u8 auto_voltage_bits(unsigned int millivolts) +{ + if (millivolts < 1800) + return 0; + if (millivolts > 3800) + return 0xff; + + millivolts -= 625; + + return millivolts / 25; +} + +static u8 down_voltage_bits(unsigned int millivolts) +{ + if (millivolts < 625) + return 0; + else if (millivolts > 3000) + return 0xff; + + millivolts -= 625; + + return millivolts / 25; +} + +static u8 ldo_voltage_bits(unsigned int millivolts) +{ + if (millivolts < 900) + return 0; + else if (millivolts > 3600) + return 0x1f; + + millivolts -= 900; + return millivolts / 100; +} + +/* Obtain voltage value from bits */ +static unsigned int auto_voltage_value(u8 bits) +{ + if (bits < 0x2f) + return 0; + + return 625 + (bits * 25); +} + + +static unsigned int down_voltage_value(u8 bits) +{ + return 625 + (bits * 25); +} + + +static unsigned int ldo_voltage_value(u8 bits) +{ + bits &= 0x1f; + + return 900 + (bits * 100); +} + +static int pcf50633_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV) +{ + struct pcf50633 *pcf; + int regulator_id, millivolts; + u8 volt_bits, regnr; + + pcf = rdev_get_drvdata(rdev); + + regulator_id = rdev_get_id(rdev); + if (regulator_id >= PCF50633_NUM_REGULATORS) + return -EINVAL; + + millivolts = min_uV / 1000; + + regnr = pcf50633_regulator_registers[regulator_id]; + + switch (regulator_id) { + case PCF50633_REGULATOR_AUTO: + volt_bits = auto_voltage_bits(millivolts); + break; + case PCF50633_REGULATOR_DOWN1: + volt_bits = down_voltage_bits(millivolts); + break; + case PCF50633_REGULATOR_DOWN2: + volt_bits = down_voltage_bits(millivolts); + break; + case PCF50633_REGULATOR_LDO1: + case PCF50633_REGULATOR_LDO2: + case PCF50633_REGULATOR_LDO3: + case PCF50633_REGULATOR_LDO4: + case PCF50633_REGULATOR_LDO5: + case PCF50633_REGULATOR_LDO6: + case PCF50633_REGULATOR_HCLDO: + volt_bits = ldo_voltage_bits(millivolts); + break; + default: + return -EINVAL; + } + + return pcf50633_reg_write(pcf, regnr, volt_bits); +} + +static int pcf50633_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct pcf50633 *pcf; + int regulator_id, millivolts, volt_bits; + u8 regnr; + + pcf = rdev_get_drvdata(rdev);; + + regulator_id = rdev_get_id(rdev); + if (regulator_id >= PCF50633_NUM_REGULATORS) + return -EINVAL; + + regnr = pcf50633_regulator_registers[regulator_id]; + + volt_bits = pcf50633_reg_read(pcf, regnr); + if (volt_bits < 0) + return -1; + + switch (regulator_id) { + case PCF50633_REGULATOR_AUTO: + millivolts = auto_voltage_value(volt_bits); + break; + case PCF50633_REGULATOR_DOWN1: + millivolts = down_voltage_value(volt_bits); + break; + case PCF50633_REGULATOR_DOWN2: + millivolts = down_voltage_value(volt_bits); + break; + case PCF50633_REGULATOR_LDO1: + case PCF50633_REGULATOR_LDO2: + case PCF50633_REGULATOR_LDO3: + case PCF50633_REGULATOR_LDO4: + case PCF50633_REGULATOR_LDO5: + case PCF50633_REGULATOR_LDO6: + case PCF50633_REGULATOR_HCLDO: + millivolts = ldo_voltage_value(volt_bits); + break; + default: + return -EINVAL; + } + + return millivolts * 1000; +} + +static int pcf50633_regulator_enable(struct regulator_dev *rdev) +{ + struct pcf50633 *pcf = rdev_get_drvdata(rdev); + int regulator_id; + u8 regnr; + + regulator_id = rdev_get_id(rdev); + if (regulator_id >= PCF50633_NUM_REGULATORS) + return -EINVAL; + + /* The *ENA register is always one after the *OUT register */ + regnr = pcf50633_regulator_registers[regulator_id] + 1; + + return pcf50633_reg_set_bit_mask(pcf, regnr, PCF50633_REGULATOR_ON, + PCF50633_REGULATOR_ON); +} + +static int pcf50633_regulator_disable(struct regulator_dev *rdev) +{ + struct pcf50633 *pcf = rdev_get_drvdata(rdev); + int regulator_id; + u8 regnr; + + regulator_id = rdev_get_id(rdev); + if (regulator_id >= PCF50633_NUM_REGULATORS) + return -EINVAL; + + /* the *ENA register is always one after the *OUT register */ + regnr = pcf50633_regulator_registers[regulator_id] + 1; + + return pcf50633_reg_set_bit_mask(pcf, regnr, + PCF50633_REGULATOR_ON, 0); +} + +static int pcf50633_regulator_is_enabled(struct regulator_dev *rdev) +{ + struct pcf50633 *pcf = rdev_get_drvdata(rdev); + int regulator_id = rdev_get_id(rdev); + u8 regnr; + + regulator_id = rdev_get_id(rdev); + if (regulator_id >= PCF50633_NUM_REGULATORS) + return -EINVAL; + + /* the *ENA register is always one after the *OUT register */ + regnr = pcf50633_regulator_registers[regulator_id] + 1; + + return pcf50633_reg_read(pcf, regnr) & PCF50633_REGULATOR_ON; +} + +static struct regulator_ops pcf50633_regulator_ops = { + .set_voltage = pcf50633_regulator_set_voltage, + .get_voltage = pcf50633_regulator_get_voltage, + .enable = pcf50633_regulator_enable, + .disable = pcf50633_regulator_disable, + .is_enabled = pcf50633_regulator_is_enabled, +}; + +static struct regulator_desc regulators[] = { + [PCF50633_REGULATOR_AUTO] = + PCF50633_REGULATOR("auto", PCF50633_REGULATOR_AUTO), + [PCF50633_REGULATOR_DOWN1] = + PCF50633_REGULATOR("down1", PCF50633_REGULATOR_DOWN1), + [PCF50633_REGULATOR_DOWN2] = + PCF50633_REGULATOR("down2", PCF50633_REGULATOR_DOWN2), + [PCF50633_REGULATOR_LDO1] = + PCF50633_REGULATOR("ldo1", PCF50633_REGULATOR_LDO1), + [PCF50633_REGULATOR_LDO2] = + PCF50633_REGULATOR("ldo2", PCF50633_REGULATOR_LDO2), + [PCF50633_REGULATOR_LDO3] = + PCF50633_REGULATOR("ldo3", PCF50633_REGULATOR_LDO3), + [PCF50633_REGULATOR_LDO4] = + PCF50633_REGULATOR("ldo4", PCF50633_REGULATOR_LDO4), + [PCF50633_REGULATOR_LDO5] = + PCF50633_REGULATOR("ldo5", PCF50633_REGULATOR_LDO5), + [PCF50633_REGULATOR_LDO6] = + PCF50633_REGULATOR("ldo6", PCF50633_REGULATOR_LDO6), + [PCF50633_REGULATOR_HCLDO] = + PCF50633_REGULATOR("hcldo", PCF50633_REGULATOR_HCLDO), + [PCF50633_REGULATOR_MEMLDO] = + PCF50633_REGULATOR("memldo", PCF50633_REGULATOR_MEMLDO), +}; + +static int __devinit pcf50633_regulator_probe(struct platform_device *pdev) +{ + struct regulator_dev *rdev; + struct pcf50633 *pcf; + + /* Already set by core driver */ + pcf = platform_get_drvdata(pdev); + + rdev = regulator_register(®ulators[pdev->id], &pdev->dev, pcf); + if (IS_ERR(rdev)) + return PTR_ERR(rdev); + + if (pcf->pdata->regulator_registered) + pcf->pdata->regulator_registered(pcf, pdev->id); + + return 0; +} + +static int __devexit pcf50633_regulator_remove(struct platform_device *pdev) +{ + struct regulator_dev *rdev = platform_get_drvdata(pdev); + + regulator_unregister(rdev); + + return 0; +} + +static struct platform_driver pcf50633_regulator_driver = { + .driver = { + .name = "pcf50633-regltr", + }, + .probe = pcf50633_regulator_probe, + .remove = __devexit_p(pcf50633_regulator_remove), +}; + +static int __init pcf50633_regulator_init(void) +{ + return platform_driver_register(&pcf50633_regulator_driver); +} +module_init(pcf50633_regulator_init); + +static void __exit pcf50633_regulator_exit(void) +{ + platform_driver_unregister(&pcf50633_regulator_driver); +} +module_exit(pcf50633_regulator_exit); + +MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); +MODULE_DESCRIPTION("PCF50633 regulator driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:pcf50633-regulator"); diff --git a/drivers/regulator/wm8350-regulator.c b/drivers/regulator/wm8350-regulator.c index c68c496b2c4..7aa35248181 100644 --- a/drivers/regulator/wm8350-regulator.c +++ b/drivers/regulator/wm8350-regulator.c @@ -1412,6 +1412,97 @@ int wm8350_register_regulator(struct wm8350 *wm8350, int reg, } EXPORT_SYMBOL_GPL(wm8350_register_regulator); +/** + * wm8350_register_led - Register a WM8350 LED output + * + * @param wm8350 The WM8350 device to configure. + * @param lednum LED device index to create. + * @param dcdc The DCDC to use for the LED. + * @param isink The ISINK to use for the LED. + * @param pdata Configuration for the LED. + * + * The WM8350 supports the use of an ISINK together with a DCDC to + * provide a power-efficient LED driver. This function registers the + * regulators and instantiates the platform device for a LED. The + * operating modes for the LED regulators must be configured using + * wm8350_isink_set_flash(), wm8350_dcdc25_set_mode() and + * wm8350_dcdc_set_slot() prior to calling this function. + */ +int wm8350_register_led(struct wm8350 *wm8350, int lednum, int dcdc, int isink, + struct wm8350_led_platform_data *pdata) +{ + struct wm8350_led *led; + struct platform_device *pdev; + int ret; + + if (lednum > ARRAY_SIZE(wm8350->pmic.led) || lednum < 0) { + dev_err(wm8350->dev, "Invalid LED index %d\n", lednum); + return -ENODEV; + } + + led = &wm8350->pmic.led[lednum]; + + if (led->pdev) { + dev_err(wm8350->dev, "LED %d already allocated\n", lednum); + return -EINVAL; + } + + pdev = platform_device_alloc("wm8350-led", lednum); + if (pdev == NULL) { + dev_err(wm8350->dev, "Failed to allocate LED %d\n", lednum); + return -ENOMEM; + } + + led->isink_consumer.dev = &pdev->dev; + led->isink_consumer.supply = "led_isink"; + led->isink_init.num_consumer_supplies = 1; + led->isink_init.consumer_supplies = &led->isink_consumer; + led->isink_init.constraints.min_uA = 0; + led->isink_init.constraints.max_uA = pdata->max_uA; + led->isink_init.constraints.valid_ops_mask = REGULATOR_CHANGE_CURRENT; + led->isink_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; + ret = wm8350_register_regulator(wm8350, isink, &led->isink_init); + if (ret != 0) { + platform_device_put(pdev); + return ret; + } + + led->dcdc_consumer.dev = &pdev->dev; + led->dcdc_consumer.supply = "led_vcc"; + led->dcdc_init.num_consumer_supplies = 1; + led->dcdc_init.consumer_supplies = &led->dcdc_consumer; + led->dcdc_init.constraints.valid_modes_mask = REGULATOR_MODE_NORMAL; + ret = wm8350_register_regulator(wm8350, dcdc, &led->dcdc_init); + if (ret != 0) { + platform_device_put(pdev); + return ret; + } + + switch (isink) { + case WM8350_ISINK_A: + wm8350->pmic.isink_A_dcdc = dcdc; + break; + case WM8350_ISINK_B: + wm8350->pmic.isink_B_dcdc = dcdc; + break; + } + + pdev->dev.platform_data = pdata; + pdev->dev.parent = wm8350->dev; + ret = platform_device_add(pdev); + if (ret != 0) { + dev_err(wm8350->dev, "Failed to register LED %d: %d\n", + lednum, ret); + platform_device_put(pdev); + return ret; + } + + led->pdev = pdev; + + return 0; +} +EXPORT_SYMBOL_GPL(wm8350_register_led); + static struct platform_driver wm8350_regulator_driver = { .probe = wm8350_regulator_probe, .remove = wm8350_regulator_remove, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4ad831de41a..cced4d10831 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -502,6 +502,13 @@ config RTC_DRV_WM8350 This driver can also be built as a module. If so, the module will be called "rtc-wm8350". +config RTC_DRV_PCF50633 + depends on MFD_PCF50633 + tristate "NXP PCF50633 RTC" + help + If you say yes here you get support for the RTC subsystem of the + NXP PCF50633 used in embedded systems. + comment "on-CPU RTC drivers" config RTC_DRV_OMAP diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 9a4340d48f2..6e28021abb9 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -74,3 +74,4 @@ obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 162330b9d1d..7e5155e88ac 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -86,13 +86,11 @@ enum ds_type { struct ds1307 { - u8 reg_addr; u8 regs[11]; enum ds_type type; unsigned long flags; #define HAS_NVRAM 0 /* bit 0 == sysfs file active */ #define HAS_ALARM 1 /* bit 1 == irq claimed */ - struct i2c_msg msg[2]; struct i2c_client *client; struct rtc_device *rtc; struct work_struct work; @@ -204,13 +202,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t) int tmp; /* read the RTC date and time registers all at once */ - ds1307->reg_addr = 0; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 7; - - tmp = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), - ds1307->msg, 2); - if (tmp != 2) { + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + DS1307_REG_SECS, 7, ds1307->regs); + if (tmp != 7) { dev_err(dev, "%s error %d\n", "read", tmp); return -EIO; } @@ -257,7 +251,6 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) t->tm_hour, t->tm_mday, t->tm_mon, t->tm_year, t->tm_wday); - *buf++ = 0; /* first register addr */ buf[DS1307_REG_SECS] = bin2bcd(t->tm_sec); buf[DS1307_REG_MIN] = bin2bcd(t->tm_min); buf[DS1307_REG_HOUR] = bin2bcd(t->tm_hour); @@ -282,23 +275,19 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) break; } - ds1307->msg[1].flags = 0; - ds1307->msg[1].len = 8; - dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", "write", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); - result = i2c_transfer(to_i2c_adapter(ds1307->client->dev.parent), - &ds1307->msg[1], 1); - if (result != 1) { - dev_err(dev, "%s error %d\n", "write", tmp); - return -EIO; + result = i2c_smbus_write_i2c_block_data(ds1307->client, 0, 7, buf); + if (result < 0) { + dev_err(dev, "%s error %d\n", "write", result); + return result; } return 0; } -static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) +static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -308,13 +297,9 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* read all ALARM1, ALARM2, and status registers at once */ - ds1307->reg_addr = DS1339_REG_ALARM1_SECS; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 9; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - ds1307->msg, 2); - if (ret != 2) { + ret = i2c_smbus_read_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, ds1307->regs); + if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm read", ret); return -EIO; } @@ -353,7 +338,7 @@ static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) +static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -371,13 +356,9 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* read current status of both alarms and the chip */ - ds1307->reg_addr = DS1339_REG_ALARM1_SECS; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = 9; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - ds1307->msg, 2); - if (ret != 2) { + ret = i2c_smbus_read_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, buf); + if (ret != 9) { dev_err(dev, "%s error %d\n", "alarm write", ret); return -EIO; } @@ -392,7 +373,6 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) ds1307->regs[6], control, status); /* set ALARM1, using 24 hour and day-of-month modes */ - *buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */ buf[0] = bin2bcd(t->time.tm_sec); buf[1] = bin2bcd(t->time.tm_min); buf[2] = bin2bcd(t->time.tm_hour); @@ -411,14 +391,11 @@ static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t) } buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I); - ds1307->msg[1].flags = 0; - ds1307->msg[1].len = 10; - - ret = i2c_transfer(to_i2c_adapter(client->dev.parent), - &ds1307->msg[1], 1); - if (ret != 1) { + ret = i2c_smbus_write_i2c_block_data(client, + DS1339_REG_ALARM1_SECS, 9, buf); + if (ret < 0) { dev_err(dev, "can't set alarm time\n"); - return -EIO; + return ret; } return 0; @@ -475,8 +452,8 @@ static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) static const struct rtc_class_ops ds13xx_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, - .read_alarm = ds1307_read_alarm, - .set_alarm = ds1307_set_alarm, + .read_alarm = ds1337_read_alarm, + .set_alarm = ds1337_set_alarm, .ioctl = ds1307_ioctl, }; @@ -490,7 +467,6 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, { struct i2c_client *client; struct ds1307 *ds1307; - struct i2c_msg msg[2]; int result; client = kobj_to_i2c_client(kobj); @@ -503,24 +479,10 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - msg[0].addr = client->addr; - msg[0].flags = 0; - msg[0].len = 1; - msg[0].buf = buf; - - buf[0] = 8 + off; - - msg[1].addr = client->addr; - msg[1].flags = I2C_M_RD; - msg[1].len = count; - msg[1].buf = buf; - - result = i2c_transfer(to_i2c_adapter(client->dev.parent), msg, 2); - if (result != 2) { + result = i2c_smbus_read_i2c_block_data(client, 8 + off, count, buf); + if (result < 0) dev_err(&client->dev, "%s error %d\n", "nvram read", result); - return -EIO; - } - return count; + return result; } static ssize_t @@ -528,8 +490,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct i2c_client *client; - u8 buffer[NVRAM_SIZE + 1]; - int ret; + int result; client = kobj_to_i2c_client(kobj); @@ -540,11 +501,12 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, if (unlikely(!count)) return count; - buffer[0] = 8 + off; - memcpy(buffer + 1, buf, count); - - ret = i2c_master_send(client, buffer, count + 1); - return (ret < 0) ? ret : (ret - 1); + result = i2c_smbus_write_i2c_block_data(client, 8 + off, count, buf); + if (result < 0) { + dev_err(&client->dev, "%s error %d\n", "nvram write", result); + return result; + } + return count; } static struct bin_attribute nvram = { @@ -571,9 +533,11 @@ static int __devinit ds1307_probe(struct i2c_client *client, const struct chip_desc *chip = &chips[id->driver_data]; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int want_irq = false; + unsigned char *buf; if (!i2c_check_functionality(adapter, - I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + I2C_FUNC_SMBUS_WRITE_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) return -EIO; if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL))) @@ -581,18 +545,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, ds1307->client = client; i2c_set_clientdata(client, ds1307); - - ds1307->msg[0].addr = client->addr; - ds1307->msg[0].flags = 0; - ds1307->msg[0].len = 1; - ds1307->msg[0].buf = &ds1307->reg_addr; - - ds1307->msg[1].addr = client->addr; - ds1307->msg[1].flags = I2C_M_RD; - ds1307->msg[1].len = sizeof(ds1307->regs); - ds1307->msg[1].buf = ds1307->regs; - ds1307->type = id->driver_data; + buf = ds1307->regs; switch (ds1307->type) { case ds_1337: @@ -602,21 +556,15 @@ static int __devinit ds1307_probe(struct i2c_client *client, INIT_WORK(&ds1307->work, ds1307_work); want_irq = true; } - - ds1307->reg_addr = DS1337_REG_CONTROL; - ds1307->msg[1].len = 2; - /* get registers that the "rtc" read below won't read... */ - tmp = i2c_transfer(adapter, ds1307->msg, 2); + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, + DS1337_REG_CONTROL, 2, buf); if (tmp != 2) { pr_debug("read error %d\n", tmp); err = -EIO; goto exit_free; } - ds1307->reg_addr = 0; - ds1307->msg[1].len = sizeof(ds1307->regs); - /* oscillator off? turn it on, so clock can tick. */ if (ds1307->regs[0] & DS1337_BIT_nEOSC) ds1307->regs[0] &= ~DS1337_BIT_nEOSC; @@ -647,9 +595,8 @@ static int __devinit ds1307_probe(struct i2c_client *client, read_rtc: /* read RTC registers */ - - tmp = i2c_transfer(adapter, ds1307->msg, 2); - if (tmp != 2) { + tmp = i2c_smbus_read_i2c_block_data(ds1307->client, 0, 8, buf); + if (tmp != 8) { pr_debug("read error %d\n", tmp); err = -EIO; goto exit_free; @@ -707,22 +654,6 @@ read_rtc: break; } - tmp = ds1307->regs[DS1307_REG_SECS]; - tmp = bcd2bin(tmp & 0x7f); - if (tmp > 60) - goto exit_bad; - tmp = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f); - if (tmp > 60) - goto exit_bad; - - tmp = bcd2bin(ds1307->regs[DS1307_REG_MDAY] & 0x3f); - if (tmp == 0 || tmp > 31) - goto exit_bad; - - tmp = bcd2bin(ds1307->regs[DS1307_REG_MONTH] & 0x1f); - if (tmp == 0 || tmp > 12) - goto exit_bad; - tmp = ds1307->regs[DS1307_REG_HOUR]; switch (ds1307->type) { case ds_1340: @@ -779,13 +710,6 @@ read_rtc: return 0; -exit_bad: - dev_dbg(&client->dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n", - "bogus register", - ds1307->regs[0], ds1307->regs[1], - ds1307->regs[2], ds1307->regs[3], - ds1307->regs[4], ds1307->regs[5], - ds1307->regs[6]); exit_irq: if (ds1307->rtc) rtc_device_unregister(ds1307->rtc); diff --git a/drivers/rtc/rtc-parisc.c b/drivers/rtc/rtc-parisc.c index 346d633655e..c6bfa6fe1a2 100644 --- a/drivers/rtc/rtc-parisc.c +++ b/drivers/rtc/rtc-parisc.c @@ -34,7 +34,8 @@ static int parisc_get_time(struct device *dev, struct rtc_time *tm) static int parisc_set_time(struct device *dev, struct rtc_time *tm) { struct parisc_rtc *p = dev_get_drvdata(dev); - unsigned long flags, ret; + unsigned long flags; + int ret; spin_lock_irqsave(&p->lock, flags); ret = set_rtc_time(tm); diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c new file mode 100644 index 00000000000..f4dd87e2907 --- /dev/null +++ b/drivers/rtc/rtc-pcf50633.c @@ -0,0 +1,344 @@ +/* NXP PCF50633 RTC Driver + * + * (C) 2006-2008 by Openmoko, Inc. + * Author: Balaji Rao <balajirrao@openmoko.org> + * All rights reserved. + * + * Broken down from monstrous PCF50633 driver mainly by + * Harald Welte, Andy Green and Werner Almesberger + * + * 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 <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/err.h> + +#include <linux/mfd/pcf50633/core.h> + +#define PCF50633_REG_RTCSC 0x59 /* Second */ +#define PCF50633_REG_RTCMN 0x5a /* Minute */ +#define PCF50633_REG_RTCHR 0x5b /* Hour */ +#define PCF50633_REG_RTCWD 0x5c /* Weekday */ +#define PCF50633_REG_RTCDT 0x5d /* Day */ +#define PCF50633_REG_RTCMT 0x5e /* Month */ +#define PCF50633_REG_RTCYR 0x5f /* Year */ +#define PCF50633_REG_RTCSCA 0x60 /* Alarm Second */ +#define PCF50633_REG_RTCMNA 0x61 /* Alarm Minute */ +#define PCF50633_REG_RTCHRA 0x62 /* Alarm Hour */ +#define PCF50633_REG_RTCWDA 0x63 /* Alarm Weekday */ +#define PCF50633_REG_RTCDTA 0x64 /* Alarm Day */ +#define PCF50633_REG_RTCMTA 0x65 /* Alarm Month */ +#define PCF50633_REG_RTCYRA 0x66 /* Alarm Year */ + +enum pcf50633_time_indexes { + PCF50633_TI_SEC, + PCF50633_TI_MIN, + PCF50633_TI_HOUR, + PCF50633_TI_WKDAY, + PCF50633_TI_DAY, + PCF50633_TI_MONTH, + PCF50633_TI_YEAR, + PCF50633_TI_EXTENT /* always last */ +}; + +struct pcf50633_time { + u_int8_t time[PCF50633_TI_EXTENT]; +}; + +struct pcf50633_rtc { + int alarm_enabled; + int second_enabled; + + struct pcf50633 *pcf; + struct rtc_device *rtc_dev; +}; + +static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf) +{ + rtc->tm_sec = bcd2bin(pcf->time[PCF50633_TI_SEC]); + rtc->tm_min = bcd2bin(pcf->time[PCF50633_TI_MIN]); + rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]); + rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]); + rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]); + rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]); + rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100; +} + +static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc) +{ + pcf->time[PCF50633_TI_SEC] = bin2bcd(rtc->tm_sec); + pcf->time[PCF50633_TI_MIN] = bin2bcd(rtc->tm_min); + pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour); + pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday); + pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday); + pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon); + pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100); +} + +static int +pcf50633_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct pcf50633_rtc *rtc = dev_get_drvdata(dev); + int err; + + if (enabled) + err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); + else + err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); + + if (err < 0) + return err; + + rtc->alarm_enabled = enabled; + + return 0; +} + +static int +pcf50633_rtc_update_irq_enable(struct device *dev, unsigned int enabled) +{ + struct pcf50633_rtc *rtc = dev_get_drvdata(dev); + int err; + + if (enabled) + err = pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); + else + err = pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); + + if (err < 0) + return err; + + rtc->second_enabled = enabled; + + return 0; +} + +static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct pcf50633_rtc *rtc; + struct pcf50633_time pcf_tm; + int ret; + + rtc = dev_get_drvdata(dev); + + ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSC, + PCF50633_TI_EXTENT, + &pcf_tm.time[0]); + if (ret != PCF50633_TI_EXTENT) { + dev_err(dev, "Failed to read time\n"); + return -EIO; + } + + dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", + pcf_tm.time[PCF50633_TI_DAY], + pcf_tm.time[PCF50633_TI_MONTH], + pcf_tm.time[PCF50633_TI_YEAR], + pcf_tm.time[PCF50633_TI_HOUR], + pcf_tm.time[PCF50633_TI_MIN], + pcf_tm.time[PCF50633_TI_SEC]); + + pcf2rtc_time(tm, &pcf_tm); + + dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", + tm->tm_mday, tm->tm_mon, tm->tm_year, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return rtc_valid_tm(tm); +} + +static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pcf50633_rtc *rtc; + struct pcf50633_time pcf_tm; + int second_masked, alarm_masked, ret = 0; + + rtc = dev_get_drvdata(dev); + + dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", + tm->tm_mday, tm->tm_mon, tm->tm_year, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + rtc2pcf_time(&pcf_tm, tm); + + dev_dbg(dev, "PCF_TIME: %02x.%02x.%02x %02x:%02x:%02x\n", + pcf_tm.time[PCF50633_TI_DAY], + pcf_tm.time[PCF50633_TI_MONTH], + pcf_tm.time[PCF50633_TI_YEAR], + pcf_tm.time[PCF50633_TI_HOUR], + pcf_tm.time[PCF50633_TI_MIN], + pcf_tm.time[PCF50633_TI_SEC]); + + + second_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_SECOND); + alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); + + if (!second_masked) + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_SECOND); + if (!alarm_masked) + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); + + /* Returns 0 on success */ + ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSC, + PCF50633_TI_EXTENT, + &pcf_tm.time[0]); + + if (!second_masked) + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_SECOND); + if (!alarm_masked) + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); + + return ret; +} + +static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pcf50633_rtc *rtc; + struct pcf50633_time pcf_tm; + int ret = 0; + + rtc = dev_get_drvdata(dev); + + alrm->enabled = rtc->alarm_enabled; + + ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, + PCF50633_TI_EXTENT, &pcf_tm.time[0]); + if (ret != PCF50633_TI_EXTENT) { + dev_err(dev, "Failed to read time\n"); + return -EIO; + } + + pcf2rtc_time(&alrm->time, &pcf_tm); + + return rtc_valid_tm(&alrm->time); +} + +static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct pcf50633_rtc *rtc; + struct pcf50633_time pcf_tm; + int alarm_masked, ret = 0; + + rtc = dev_get_drvdata(dev); + + rtc2pcf_time(&pcf_tm, &alrm->time); + + /* do like mktime does and ignore tm_wday */ + pcf_tm.time[PCF50633_TI_WKDAY] = 7; + + alarm_masked = pcf50633_irq_mask_get(rtc->pcf, PCF50633_IRQ_ALARM); + + /* disable alarm interrupt */ + if (!alarm_masked) + pcf50633_irq_mask(rtc->pcf, PCF50633_IRQ_ALARM); + + /* Returns 0 on success */ + ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, + PCF50633_TI_EXTENT, &pcf_tm.time[0]); + + if (!alarm_masked) + pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); + + return ret; +} + +static struct rtc_class_ops pcf50633_rtc_ops = { + .read_time = pcf50633_rtc_read_time, + .set_time = pcf50633_rtc_set_time, + .read_alarm = pcf50633_rtc_read_alarm, + .set_alarm = pcf50633_rtc_set_alarm, + .alarm_irq_enable = pcf50633_rtc_alarm_irq_enable, + .update_irq_enable = pcf50633_rtc_update_irq_enable, +}; + +static void pcf50633_rtc_irq(int irq, void *data) +{ + struct pcf50633_rtc *rtc = data; + + switch (irq) { + case PCF50633_IRQ_ALARM: + rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); + break; + case PCF50633_IRQ_SECOND: + rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); + break; + } +} + +static int __devinit pcf50633_rtc_probe(struct platform_device *pdev) +{ + struct pcf50633_subdev_pdata *pdata; + struct pcf50633_rtc *rtc; + + + rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + pdata = pdev->dev.platform_data; + rtc->pcf = pdata->pcf; + platform_set_drvdata(pdev, rtc); + rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev, + &pcf50633_rtc_ops, THIS_MODULE); + + if (IS_ERR(rtc->rtc_dev)) { + kfree(rtc); + return PTR_ERR(rtc->rtc_dev); + } + + pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, + pcf50633_rtc_irq, rtc); + pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_SECOND, + pcf50633_rtc_irq, rtc); + + return 0; +} + +static int __devexit pcf50633_rtc_remove(struct platform_device *pdev) +{ + struct pcf50633_rtc *rtc; + + rtc = platform_get_drvdata(pdev); + + pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_ALARM); + pcf50633_free_irq(rtc->pcf, PCF50633_IRQ_SECOND); + + rtc_device_unregister(rtc->rtc_dev); + kfree(rtc); + + return 0; +} + +static struct platform_driver pcf50633_rtc_driver = { + .driver = { + .name = "pcf50633-rtc", + }, + .probe = pcf50633_rtc_probe, + .remove = __devexit_p(pcf50633_rtc_remove), +}; + +static int __init pcf50633_rtc_init(void) +{ + return platform_driver_register(&pcf50633_rtc_driver); +} +module_init(pcf50633_rtc_init); + +static void __exit pcf50633_rtc_exit(void) +{ + platform_driver_unregister(&pcf50633_rtc_driver); +} +module_exit(pcf50633_rtc_exit); + +MODULE_DESCRIPTION("PCF50633 RTC driver"); +MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 570ae59c1d5..bd591499414 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -336,6 +336,9 @@ static int dasd_state_ready_to_online(struct dasd_device * device) { int rc; + struct gendisk *disk; + struct disk_part_iter piter; + struct hd_struct *part; if (device->discipline->ready_to_online) { rc = device->discipline->ready_to_online(device); @@ -343,8 +346,14 @@ dasd_state_ready_to_online(struct dasd_device * device) return rc; } device->state = DASD_STATE_ONLINE; - if (device->block) + if (device->block) { dasd_schedule_block_bh(device->block); + disk = device->block->bdev->bd_disk; + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); + while ((part = disk_part_iter_next(&piter))) + kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE); + disk_part_iter_exit(&piter); + } return 0; } @@ -354,6 +363,9 @@ dasd_state_ready_to_online(struct dasd_device * device) static int dasd_state_online_to_ready(struct dasd_device *device) { int rc; + struct gendisk *disk; + struct disk_part_iter piter; + struct hd_struct *part; if (device->discipline->online_to_ready) { rc = device->discipline->online_to_ready(device); @@ -361,6 +373,13 @@ static int dasd_state_online_to_ready(struct dasd_device *device) return rc; } device->state = DASD_STATE_READY; + if (device->block) { + disk = device->block->bdev->bd_disk; + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); + while ((part = disk_part_iter_next(&piter))) + kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE); + disk_part_iter_exit(&piter); + } return 0; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index b8f9c00633f..d82aad5224f 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2621,7 +2621,7 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } } - /* double-check if current erp/cqr was successfull */ + /* double-check if current erp/cqr was successful */ if ((cqr->irb.scsw.cmd.cstat == 0x00) && (cqr->irb.scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 2ef25731d19..300e28a531f 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -206,6 +206,8 @@ dasd_feature_list(char *str, char **endp) features |= DASD_FEATURE_USEDIAG; else if (len == 6 && !strncmp(str, "erplog", 6)) features |= DASD_FEATURE_ERPLOG; + else if (len == 8 && !strncmp(str, "failfast", 8)) + features |= DASD_FEATURE_FAILFAST; else { MESSAGE(KERN_WARNING, "unsupported feature: %*s, " @@ -667,6 +669,51 @@ dasd_device_from_cdev(struct ccw_device *cdev) */ /* + * failfast controls the behaviour, if no path is available + */ +static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dasd_devmap *devmap; + int ff_flag; + + devmap = dasd_find_busid(dev->bus_id); + if (!IS_ERR(devmap)) + ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0; + else + ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0; + return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n"); +} + +static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + int val; + char *endp; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + + val = simple_strtoul(buf, &endp, 0); + if (((endp + 1) < (buf + count)) || (val > 1)) + return -EINVAL; + + spin_lock(&dasd_devmap_lock); + if (val) + devmap->features |= DASD_FEATURE_FAILFAST; + else + devmap->features &= ~DASD_FEATURE_FAILFAST; + if (devmap->device) + devmap->device->features = devmap->features; + spin_unlock(&dasd_devmap_lock); + return count; +} + +static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); + +/* * readonly controls the readonly status of a dasd */ static ssize_t @@ -1020,6 +1067,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_use_diag.attr, &dev_attr_eer_enabled.attr, &dev_attr_erplog.attr, + &dev_attr_failfast.attr, NULL, }; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 7844461a995..ef2a5695205 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -544,7 +544,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); - if (blk_noretry_request(req)) + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index bd2c52e2076..bdb87998f36 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1700,7 +1700,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, recid++; } } - if (blk_noretry_request(req)) + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = startdev; cqr->memdev = startdev; diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 7d442aeff3d..f1d17602169 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -355,7 +355,8 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, recid++; } } - if (blk_noretry_request(req)) + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 05a14536c36..4a39084d9c9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -199,7 +199,7 @@ struct dasd_ccw_req { #define DASD_CQR_ERROR 0x82 /* request is completed with error */ #define DASD_CQR_CLEAR_PENDING 0x83 /* request is clear pending */ #define DASD_CQR_CLEARED 0x84 /* request was cleared */ -#define DASD_CQR_SUCCESS 0x85 /* request was successfull */ +#define DASD_CQR_SUCCESS 0x85 /* request was successful */ /* per dasd_ccw_req flags */ diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 643033890e3..0769ced52db 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -100,7 +100,7 @@ comment "S/390 tape interface support" config S390_TAPE_BLOCK bool "Support for tape block devices" - depends on S390_TAPE + depends on S390_TAPE && BLOCK help Select this option if you want to access your channel-attached tape devices using the block device interface. This interface is similar diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 4005c44a404..71605a179d6 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -801,7 +801,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) static inline int tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) { - DBF_EVENT(3, "Error Recovery successfull for %s\n", + DBF_EVENT(3, "Error Recovery successful for %s\n", tape_op_verbose[request->op]); return tape_3590_done(device, request); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 06b71823f39..659f8a79165 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -379,7 +379,7 @@ int cio_commit_config(struct subchannel *sch) if (ccode < 0) /* -EIO if msch gets a program check. */ return ccode; switch (ccode) { - case 0: /* successfull */ + case 0: /* successful */ if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index f8a3b6967f6..da7afb04e71 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -169,6 +169,8 @@ static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) q->nr); debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, debugfs_root, q, &debugfs_fops); + if (IS_ERR(debugfs_queues[i])) + debugfs_queues[i] = NULL; } void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 744f928a59e..10cb0f8726e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -114,7 +114,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) * @count: count of buffers to examine * @auto_ack: automatically acknowledge buffers * - * Returns the number of successfull extracted equal buffer states. + * Returns the number of successfully extracted equal buffer states. * Stops processing if a state is different from the last buffers state. */ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 591a2b3ae4c..07ab8a5c1c4 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -916,6 +916,21 @@ static struct ethtool_ops qeth_l2_osn_ops = { .get_drvinfo = qeth_core_get_drvinfo, }; +static const struct net_device_ops qeth_l2_netdev_ops = { + .ndo_open = qeth_l2_open, + .ndo_stop = qeth_l2_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l2_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l2_set_multicast_list, + .ndo_do_ioctl = qeth_l2_do_ioctl, + .ndo_set_mac_address = qeth_l2_set_mac_address, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, +}; + static int qeth_l2_setup_netdev(struct qeth_card *card) { switch (card->info.type) { @@ -937,19 +952,9 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) return -ENODEV; card->dev->ml_priv = card; - card->dev->tx_timeout = &qeth_tx_timeout; card->dev->watchdog_timeo = QETH_TX_TIMEOUT; - card->dev->open = qeth_l2_open; - card->dev->stop = qeth_l2_stop; - card->dev->hard_start_xmit = qeth_l2_hard_start_xmit; - card->dev->do_ioctl = qeth_l2_do_ioctl; - card->dev->get_stats = qeth_get_stats; - card->dev->change_mtu = qeth_change_mtu; - card->dev->set_multicast_list = qeth_l2_set_multicast_list; - card->dev->vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid; - card->dev->vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid; - card->dev->set_mac_address = qeth_l2_set_mac_address; card->dev->mtu = card->info.initial_mtu; + card->dev->netdev_ops = &qeth_l2_netdev_ops; if (card->info.type != QETH_CARD_TYPE_OSN) SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops); else diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 4693ee4e7b9..3d04920b9bb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -1829,28 +1829,6 @@ static void qeth_l3_vlan_rx_register(struct net_device *dev, static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { - struct net_device *vlandev; - struct qeth_card *card = dev->ml_priv; - struct in_device *in_dev; - - if (card->info.type == QETH_CARD_TYPE_IQD) - return; - - vlandev = vlan_group_get_device(card->vlangrp, vid); - vlandev->neigh_setup = qeth_l3_neigh_setup; - - in_dev = in_dev_get(vlandev); -#ifdef CONFIG_SYSCTL - neigh_sysctl_unregister(in_dev->arp_parms); -#endif - neigh_parms_release(&arp_tbl, in_dev->arp_parms); - - in_dev->arp_parms = neigh_parms_alloc(vlandev, &arp_tbl); -#ifdef CONFIG_SYSCTL - neigh_sysctl_register(vlandev, in_dev->arp_parms, NET_IPV4, - NET_IPV4_NEIGH, "ipv4", NULL, NULL); -#endif - in_dev_put(in_dev); return; } @@ -2916,6 +2894,37 @@ qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np) return 0; } +static const struct net_device_ops qeth_l3_netdev_ops = { + .ndo_open = qeth_l3_open, + .ndo_stop = qeth_l3_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_do_ioctl = qeth_l3_do_ioctl, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, + .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, +}; + +static const struct net_device_ops qeth_l3_osa_netdev_ops = { + .ndo_open = qeth_l3_open, + .ndo_stop = qeth_l3_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_do_ioctl = qeth_l3_do_ioctl, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, + .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, + .ndo_neigh_setup = qeth_l3_neigh_setup, +}; + static int qeth_l3_setup_netdev(struct qeth_card *card) { if (card->info.type == QETH_CARD_TYPE_OSAE) { @@ -2926,11 +2935,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) #endif if (!card->dev) return -ENODEV; + card->dev->netdev_ops = &qeth_l3_netdev_ops; } else { card->dev = alloc_etherdev(0); if (!card->dev) return -ENODEV; - card->dev->neigh_setup = qeth_l3_neigh_setup; + card->dev->netdev_ops = &qeth_l3_osa_netdev_ops; /*IPv6 address autoconfiguration stuff*/ qeth_l3_get_unique_id(card); @@ -2943,25 +2953,14 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) if (!card->dev) return -ENODEV; card->dev->flags |= IFF_NOARP; + card->dev->netdev_ops = &qeth_l3_netdev_ops; qeth_l3_iqd_read_initial_mac(card); } else return -ENODEV; - card->dev->hard_start_xmit = qeth_l3_hard_start_xmit; card->dev->ml_priv = card; - card->dev->tx_timeout = &qeth_tx_timeout; card->dev->watchdog_timeo = QETH_TX_TIMEOUT; - card->dev->open = qeth_l3_open; - card->dev->stop = qeth_l3_stop; - card->dev->do_ioctl = qeth_l3_do_ioctl; - card->dev->get_stats = qeth_get_stats; - card->dev->change_mtu = qeth_change_mtu; - card->dev->set_multicast_list = qeth_l3_set_multicast_list; - card->dev->vlan_rx_register = qeth_l3_vlan_rx_register; - card->dev->vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid; - card->dev->vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid; card->dev->mtu = card->info.initial_mtu; - card->dev->set_mac_address = NULL; SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops); card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index b7322976d2b..256c7bec7bd 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -884,6 +884,7 @@ config SCSI_IBMVSCSI tristate "IBM Virtual SCSI support" depends on PPC_PSERIES || PPC_ISERIES select SCSI_SRP_ATTRS + select VIOPATH if PPC_ISERIES help This is the IBM POWER Virtual SCSI Client diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c index 9e64b21ef63..c889d845868 100644 --- a/drivers/scsi/NCR_D700.c +++ b/drivers/scsi/NCR_D700.c @@ -318,7 +318,7 @@ NCR_D700_probe(struct device *dev) return -ENOMEM; p->dev = dev; - snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id); + snprintf(p->name, sizeof(p->name), "D700(%s)", dev_name(dev)); if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) { printk(KERN_ERR "D700: request_irq failed\n"); kfree(p); diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 07d572fecee..37dd47136fb 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -169,10 +169,8 @@ int __init a2091_detect(struct scsi_host_template *tpnt) continue; instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata)); - if (instance == NULL) { - release_mem_region(address, 256); - continue; - } + if (instance == NULL) + goto release; instance->base = ZTWO_VADDR(address); instance->irq = IRQ_AMIGA_PORTS; instance->unique_id = z->slotaddr; @@ -183,10 +181,18 @@ int __init a2091_detect(struct scsi_host_template *tpnt) HDATA(instance)->fast = 0; HDATA(instance)->dma_mode = CTRL_DMA; wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); - request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", - instance); + if (request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, "A2091 SCSI", + instance)) + goto unregister; DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN; num_a2091++; + continue; + +unregister: + scsi_unregister(instance); + wd33c93_release(); +release: + release_mem_region(address, 256); } return num_a2091; diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 2f602720193..7507d8bc57a 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -2527,7 +2527,7 @@ static void asc_prt_scsi_host(struct Scsi_Host *s) { struct asc_board *boardp = shost_priv(s); - printk("Scsi_Host at addr 0x%p, device %s\n", s, boardp->dev->bus_id); + printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev)); printk(" host_busy %u, host_no %d, last_reset %d,\n", s->host_busy, s->host_no, (unsigned)s->last_reset); diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index d4640ef6d44..78eb86fc627 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -189,7 +189,7 @@ int asd_I_T_nexus_reset(struct domain_device *dev) asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE); /* send a hard reset */ ASD_DPRINTK("sending %s reset to %s\n", - reset_type ? "hard" : "soft", phy->dev.bus_id); + reset_type ? "hard" : "soft", dev_name(&phy->dev)); res = sas_phy_reset(phy, reset_type); if (res == TMF_RESP_FUNC_COMPLETE) { /* wait for the maximum settle time */ diff --git a/drivers/scsi/cxgb3i/cxgb3i_ddp.c b/drivers/scsi/cxgb3i/cxgb3i_ddp.c index 1a41f04264f..08f3a09d923 100644 --- a/drivers/scsi/cxgb3i/cxgb3i_ddp.c +++ b/drivers/scsi/cxgb3i/cxgb3i_ddp.c @@ -11,6 +11,7 @@ */ #include <linux/skbuff.h> +#include <linux/scatterlist.h> /* from cxgb3 LLD */ #include "common.h" diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index ca736375240..5d1bf7e3d24 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -329,12 +329,16 @@ int __init gvp11_detect(struct scsi_host_template *tpnt) (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 : WD33C93_FS_12_15); - request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI", - instance); + if (request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, "GVP11 SCSI", + instance)) + goto unregister; DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE; num_gvp11++; continue; +unregister: + scsi_unregister(instance); + wd33c93_release(); release: release_mem_region(address, 256); } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 3fdbb13e80a..aa670a1d151 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -388,8 +388,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) shost->dma_boundary = 0xffffffff; device_initialize(&shost->shost_gendev); - snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d", - shost->host_no); + dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); #ifndef CONFIG_SYSFS_DEPRECATED shost->shost_gendev.bus = &scsi_bus_type; #endif @@ -398,8 +397,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) device_initialize(&shost->shost_dev); shost->shost_dev.parent = &shost->shost_gendev; shost->shost_dev.class = &shost_class; - snprintf(shost->shost_dev.bus_id, BUS_ID_SIZE, "host%d", - shost->host_no); + dev_set_name(&shost->shost_dev, "host%d", shost->host_no); shost->shost_dev.groups = scsi_sysfs_shost_attr_groups; shost->ehandler = kthread_run(scsi_error_handler, shost, diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 44f202f3310..ee0739b217b 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -101,7 +101,7 @@ static const struct { { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_NO_CONNECT, 1, 1, "network down" }, + { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, @@ -115,11 +115,11 @@ static const struct { { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ABORT, 0, 1, "invalid parameter" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ABORT, 0, 1, "missing parameter" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" }, { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ABORT, 0, 1, "transaction cancelled" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ABORT, 0, 1, "transaction cancelled implicit" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" }, + { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" }, { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, @@ -1145,10 +1145,10 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs); strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); strncpy(login_info->device_name, - vhost->host->shost_gendev.bus_id, IBMVFC_MAX_NAME); + dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME); location = of_get_property(of_node, "ibm,loc-code", NULL); - location = location ? location : vhost->dev->bus_id; + location = location ? location : dev_name(vhost->dev); strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); } diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 868d35ea01b..5c541f7850f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -89,6 +89,7 @@ static int max_id = 64; static int max_channel = 3; static int init_timeout = 5; static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; +static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; static struct scsi_transport_template *ibmvscsi_transport_template; @@ -1633,7 +1634,7 @@ static struct scsi_host_template driver_template = { static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) { /* iu_storage data allocated in initialize_event_pool */ - unsigned long desired_io = max_requests * sizeof(union viosrp_iu); + unsigned long desired_io = max_events * sizeof(union viosrp_iu); /* add io space for sg data */ desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 * @@ -1657,7 +1658,6 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) vdev->dev.driver_data = NULL; - driver_template.can_queue = max_requests - 2; host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); if (!host) { dev_err(&vdev->dev, "couldn't allocate host data\n"); @@ -1673,12 +1673,12 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) atomic_set(&hostdata->request_limit, -1); hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT; - rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_requests); + rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); if (rc != 0 && rc != H_RESOURCE) { dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); goto init_crq_failed; } - if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) { + if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) { dev_err(&vdev->dev, "couldn't initialize event pool\n"); goto init_pool_failed; } @@ -1730,7 +1730,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) add_host_failed: release_event_pool(&hostdata->pool, hostdata); init_pool_failed: - ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_requests); + ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); init_crq_failed: scsi_host_put(host); scsi_host_alloc_failed: @@ -1742,7 +1742,7 @@ static int ibmvscsi_remove(struct vio_dev *vdev) struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data; release_event_pool(&hostdata->pool, hostdata); ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, - max_requests); + max_events); srp_remove_host(hostdata->host); scsi_remove_host(hostdata->host); @@ -1779,6 +1779,10 @@ int __init ibmvscsi_module_init(void) { int ret; + /* Ensure we have two requests to do error recovery */ + driver_template.can_queue = max_requests; + max_events = max_requests + 2; + if (firmware_has_feature(FW_FEATURE_ISERIES)) ibmvscsi_ops = &iseriesvscsi_ops; else if (firmware_has_feature(FW_FEATURE_VIO)) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 0edfb1fa63c..841f460edbc 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -2184,7 +2184,7 @@ static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg, sizeof(struct ipr_dump_entry_header); driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID; - strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id); + strcpy(driver_dump->location_entry.location, dev_name(&ioa_cfg->pdev->dev)); driver_dump->hdr.num_entries++; } diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h index 59459141b43..8f872f816fe 100644 --- a/drivers/scsi/ipr.h +++ b/drivers/scsi/ipr.h @@ -1272,7 +1272,7 @@ struct ipr_dump_entry_header { struct ipr_dump_location_entry { struct ipr_dump_entry_header hdr; - u8 location[BUS_ID_SIZE]; + u8 location[20]; }__attribute__((packed)); struct ipr_dump_trace_entry { diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c index 3126824da36..4a4e6954ec7 100644 --- a/drivers/scsi/lasi700.c +++ b/drivers/scsi/lasi700.c @@ -103,8 +103,7 @@ lasi700_probe(struct parisc_device *dev) hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); if (!hostdata) { - printk(KERN_ERR "%s: Failed to allocate host data\n", - dev->dev.bus_id); + dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); return -ENOMEM; } diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c index 709a6f75ca9..facc5bfcf7d 100644 --- a/drivers/scsi/libsas/sas_discover.c +++ b/drivers/scsi/libsas/sas_discover.c @@ -169,7 +169,7 @@ int sas_notify_lldd_dev_found(struct domain_device *dev) if (res) { printk("sas: driver on pcidev %s cannot handle " "device %llx, error:%d\n", - sas_ha->dev->bus_id, + dev_name(sas_ha->dev), SAS_ADDR(dev->sas_addr), res); } } diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c index bf34a236f94..c17c25030f1 100644 --- a/drivers/scsi/libsas/sas_dump.c +++ b/drivers/scsi/libsas/sas_dump.c @@ -56,7 +56,7 @@ void sas_dprint_phye(int phyid, enum phy_event pe) void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he) { - SAS_DPRINTK("ha %s: %s event\n", sas_ha->dev->bus_id, + SAS_DPRINTK("ha %s: %s event\n", dev_name(sas_ha->dev), sas_hae_str[he]); } diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index 16f93123271..d110a366c48 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -199,8 +199,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_DISCOVER: - req->data_len =- 16; - if (req->data_len < 0) { + req->data_len -= 16; + if ((int)req->data_len < 0) { req->data_len = 0; error = -EINVAL; goto out; @@ -215,8 +215,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_REPORT_PHY_SATA: - req->data_len =- 16; - if (req->data_len < 0) { + req->data_len -= 16; + if ((int)req->data_len < 0) { req->data_len = 0; error = -EINVAL; goto out; @@ -238,8 +238,8 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_PHY_CONTROL: - req->data_len =- 44; - if (req->data_len < 0) { + req->data_len -= 44; + if ((int)req->data_len < 0) { req->data_len = 0; error = -EINVAL; goto out; diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c index 139935a121b..e6ac59c023f 100644 --- a/drivers/scsi/libsas/sas_port.c +++ b/drivers/scsi/libsas/sas_port.c @@ -113,7 +113,7 @@ static void sas_form_port(struct asd_sas_phy *phy) sas_port_add_phy(port->port, phy->phy); SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n", - phy->phy->dev.bus_id,port->port->dev.bus_id, + dev_name(&phy->phy->dev), dev_name(&port->port->dev), port->phy_mask, SAS_ADDR(port->attached_sas_addr)); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4c77038c8f1..6c867311cef 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1795,12 +1795,13 @@ lpfc_block_mgmt_io(struct lpfc_hba * phba) int lpfc_online(struct lpfc_hba *phba) { - struct lpfc_vport *vport = phba->pport; + struct lpfc_vport *vport; struct lpfc_vport **vports; int i; if (!phba) return 0; + vport = phba->pport; if (!(vport->fc_flag & FC_OFFLINE_MODE)) return 0; diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c index 1dd70d7a494..23e5a876bb1 100644 --- a/drivers/scsi/mvsas.c +++ b/drivers/scsi/mvsas.c @@ -2959,7 +2959,7 @@ static int __devinit mvs_hw_init(struct mvs_info *mvi) /* enable auto port detection */ mw32(GBL_PORT_TYPE, MODE_AUTO_DET_EN); - msleep(100); + msleep(1100); /* init and reset phys */ for (i = 0; i < mvi->chip->n_phy; i++) { u32 lo = be32_to_cpu(*(u32 *)&mvi->sas_addr[4]); diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 165ff884f48..67cde013806 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c @@ -114,7 +114,7 @@ static int aha152x_probe(struct pcmcia_device *link) link->io.NumPorts1 = 0x20; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.IOAddrLines = 10; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index cd53627cc76..c7acef50d5d 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -303,7 +303,7 @@ qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj, else if (start == (ha->flt_region_boot * 4) || start == (ha->flt_region_fw * 4)) valid = 1; - else if (IS_QLA25XX(ha) && + else if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && start == (ha->flt_region_vpd_nvram * 4)) valid = 1; if (!valid) { @@ -815,6 +815,21 @@ qla2x00_total_isp_aborts_show(struct device *dev, ha->qla_stats.total_isp_aborts); } +static ssize_t +qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA81XX(ha)) + return snprintf(buf, PAGE_SIZE, "\n"); + + return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x (%x)\n", + ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2], + ha->mpi_version[3], ha->mpi_capabilities); +} + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -839,6 +854,7 @@ static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, NULL); static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, NULL); +static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -858,6 +874,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_optrom_fcode_version, &dev_attr_optrom_fw_version, &dev_attr_total_isp_aborts, + &dev_attr_mpi_version, NULL, }; @@ -892,6 +909,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost) case PORT_SPEED_8GB: speed = FC_PORTSPEED_8GBIT; break; + case PORT_SPEED_10GB: + speed = FC_PORTSPEED_10GBIT; + break; } fc_host_speed(shost) = speed; } @@ -1382,7 +1402,9 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha) fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports; fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; - if (IS_QLA25XX(ha)) + if (IS_QLA81XX(ha)) + speed = FC_PORTSPEED_10GBIT; + else if (IS_QLA25XX(ha)) speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; else if (IS_QLA24XX_TYPE(ha)) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 1cf77772623..34760f8d4f1 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -310,6 +310,76 @@ qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count, *buf++ = htons(RD_REG_WORD(dmp_reg++)); } +static inline void * +qla24xx_copy_eft(struct qla_hw_data *ha, void *ptr) +{ + if (!ha->eft) + return ptr; + + memcpy(ptr, ha->eft, ntohl(ha->fw_dump->eft_size)); + return ptr + ntohl(ha->fw_dump->eft_size); +} + +static inline void * +qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) +{ + uint32_t cnt; + uint32_t *iter_reg; + struct qla2xxx_fce_chain *fcec = ptr; + + if (!ha->fce) + return ptr; + + *last_chain = &fcec->type; + fcec->type = __constant_htonl(DUMP_CHAIN_FCE); + fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + + fce_calc_size(ha->fce_bufs)); + fcec->size = htonl(fce_calc_size(ha->fce_bufs)); + fcec->addr_l = htonl(LSD(ha->fce_dma)); + fcec->addr_h = htonl(MSD(ha->fce_dma)); + + iter_reg = fcec->eregs; + for (cnt = 0; cnt < 8; cnt++) + *iter_reg++ = htonl(ha->fce_mb[cnt]); + + memcpy(iter_reg, ha->fce, ntohl(fcec->size)); + + return iter_reg; +} + +static inline void * +qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) +{ + uint32_t cnt, que_idx; + uint8_t req_cnt, rsp_cnt, que_cnt; + struct qla2xxx_mq_chain *mq = ptr; + struct device_reg_25xxmq __iomem *reg; + + if (!ha->mqenable) + return ptr; + + mq = ptr; + *last_chain = &mq->type; + mq->type = __constant_htonl(DUMP_CHAIN_MQ); + mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain)); + + req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues); + rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); + que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt; + mq->count = htonl(que_cnt); + for (cnt = 0; cnt < que_cnt; cnt++) { + reg = (struct device_reg_25xxmq *) ((void *) + ha->mqiobase + cnt * QLA_QUE_PAGE); + que_idx = cnt * 4; + mq->qregs[que_idx] = htonl(RD_REG_DWORD(®->req_q_in)); + mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(®->req_q_out)); + mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(®->rsp_q_in)); + mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(®->rsp_q_out)); + } + + return ptr + sizeof(struct qla2xxx_mq_chain); +} + /** * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. * @ha: HA context @@ -913,8 +983,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) goto qla24xx_fw_dump_failed_0; nxt = qla2xxx_copy_queues(ha, nxt); - if (ha->eft) - memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); + + qla24xx_copy_eft(ha, nxt); qla24xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { @@ -942,19 +1012,14 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint32_t risc_address; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - struct device_reg_25xxmq __iomem *reg25; uint32_t __iomem *dmp_reg; uint32_t *iter_reg; uint16_t __iomem *mbx_reg; unsigned long flags; struct qla25xx_fw_dump *fw; uint32_t ext_mem_cnt; - void *nxt; - struct qla2xxx_fce_chain *fcec; - struct qla2xxx_mq_chain *mq = NULL; - uint32_t qreg_size; - uint8_t req_cnt, rsp_cnt, que_cnt; - uint32_t que_idx; + void *nxt, *nxt_chain; + uint32_t *last_chain = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); risc_address = ext_mem_cnt = 0; @@ -1001,28 +1066,6 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); - /* Multi queue registers */ - if (ha->mqenable) { - qreg_size = sizeof(struct qla2xxx_mq_chain); - mq = kzalloc(qreg_size, GFP_KERNEL); - if (!mq) - goto qla25xx_fw_dump_failed_0; - req_cnt = find_first_zero_bit(ha->req_qid_map, ha->max_queues); - rsp_cnt = find_first_zero_bit(ha->rsp_qid_map, ha->max_queues); - que_cnt = req_cnt > rsp_cnt ? req_cnt : rsp_cnt; - mq->count = htonl(que_cnt); - mq->chain_size = htonl(qreg_size); - mq->type = __constant_htonl(DUMP_CHAIN_MQ); - for (cnt = 0; cnt < que_cnt; cnt++) { - reg25 = (struct device_reg_25xxmq *) ((void *) - ha->mqiobase + cnt * QLA_QUE_PAGE); - que_idx = cnt * 4; - mq->qregs[que_idx] = htonl(reg25->req_q_in); - mq->qregs[que_idx+1] = htonl(reg25->req_q_out); - mq->qregs[que_idx+2] = htonl(reg25->rsp_q_in); - mq->qregs[que_idx+3] = htonl(reg25->rsp_q_out); - } - } WRT_REG_DWORD(®->iobase_window, 0x00); RD_REG_DWORD(®->iobase_window); @@ -1240,6 +1283,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); qla24xx_read_window(reg, 0x6F00, 16, iter_reg); + /* Multi queue registers */ + nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset, + &last_chain); + rval = qla24xx_soft_reset(ha); if (rval != QLA_SUCCESS) goto qla25xx_fw_dump_failed_0; @@ -1249,39 +1296,341 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) if (rval != QLA_SUCCESS) goto qla25xx_fw_dump_failed_0; - /* Fibre Channel Trace Buffer. */ nxt = qla2xxx_copy_queues(ha, nxt); - if (ha->eft) - memcpy(nxt, ha->eft, ntohl(ha->fw_dump->eft_size)); - /* Fibre Channel Event Buffer. */ - if (!ha->fce) - goto qla25xx_fw_dump_failed_0; + nxt = qla24xx_copy_eft(ha, nxt); + + /* Chain entries -- started with MQ. */ + qla25xx_copy_fce(ha, nxt_chain, &last_chain); + if (last_chain) { + ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); + *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + } - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); +qla25xx_fw_dump_failed_0: + if (rval != QLA_SUCCESS) { + qla_printk(KERN_WARNING, ha, + "Failed to dump firmware (%x)!!!\n", rval); + ha->fw_dumped = 0; - if (ha->mqenable) { - nxt = nxt + ntohl(ha->fw_dump->eft_size); - memcpy(nxt, mq, qreg_size); - kfree(mq); - fcec = nxt + qreg_size; } else { - fcec = nxt + ntohl(ha->fw_dump->eft_size); + qla_printk(KERN_INFO, ha, + "Firmware dump saved to temp buffer (%ld/%p).\n", + base_vha->host_no, ha->fw_dump); + ha->fw_dumped = 1; } - fcec->type = __constant_htonl(DUMP_CHAIN_FCE | DUMP_CHAIN_LAST); - fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + - fce_calc_size(ha->fce_bufs)); - fcec->size = htonl(fce_calc_size(ha->fce_bufs)); - fcec->addr_l = htonl(LSD(ha->fce_dma)); - fcec->addr_h = htonl(MSD(ha->fce_dma)); - iter_reg = fcec->eregs; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(ha->fce_mb[cnt]); +qla25xx_fw_dump_failed: + if (!hardware_locked) + spin_unlock_irqrestore(&ha->hardware_lock, flags); +} - memcpy(iter_reg, ha->fce, ntohl(fcec->size)); +void +qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) +{ + int rval; + uint32_t cnt; + uint32_t risc_address; + struct qla_hw_data *ha = vha->hw; + struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + uint32_t __iomem *dmp_reg; + uint32_t *iter_reg; + uint16_t __iomem *mbx_reg; + unsigned long flags; + struct qla81xx_fw_dump *fw; + uint32_t ext_mem_cnt; + void *nxt, *nxt_chain; + uint32_t *last_chain = NULL; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); -qla25xx_fw_dump_failed_0: + risc_address = ext_mem_cnt = 0; + flags = 0; + + if (!hardware_locked) + spin_lock_irqsave(&ha->hardware_lock, flags); + + if (!ha->fw_dump) { + qla_printk(KERN_WARNING, ha, + "No buffer available for dump!!!\n"); + goto qla81xx_fw_dump_failed; + } + + if (ha->fw_dumped) { + qla_printk(KERN_WARNING, ha, + "Firmware has been previously dumped (%p) -- ignoring " + "request...\n", ha->fw_dump); + goto qla81xx_fw_dump_failed; + } + fw = &ha->fw_dump->isp.isp81; + qla2xxx_prep_dump(ha, ha->fw_dump); + + fw->host_status = htonl(RD_REG_DWORD(®->host_status)); + + /* Pause RISC. */ + rval = qla24xx_pause_risc(reg); + if (rval != QLA_SUCCESS) + goto qla81xx_fw_dump_failed_0; + + /* Host/Risc registers. */ + iter_reg = fw->host_risc_reg; + iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg); + qla24xx_read_window(reg, 0x7010, 16, iter_reg); + + /* PCIe registers. */ + WRT_REG_DWORD(®->iobase_addr, 0x7C00); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_window, 0x01); + dmp_reg = ®->iobase_c4; + fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++)); + fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); + fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); + fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); + + WRT_REG_DWORD(®->iobase_window, 0x00); + RD_REG_DWORD(®->iobase_window); + + /* Host interface registers. */ + dmp_reg = ®->flash_addr; + for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) + fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Disable interrupts. */ + WRT_REG_DWORD(®->ictrl, 0); + RD_REG_DWORD(®->ictrl); + + /* Shadow registers. */ + WRT_REG_DWORD(®->iobase_addr, 0x0F70); + RD_REG_DWORD(®->iobase_addr); + WRT_REG_DWORD(®->iobase_select, 0xB0000000); + fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0100000); + fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0200000); + fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0300000); + fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0400000); + fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0500000); + fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0600000); + fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0700000); + fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0800000); + fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0900000); + fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + WRT_REG_DWORD(®->iobase_select, 0xB0A00000); + fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); + + /* RISC I/O register. */ + WRT_REG_DWORD(®->iobase_addr, 0x0010); + fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); + + /* Mailbox registers. */ + mbx_reg = ®->mailbox0; + for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) + fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); + + /* Transfer sequence registers. */ + iter_reg = fw->xseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); + qla24xx_read_window(reg, 0xBF70, 16, iter_reg); + + iter_reg = fw->xseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg); + qla24xx_read_window(reg, 0xBFE0, 16, iter_reg); + + qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); + + /* Receive sequence registers. */ + iter_reg = fw->rseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); + qla24xx_read_window(reg, 0xFF70, 16, iter_reg); + + iter_reg = fw->rseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg); + qla24xx_read_window(reg, 0xFFD0, 16, iter_reg); + + qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); + qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); + + /* Auxiliary sequence registers. */ + iter_reg = fw->aseq_gp_reg; + iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg); + qla24xx_read_window(reg, 0xB070, 16, iter_reg); + + iter_reg = fw->aseq_0_reg; + iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg); + qla24xx_read_window(reg, 0xB0D0, 16, iter_reg); + + qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg); + qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg); + + /* Command DMA registers. */ + qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); + + /* Queues. */ + iter_reg = fw->req0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->resp0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + iter_reg = fw->req1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); + dmp_reg = ®->iobase_q; + for (cnt = 0; cnt < 7; cnt++) + *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); + + /* Transmit DMA registers. */ + iter_reg = fw->xmt0_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); + qla24xx_read_window(reg, 0x7610, 16, iter_reg); + + iter_reg = fw->xmt1_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); + qla24xx_read_window(reg, 0x7630, 16, iter_reg); + + iter_reg = fw->xmt2_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); + qla24xx_read_window(reg, 0x7650, 16, iter_reg); + + iter_reg = fw->xmt3_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); + qla24xx_read_window(reg, 0x7670, 16, iter_reg); + + iter_reg = fw->xmt4_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); + qla24xx_read_window(reg, 0x7690, 16, iter_reg); + + qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); + + /* Receive DMA registers. */ + iter_reg = fw->rcvt0_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); + qla24xx_read_window(reg, 0x7710, 16, iter_reg); + + iter_reg = fw->rcvt1_data_dma_reg; + iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); + qla24xx_read_window(reg, 0x7730, 16, iter_reg); + + /* RISC registers. */ + iter_reg = fw->risc_gp_reg; + iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); + qla24xx_read_window(reg, 0x0F70, 16, iter_reg); + + /* Local memory controller registers. */ + iter_reg = fw->lmc_reg; + iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg); + qla24xx_read_window(reg, 0x3070, 16, iter_reg); + + /* Fibre Protocol Module registers. */ + iter_reg = fw->fpm_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg); + qla24xx_read_window(reg, 0x40D0, 16, iter_reg); + + /* Frame Buffer registers. */ + iter_reg = fw->fb_hdw_reg; + iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); + iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg); + qla24xx_read_window(reg, 0x6F00, 16, iter_reg); + + /* Multi queue registers */ + nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset, + &last_chain); + + rval = qla24xx_soft_reset(ha); + if (rval != QLA_SUCCESS) + goto qla81xx_fw_dump_failed_0; + + rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), + &nxt); + if (rval != QLA_SUCCESS) + goto qla81xx_fw_dump_failed_0; + + nxt = qla2xxx_copy_queues(ha, nxt); + + nxt = qla24xx_copy_eft(ha, nxt); + + /* Chain entries -- started with MQ. */ + qla25xx_copy_fce(ha, nxt_chain, &last_chain); + if (last_chain) { + ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); + *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + } + +qla81xx_fw_dump_failed_0: if (rval != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Failed to dump firmware (%x)!!!\n", rval); @@ -1294,10 +1643,11 @@ qla25xx_fw_dump_failed_0: ha->fw_dumped = 1; } -qla25xx_fw_dump_failed: +qla81xx_fw_dump_failed: if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); } + /****************************************************************************/ /* Driver Debug Functions. */ /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index c1794a70a45..f660dd70b72 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -251,6 +251,45 @@ struct qla25xx_fw_dump { uint32_t ext_mem[1]; }; +struct qla81xx_fw_dump { + uint32_t host_status; + uint32_t host_risc_reg[32]; + uint32_t pcie_regs[4]; + uint32_t host_reg[32]; + uint32_t shadow_reg[11]; + uint32_t risc_io_reg; + uint16_t mailbox_reg[32]; + uint32_t xseq_gp_reg[128]; + uint32_t xseq_0_reg[48]; + uint32_t xseq_1_reg[16]; + uint32_t rseq_gp_reg[128]; + uint32_t rseq_0_reg[32]; + uint32_t rseq_1_reg[16]; + uint32_t rseq_2_reg[16]; + uint32_t aseq_gp_reg[128]; + uint32_t aseq_0_reg[32]; + uint32_t aseq_1_reg[16]; + uint32_t aseq_2_reg[16]; + uint32_t cmd_dma_reg[16]; + uint32_t req0_dma_reg[15]; + uint32_t resp0_dma_reg[15]; + uint32_t req1_dma_reg[15]; + uint32_t xmt0_dma_reg[32]; + uint32_t xmt1_dma_reg[32]; + uint32_t xmt2_dma_reg[32]; + uint32_t xmt3_dma_reg[32]; + uint32_t xmt4_dma_reg[32]; + uint32_t xmt_data_dma_reg[16]; + uint32_t rcvt0_data_dma_reg[32]; + uint32_t rcvt1_data_dma_reg[32]; + uint32_t risc_gp_reg[128]; + uint32_t lmc_reg[128]; + uint32_t fpm_hdw_reg[224]; + uint32_t fb_hdw_reg[208]; + uint32_t code_ram[0x2000]; + uint32_t ext_mem[1]; +}; + #define EFT_NUM_BUFFERS 4 #define EFT_BYTES_PER_BUFFER 0x4000 #define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) @@ -313,5 +352,6 @@ struct qla2xxx_fw_dump { struct qla2300_fw_dump isp23; struct qla24xx_fw_dump isp24; struct qla25xx_fw_dump isp25; + struct qla81xx_fw_dump isp81; } isp; }; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a29c9520497..023ee77fb02 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -187,7 +187,6 @@ struct req_que; * SCSI Request Block */ typedef struct srb { - struct scsi_qla_host *vha; /* HA the SP is queued on */ struct req_que *que; struct fc_port *fcport; @@ -2136,7 +2135,6 @@ struct qla_msix_entry { /* Work events. */ enum qla_work_type { QLA_EVT_AEN, - QLA_EVT_HWE_LOG, }; @@ -2151,10 +2149,6 @@ struct qla_work_evt { enum fc_host_event_code code; u32 data; } aen; - struct { - uint16_t code; - uint16_t d1, d2, d3; - } hwe; } u; }; @@ -2309,6 +2303,7 @@ struct qla_hw_data { #define PORT_SPEED_2GB 0x01 #define PORT_SPEED_4GB 0x03 #define PORT_SPEED_8GB 0x04 +#define PORT_SPEED_10GB 0x13 uint16_t link_data_rate; /* F/W operating speed */ uint8_t current_topology; @@ -2328,6 +2323,7 @@ struct qla_hw_data { #define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532 #define PCI_DEVICE_ID_QLOGIC_ISP8432 0x8432 +#define PCI_DEVICE_ID_QLOGIC_ISP8001 0x8001 uint32_t device_type; #define DT_ISP2100 BIT_0 #define DT_ISP2200 BIT_1 @@ -2342,7 +2338,8 @@ struct qla_hw_data { #define DT_ISP5432 BIT_10 #define DT_ISP2532 BIT_11 #define DT_ISP8432 BIT_12 -#define DT_ISP_LAST (DT_ISP8432 << 1) +#define DT_ISP8001 BIT_13 +#define DT_ISP_LAST (DT_ISP8001 << 1) #define DT_IIDMA BIT_26 #define DT_FWI2 BIT_27 @@ -2364,6 +2361,7 @@ struct qla_hw_data { #define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432) #define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532) #define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432) +#define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) @@ -2373,8 +2371,11 @@ struct qla_hw_data { #define IS_QLA84XX(ha) (IS_QLA8432(ha)) #define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ IS_QLA84XX(ha)) +#define IS_QLA81XX(ha) (IS_QLA8001(ha)) #define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \ - IS_QLA25XX(ha)) + IS_QLA25XX(ha) || IS_QLA81XX(ha)) +#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && \ + (ha)->flags.msix_enabled) #define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) #define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) @@ -2472,6 +2473,9 @@ struct qla_hw_data { uint8_t fw_seriallink_options[4]; uint16_t fw_seriallink_options24[4]; + uint8_t mpi_version[4]; + uint32_t mpi_capabilities; + /* Firmware dump information. */ struct qla2xxx_fw_dump *fw_dump; uint32_t fw_dump_len; @@ -2480,6 +2484,7 @@ struct qla_hw_data { dma_addr_t eft_dma; void *eft; + uint32_t chain_offset; struct dentry *dfs_dir; struct dentry *dfs_fce; dma_addr_t fce_dma; @@ -2489,10 +2494,6 @@ struct qla_hw_data { uint64_t fce_wr, fce_rd; struct mutex fce_mutex; - uint32_t hw_event_start; - uint32_t hw_event_ptr; - uint32_t hw_event_pause_errors; - uint32_t pci_attr; uint16_t chip_revision; @@ -2522,6 +2523,12 @@ struct qla_hw_data { uint8_t fcode_revision[16]; uint32_t fw_revision[4]; + /* Offsets for flash/nvram access (set to ~0 if not used). */ + uint32_t flash_conf_off; + uint32_t flash_data_off; + uint32_t nvram_conf_off; + uint32_t nvram_data_off; + uint32_t fdt_wrt_disable; uint32_t fdt_erase_cmd; uint32_t fdt_block_size; @@ -2533,7 +2540,6 @@ struct qla_hw_data { uint32_t flt_region_boot; uint32_t flt_region_fw; uint32_t flt_region_vpd_nvram; - uint32_t flt_region_hw_event; uint32_t flt_region_npiv_conf; /* Needed for BEACON */ @@ -2737,6 +2743,7 @@ typedef struct scsi_qla_host { #define OPTROM_SIZE_2322 0x100000 #define OPTROM_SIZE_24XX 0x100000 #define OPTROM_SIZE_25XX 0x200000 +#define OPTROM_SIZE_81XX 0x400000 #include "qla_gbl.h" #include "qla_dbg.h" diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 0e366a1b44b..c66036da7d2 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -113,7 +113,8 @@ int qla2x00_dfs_setup(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; - if (!IS_QLA25XX(ha)) + + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)) goto out; if (!ha->fce) goto out; diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index ee1f1e794c2..7abb045a041 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1215,9 +1215,10 @@ struct qla_fdt_layout { struct qla_flt_location { uint8_t sig[4]; - uint32_t start_lo; - uint32_t start_hi; - uint16_t unused; + uint16_t start_lo; + uint16_t start_hi; + uint8_t version; + uint8_t unused[5]; uint16_t checksum; }; @@ -1390,4 +1391,291 @@ struct access_chip_rsp_84xx { uint32_t reserved[12]; }; + +/* 81XX Support **************************************************************/ + +#define MBA_DCBX_START 0x8016 +#define MBA_DCBX_COMPLETE 0x8030 +#define MBA_FCF_CONF_ERR 0x8031 +#define MBA_DCBX_PARAM_UPDATE 0x8032 +#define MBA_IDC_COMPLETE 0x8100 +#define MBA_IDC_NOTIFY 0x8101 +#define MBA_IDC_TIME_EXT 0x8102 + +struct nvram_81xx { + /* NVRAM header. */ + uint8_t id[4]; + uint16_t nvram_version; + uint16_t reserved_0; + + /* Firmware Initialization Control Block. */ + uint16_t version; + uint16_t reserved_1; + uint16_t frame_payload_size; + uint16_t execution_throttle; + uint16_t exchange_count; + uint16_t reserved_2; + + uint8_t port_name[WWN_SIZE]; + uint8_t node_name[WWN_SIZE]; + + uint16_t login_retry_count; + uint16_t reserved_3; + uint16_t interrupt_delay_timer; + uint16_t login_timeout; + + uint32_t firmware_options_1; + uint32_t firmware_options_2; + uint32_t firmware_options_3; + + uint16_t reserved_4[4]; + + /* Offset 64. */ + uint8_t enode_mac[6]; + uint16_t reserved_5[5]; + + /* Offset 80. */ + uint16_t reserved_6[24]; + + /* Offset 128. */ + uint16_t reserved_7[64]; + + /* + * BIT 0 = Enable spinup delay + * BIT 1 = Disable BIOS + * BIT 2 = Enable Memory Map BIOS + * BIT 3 = Enable Selectable Boot + * BIT 4 = Disable RISC code load + * BIT 5 = Disable Serdes + * BIT 6 = Opt boot mode + * BIT 7 = Interrupt enable + * + * BIT 8 = EV Control enable + * BIT 9 = Enable lip reset + * BIT 10 = Enable lip full login + * BIT 11 = Enable target reset + * BIT 12 = Stop firmware + * BIT 13 = Enable nodename option + * BIT 14 = Default WWPN valid + * BIT 15 = Enable alternate WWN + * + * BIT 16 = CLP LUN string + * BIT 17 = CLP Target string + * BIT 18 = CLP BIOS enable string + * BIT 19 = CLP Serdes string + * BIT 20 = CLP WWPN string + * BIT 21 = CLP WWNN string + * BIT 22 = + * BIT 23 = + * BIT 24 = Keep WWPN + * BIT 25 = Temp WWPN + * BIT 26-31 = + */ + uint32_t host_p; + + uint8_t alternate_port_name[WWN_SIZE]; + uint8_t alternate_node_name[WWN_SIZE]; + + uint8_t boot_port_name[WWN_SIZE]; + uint16_t boot_lun_number; + uint16_t reserved_8; + + uint8_t alt1_boot_port_name[WWN_SIZE]; + uint16_t alt1_boot_lun_number; + uint16_t reserved_9; + + uint8_t alt2_boot_port_name[WWN_SIZE]; + uint16_t alt2_boot_lun_number; + uint16_t reserved_10; + + uint8_t alt3_boot_port_name[WWN_SIZE]; + uint16_t alt3_boot_lun_number; + uint16_t reserved_11; + + /* + * BIT 0 = Selective Login + * BIT 1 = Alt-Boot Enable + * BIT 2 = Reserved + * BIT 3 = Boot Order List + * BIT 4 = Reserved + * BIT 5 = Selective LUN + * BIT 6 = Reserved + * BIT 7-31 = + */ + uint32_t efi_parameters; + + uint8_t reset_delay; + uint8_t reserved_12; + uint16_t reserved_13; + + uint16_t boot_id_number; + uint16_t reserved_14; + + uint16_t max_luns_per_target; + uint16_t reserved_15; + + uint16_t port_down_retry_count; + uint16_t link_down_timeout; + + /* FCode parameters. */ + uint16_t fcode_parameter; + + uint16_t reserved_16[3]; + + /* Offset 352. */ + uint8_t reserved_17[4]; + uint16_t reserved_18[5]; + uint8_t reserved_19[2]; + uint16_t reserved_20[8]; + + /* Offset 384. */ + uint8_t reserved_21[16]; + uint16_t reserved_22[8]; + + /* Offset 416. */ + uint16_t reserved_23[32]; + + /* Offset 480. */ + uint8_t model_name[16]; + + /* Offset 496. */ + uint16_t feature_mask_l; + uint16_t feature_mask_h; + uint16_t reserved_24[2]; + + uint16_t subsystem_vendor_id; + uint16_t subsystem_device_id; + + uint32_t checksum; +}; + +/* + * ISP Initialization Control Block. + * Little endian except where noted. + */ +#define ICB_VERSION 1 +struct init_cb_81xx { + uint16_t version; + uint16_t reserved_1; + + uint16_t frame_payload_size; + uint16_t execution_throttle; + uint16_t exchange_count; + + uint16_t reserved_2; + + uint8_t port_name[WWN_SIZE]; /* Big endian. */ + uint8_t node_name[WWN_SIZE]; /* Big endian. */ + + uint16_t response_q_inpointer; + uint16_t request_q_outpointer; + + uint16_t login_retry_count; + + uint16_t prio_request_q_outpointer; + + uint16_t response_q_length; + uint16_t request_q_length; + + uint16_t reserved_3; + + uint16_t prio_request_q_length; + + uint32_t request_q_address[2]; + uint32_t response_q_address[2]; + uint32_t prio_request_q_address[2]; + + uint8_t reserved_4[8]; + + uint16_t atio_q_inpointer; + uint16_t atio_q_length; + uint32_t atio_q_address[2]; + + uint16_t interrupt_delay_timer; /* 100us increments. */ + uint16_t login_timeout; + + /* + * BIT 0-3 = Reserved + * BIT 4 = Enable Target Mode + * BIT 5 = Disable Initiator Mode + * BIT 6 = Reserved + * BIT 7 = Reserved + * + * BIT 8-13 = Reserved + * BIT 14 = Node Name Option + * BIT 15-31 = Reserved + */ + uint32_t firmware_options_1; + + /* + * BIT 0 = Operation Mode bit 0 + * BIT 1 = Operation Mode bit 1 + * BIT 2 = Operation Mode bit 2 + * BIT 3 = Operation Mode bit 3 + * BIT 4-7 = Reserved + * + * BIT 8 = Enable Class 2 + * BIT 9 = Enable ACK0 + * BIT 10 = Reserved + * BIT 11 = Enable FC-SP Security + * BIT 12 = FC Tape Enable + * BIT 13 = Reserved + * BIT 14 = Enable Target PRLI Control + * BIT 15-31 = Reserved + */ + uint32_t firmware_options_2; + + /* + * BIT 0-3 = Reserved + * BIT 4 = FCP RSP Payload bit 0 + * BIT 5 = FCP RSP Payload bit 1 + * BIT 6 = Enable Receive Out-of-Order data frame handling + * BIT 7 = Reserved + * + * BIT 8 = Reserved + * BIT 9 = Enable Out-of-Order FCP_XFER_RDY relative offset handling + * BIT 10-16 = Reserved + * BIT 17 = Enable multiple FCFs + * BIT 18-20 = MAC addressing mode + * BIT 21-25 = Ethernet data rate + * BIT 26 = Enable ethernet header rx IOCB for ATIO q + * BIT 27 = Enable ethernet header rx IOCB for response q + * BIT 28 = SPMA selection bit 0 + * BIT 28 = SPMA selection bit 1 + * BIT 30-31 = Reserved + */ + uint32_t firmware_options_3; + + uint8_t reserved_5[8]; + + uint8_t enode_mac[6]; + + uint8_t reserved_6[10]; +}; + +struct mid_init_cb_81xx { + struct init_cb_81xx init_cb; + + uint16_t count; + uint16_t options; + + struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; +}; + +#define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000 +#define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000 + +/* 81XX Flash locations -- occupies second 2MB region. */ +#define FA_BOOT_CODE_ADDR_81 0x80000 +#define FA_RISC_CODE_ADDR_81 0xA0000 +#define FA_FW_AREA_ADDR_81 0xC0000 +#define FA_VPD_NVRAM_ADDR_81 0xD0000 +#define FA_FEATURE_ADDR_81 0xD4000 +#define FA_FLASH_DESCR_ADDR_81 0xD8000 +#define FA_FLASH_LAYOUT_ADDR_81 0xD8400 +#define FA_HW_EVENT0_ADDR_81 0xDC000 +#define FA_HW_EVENT1_ADDR_81 0xDC400 +#define FA_NPIV_CONF0_ADDR_81 0xD1000 +#define FA_NPIV_CONF1_ADDR_81 0xD2000 + #endif diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 0011e31205d..ba491335375 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -28,8 +28,10 @@ extern void qla2x00_reset_adapter(struct scsi_qla_host *); extern void qla24xx_reset_adapter(struct scsi_qla_host *); extern int qla2x00_nvram_config(struct scsi_qla_host *); extern int qla24xx_nvram_config(struct scsi_qla_host *); +extern int qla81xx_nvram_config(struct scsi_qla_host *); extern void qla2x00_update_fw_options(struct scsi_qla_host *); extern void qla24xx_update_fw_options(scsi_qla_host_t *); +extern void qla81xx_update_fw_options(scsi_qla_host_t *); extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); @@ -69,8 +71,6 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum fc_host_event_code, u32); -extern int qla2x00_post_hwe_work(struct scsi_qla_host *, uint16_t , uint16_t, - uint16_t, uint16_t); extern void qla2x00_abort_fcport_cmds(fc_port_t *); extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, @@ -143,7 +143,7 @@ qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); extern void qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *, - uint16_t *, uint16_t *, uint16_t *, uint32_t *); + uint16_t *, uint16_t *, uint16_t *, uint32_t *, uint8_t *, uint32_t *); extern int qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *); @@ -317,9 +317,6 @@ extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); -extern int qla2xxx_hw_event_log(scsi_qla_host_t *, uint16_t , uint16_t, - uint16_t, uint16_t); - extern int qla2xxx_get_flash_info(scsi_qla_host_t *); extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); @@ -332,6 +329,7 @@ extern void qla2100_fw_dump(scsi_qla_host_t *, int); extern void qla2300_fw_dump(scsi_qla_host_t *, int); extern void qla24xx_fw_dump(scsi_qla_host_t *, int); extern void qla25xx_fw_dump(scsi_qla_host_t *, int); +extern void qla81xx_fw_dump(scsi_qla_host_t *, int); extern void qla2x00_dump_regs(scsi_qla_host_t *); extern void qla2x00_dump_buffer(uint8_t *, uint32_t); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 0a6f7297399..557f58d5bf8 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1535,7 +1535,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) eiter = (struct ct_fdmi_port_attr *) (entries + size); eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); eiter->len = __constant_cpu_to_be16(4 + 4); - if (IS_QLA25XX(ha)) + if (IS_QLA81XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32( + FDMI_PORT_SPEED_10GB); + else if (IS_QLA25XX(ha)) eiter->a.sup_speed = __constant_cpu_to_be32( FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB); @@ -1575,6 +1578,10 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *vha) eiter->a.cur_speed = __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB); break; + case PORT_SPEED_10GB: + eiter->a.cur_speed = + __constant_cpu_to_be32(FDMI_PORT_SPEED_10GB); + break; default: eiter->a.cur_speed = __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 52ed56ecf19..2d4f32b4df5 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -552,10 +552,6 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) d2 = RD_REG_DWORD(®->ctrl_status); barrier(); } - if (cnt == 0 || hw_evt) - qla2xxx_hw_event_log(vha, HW_EVENT_RESET_ERR, - RD_REG_WORD(®->mailbox1), RD_REG_WORD(®->mailbox2), - RD_REG_WORD(®->mailbox3)); WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); RD_REG_DWORD(®->hccr); @@ -574,6 +570,9 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) } spin_unlock_irqrestore(&ha->hardware_lock, flags); + + if (IS_NOPOLLING_TYPE(ha)) + ha->isp_ops->enable_intrs(ha); } /** @@ -779,16 +778,19 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) mem_size = (ha->fw_memory_size - 0x11000 + 1) * sizeof(uint16_t); } else if (IS_FWI2_CAPABLE(ha)) { - fixed_size = IS_QLA25XX(ha) ? - offsetof(struct qla25xx_fw_dump, ext_mem) : - offsetof(struct qla24xx_fw_dump, ext_mem); + if (IS_QLA81XX(ha)) + fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); + else if (IS_QLA25XX(ha)) + fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem); + else + fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); mem_size = (ha->fw_memory_size - 0x100000 + 1) * sizeof(uint32_t); if (ha->mqenable) mq_size = sizeof(struct qla2xxx_mq_chain); /* Allocate memory for Fibre Channel Event Buffer. */ - if (!IS_QLA25XX(ha)) + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)) goto try_eft; tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, @@ -851,7 +853,9 @@ cont_alloc: dump_size = offsetof(struct qla2xxx_fw_dump, isp); dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + - mq_size + eft_size + fce_size; + eft_size; + ha->chain_offset = dump_size; + dump_size += mq_size + fce_size; ha->fw_dump = vmalloc(dump_size); if (!ha->fw_dump) { @@ -987,7 +991,8 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) &ha->fw_major_version, &ha->fw_minor_version, &ha->fw_subminor_version, - &ha->fw_attributes, &ha->fw_memory_size); + &ha->fw_attributes, &ha->fw_memory_size, + ha->mpi_version, &ha->mpi_capabilities); ha->flags.npiv_supported = 0; if (IS_QLA2XXX_MIDTYPE(ha) && (ha->fw_attributes & BIT_2)) { @@ -1665,10 +1670,6 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " "invalid -- WWPN) defaults.\n"); - if (chksum) - qla2xxx_hw_event_log(vha, HW_EVENT_NVRAM_CHKSUM_ERR, 0, - MSW(chksum), LSW(chksum)); - /* * Set default initialization control block. */ @@ -4255,3 +4256,269 @@ qla84xx_init_chip(scsi_qla_host_t *vha) return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: QLA_SUCCESS; } + +/* 81XX Support **************************************************************/ + +int +qla81xx_nvram_config(scsi_qla_host_t *vha) +{ + int rval; + struct init_cb_81xx *icb; + struct nvram_81xx *nv; + uint32_t *dptr; + uint8_t *dptr1, *dptr2; + uint32_t chksum; + uint16_t cnt; + struct qla_hw_data *ha = vha->hw; + + rval = QLA_SUCCESS; + icb = (struct init_cb_81xx *)ha->init_cb; + nv = ha->nvram; + + /* Determine NVRAM starting address. */ + ha->nvram_size = sizeof(struct nvram_81xx); + ha->nvram_base = FA_NVRAM_FUNC0_ADDR; + ha->vpd_size = FA_NVRAM_VPD_SIZE; + ha->vpd_base = FA_NVRAM_VPD0_ADDR; + if (PCI_FUNC(ha->pdev->devfn) & 1) { + ha->nvram_base = FA_NVRAM_FUNC1_ADDR; + ha->vpd_base = FA_NVRAM_VPD1_ADDR; + } + + /* Get VPD data into cache */ + ha->vpd = ha->nvram + VPD_OFFSET; + ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, + ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4); + + /* Get NVRAM data into cache and calculate checksum. */ + dptr = (uint32_t *)nv; + ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base, + ha->nvram_size); + for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) + chksum += le32_to_cpu(*dptr++); + + DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no)); + DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size)); + + /* Bad NVRAM data, set defaults parameters. */ + if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' + || nv->id[3] != ' ' || + nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { + /* Reset NVRAM data. */ + qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: " + "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0], + le16_to_cpu(nv->nvram_version)); + qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet " + "invalid -- WWPN) defaults.\n"); + + /* + * Set default initialization control block. + */ + memset(nv, 0, ha->nvram_size); + nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); + nv->version = __constant_cpu_to_le16(ICB_VERSION); + nv->frame_payload_size = __constant_cpu_to_le16(2048); + nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); + nv->exchange_count = __constant_cpu_to_le16(0); + nv->port_name[0] = 0x21; + nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn); + nv->port_name[2] = 0x00; + nv->port_name[3] = 0xe0; + nv->port_name[4] = 0x8b; + nv->port_name[5] = 0x1c; + nv->port_name[6] = 0x55; + nv->port_name[7] = 0x86; + nv->node_name[0] = 0x20; + nv->node_name[1] = 0x00; + nv->node_name[2] = 0x00; + nv->node_name[3] = 0xe0; + nv->node_name[4] = 0x8b; + nv->node_name[5] = 0x1c; + nv->node_name[6] = 0x55; + nv->node_name[7] = 0x86; + nv->login_retry_count = __constant_cpu_to_le16(8); + nv->interrupt_delay_timer = __constant_cpu_to_le16(0); + nv->login_timeout = __constant_cpu_to_le16(0); + nv->firmware_options_1 = + __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); + nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); + nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); + nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); + nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); + nv->efi_parameters = __constant_cpu_to_le32(0); + nv->reset_delay = 5; + nv->max_luns_per_target = __constant_cpu_to_le16(128); + nv->port_down_retry_count = __constant_cpu_to_le16(30); + nv->link_down_timeout = __constant_cpu_to_le16(30); + nv->enode_mac[0] = 0x01; + nv->enode_mac[1] = 0x02; + nv->enode_mac[2] = 0x03; + nv->enode_mac[3] = 0x04; + nv->enode_mac[4] = 0x05; + nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + + rval = 1; + } + + /* Reset Initialization control block */ + memset(icb, 0, sizeof(struct init_cb_81xx)); + + /* Copy 1st segment. */ + dptr1 = (uint8_t *)icb; + dptr2 = (uint8_t *)&nv->version; + cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version; + while (cnt--) + *dptr1++ = *dptr2++; + + icb->login_retry_count = nv->login_retry_count; + + /* Copy 2nd segment. */ + dptr1 = (uint8_t *)&icb->interrupt_delay_timer; + dptr2 = (uint8_t *)&nv->interrupt_delay_timer; + cnt = (uint8_t *)&icb->reserved_5 - + (uint8_t *)&icb->interrupt_delay_timer; + while (cnt--) + *dptr1++ = *dptr2++; + + memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac)); + /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */ + if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) { + icb->enode_mac[0] = 0x01; + icb->enode_mac[1] = 0x02; + icb->enode_mac[2] = 0x03; + icb->enode_mac[3] = 0x04; + icb->enode_mac[4] = 0x05; + icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn); + } + + /* + * Setup driver NVRAM options. + */ + qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), + "QLE81XX"); + + /* Use alternate WWN? */ + if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { + memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); + memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); + } + + /* Prepare nodename */ + if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { + /* + * Firmware will apply the following mask if the nodename was + * not provided. + */ + memcpy(icb->node_name, icb->port_name, WWN_SIZE); + icb->node_name[0] &= 0xF0; + } + + /* Set host adapter parameters. */ + ha->flags.disable_risc_code_load = 0; + ha->flags.enable_lip_reset = 0; + ha->flags.enable_lip_full_login = + le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; + ha->flags.enable_target_reset = + le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; + ha->flags.enable_led_scheme = 0; + ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; + + ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & + (BIT_6 | BIT_5 | BIT_4)) >> 4; + + /* save HBA serial number */ + ha->serial0 = icb->port_name[5]; + ha->serial1 = icb->port_name[6]; + ha->serial2 = icb->port_name[7]; + memcpy(vha->node_name, icb->node_name, WWN_SIZE); + memcpy(vha->port_name, icb->port_name, WWN_SIZE); + + icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + + ha->retry_count = le16_to_cpu(nv->login_retry_count); + + /* Set minimum login_timeout to 4 seconds. */ + if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) + nv->login_timeout = cpu_to_le16(ql2xlogintimeout); + if (le16_to_cpu(nv->login_timeout) < 4) + nv->login_timeout = __constant_cpu_to_le16(4); + ha->login_timeout = le16_to_cpu(nv->login_timeout); + icb->login_timeout = nv->login_timeout; + + /* Set minimum RATOV to 100 tenths of a second. */ + ha->r_a_tov = 100; + + ha->loop_reset_delay = nv->reset_delay; + + /* Link Down Timeout = 0: + * + * When Port Down timer expires we will start returning + * I/O's to OS with "DID_NO_CONNECT". + * + * Link Down Timeout != 0: + * + * The driver waits for the link to come up after link down + * before returning I/Os to OS with "DID_NO_CONNECT". + */ + if (le16_to_cpu(nv->link_down_timeout) == 0) { + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); + } else { + ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout); + ha->loop_down_abort_time = + (LOOP_DOWN_TIME - ha->link_down_timeout); + } + + /* Need enough time to try and get the port back. */ + ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count); + if (qlport_down_retry) + ha->port_down_retry_count = qlport_down_retry; + + /* Set login_retry_count */ + ha->login_retry_count = le16_to_cpu(nv->login_retry_count); + if (ha->port_down_retry_count == + le16_to_cpu(nv->port_down_retry_count) && + ha->port_down_retry_count > 3) + ha->login_retry_count = ha->port_down_retry_count; + else if (ha->port_down_retry_count > (int)ha->login_retry_count) + ha->login_retry_count = ha->port_down_retry_count; + if (ql2xloginretrycount) + ha->login_retry_count = ql2xloginretrycount; + + /* Enable ZIO. */ + if (!vha->flags.init_done) { + ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & + (BIT_3 | BIT_2 | BIT_1 | BIT_0); + ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? + le16_to_cpu(icb->interrupt_delay_timer): 2; + } + icb->firmware_options_2 &= __constant_cpu_to_le32( + ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); + vha->flags.process_response_queue = 0; + if (ha->zio_mode != QLA_ZIO_DISABLED) { + ha->zio_mode = QLA_ZIO_MODE_6; + + DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay " + "(%d us).\n", vha->host_no, ha->zio_mode, + ha->zio_timer * 100)); + qla_printk(KERN_INFO, ha, + "ZIO mode %d enabled; timer delay (%d us).\n", + ha->zio_mode, ha->zio_timer * 100); + + icb->firmware_options_2 |= cpu_to_le32( + (uint32_t)ha->zio_mode); + icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer); + vha->flags.process_response_queue = 1; + } + + if (rval) { + DEBUG2_3(printk(KERN_WARNING + "scsi(%ld): NVRAM configuration failed!\n", vha->host_no)); + } + return (rval); +} + +void +qla81xx_update_fw_options(scsi_qla_host_t *ha) +{ +} diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 5bedc9d0594..2258152b1f4 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -173,7 +173,7 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, return; } - vha = sp->vha; + vha = sp->fcport->vha; req = sp->que; cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); @@ -234,7 +234,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, return; } - vha = sp->vha; + vha = sp->fcport->vha; req = sp->que; cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); @@ -294,7 +294,7 @@ qla2x00_start_scsi(srb_t *sp) /* Setup device pointers. */ ret = 0; - vha = sp->vha; + vha = sp->fcport->vha; ha = vha->hw; reg = &ha->iobase->isp; cmd = sp->cmd; @@ -353,7 +353,6 @@ qla2x00_start_scsi(srb_t *sp) /* Build command packet */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; - sp->vha = vha; sp->que = req; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; @@ -656,7 +655,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, return; } - vha = sp->vha; + vha = sp->fcport->vha; req = sp->que; /* Set transfer direction */ @@ -723,7 +722,7 @@ qla24xx_start_scsi(srb_t *sp) struct req_que *req = NULL; struct rsp_que *rsp = NULL; struct scsi_cmnd *cmd = sp->cmd; - struct scsi_qla_host *vha = sp->vha; + struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; uint16_t que_id; @@ -791,7 +790,6 @@ qla24xx_start_scsi(srb_t *sp) /* Build command packet. */ req->current_outstanding_cmd = handle; req->outstanding_cmds[handle] = sp; - sp->vha = vha; sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle; req->cnt -= req_cnt; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d5fb79a8800..789fc576f22 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -275,7 +275,7 @@ void qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) { #define LS_UNKNOWN 2 - static char *link_speeds[5] = { "1", "2", "?", "4", "8" }; + static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" }; char *link_speed; uint16_t handle_cnt; uint16_t cnt; @@ -288,6 +288,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) /* Setup to process RIO completion. */ handle_cnt = 0; + if (IS_QLA81XX(ha)) + goto skip_rio; switch (mb[0]) { case MBA_SCSI_COMPLETION: handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1])); @@ -339,7 +341,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) default: break; } - +skip_rio: switch (mb[0]) { case MBA_SCSI_COMPLETION: /* Fast Post */ if (!vha->flags.online) @@ -362,7 +364,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n", mb[1], mb[2], mb[3]); - qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]); ha->isp_ops->fw_dump(vha, 1); if (IS_FWI2_CAPABLE(ha)) { @@ -387,7 +388,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) vha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n"); - qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; @@ -396,7 +396,6 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) vha->host_no)); qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n"); - qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]); set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); break; @@ -436,6 +435,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) link_speed = link_speeds[LS_UNKNOWN]; if (mb[1] < 5) link_speed = link_speeds[mb[1]]; + else if (mb[1] == 0x13) + link_speed = link_speeds[5]; ha->link_data_rate = mb[1]; } @@ -495,12 +496,17 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]); break; + /* case MBA_DCBX_COMPLETE: */ case MBA_POINT_TO_POINT: /* Point-to-Point */ if (IS_QLA2100(ha)) break; - DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n", - vha->host_no)); + if (IS_QLA81XX(ha)) + DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x " + "%04x\n", vha->host_no, mb[1], mb[2], mb[3])); + else + DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE " + "received.\n", vha->host_no)); /* * Until there's a transition from loop down to loop up, treat @@ -641,10 +647,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) /* case MBA_RIO_RESPONSE: */ case MBA_ZIO_RESPONSE: - DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n", - vha->host_no)); - DEBUG(printk(KERN_INFO - "scsi(%ld): [R|Z]IO update completion.\n", + DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n", vha->host_no)); if (IS_FWI2_CAPABLE(ha)) @@ -698,6 +701,35 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) } spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags); break; + case MBA_DCBX_START: + DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n", + vha->host_no, mb[1], mb[2], mb[3])); + break; + case MBA_DCBX_PARAM_UPDATE: + DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- " + "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3])); + break; + case MBA_FCF_CONF_ERR: + DEBUG2(printk("scsi(%ld): FCF Configuration Error -- " + "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3])); + break; + case MBA_IDC_COMPLETE: + DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " + "Complete -- %04x %04x %04x\n", vha->host_no, mb[1], mb[2], + mb[3])); + break; + case MBA_IDC_NOTIFY: + DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " + "Request Notification -- %04x %04x %04x\n", vha->host_no, + mb[1], mb[2], mb[3])); + /**** Mailbox registers 4 - 7 valid!!! */ + break; + case MBA_IDC_TIME_EXT: + DEBUG2(printk("scsi(%ld): Inter-Driver Commucation " + "Time Extension -- %04x %04x %04x\n", vha->host_no, mb[1], + mb[2], mb[3])); + /**** Mailbox registers 4 - 7 valid!!! */ + break; } if (!vha->vp_idx && ha->num_vhosts) @@ -1510,7 +1542,7 @@ qla2xxx_check_risc_status(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - if (!IS_QLA25XX(ha)) + if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha)) return; rval = QLA_SUCCESS; @@ -1590,12 +1622,6 @@ qla24xx_intr_handler(int irq, void *dev_id) if (pci_channel_offline(ha->pdev)) break; - if (ha->hw_event_pause_errors == 0) - qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR, - 0, MSW(stat), LSW(stat)); - else if (ha->hw_event_pause_errors < 0xffffffff) - ha->hw_event_pause_errors++; - hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1740,12 +1766,6 @@ qla24xx_msix_default(int irq, void *dev_id) if (pci_channel_offline(ha->pdev)) break; - if (ha->hw_event_pause_errors == 0) - qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR, - 0, MSW(stat), LSW(stat)); - else if (ha->hw_event_pause_errors < 0xffffffff) - ha->hw_event_pause_errors++; - hccr = RD_REG_DWORD(®->hccr); qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, " @@ -1944,7 +1964,8 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) device_reg_t __iomem *reg = ha->iobase; /* If possible, enable MSI-X. */ - if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) + if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && + !IS_QLA8432(ha) && !IS_QLA8001(ha)) goto skip_msix; if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX || @@ -1979,7 +2000,8 @@ qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) "MSI-X: Falling back-to INTa mode -- %d.\n", ret); skip_msix: - if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha)) + if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && + !IS_QLA8001(ha)) goto skip_msi; ret = pci_enable_msi(ha->pdev); @@ -2000,6 +2022,12 @@ skip_msi: ha->flags.inta_enabled = 1; clear_risc_ints: + /* + * FIXME: Noted that 8014s were being dropped during NK testing. + * Timing deltas during MSI-X/INTa transitions? + */ + if (IS_QLA81XX(ha)) + goto fail; spin_lock_irq(&ha->hardware_lock); if (IS_FWI2_CAPABLE(ha)) { WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); @@ -2044,7 +2072,7 @@ qla2x00_get_rsp_host(struct rsp_que *rsp) if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) { sp = req->outstanding_cmds[pkt->handle]; if (sp) - vha = sp->vha; + vha = sp->fcport->vha; } } if (!vha) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index a99976f5fab..db4df45234a 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -123,8 +123,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Wait for mbx cmd completion until timeout */ - if (!abort_active && io_lock_on) { - + if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) { set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); if (IS_FWI2_CAPABLE(ha)) @@ -218,7 +217,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Clean up */ ha->mcp = NULL; - if (abort_active || !io_lock_on) { + if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) { DEBUG11(printk("%s(%ld): checking for additional resp " "interrupt.\n", __func__, base_vha->host_no)); @@ -412,7 +411,8 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) */ void qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, - uint16_t *subminor, uint16_t *attributes, uint32_t *memory) + uint16_t *subminor, uint16_t *attributes, uint32_t *memory, uint8_t *mpi, + uint32_t *mpi_caps) { int rval; mbx_cmd_t mc; @@ -423,6 +423,8 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, mcp->mb[0] = MBC_GET_FIRMWARE_VERSION; mcp->out_mb = MBX_0; mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + if (IS_QLA81XX(vha->hw)) + mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10; mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(vha, mcp); @@ -436,6 +438,13 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha, uint16_t *major, uint16_t *minor, *memory = 0x1FFFF; /* Defaults to 128KB. */ else *memory = (mcp->mb[5] << 16) | mcp->mb[4]; + if (IS_QLA81XX(vha->hw)) { + mpi[0] = mcp->mb[10] >> 8; + mpi[1] = mcp->mb[10] & 0xff; + mpi[2] = mcp->mb[11] >> 8; + mpi[3] = mcp->mb[11] & 0xff; + *mpi_caps = (mcp->mb[12] << 16) | mcp->mb[13]; + } if (rval != QLA_SUCCESS) { /*EMPTY*/ @@ -568,7 +577,6 @@ int qla2x00_mbx_reg_test(scsi_qla_host_t *vha) { int rval; - struct qla_hw_data *ha = vha->hw; mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; @@ -595,14 +603,6 @@ qla2x00_mbx_reg_test(scsi_qla_host_t *vha) if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || mcp->mb[7] != 0x2525) rval = QLA_FUNCTION_FAILED; - if (rval == QLA_FUNCTION_FAILED) { - struct device_reg_24xx __iomem *reg = - &ha->iobase->isp24; - - qla2xxx_hw_event_log(vha, HW_EVENT_ISP_ERR, 0, - LSW(RD_REG_DWORD(®->hccr)), - LSW(RD_REG_DWORD(®->istatus))); - } } if (rval != QLA_SUCCESS) { @@ -1363,7 +1363,13 @@ qla2x00_lip_reset(scsi_qla_host_t *vha) DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); - if (IS_FWI2_CAPABLE(vha->hw)) { + if (IS_QLA81XX(vha->hw)) { + /* Logout across all FCFs. */ + mcp->mb[0] = MBC_LIP_FULL_LOGIN; + mcp->mb[1] = BIT_1; + mcp->mb[2] = 0; + mcp->out_mb = MBX_2|MBX_1|MBX_0; + } else if (IS_FWI2_CAPABLE(vha->hw)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; mcp->mb[1] = BIT_6; mcp->mb[2] = 0; @@ -1853,6 +1859,9 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; + if (IS_QLA81XX(vha->hw)) + return QLA_SUCCESS; + DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n", vha->host_no)); @@ -2512,7 +2521,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma, mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_QLA25XX(vha->hw)) + if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw)) return QLA_FUNCTION_FAILED; DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no)); @@ -3155,7 +3164,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp, mcp->mb[7] = LSW(MSD(rsp->dma)); mcp->mb[5] = rsp->length; mcp->mb[11] = rsp->vp_idx; - mcp->mb[14] = rsp->msix->vector; + mcp->mb[14] = rsp->msix->entry; mcp->mb[13] = rsp->rid; reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) + diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 386ffeae5b5..886323130fc 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -614,8 +614,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, req->vp_idx = vp_idx; req->qos = qos; - if (ha->rsp_q_map[rsp_que]) + if (ha->rsp_q_map[rsp_que]) { req->rsp = ha->rsp_q_map[rsp_que]; + req->rsp->req = req; + } /* Use alternate PCI bus number */ if (MSB(req->rid)) options |= BIT_4; diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8ea927788b3..4a71f522f92 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -404,26 +404,9 @@ static char * qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str) { struct qla_hw_data *ha = vha->hw; - sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, - ha->fw_minor_version, - ha->fw_subminor_version); - if (ha->fw_attributes & BIT_0) - strcat(str, "[Class 2] "); - if (ha->fw_attributes & BIT_1) - strcat(str, "[IP] "); - if (ha->fw_attributes & BIT_2) - strcat(str, "[Multi-ID] "); - if (ha->fw_attributes & BIT_3) - strcat(str, "[SB-2] "); - if (ha->fw_attributes & BIT_4) - strcat(str, "[T10 CRC] "); - if (ha->fw_attributes & BIT_5) - strcat(str, "[VI] "); - if (ha->fw_attributes & BIT_10) - strcat(str, "[84XX] "); - if (ha->fw_attributes & BIT_13) - strcat(str, "[Experimental]"); + sprintf(str, "%d.%02d.%02d (%x)", ha->fw_major_version, + ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes); return str; } @@ -438,7 +421,6 @@ qla2x00_get_new_sp(scsi_qla_host_t *vha, fc_port_t *fcport, if (!sp) return sp; - sp->vha = vha; sp->fcport = fcport; sp->cmd = cmd; sp->que = ha->req_q_map[0]; @@ -1182,7 +1164,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) continue; for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { sp = req->outstanding_cmds[cnt]; - if (sp && sp->vha == vha) { + if (sp && sp->fcport->vha == vha) { req->outstanding_cmds[cnt] = NULL; sp->cmd->result = res; qla2x00_sp_compl(ha, sp); @@ -1329,6 +1311,8 @@ qla24xx_disable_intrs(struct qla_hw_data *ha) unsigned long flags = 0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; + if (IS_NOPOLLING_TYPE(ha)) + return; spin_lock_irqsave(&ha->hardware_lock, flags); ha->interrupts_on = 0; WRT_REG_DWORD(®->ictrl, 0); @@ -1488,6 +1472,44 @@ static struct isp_operations qla25xx_isp_ops = { .rd_req_reg = qla24xx_rd_req_reg, }; +static struct isp_operations qla81xx_isp_ops = { + .pci_config = qla25xx_pci_config, + .reset_chip = qla24xx_reset_chip, + .chip_diag = qla24xx_chip_diag, + .config_rings = qla24xx_config_rings, + .reset_adapter = qla24xx_reset_adapter, + .nvram_config = qla81xx_nvram_config, + .update_fw_options = qla81xx_update_fw_options, + .load_risc = qla24xx_load_risc, + .pci_info_str = qla24xx_pci_info_str, + .fw_version_str = qla24xx_fw_version_str, + .intr_handler = qla24xx_intr_handler, + .enable_intrs = qla24xx_enable_intrs, + .disable_intrs = qla24xx_disable_intrs, + .abort_command = qla24xx_abort_command, + .target_reset = qla24xx_abort_target, + .lun_reset = qla24xx_lun_reset, + .fabric_login = qla24xx_login_fabric, + .fabric_logout = qla24xx_fabric_logout, + .calc_req_entries = NULL, + .build_iocbs = NULL, + .prep_ms_iocb = qla24xx_prep_ms_iocb, + .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, + .read_nvram = qla25xx_read_nvram_data, + .write_nvram = qla25xx_write_nvram_data, + .fw_dump = qla81xx_fw_dump, + .beacon_on = qla24xx_beacon_on, + .beacon_off = qla24xx_beacon_off, + .beacon_blink = qla24xx_beacon_blink, + .read_optrom = qla25xx_read_optrom_data, + .write_optrom = qla24xx_write_optrom_data, + .get_flash_version = qla24xx_get_flash_version, + .start_scsi = qla24xx_start_scsi, + .wrt_req_reg = qla24xx_wrt_req_reg, + .wrt_rsp_reg = qla24xx_wrt_rsp_reg, + .rd_req_reg = qla24xx_rd_req_reg, +}; + static inline void qla2x00_set_isp_flags(struct qla_hw_data *ha) { @@ -1567,6 +1589,13 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP8001: + ha->device_type |= DT_ISP8001; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; } } @@ -1629,7 +1658,7 @@ skip_pio: /* Determine queue resources */ ha->max_queues = 1; - if (ql2xmaxqueues <= 1 || !IS_QLA25XX(ha)) + if (ql2xmaxqueues <= 1 || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) goto mqiobase_exit; ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), pci_resource_len(ha->pdev, 3)); @@ -1706,7 +1735,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532) { + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001) { bars = pci_select_bars(pdev, IORESOURCE_MEM); sht = &qla24xx_driver_template; mem_only = 1; @@ -1760,6 +1790,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) rsp_length = RESPONSE_ENTRY_CNT_2100; ha->max_loop_id = SNS_LAST_LOOP_ID_2100; ha->gid_list_info_size = 4; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2100_isp_ops; } else if (IS_QLA2200(ha)) { ha->mbx_count = MAILBOX_REGISTER_COUNT; @@ -1767,6 +1801,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) rsp_length = RESPONSE_ENTRY_CNT_2100; ha->max_loop_id = SNS_LAST_LOOP_ID_2100; ha->gid_list_info_size = 4; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2100_isp_ops; } else if (IS_QLA23XX(ha)) { ha->mbx_count = MAILBOX_REGISTER_COUNT; @@ -1776,6 +1814,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->gid_list_info_size = 6; if (IS_QLA2322(ha) || IS_QLA6322(ha)) ha->optrom_size = OPTROM_SIZE_2322; + ha->flash_conf_off = ~0; + ha->flash_data_off = ~0; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; ha->isp_ops = &qla2300_isp_ops; } else if (IS_QLA24XX_TYPE(ha)) { ha->mbx_count = MAILBOX_REGISTER_COUNT; @@ -1787,6 +1829,10 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->optrom_size = OPTROM_SIZE_24XX; ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA24XX; ha->isp_ops = &qla24xx_isp_ops; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA; + ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; + ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; } else if (IS_QLA25XX(ha)) { ha->mbx_count = MAILBOX_REGISTER_COUNT; req_length = REQUEST_ENTRY_CNT_24XX; @@ -1797,6 +1843,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->optrom_size = OPTROM_SIZE_25XX; ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; ha->isp_ops = &qla25xx_isp_ops; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA; + ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; + ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; + } else if (IS_QLA81XX(ha)) { + ha->mbx_count = MAILBOX_REGISTER_COUNT; + req_length = REQUEST_ENTRY_CNT_24XX; + rsp_length = RESPONSE_ENTRY_CNT_2300; + ha->max_loop_id = SNS_LAST_LOOP_ID_2300; + ha->init_cb_size = sizeof(struct mid_init_cb_81xx); + ha->gid_list_info_size = 8; + ha->optrom_size = OPTROM_SIZE_81XX; + ha->isp_ops = &qla81xx_isp_ops; + ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; + ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; + ha->nvram_conf_off = ~0; + ha->nvram_data_off = ~0; } mutex_init(&ha->vport_lock); @@ -2458,23 +2521,6 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, return qla2x00_post_work(vha, e, 1); } -int -qla2x00_post_hwe_work(struct scsi_qla_host *vha, uint16_t code, uint16_t d1, - uint16_t d2, uint16_t d3) -{ - struct qla_work_evt *e; - - e = qla2x00_alloc_work(vha, QLA_EVT_HWE_LOG, 1); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.hwe.code = code; - e->u.hwe.d1 = d1; - e->u.hwe.d2 = d2; - e->u.hwe.d3 = d3; - return qla2x00_post_work(vha, e, 1); -} - static void qla2x00_do_work(struct scsi_qla_host *vha) { @@ -2492,10 +2538,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) fc_host_post_event(vha->host, fc_get_event_number(), e->u.aen.code, e->u.aen.data); break; - case QLA_EVT_HWE_LOG: - qla2xxx_hw_event_log(vha, e->u.hwe.code, e->u.hwe.d1, - e->u.hwe.d2, e->u.hwe.d3); - break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -2914,13 +2956,14 @@ qla2x00_timer(scsi_qla_host_t *vha) /* Firmware interface routines. */ -#define FW_BLOBS 6 +#define FW_BLOBS 7 #define FW_ISP21XX 0 #define FW_ISP22XX 1 #define FW_ISP2300 2 #define FW_ISP2322 3 #define FW_ISP24XX 4 #define FW_ISP25XX 5 +#define FW_ISP81XX 6 #define FW_FILE_ISP21XX "ql2100_fw.bin" #define FW_FILE_ISP22XX "ql2200_fw.bin" @@ -2928,6 +2971,7 @@ qla2x00_timer(scsi_qla_host_t *vha) #define FW_FILE_ISP2322 "ql2322_fw.bin" #define FW_FILE_ISP24XX "ql2400_fw.bin" #define FW_FILE_ISP25XX "ql2500_fw.bin" +#define FW_FILE_ISP81XX "ql8100_fw.bin" static DEFINE_MUTEX(qla_fw_lock); @@ -2938,6 +2982,7 @@ static struct fw_blob qla_fw_blobs[FW_BLOBS] = { { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, { .name = FW_FILE_ISP24XX, }, { .name = FW_FILE_ISP25XX, }, + { .name = FW_FILE_ISP81XX, }, }; struct fw_blob * @@ -2959,6 +3004,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha) blob = &qla_fw_blobs[FW_ISP24XX]; } else if (IS_QLA25XX(ha)) { blob = &qla_fw_blobs[FW_ISP25XX]; + } else if (IS_QLA81XX(ha)) { + blob = &qla_fw_blobs[FW_ISP81XX]; } mutex_lock(&qla_fw_lock); @@ -3112,6 +3159,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) }, { 0 }, }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); @@ -3200,3 +3248,4 @@ MODULE_FIRMWARE(FW_FILE_ISP2300); MODULE_FIRMWARE(FW_FILE_ISP2322); MODULE_FIRMWARE(FW_FILE_ISP24XX); MODULE_FIRMWARE(FW_FILE_ISP25XX); +MODULE_FIRMWARE(FW_FILE_ISP81XX); diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index c538ee1b1a3..303f8ee11f2 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -425,27 +425,27 @@ qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat) #define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) static inline uint32_t -flash_conf_to_access_addr(uint32_t faddr) +flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr) { - return FARX_ACCESS_FLASH_CONF | faddr; + return ha->flash_conf_off | faddr; } static inline uint32_t -flash_data_to_access_addr(uint32_t faddr) +flash_data_addr(struct qla_hw_data *ha, uint32_t faddr) { - return FARX_ACCESS_FLASH_DATA | faddr; + return ha->flash_data_off | faddr; } static inline uint32_t -nvram_conf_to_access_addr(uint32_t naddr) +nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr) { - return FARX_ACCESS_NVRAM_CONF | naddr; + return ha->nvram_conf_off | naddr; } static inline uint32_t -nvram_data_to_access_addr(uint32_t naddr) +nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr) { - return FARX_ACCESS_NVRAM_DATA | naddr; + return ha->nvram_data_off | naddr; } static uint32_t @@ -481,10 +481,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { uint32_t i; + struct qla_hw_data *ha = vha->hw; + /* Dword reads to flash. */ for (i = 0; i < dwords; i++, faddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(vha->hw, - flash_data_to_access_addr(faddr))); + dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, + flash_data_addr(ha, faddr))); return dwptr; } @@ -518,7 +520,7 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, { uint32_t ids; - ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab)); + ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x03ab)); *man_id = LSB(ids); *flash_id = MSB(ids); @@ -530,8 +532,7 @@ qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, * Example: ATMEL 0x00 01 45 1F * Extract MFG and Dev ID from last two bytes. */ - ids = qla24xx_read_flash_dword(ha, - flash_data_to_access_addr(0xd009f)); + ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x009f)); *man_id = LSB(ids); *flash_id = MSB(ids); } @@ -555,9 +556,13 @@ qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) /* Begin with sane defaults. */ loc = locations[0]; - *start = IS_QLA24XX_TYPE(ha) ? FA_FLASH_LAYOUT_ADDR_24: - FA_FLASH_LAYOUT_ADDR; - + *start = 0; + if (IS_QLA24XX_TYPE(ha)) + *start = FA_FLASH_LAYOUT_ADDR_24; + else if (IS_QLA25XX(ha)) + *start = FA_FLASH_LAYOUT_ADDR; + else if (IS_QLA81XX(ha)) + *start = FA_FLASH_LAYOUT_ADDR_81; /* Begin with first PCI expansion ROM header. */ buf = (uint8_t *)req->ring; dcode = (uint32_t *)req->ring; @@ -618,6 +623,22 @@ static void qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) { const char *loc, *locations[] = { "DEF", "FLT" }; + const uint32_t def_fw[] = + { FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 }; + const uint32_t def_boot[] = + { FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR_81 }; + const uint32_t def_vpd_nvram[] = + { FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR_81 }; + const uint32_t def_fdt[] = + { FA_FLASH_DESCR_ADDR_24, FA_FLASH_DESCR_ADDR, + FA_FLASH_DESCR_ADDR_81 }; + const uint32_t def_npiv_conf0[] = + { FA_NPIV_CONF0_ADDR_24, FA_NPIV_CONF0_ADDR, + FA_NPIV_CONF0_ADDR_81 }; + const uint32_t def_npiv_conf1[] = + { FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR, + FA_NPIV_CONF1_ADDR_81 }; + uint32_t def; uint16_t *wptr; uint16_t cnt, chksum; uint32_t start; @@ -676,20 +697,12 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) case FLT_REG_FDT: ha->flt_region_fdt = start; break; - case FLT_REG_HW_EVENT_0: - if (!PCI_FUNC(ha->pdev->devfn)) - ha->flt_region_hw_event = start; - break; - case FLT_REG_HW_EVENT_1: - if (PCI_FUNC(ha->pdev->devfn)) - ha->flt_region_hw_event = start; - break; case FLT_REG_NPIV_CONF_0: - if (!PCI_FUNC(ha->pdev->devfn)) + if (!(PCI_FUNC(ha->pdev->devfn) & 1)) ha->flt_region_npiv_conf = start; break; case FLT_REG_NPIV_CONF_1: - if (PCI_FUNC(ha->pdev->devfn)) + if (PCI_FUNC(ha->pdev->devfn) & 1) ha->flt_region_npiv_conf = start; break; } @@ -699,22 +712,24 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) no_flash_data: /* Use hardcoded defaults. */ loc = locations[0]; - ha->flt_region_fw = FA_RISC_CODE_ADDR; - ha->flt_region_boot = FA_BOOT_CODE_ADDR; - ha->flt_region_vpd_nvram = FA_VPD_NVRAM_ADDR; - ha->flt_region_fdt = IS_QLA24XX_TYPE(ha) ? FA_FLASH_DESCR_ADDR_24: - FA_FLASH_DESCR_ADDR; - ha->flt_region_hw_event = !PCI_FUNC(ha->pdev->devfn) ? - FA_HW_EVENT0_ADDR: FA_HW_EVENT1_ADDR; - ha->flt_region_npiv_conf = !PCI_FUNC(ha->pdev->devfn) ? - (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF0_ADDR_24: FA_NPIV_CONF0_ADDR): - (IS_QLA24XX_TYPE(ha) ? FA_NPIV_CONF1_ADDR_24: FA_NPIV_CONF1_ADDR); + def = 0; + if (IS_QLA24XX_TYPE(ha)) + def = 0; + else if (IS_QLA25XX(ha)) + def = 1; + else if (IS_QLA81XX(ha)) + def = 2; + ha->flt_region_fw = def_fw[def]; + ha->flt_region_boot = def_boot[def]; + ha->flt_region_vpd_nvram = def_vpd_nvram[def]; + ha->flt_region_fdt = def_fdt[def]; + ha->flt_region_npiv_conf = !(PCI_FUNC(ha->pdev->devfn) & 1) ? + def_npiv_conf0[def]: def_npiv_conf1[def]; done: DEBUG2(qla_printk(KERN_DEBUG, ha, "FLT[%s]: boot=0x%x fw=0x%x " - "vpd_nvram=0x%x fdt=0x%x flt=0x%x hwe=0x%x npiv=0x%x.\n", loc, + "vpd_nvram=0x%x fdt=0x%x flt=0x%x npiv=0x%x.\n", loc, ha->flt_region_boot, ha->flt_region_fw, ha->flt_region_vpd_nvram, - ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_hw_event, - ha->flt_region_npiv_conf)); + ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf)); } static void @@ -757,14 +772,14 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) mid = le16_to_cpu(fdt->man_id); fid = le16_to_cpu(fdt->id); ha->fdt_wrt_disable = fdt->wrt_disable_bits; - ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0300 | fdt->erase_cmd); + ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0300 | fdt->erase_cmd); ha->fdt_block_size = le32_to_cpu(fdt->block_size); if (fdt->unprotect_sec_cmd) { - ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0300 | + ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 | fdt->unprotect_sec_cmd); ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? - flash_conf_to_access_addr(0x0300 | fdt->protect_sec_cmd): - flash_conf_to_access_addr(0x0336); + flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd): + flash_conf_addr(ha, 0x0336); } goto done; no_flash_data: @@ -773,7 +788,7 @@ no_flash_data: mid = man_id; fid = flash_id; ha->fdt_wrt_disable = 0x9c; - ha->fdt_erase_cmd = flash_conf_to_access_addr(0x03d8); + ha->fdt_erase_cmd = flash_conf_addr(ha, 0x03d8); switch (man_id) { case 0xbf: /* STT flash. */ if (flash_id == 0x8e) @@ -782,16 +797,16 @@ no_flash_data: ha->fdt_block_size = FLASH_BLK_SIZE_32K; if (flash_id == 0x80) - ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0352); + ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0352); break; case 0x13: /* ST M25P80. */ ha->fdt_block_size = FLASH_BLK_SIZE_64K; break; case 0x1f: /* Atmel 26DF081A. */ ha->fdt_block_size = FLASH_BLK_SIZE_4K; - ha->fdt_erase_cmd = flash_conf_to_access_addr(0x0320); - ha->fdt_unprotect_sec_cmd = flash_conf_to_access_addr(0x0339); - ha->fdt_protect_sec_cmd = flash_conf_to_access_addr(0x0336); + ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0320); + ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0339); + ha->fdt_protect_sec_cmd = flash_conf_addr(ha, 0x0336); break; default: /* Default to 64 kb sector size. */ @@ -813,7 +828,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha) uint32_t flt_addr; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha)) return QLA_SUCCESS; ret = qla2xxx_find_flt_start(vha, &flt_addr); @@ -838,7 +853,7 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) struct qla_npiv_entry *entry; struct qla_hw_data *ha = vha->hw; - if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) + if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_QLA81XX(ha)) return; ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr, @@ -930,9 +945,9 @@ qla24xx_unprotect_flash(struct qla_hw_data *ha) return; /* Disable flash write-protection. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); + qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); /* Some flash parts need an additional zero-write to clear bits.*/ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); + qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); } static void @@ -945,11 +960,10 @@ qla24xx_protect_flash(struct qla_hw_data *ha) goto skip_wrt_protect; /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), + qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), ha->fdt_wrt_disable); for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, - flash_conf_to_access_addr(0x005)) & BIT_0; + qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x005)) & BIT_0; cnt--) { udelay(10); } @@ -977,7 +991,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, ret = QLA_SUCCESS; /* Prepare burst-capable write on supported ISPs. */ - if (IS_QLA25XX(ha) && !(faddr & 0xfff) && + if ((IS_QLA25XX(ha) || IS_QLA81XX(ha)) && !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) { optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, &optrom_dma, GFP_KERNEL); @@ -989,7 +1003,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, } rest_addr = (ha->fdt_block_size >> 2) - 1; - sec_mask = 0x80000 - (ha->fdt_block_size >> 2); + sec_mask = (ha->optrom_size >> 2) - (ha->fdt_block_size >> 2); qla24xx_unprotect_flash(ha); @@ -1024,13 +1038,13 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, *s = cpu_to_le32(*d); ret = qla2x00_load_ram(vha, optrom_dma, - flash_data_to_access_addr(faddr), + flash_data_addr(ha, faddr), OPTROM_BURST_DWORDS); if (ret != QLA_SUCCESS) { qla_printk(KERN_WARNING, ha, "Unable to burst-write optrom segment " "(%x/%x/%llx).\n", ret, - flash_data_to_access_addr(faddr), + flash_data_addr(ha, faddr), (unsigned long long)optrom_dma); qla_printk(KERN_WARNING, ha, "Reverting to slow-write.\n"); @@ -1047,7 +1061,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, } ret = qla24xx_write_flash_dword(ha, - flash_data_to_access_addr(faddr), cpu_to_le32(*dwptr)); + flash_data_addr(ha, faddr), cpu_to_le32(*dwptr)); if (ret != QLA_SUCCESS) { DEBUG9(printk("%s(%ld) Unable to program flash " "address=%x data=%x.\n", __func__, @@ -1098,12 +1112,13 @@ qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, { uint32_t i; uint32_t *dwptr; + struct qla_hw_data *ha = vha->hw; /* Dword reads to flash. */ dwptr = (uint32_t *)buf; for (i = 0; i < bytes >> 2; i++, naddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(vha->hw, - nvram_data_to_access_addr(naddr))); + dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, + nvram_data_addr(ha, naddr))); return buf; } @@ -1160,17 +1175,14 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ /* Disable NVRAM write-protection. */ - qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), - 0); - qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), - 0); + qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0); + qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0); /* Dword writes to flash. */ dwptr = (uint32_t *)buf; for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) { ret = qla24xx_write_flash_dword(ha, - nvram_data_to_access_addr(naddr), - cpu_to_le32(*dwptr)); + nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr)); if (ret != QLA_SUCCESS) { DEBUG9(qla_printk("Unable to program nvram address=%x " "data=%x.\n", naddr, *dwptr)); @@ -1179,8 +1191,7 @@ qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, } /* Enable NVRAM write-protection. */ - qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), - 0x8c); + qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0x8c); /* Disable flash write. */ WRT_REG_DWORD(®->ctrl_status, @@ -1202,8 +1213,7 @@ qla25xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, dwptr = (uint32_t *)buf; for (i = 0; i < bytes >> 2; i++, naddr++) dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - flash_data_to_access_addr(ha->flt_region_vpd_nvram | - naddr))); + flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr))); return buf; } @@ -2246,12 +2256,12 @@ qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, burst = left; rval = qla2x00_dump_ram(vha, optrom_dma, - flash_data_to_access_addr(faddr), burst); + flash_data_addr(ha, faddr), burst); if (rval) { qla_printk(KERN_WARNING, ha, "Unable to burst-read optrom segment " "(%x/%x/%llx).\n", rval, - flash_data_to_access_addr(faddr), + flash_data_addr(ha, faddr), (unsigned long long)optrom_dma); qla_printk(KERN_WARNING, ha, "Reverting to slow-read.\n"); @@ -2648,108 +2658,3 @@ qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size) return 0; } - -static int -qla2xxx_hw_event_store(scsi_qla_host_t *vha, uint32_t *fdata) -{ - uint32_t d[2], faddr; - struct qla_hw_data *ha = vha->hw; - - /* Locate first empty entry. */ - for (;;) { - if (ha->hw_event_ptr >= - ha->flt_region_hw_event + FA_HW_EVENT_SIZE) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "HW event -- Log Full!\n")); - return QLA_MEMORY_ALLOC_FAILED; - } - - qla24xx_read_flash_data(vha, d, ha->hw_event_ptr, 2); - faddr = flash_data_to_access_addr(ha->hw_event_ptr); - ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; - if (d[0] == __constant_cpu_to_le32(0xffffffff) && - d[1] == __constant_cpu_to_le32(0xffffffff)) { - qla24xx_unprotect_flash(ha); - - qla24xx_write_flash_dword(ha, faddr++, - cpu_to_le32(jiffies)); - qla24xx_write_flash_dword(ha, faddr++, 0); - qla24xx_write_flash_dword(ha, faddr++, *fdata++); - qla24xx_write_flash_dword(ha, faddr++, *fdata); - - qla24xx_protect_flash(ha); - break; - } - } - return QLA_SUCCESS; -} - -int -qla2xxx_hw_event_log(scsi_qla_host_t *vha, uint16_t code, uint16_t d1, - uint16_t d2, uint16_t d3) -{ -#define QMARK(a, b, c, d) \ - cpu_to_le32(LSB(a) << 24 | LSB(b) << 16 | LSB(c) << 8 | LSB(d)) - struct qla_hw_data *ha = vha->hw; - int rval; - uint32_t marker[2], fdata[4]; - - if (ha->flt_region_hw_event == 0) - return QLA_FUNCTION_FAILED; - - DEBUG2(qla_printk(KERN_WARNING, ha, - "HW event -- code=%x, d1=%x, d2=%x, d3=%x.\n", code, d1, d2, d3)); - - /* If marker not already found, locate or write. */ - if (!ha->flags.hw_event_marker_found) { - /* Create marker. */ - marker[0] = QMARK('L', ha->fw_major_version, - ha->fw_minor_version, ha->fw_subminor_version); - marker[1] = QMARK(QLA_DRIVER_MAJOR_VER, QLA_DRIVER_MINOR_VER, - QLA_DRIVER_PATCH_VER, QLA_DRIVER_BETA_VER); - - /* Locate marker. */ - ha->hw_event_ptr = ha->flt_region_hw_event; - for (;;) { - qla24xx_read_flash_data(vha, fdata, ha->hw_event_ptr, - 4); - if (fdata[0] == __constant_cpu_to_le32(0xffffffff) && - fdata[1] == __constant_cpu_to_le32(0xffffffff)) - break; - ha->hw_event_ptr += FA_HW_EVENT_ENTRY_SIZE; - if (ha->hw_event_ptr >= - ha->flt_region_hw_event + FA_HW_EVENT_SIZE) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "HW event -- Log Full!\n")); - return QLA_MEMORY_ALLOC_FAILED; - } - if (fdata[2] == marker[0] && fdata[3] == marker[1]) { - ha->flags.hw_event_marker_found = 1; - break; - } - } - /* No marker, write it. */ - if (!ha->flags.hw_event_marker_found) { - rval = qla2xxx_hw_event_store(vha, marker); - if (rval != QLA_SUCCESS) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "HW event -- Failed marker write=%x.!\n", - rval)); - return rval; - } - ha->flags.hw_event_marker_found = 1; - } - } - - /* Store error. */ - fdata[0] = cpu_to_le32(code << 16 | d1); - fdata[1] = cpu_to_le32(d2 << 16 | d3); - rval = qla2xxx_hw_event_store(vha, fdata); - if (rval != QLA_SUCCESS) { - DEBUG2(qla_printk(KERN_WARNING, ha, - "HW event -- Failed error write=%x.!\n", - rval)); - } - - return rval; -} diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index be22f3a09f8..808bab6ef06 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,9 +7,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.02.03-k1" +#define QLA2XXX_VERSION "8.03.00-k1" #define QLA_DRIVER_MAJOR_VER 8 -#define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 3 +#define QLA_DRIVER_MINOR_VER 3 +#define QLA_DRIVER_PATCH_VER 0 #define QLA_DRIVER_BETA_VER 0 diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c index 913a931176e..8e5c169b03f 100644 --- a/drivers/scsi/raid_class.c +++ b/drivers/scsi/raid_class.c @@ -237,8 +237,7 @@ int raid_component_add(struct raid_template *r,struct device *raid_dev, rc->dev.parent = get_device(component_dev); rc->num = rd->component_count++; - snprintf(rc->dev.bus_id, sizeof(rc->dev.bus_id), - "component-%d", rc->num); + dev_set_name(&rc->dev, "component-%d", rc->num); list_add_tail(&rc->node, &rd->component_list); rc->dev.class = &raid_class.class; err = device_add(&rc->dev); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index f8b79d401d5..42e72a2c1f9 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -651,10 +651,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) unsigned long timeout; int rtn = 0; - /* - * We will use a queued command if possible, otherwise we will - * emulate the queuing and calling of completion function ourselves. - */ atomic_inc(&cmd->device->iorequest_cnt); /* check if the device is still usable */ diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 27c633f5579..6eebd0bbe8a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2508,7 +2508,7 @@ static void pseudo_0_release(struct device *dev) } static struct device pseudo_primary = { - .bus_id = "pseudo_0", + .init_name = "pseudo_0", .release = pseudo_0_release, }; @@ -2680,7 +2680,7 @@ static int sdebug_add_adapter(void) sdbg_host->dev.bus = &pseudo_lld_bus; sdbg_host->dev.parent = &pseudo_primary; sdbg_host->dev.release = &sdebug_release_adapter; - sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); + dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); error = device_register(&sdbg_host->dev); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index d86ebea9350..ad6a1370761 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -124,34 +124,22 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) enum blk_eh_timer_return scsi_times_out(struct request *req) { struct scsi_cmnd *scmd = req->special; - enum blk_eh_timer_return (*eh_timed_out)(struct scsi_cmnd *); enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; scsi_log_completion(scmd, TIMEOUT_ERROR); if (scmd->device->host->transportt->eh_timed_out) - eh_timed_out = scmd->device->host->transportt->eh_timed_out; + rtn = scmd->device->host->transportt->eh_timed_out(scmd); else if (scmd->device->host->hostt->eh_timed_out) - eh_timed_out = scmd->device->host->hostt->eh_timed_out; - else - eh_timed_out = NULL; + rtn = scmd->device->host->hostt->eh_timed_out(scmd); - if (eh_timed_out) { - rtn = eh_timed_out(scmd); - switch (rtn) { - case BLK_EH_NOT_HANDLED: - break; - default: - return rtn; - } - } - - if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { + if (unlikely(rtn == BLK_EH_NOT_HANDLED && + !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) { scmd->result |= DID_TIME_OUT << 16; - return BLK_EH_HANDLED; + rtn = BLK_EH_HANDLED; } - return BLK_EH_NOT_HANDLED; + return rtn; } /** diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 2ae4f8fc583..b98f763931c 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -167,10 +167,17 @@ EXPORT_SYMBOL(scsi_set_medium_removal); static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) { struct device *dev = scsi_get_device(sdev->host); + const char *name; if (!dev) return -ENXIO; - return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id))? -EFAULT: 0; + + name = dev_name(dev); + + /* compatibility with old ioctl which only returned + * 20 characters */ + return copy_to_user(arg, name, min(strlen(name), (size_t)20)) + ? -EFAULT: 0; } diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index f2f51e0333e..940dc32ff0d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -91,26 +91,19 @@ static void scsi_unprep_request(struct request *req) scsi_put_command(cmd); } -/* - * Function: scsi_queue_insert() - * - * Purpose: Insert a command in the midlevel queue. - * - * Arguments: cmd - command that we are adding to queue. - * reason - why we are inserting command to queue. - * - * Lock status: Assumed that lock is not held upon entry. - * - * Returns: Nothing. - * - * Notes: We do this for one of two cases. Either the host is busy - * and it cannot accept any more commands for the time being, - * or the device returned QUEUE_FULL and can accept no more - * commands. - * Notes: This could be called either from an interrupt context or a - * normal process context. +/** + * __scsi_queue_insert - private queue insertion + * @cmd: The SCSI command being requeued + * @reason: The reason for the requeue + * @unbusy: Whether the queue should be unbusied + * + * This is a private queue insertion. The public interface + * scsi_queue_insert() always assumes the queue should be unbusied + * because it's always called before the completion. This function is + * for a requeue after completion, which should only occur in this + * file. */ -int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) { struct Scsi_Host *host = cmd->device->host; struct scsi_device *device = cmd->device; @@ -150,7 +143,8 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) * Decrement the counters, since these commands are no longer * active on the host/device. */ - scsi_device_unbusy(device); + if (unbusy) + scsi_device_unbusy(device); /* * Requeue this command. It will go before all other commands @@ -172,6 +166,29 @@ int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) return 0; } +/* + * Function: scsi_queue_insert() + * + * Purpose: Insert a command in the midlevel queue. + * + * Arguments: cmd - command that we are adding to queue. + * reason - why we are inserting command to queue. + * + * Lock status: Assumed that lock is not held upon entry. + * + * Returns: Nothing. + * + * Notes: We do this for one of two cases. Either the host is busy + * and it cannot accept any more commands for the time being, + * or the device returned QUEUE_FULL and can accept no more + * commands. + * Notes: This could be called either from an interrupt context or a + * normal process context. + */ +int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) +{ + return __scsi_queue_insert(cmd, reason, 1); +} /** * scsi_execute - insert request and wait for the result * @sdev: scsi device @@ -684,6 +701,8 @@ void scsi_run_host_queues(struct Scsi_Host *shost) scsi_run_queue(sdev->request_queue); } +static void __scsi_release_buffers(struct scsi_cmnd *, int); + /* * Function: scsi_end_request() * @@ -732,6 +751,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * leftovers in the front of the * queue, and goose the queue again. */ + scsi_release_buffers(cmd); scsi_requeue_command(q, cmd); cmd = NULL; } @@ -743,6 +763,7 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, * This will goose the queue request function at the end, so we don't * need to worry about launching another command. */ + __scsi_release_buffers(cmd, 0); scsi_next_command(cmd); return NULL; } @@ -798,6 +819,26 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb) __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free); } +static void __scsi_release_buffers(struct scsi_cmnd *cmd, int do_bidi_check) +{ + + if (cmd->sdb.table.nents) + scsi_free_sgtable(&cmd->sdb); + + memset(&cmd->sdb, 0, sizeof(cmd->sdb)); + + if (do_bidi_check && scsi_bidi_cmnd(cmd)) { + struct scsi_data_buffer *bidi_sdb = + cmd->request->next_rq->special; + scsi_free_sgtable(bidi_sdb); + kmem_cache_free(scsi_sdb_cache, bidi_sdb); + cmd->request->next_rq->special = NULL; + } + + if (scsi_prot_sg_count(cmd)) + scsi_free_sgtable(cmd->prot_sdb); +} + /* * Function: scsi_release_buffers() * @@ -817,21 +858,7 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb) */ void scsi_release_buffers(struct scsi_cmnd *cmd) { - if (cmd->sdb.table.nents) - scsi_free_sgtable(&cmd->sdb); - - memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - - if (scsi_bidi_cmnd(cmd)) { - struct scsi_data_buffer *bidi_sdb = - cmd->request->next_rq->special; - scsi_free_sgtable(bidi_sdb); - kmem_cache_free(scsi_sdb_cache, bidi_sdb); - cmd->request->next_rq->special = NULL; - } - - if (scsi_prot_sg_count(cmd)) - scsi_free_sgtable(cmd->prot_sdb); + __scsi_release_buffers(cmd, 1); } EXPORT_SYMBOL(scsi_release_buffers); @@ -945,7 +972,6 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } BUG_ON(blk_bidi_rq(req)); /* bidi not support for !blk_pc_request yet */ - scsi_release_buffers(cmd); /* * Next deal with any sectors which we were able to correctly @@ -963,6 +989,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) return; this_count = blk_rq_bytes(req); + error = -EIO; + if (host_byte(result) == DID_RESET) { /* Third party bus reset or reset for error recovery * reasons. Just retry the command and see what @@ -1004,13 +1032,18 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* This will issue a new 6-byte command. */ cmd->device->use_10_for_rw = 0; action = ACTION_REPREP; + } else if (sshdr.asc == 0x10) /* DIX */ { + description = "Host Data Integrity Failure"; + action = ACTION_FAIL; + error = -EILSEQ; } else action = ACTION_FAIL; break; case ABORTED_COMMAND: if (sshdr.asc == 0x10) { /* DIF */ + description = "Target Data Integrity Failure"; action = ACTION_FAIL; - description = "Data Integrity Failure"; + error = -EILSEQ; } else action = ACTION_RETRY; break; @@ -1029,6 +1062,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) case 0x09: /* self test in progress */ action = ACTION_DELAYED_RETRY; break; + default: + description = "Device not ready"; + action = ACTION_FAIL; + break; } } else { description = "Device not ready"; @@ -1052,9 +1089,10 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) switch (action) { case ACTION_FAIL: /* Give up and fail the remainder of the request */ + scsi_release_buffers(cmd); if (!(req->cmd_flags & REQ_QUIET)) { if (description) - scmd_printk(KERN_INFO, cmd, "%s", + scmd_printk(KERN_INFO, cmd, "%s\n", description); scsi_print_result(cmd); if (driver_byte(result) & DRIVER_SENSE) @@ -1067,15 +1105,16 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) /* Unprep the request and put it back at the head of the queue. * A new command will be prepared and issued. */ + scsi_release_buffers(cmd); scsi_requeue_command(q, cmd); break; case ACTION_RETRY: /* Retry the same command immediately */ - scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY); + __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0); break; case ACTION_DELAYED_RETRY: /* Retry the same command after a delay */ - scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); + __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0); break; } } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 17914a346f7..66505bb7941 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -414,8 +414,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, device_initialize(dev); starget->reap_ref = 1; dev->parent = get_device(parent); - sprintf(dev->bus_id, "target%d:%d:%d", - shost->host_no, channel, id); + dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); #ifndef CONFIG_SYSFS_DEPRECATED dev->bus = &scsi_bus_type; #endif @@ -1024,7 +1023,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (rescan || !scsi_device_created(sdev)) { SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: device exists on %s\n", - sdev->sdev_gendev.bus_id)); + dev_name(&sdev->sdev_gendev))); if (sdevp) *sdevp = sdev; else @@ -1163,7 +1162,7 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget, struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of" - "%s\n", starget->dev.bus_id)); + "%s\n", dev_name(&starget->dev))); max_dev_lun = min(max_scsi_luns, shost->max_lun); /* diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 93c28f30bbd..da63802cbf9 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1079,16 +1079,14 @@ void scsi_sysfs_device_initialize(struct scsi_device *sdev) device_initialize(&sdev->sdev_gendev); sdev->sdev_gendev.bus = &scsi_bus_type; sdev->sdev_gendev.type = &scsi_dev_type; - sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d", - sdev->host->host_no, sdev->channel, sdev->id, - sdev->lun); - + dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%d", + sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); + device_initialize(&sdev->sdev_dev); sdev->sdev_dev.parent = &sdev->sdev_gendev; sdev->sdev_dev.class = &sdev_class; - snprintf(sdev->sdev_dev.bus_id, BUS_ID_SIZE, - "%d:%d:%d:%d", sdev->host->host_no, - sdev->channel, sdev->id, sdev->lun); + dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d", + sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); sdev->scsi_level = starget->scsi_level; transport_setup_device(&sdev->sdev_gendev); spin_lock_irqsave(shost->host_lock, flags); diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 062304de485..5f77417ed58 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -2407,8 +2407,12 @@ fc_rport_final_delete(struct work_struct *work) /* * Notify the driver that the rport is now dead. The LLDD will * also guarantee that any communication to the rport is terminated + * + * Avoid this call if we already called it when we preserved the + * rport for the binding. */ - if (i->f->dev_loss_tmo_callbk) + if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && + (i->f->dev_loss_tmo_callbk)) i->f->dev_loss_tmo_callbk(rport); transport_remove_device(dev); @@ -2486,8 +2490,8 @@ fc_rport_create(struct Scsi_Host *shost, int channel, device_initialize(dev); /* takes self reference */ dev->parent = get_device(&shost->shost_gendev); /* parent reference */ dev->release = fc_rport_dev_release; - sprintf(dev->bus_id, "rport-%d:%d-%d", - shost->host_no, channel, rport->number); + dev_set_name(dev, "rport-%d:%d-%d", + shost->host_no, channel, rport->number); transport_setup_device(dev); error = device_add(dev); @@ -2647,7 +2651,8 @@ fc_remote_port_add(struct Scsi_Host *shost, int channel, spin_lock_irqsave(shost->host_lock, flags); rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | - FC_RPORT_DEVLOSS_PENDING); + FC_RPORT_DEVLOSS_PENDING | + FC_RPORT_DEVLOSS_CALLBK_DONE); /* if target, initiate a scan */ if (rport->scsi_target_id != -1) { @@ -2944,6 +2949,7 @@ fc_timeout_deleted_rport(struct work_struct *work) struct fc_rport *rport = container_of(work, struct fc_rport, dev_loss_work.work); struct Scsi_Host *shost = rport_to_shost(rport); + struct fc_internal *i = to_fc_internal(shost->transportt); struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; @@ -3011,6 +3017,7 @@ fc_timeout_deleted_rport(struct work_struct *work) rport->roles = FC_PORT_ROLE_UNKNOWN; rport->port_state = FC_PORTSTATE_NOTPRESENT; rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; + rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; /* * Pre-emptively kill I/O rather than waiting for the work queue @@ -3046,8 +3053,18 @@ fc_timeout_deleted_rport(struct work_struct *work) * all attached scsi devices. */ fc_queue_work(shost, &rport->stgt_delete_work); + + /* + * Notify the driver that the rport is now dead. The LLDD will + * also guarantee that any communication to the rport is terminated + * + * Note: we set the CALLBK_DONE flag above to correspond + */ + if (i->f->dev_loss_tmo_callbk) + i->f->dev_loss_tmo_callbk(rport); } + /** * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target. * @work: rport to terminate io on. @@ -3164,8 +3181,8 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev, device_initialize(dev); /* takes self reference */ dev->parent = get_device(pdev); /* takes parent reference */ dev->release = fc_vport_dev_release; - sprintf(dev->bus_id, "vport-%d:%d-%d", - shost->host_no, channel, vport->number); + dev_set_name(dev, "vport-%d:%d-%d", + shost->host_no, channel, vport->number); transport_setup_device(dev); error = device_add(dev); @@ -3188,19 +3205,19 @@ fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev, */ if (pdev != &shost->shost_gendev) { error = sysfs_create_link(&shost->shost_gendev.kobj, - &dev->kobj, dev->bus_id); + &dev->kobj, dev_name(dev)); if (error) printk(KERN_ERR "%s: Cannot create vport symlinks for " "%s, err=%d\n", - __func__, dev->bus_id, error); + __func__, dev_name(dev), error); } spin_lock_irqsave(shost->host_lock, flags); vport->flags &= ~FC_VPORT_CREATING; spin_unlock_irqrestore(shost->host_lock, flags); dev_printk(KERN_NOTICE, pdev, - "%s created via shost%d channel %d\n", dev->bus_id, + "%s created via shost%d channel %d\n", dev_name(dev), shost->host_no, channel); *ret_vport = vport; @@ -3297,7 +3314,7 @@ fc_vport_terminate(struct fc_vport *vport) return stat; if (dev->parent != &shost->shost_gendev) - sysfs_remove_link(&shost->shost_gendev.kobj, dev->bus_id); + sysfs_remove_link(&shost->shost_gendev.kobj, dev_name(dev)); transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); @@ -3329,7 +3346,7 @@ fc_vport_sched_delete(struct work_struct *work) dev_printk(KERN_ERR, vport->dev.parent, "%s: %s could not be deleted created via " "shost%d channel %d - error %d\n", __func__, - vport->dev.bus_id, vport->shost->host_no, + dev_name(&vport->dev), vport->shost->host_no, vport->channel, stat); } diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 4a803ebaf50..75c9297694c 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -187,8 +187,7 @@ iscsi_create_endpoint(int dd_size) ep->id = id; ep->dev.class = &iscsi_endpoint_class; - snprintf(ep->dev.bus_id, BUS_ID_SIZE, "ep-%llu", - (unsigned long long) id); + dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id); err = device_register(&ep->dev); if (err) goto free_ep; @@ -724,8 +723,7 @@ int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) } session->target_id = id; - snprintf(session->dev.bus_id, BUS_ID_SIZE, "session%u", - session->sid); + dev_set_name(&session->dev, "session%u", session->sid); err = device_add(&session->dev); if (err) { iscsi_cls_session_printk(KERN_ERR, session, @@ -898,8 +896,7 @@ iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) if (!get_device(&session->dev)) goto free_conn; - snprintf(conn->dev.bus_id, BUS_ID_SIZE, "connection%d:%u", - session->sid, cid); + dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid); conn->dev.parent = &session->dev; conn->dev.release = iscsi_conn_release; err = device_register(&conn->dev); @@ -1816,7 +1813,7 @@ iscsi_register_transport(struct iscsi_transport *tt) priv->t.create_work_queue = 1; priv->dev.class = &iscsi_transport_class; - snprintf(priv->dev.bus_id, BUS_ID_SIZE, "%s", tt->name); + dev_set_name(&priv->dev, "%s", tt->name); err = device_register(&priv->dev); if (err) goto free_priv; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 366609386be..50988cbf7b2 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -207,7 +207,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) struct request_queue *q; int error; struct device *dev; - char namebuf[BUS_ID_SIZE]; + char namebuf[20]; const char *name; void (*release)(struct device *); @@ -219,7 +219,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) if (rphy) { q = blk_init_queue(sas_non_host_smp_request, NULL); dev = &rphy->dev; - name = dev->bus_id; + name = dev_name(dev); release = NULL; } else { q = blk_init_queue(sas_host_smp_request, NULL); @@ -629,10 +629,10 @@ struct sas_phy *sas_phy_alloc(struct device *parent, int number) INIT_LIST_HEAD(&phy->port_siblings); if (scsi_is_sas_expander_device(parent)) { struct sas_rphy *rphy = dev_to_rphy(parent); - sprintf(phy->dev.bus_id, "phy-%d:%d:%d", shost->host_no, + dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no, rphy->scsi_target_id, number); } else - sprintf(phy->dev.bus_id, "phy-%d:%d", shost->host_no, number); + dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number); transport_setup_device(&phy->dev); @@ -770,7 +770,7 @@ static void sas_port_create_link(struct sas_port *port, int res; res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, - phy->dev.bus_id); + dev_name(&phy->dev)); if (res) goto err; res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); @@ -785,7 +785,7 @@ err: static void sas_port_delete_link(struct sas_port *port, struct sas_phy *phy) { - sysfs_remove_link(&port->dev.kobj, phy->dev.bus_id); + sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev)); sysfs_remove_link(&phy->dev.kobj, "port"); } @@ -821,11 +821,11 @@ struct sas_port *sas_port_alloc(struct device *parent, int port_id) if (scsi_is_sas_expander_device(parent)) { struct sas_rphy *rphy = dev_to_rphy(parent); - sprintf(port->dev.bus_id, "port-%d:%d:%d", shost->host_no, - rphy->scsi_target_id, port->port_identifier); + dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no, + rphy->scsi_target_id, port->port_identifier); } else - sprintf(port->dev.bus_id, "port-%d:%d", shost->host_no, - port->port_identifier); + dev_set_name(&port->dev, "port-%d:%d", shost->host_no, + port->port_identifier); transport_setup_device(&port->dev); @@ -935,7 +935,7 @@ void sas_port_delete(struct sas_port *port) if (port->is_backlink) { struct device *parent = port->dev.parent; - sysfs_remove_link(&port->dev.kobj, parent->bus_id); + sysfs_remove_link(&port->dev.kobj, dev_name(parent)); port->is_backlink = 0; } @@ -984,7 +984,8 @@ void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) /* If this trips, you added a phy that was already * part of a different port */ if (unlikely(tmp != phy)) { - dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", phy->dev.bus_id); + dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", + dev_name(&phy->dev)); BUG(); } } else { @@ -1023,7 +1024,7 @@ void sas_port_mark_backlink(struct sas_port *port) return; port->is_backlink = 1; res = sysfs_create_link(&port->dev.kobj, &parent->kobj, - parent->bus_id); + dev_name(parent)); if (res) goto err; return; @@ -1367,11 +1368,12 @@ struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) rdev->rphy.dev.release = sas_end_device_release; if (scsi_is_sas_expander_device(parent->dev.parent)) { struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); - sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d:%d", - shost->host_no, rphy->scsi_target_id, parent->port_identifier); + dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d", + shost->host_no, rphy->scsi_target_id, + parent->port_identifier); } else - sprintf(rdev->rphy.dev.bus_id, "end_device-%d:%d", - shost->host_no, parent->port_identifier); + dev_set_name(&rdev->rphy.dev, "end_device-%d:%d", + shost->host_no, parent->port_identifier); rdev->rphy.identify.device_type = SAS_END_DEVICE; sas_rphy_initialize(&rdev->rphy); transport_setup_device(&rdev->rphy.dev); @@ -1411,8 +1413,8 @@ struct sas_rphy *sas_expander_alloc(struct sas_port *parent, mutex_lock(&sas_host->lock); rdev->rphy.scsi_target_id = sas_host->next_expander_id++; mutex_unlock(&sas_host->lock); - sprintf(rdev->rphy.dev.bus_id, "expander-%d:%d", - shost->host_no, rdev->rphy.scsi_target_id); + dev_set_name(&rdev->rphy.dev, "expander-%d:%d", + shost->host_no, rdev->rphy.scsi_target_id); rdev->rphy.identify.device_type = type; sas_rphy_initialize(&rdev->rphy); transport_setup_device(&rdev->rphy.dev); @@ -1445,7 +1447,7 @@ int sas_rphy_add(struct sas_rphy *rphy) transport_add_device(&rphy->dev); transport_configure_device(&rphy->dev); if (sas_bsg_initialize(shost, rphy)) - printk("fail to a bsg device %s\n", rphy->dev.bus_id); + printk("fail to a bsg device %s\n", dev_name(&rphy->dev)); mutex_lock(&sas_host->lock); diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 8a7af951d98..21a045e0559 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -212,7 +212,7 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, rport->roles = ids->roles; id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id); - sprintf(rport->dev.bus_id, "port-%d:%d", shost->host_no, id); + dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id); transport_setup_device(&rport->dev); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e035c111401..d57566b8be0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1830,7 +1830,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) device_initialize(&sdkp->dev); sdkp->dev.parent = &sdp->sdev_gendev; sdkp->dev.class = &sd_disk_class; - strncpy(sdkp->dev.bus_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); + dev_set_name(&sdkp->dev, dev_name(&sdp->sdev_gendev)); if (device_add(&sdkp->dev)) goto out_free_index; diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 3ebb1f28949..184dff49279 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -142,7 +142,7 @@ static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix) static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors) { struct sd_dif_tuple *sdt = prot; - char *tag = tag_buf; + u8 *tag = tag_buf; unsigned int i, j; for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { @@ -154,7 +154,7 @@ static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors) { struct sd_dif_tuple *sdt = prot; - char *tag = tag_buf; + u8 *tag = tag_buf; unsigned int i, j; for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { @@ -256,7 +256,7 @@ static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix) static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors) { struct sd_dif_tuple *sdt = prot; - char *tag = tag_buf; + u8 *tag = tag_buf; unsigned int i, j; for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) { @@ -269,7 +269,7 @@ static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors) { struct sd_dif_tuple *sdt = prot; - char *tag = tag_buf; + u8 *tag = tag_buf; unsigned int i, j; for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { @@ -374,7 +374,10 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsig else csum_convert = 0; + BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6)); + switch (scmd->cmnd[0]) { + case READ_6: case READ_10: case READ_12: case READ_16: @@ -390,6 +393,7 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsig break; + case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_16: @@ -475,8 +479,9 @@ int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_s error: kunmap_atomic(sdt, KM_USER0); - sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u\n", - __func__, virt, phys, be32_to_cpu(sdt->ref_tag)); + sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u, app %4x\n", + __func__, virt, phys, be32_to_cpu(sdt->ref_tag), + be16_to_cpu(sdt->app_tag)); return -EIO; } diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 7f0df29f3a6..e946e05db7f 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -526,7 +526,7 @@ static int ses_intf_add(struct device *cdev, if (!scomp) goto err_free; - edev = enclosure_register(cdev->parent, sdev->sdev_gendev.bus_id, + edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), components, &ses_enclosure_callbacks); if (IS_ERR(edev)) { err = PTR_ERR(edev); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 5103855242a..8f0bd3f7a59 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1669,6 +1669,8 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->pages = req_schp->pages; md->page_order = req_schp->page_order; md->nr_entries = req_schp->k_use_sg; + md->offset = 0; + md->null_mapped = hp->dxferp ? 0 : 1; } if (iov_count) diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 31fe6051c79..0807b260268 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -297,7 +297,7 @@ out: return err; } -static void __exit sgiwd93_remove(struct platform_device *pdev) +static int __exit sgiwd93_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; @@ -307,6 +307,7 @@ static void __exit sgiwd93_remove(struct platform_device *pdev) free_irq(pd->irq, host); dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); scsi_host_put(host); + return 0; } static struct platform_driver sgiwd93_driver = { diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c index d63d229e232..6dc8b846c11 100644 --- a/drivers/scsi/sim710.c +++ b/drivers/scsi/sim710.c @@ -102,7 +102,7 @@ sim710_probe_common(struct device *dev, unsigned long base_addr, struct NCR_700_Host_Parameters *hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - printk(KERN_NOTICE "sim710: %s\n", dev->bus_id); + printk(KERN_NOTICE "sim710: %s\n", dev_name(dev)); printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", irq, clock, base_addr, scsi_id); @@ -305,7 +305,7 @@ sim710_eisa_probe(struct device *dev) scsi_id = ffs(val) - 1; if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) { - printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev->bus_id); + printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev_name(dev)); scsi_id = 7; } } else { diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 2bbef4c45a0..77f0b2cdaa9 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -78,8 +78,7 @@ static int __init snirm710_probe(struct platform_device *dev) base = res->start; hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); if (!hostdata) { - printk(KERN_ERR "%s: Failed to allocate host data\n", - dev->dev.bus_id); + dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); return -ENOMEM; } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7f3f317ee6c..c6f19ee8f2c 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20080504"; +static const char *verstr = "20081215"; #include <linux/module.h> @@ -182,18 +182,16 @@ static struct scsi_tape **scsi_tapes = NULL; static int modes_defined; -static struct st_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(struct st_buffer *, int, int); static void clear_buffer(struct st_buffer *); static void normalize_buffer(struct st_buffer *); static int append_to_buffer(const char __user *, struct st_buffer *, int); static int from_buffer(struct st_buffer *, char __user *, int); static void move_buffer_data(struct st_buffer *, int); -static void buf_to_sg(struct st_buffer *, unsigned int); -static int sgl_map_user_pages(struct scatterlist *, const unsigned int, +static int sgl_map_user_pages(struct st_buffer *, const unsigned int, unsigned long, size_t, int); -static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); +static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); static int st_probe(struct device *); static int st_remove(struct device *); @@ -435,22 +433,6 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) return (-EIO); } - -/* Wakeup from interrupt */ -static void st_sleep_done(void *data, char *sense, int result, int resid) -{ - struct st_request *SRpnt = data; - struct scsi_tape *STp = SRpnt->stp; - - memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); - (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; - (STp->buffer)->cmdstat.residual = resid; - DEB( STp->write_pending = 0; ) - - if (SRpnt->waiting) - complete(SRpnt->waiting); -} - static struct st_request *st_allocate_request(struct scsi_tape *stp) { struct st_request *streq; @@ -475,6 +457,63 @@ static void st_release_request(struct st_request *streq) kfree(streq); } +static void st_scsi_execute_end(struct request *req, int uptodate) +{ + struct st_request *SRpnt = req->end_io_data; + struct scsi_tape *STp = SRpnt->stp; + + STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; + STp->buffer->cmdstat.residual = req->data_len; + + if (SRpnt->waiting) + complete(SRpnt->waiting); + + blk_rq_unmap_user(SRpnt->bio); + __blk_put_request(req->q, req); +} + +static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + int timeout, int retries) +{ + struct request *req; + struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; + int err = 0; + int write = (data_direction == DMA_TO_DEVICE); + + req = blk_get_request(SRpnt->stp->device->request_queue, write, + GFP_KERNEL); + if (!req) + return DRIVER_ERROR << 24; + + req->cmd_type = REQ_TYPE_BLOCK_PC; + req->cmd_flags |= REQ_QUIET; + + mdata->null_mapped = 1; + + if (bufflen) { + err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, + GFP_KERNEL); + if (err) { + blk_put_request(req); + return DRIVER_ERROR << 24; + } + } + + SRpnt->bio = req->bio; + req->cmd_len = COMMAND_SIZE(cmd[0]); + memset(req->cmd, 0, BLK_MAX_CDB); + memcpy(req->cmd, cmd, req->cmd_len); + req->sense = SRpnt->sense; + req->sense_len = 0; + req->timeout = timeout; + req->retries = retries; + req->end_io_data = SRpnt; + + blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end); + return 0; +} + /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise write_behind_check() is used to check that the command has finished. */ @@ -483,6 +522,8 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd int bytes, int direction, int timeout, int retries, int do_wait) { struct completion *waiting; + struct rq_map_data *mdata = &STp->buffer->map_data; + int ret; /* if async, make sure there's no command outstanding */ if (!do_wait && ((STp->buffer)->last_SRpnt)) { @@ -510,21 +551,27 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd init_completion(waiting); SRpnt->waiting = waiting; - if (!STp->buffer->do_dio) - buf_to_sg(STp->buffer, bytes); + if (STp->buffer->do_dio) { + mdata->nr_entries = STp->buffer->sg_segs; + mdata->pages = STp->buffer->mapped_pages; + } else { + mdata->nr_entries = + DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order); + STp->buffer->map_data.pages = STp->buffer->reserved_pages; + STp->buffer->map_data.offset = 0; + } memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); STp->buffer->cmdstat.have_sense = 0; STp->buffer->syscall_result = 0; - if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, - &((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs, - timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) { + ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout, + retries); + if (ret) { /* could not allocate the buffer or request was too large */ (STp->buffer)->syscall_result = (-EBUSY); (STp->buffer)->last_SRpnt = NULL; - } - else if (do_wait) { + } else if (do_wait) { wait_for_completion(waiting); SRpnt->waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); @@ -533,28 +580,6 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd return SRpnt; } -static int st_scsi_kern_execute(struct st_request *streq, - const unsigned char *cmd, int data_direction, - void *buffer, unsigned bufflen, int timeout, - int retries) -{ - struct scsi_tape *stp = streq->stp; - int ret, resid; - - stp->buffer->cmdstat.have_sense = 0; - memcpy(streq->cmd, cmd, sizeof(streq->cmd)); - - ret = scsi_execute(stp->device, cmd, data_direction, buffer, bufflen, - streq->sense, timeout, retries, 0, &resid); - if (driver_byte(ret) & DRIVER_ERROR) - return -EBUSY; - - stp->buffer->cmdstat.midlevel_result = streq->result = ret; - stp->buffer->cmdstat.residual = resid; - stp->buffer->syscall_result = st_chk_result(stp, streq); - - return 0; -} /* Handle the write-behind checking (waits for completion). Returns -ENOSPC if write has been correct but EOM early warning reached, -EIO if write ended in @@ -627,7 +652,6 @@ static int cross_eof(struct scsi_tape * STp, int forward) { struct st_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; - int ret; cmd[0] = SPACE; cmd[1] = 0x01; /* Space FileMarks */ @@ -641,26 +665,20 @@ static int cross_eof(struct scsi_tape * STp, int forward) DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n", tape_name(STp), forward ? "forward" : "backward")); - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, + STp->device->request_queue->rq_timeout, + MAX_RETRIES, 1); if (!SRpnt) - return STp->buffer->syscall_result; - - ret = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0, - STp->device->request_queue->rq_timeout, - MAX_RETRIES); - if (ret) - goto out; + return (STp->buffer)->syscall_result; - ret = STp->buffer->syscall_result; + st_release_request(SRpnt); + SRpnt = NULL; if ((STp->buffer)->cmdstat.midlevel_result != 0) printk(KERN_ERR "%s: Stepping over filemark %s failed.\n", tape_name(STp), forward ? "forward" : "backward"); -out: - st_release_request(SRpnt); - - return ret; + return (STp->buffer)->syscall_result; } @@ -881,24 +899,21 @@ static int test_ready(struct scsi_tape *STp, int do_wait) int attentions, waits, max_wait, scode; int retval = CHKRES_READY, new_session = 0; unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; + struct st_request *SRpnt = NULL; struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - SRpnt = st_allocate_request(STp); - if (!SRpnt) - return STp->buffer->syscall_result; - max_wait = do_wait ? ST_BLOCK_SECONDS : 0; for (attentions=waits=0; ; ) { memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; + SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, + STp->long_timeout, MAX_READY_RETRIES, 1); - retval = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0, - STp->long_timeout, - MAX_READY_RETRIES); - if (retval) + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; break; + } if (cmdstatp->have_sense) { @@ -942,8 +957,8 @@ static int test_ready(struct scsi_tape *STp, int do_wait) break; } - st_release_request(SRpnt); - + if (SRpnt != NULL) + st_release_request(SRpnt); return retval; } @@ -1020,24 +1035,17 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) } } - SRpnt = st_allocate_request(STp); - if (!SRpnt) { - retval = STp->buffer->syscall_result; - goto err_out; - } - if (STp->omit_blklims) STp->min_block = STp->max_block = (-1); else { memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); cmd[0] = READ_BLOCK_LIMITS; - retval = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE, - STp->buffer->b_data, 6, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES); - if (retval) { - st_release_request(SRpnt); + SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE, + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; goto err_out; } @@ -1061,12 +1069,11 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) cmd[0] = MODE_SENSE; cmd[4] = 12; - retval = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE, - STp->buffer->b_data, 12, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES); - if (retval) { - st_release_request(SRpnt); + SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE, + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); + if (!SRpnt) { + retval = (STp->buffer)->syscall_result; goto err_out; } @@ -1296,17 +1303,11 @@ static int st_flush(struct file *filp, fl_owner_t id) cmd[0] = WRITE_FILEMARKS; cmd[4] = 1 + STp->two_fm; - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, + STp->device->request_queue->rq_timeout, + MAX_WRITE_RETRIES, 1); if (!SRpnt) { - result = STp->buffer->syscall_result; - goto out; - } - - result = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0, - STp->device->request_queue->rq_timeout, - MAX_WRITE_RETRIES); - if (result) { - st_release_request(SRpnt); + result = (STp->buffer)->syscall_result; goto out; } @@ -1471,8 +1472,8 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, if (i && ((unsigned long)buf & queue_dma_alignment( STp->device->request_queue)) == 0) { - i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg, - (unsigned long)buf, count, (is_read ? READ : WRITE)); + i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf, + count, (is_read ? READ : WRITE)); if (i > 0) { STbp->do_dio = i; STbp->buffer_bytes = 0; /* can be used as transfer counter */ @@ -1480,7 +1481,6 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, else STbp->do_dio = 0; /* fall back to buffering with any error */ STbp->sg_segs = STbp->do_dio; - STbp->frp_sg_current = 0; DEB( if (STbp->do_dio) { STp->nbr_dio++; @@ -1526,7 +1526,7 @@ static void release_buffering(struct scsi_tape *STp, int is_read) STbp = STp->buffer; if (STbp->do_dio) { - sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read); + sgl_unmap_user_pages(STbp, STbp->do_dio, is_read); STbp->do_dio = 0; STbp->sg_segs = 0; } @@ -2372,7 +2372,6 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) { unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; - int ret; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SENSE; @@ -2381,17 +2380,14 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) cmd[2] = page; cmd[4] = 255; - SRpnt = st_allocate_request(STp); - if (!SRpnt) - return STp->buffer->syscall_result; + SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE, + STp->device->request_queue->rq_timeout, 0, 1); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; - ret = st_scsi_kern_execute(SRpnt, cmd, DMA_FROM_DEVICE, - STp->buffer->b_data, cmd[4], - STp->device->request_queue->rq_timeout, - MAX_RETRIES); st_release_request(SRpnt); - return ret ? : STp->buffer->syscall_result; + return STp->buffer->syscall_result; } @@ -2399,9 +2395,10 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */ static int write_mode_page(struct scsi_tape *STp, int page, int slow) { - int pgo, timeout, ret = 0; + int pgo; unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; + int timeout; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; @@ -2415,21 +2412,16 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow) (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP; (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; - SRpnt = st_allocate_request(STp); - if (!SRpnt) - return ret; - - timeout = slow ? STp->long_timeout : - STp->device->request_queue->rq_timeout; - - ret = st_scsi_kern_execute(SRpnt, cmd, DMA_TO_DEVICE, - STp->buffer->b_data, cmd[4], timeout, 0); - if (!ret) - ret = STp->buffer->syscall_result; + timeout = slow ? + STp->long_timeout : STp->device->request_queue->rq_timeout; + SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE, + timeout, 0, 1); + if (SRpnt == NULL) + return (STp->buffer)->syscall_result; st_release_request(SRpnt); - return ret; + return STp->buffer->syscall_result; } @@ -2547,16 +2539,13 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod printk(ST_DEB_MSG "%s: Loading tape.\n", name); ); - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, + timeout, MAX_RETRIES, 1); if (!SRpnt) - return STp->buffer->syscall_result; - - retval = st_scsi_kern_execute(SRpnt, cmd, DMA_NONE, NULL, 0, timeout, - MAX_RETRIES); - if (retval) - goto out; + return (STp->buffer)->syscall_result; retval = (STp->buffer)->syscall_result; + st_release_request(SRpnt); if (!retval) { /* SCSI command successful */ @@ -2575,8 +2564,6 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod STps = &(STp->ps[STp->partition]); STps->drv_file = STps->drv_block = (-1); } -out: - st_release_request(SRpnt); return retval; } @@ -2852,15 +2839,12 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon return (-ENOSYS); } - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction, + timeout, MAX_RETRIES, 1); if (!SRpnt) return (STp->buffer)->syscall_result; - ioctl_result = st_scsi_kern_execute(SRpnt, cmd, direction, - STp->buffer->b_data, datalen, - timeout, MAX_RETRIES); - if (!ioctl_result) - ioctl_result = (STp->buffer)->syscall_result; + ioctl_result = (STp->buffer)->syscall_result; if (!ioctl_result) { /* SCSI command successful */ st_release_request(SRpnt); @@ -3022,17 +3006,11 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti if (!logical && !STp->scsi2_logical) scmd[1] = 1; } - - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE, + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); if (!SRpnt) - return STp->buffer->syscall_result; - - result = st_scsi_kern_execute(SRpnt, scmd, DMA_FROM_DEVICE, - STp->buffer->b_data, 20, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES); - if (result) - goto out; + return (STp->buffer)->syscall_result; if ((STp->buffer)->syscall_result != 0 || (STp->device->scsi_level >= SCSI_2 && @@ -3060,7 +3038,6 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name, *block, *partition)); } -out: st_release_request(SRpnt); SRpnt = NULL; @@ -3135,14 +3112,10 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition timeout = STp->device->request_queue->rq_timeout; } - SRpnt = st_allocate_request(STp); + SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, + timeout, MAX_READY_RETRIES, 1); if (!SRpnt) - return STp->buffer->syscall_result; - - result = st_scsi_kern_execute(SRpnt, scmd, DMA_NONE, NULL, 0, - timeout, MAX_READY_RETRIES); - if (result) - goto out; + return (STp->buffer)->syscall_result; STps->drv_block = STps->drv_file = (-1); STps->eof = ST_NOEOF; @@ -3167,7 +3140,7 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition STps->drv_block = STps->drv_file = 0; result = 0; } -out: + st_release_request(SRpnt); SRpnt = NULL; @@ -3696,38 +3669,34 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a /* Try to allocate a new tape buffer. Calling function must not hold dev_arr_lock. */ -static struct st_buffer * - new_tape_buffer(int from_initialization, int need_dma, int max_sg) +static struct st_buffer *new_tape_buffer(int need_dma, int max_sg) { - int i, got = 0; - gfp_t priority; struct st_buffer *tb; - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) + - max_sg * sizeof(struct st_buf_fragment); - tb = kzalloc(i, priority); + tb = kzalloc(sizeof(struct st_buffer), GFP_ATOMIC); if (!tb) { printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); return NULL; } - tb->frp_segs = tb->orig_frp_segs = 0; + tb->frp_segs = 0; tb->use_sg = max_sg; - tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); - tb->dma = need_dma; - tb->buffer_size = got; - sg_init_table(tb->sg, max_sg); + tb->buffer_size = 0; + + tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *), + GFP_ATOMIC); + if (!tb->reserved_pages) { + kfree(tb); + return NULL; + } return tb; } /* Try to allocate enough space in the tape buffer */ +#define ST_MAX_ORDER 6 + static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) { int segs, nbr, max_segs, b_size, order, got; @@ -3747,33 +3716,45 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm priority = GFP_KERNEL | __GFP_NOWARN; if (need_dma) priority |= GFP_DMA; - for (b_size = PAGE_SIZE, order=0; order <= 6 && - b_size < new_size - STbuffer->buffer_size; - order++, b_size *= 2) - ; /* empty */ + + if (STbuffer->cleared) + priority |= __GFP_ZERO; + + if (STbuffer->frp_segs) { + order = STbuffer->map_data.page_order; + b_size = PAGE_SIZE << order; + } else { + for (b_size = PAGE_SIZE, order = 0; + order < ST_MAX_ORDER && b_size < new_size; + order++, b_size *= 2) + ; /* empty */ + } + if (max_segs * (PAGE_SIZE << order) < new_size) { + if (order == ST_MAX_ORDER) + return 0; + normalize_buffer(STbuffer); + return enlarge_buffer(STbuffer, new_size, need_dma); + } for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; segs < max_segs && got < new_size;) { - STbuffer->frp[segs].page = alloc_pages(priority, order); - if (STbuffer->frp[segs].page == NULL) { - if (new_size - got <= (max_segs - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ - order--; - continue; - } + struct page *page; + + page = alloc_pages(priority, order); + if (!page) { DEB(STbuffer->buffer_size = got); normalize_buffer(STbuffer); return 0; } - STbuffer->frp[segs].length = b_size; + STbuffer->frp_segs += 1; got += b_size; STbuffer->buffer_size = got; - if (STbuffer->cleared) - memset(page_address(STbuffer->frp[segs].page), 0, b_size); + STbuffer->reserved_pages[segs] = page; segs++; } - STbuffer->b_data = page_address(STbuffer->frp[0].page); + STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); + STbuffer->map_data.page_order = order; return 1; } @@ -3785,7 +3766,8 @@ static void clear_buffer(struct st_buffer * st_bp) int i; for (i=0; i < st_bp->frp_segs; i++) - memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); + memset(page_address(st_bp->reserved_pages[i]), 0, + PAGE_SIZE << st_bp->map_data.page_order); st_bp->cleared = 1; } @@ -3793,16 +3775,16 @@ static void clear_buffer(struct st_buffer * st_bp) /* Release the extra buffer */ static void normalize_buffer(struct st_buffer * STbuffer) { - int i, order; + int i, order = STbuffer->map_data.page_order; - for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) { - order = get_order(STbuffer->frp[i].length); - __free_pages(STbuffer->frp[i].page, order); - STbuffer->buffer_size -= STbuffer->frp[i].length; + for (i = 0; i < STbuffer->frp_segs; i++) { + __free_pages(STbuffer->reserved_pages[i], order); + STbuffer->buffer_size -= (PAGE_SIZE << order); } - STbuffer->frp_segs = STbuffer->orig_frp_segs; - STbuffer->frp_sg_current = 0; + STbuffer->frp_segs = 0; STbuffer->sg_segs = 0; + STbuffer->map_data.page_order = 0; + STbuffer->map_data.offset = 0; } @@ -3811,18 +3793,19 @@ static void normalize_buffer(struct st_buffer * STbuffer) static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->map_data.page_order; for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_from_user(page_address(page) + offset, ubp, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3842,18 +3825,19 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->map_data.page_order; for (i = 0, offset = st_bp->read_pointer; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: from_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_to_user(ubp, page_address(page) + offset, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3874,6 +3858,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) { int src_seg, dst_seg, src_offset = 0, dst_offset; int count, total; + int length = PAGE_SIZE << st_bp->map_data.page_order; if (offset == 0) return; @@ -3881,24 +3866,26 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) total=st_bp->buffer_bytes - offset; for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { src_offset = offset; - if (src_offset < st_bp->frp[src_seg].length) + if (src_offset < length) break; - offset -= st_bp->frp[src_seg].length; + offset -= length; } st_bp->buffer_bytes = st_bp->read_pointer = total; for (dst_seg=dst_offset=0; total > 0; ) { - count = min(st_bp->frp[dst_seg].length - dst_offset, - st_bp->frp[src_seg].length - src_offset); - memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset, - page_address(st_bp->frp[src_seg].page) + src_offset, count); + struct page *dpage = st_bp->reserved_pages[dst_seg]; + struct page *spage = st_bp->reserved_pages[src_seg]; + + count = min(length - dst_offset, length - src_offset); + memmove(page_address(dpage) + dst_offset, + page_address(spage) + src_offset, count); src_offset += count; - if (src_offset >= st_bp->frp[src_seg].length) { + if (src_offset >= length) { src_seg++; src_offset = 0; } dst_offset += count; - if (dst_offset >= st_bp->frp[dst_seg].length) { + if (dst_offset >= length) { dst_seg++; dst_offset = 0; } @@ -3906,32 +3893,6 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) } } - -/* Fill the s/g list up to the length required for this transfer */ -static void buf_to_sg(struct st_buffer *STbp, unsigned int length) -{ - int i; - unsigned int count; - struct scatterlist *sg; - struct st_buf_fragment *frp; - - if (length == STbp->frp_sg_current) - return; /* work already done */ - - sg = &(STbp->sg[0]); - frp = STbp->frp; - for (i=count=0; count < length; i++) { - if (length - count > frp[i].length) - sg_set_page(&sg[i], frp[i].page, frp[i].length, 0); - else - sg_set_page(&sg[i], frp[i].page, length - count, 0); - count += sg[i].length; - } - STbp->sg_segs = i; - STbp->frp_sg_current = length; -} - - /* Validate the options from command line or module parameters */ static void validate_options(void) { @@ -4026,7 +3987,7 @@ static int st_probe(struct device *dev) SDp->request_queue->max_phys_segments); if (st_max_sg_segs < i) i = st_max_sg_segs; - buffer = new_tape_buffer(1, (SDp->host)->unchecked_isa_dma, i); + buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i); if (buffer == NULL) { printk(KERN_ERR "st: Can't allocate new tape buffer. Device not attached.\n"); @@ -4280,8 +4241,8 @@ static void scsi_tape_release(struct kref *kref) tpnt->device = NULL; if (tpnt->buffer) { - tpnt->buffer->orig_frp_segs = 0; normalize_buffer(tpnt->buffer); + kfree(tpnt->buffer->reserved_pages); kfree(tpnt->buffer); } @@ -4567,14 +4528,16 @@ out: } /* The following functions may be useful for a larger audience. */ -static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, - unsigned long uaddr, size_t count, int rw) +static int sgl_map_user_pages(struct st_buffer *STbp, + const unsigned int max_pages, unsigned long uaddr, + size_t count, int rw) { unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long start = uaddr >> PAGE_SHIFT; const int nr_pages = end - start; int res, i, j; struct page **pages; + struct rq_map_data *mdata = &STbp->map_data; /* User attempted Overflow! */ if ((uaddr + count) < uaddr) @@ -4616,24 +4579,11 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa flush_dcache_page(pages[i]); } - /* Populate the scatter/gather list */ - sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK); - if (nr_pages > 1) { - sgl[0].length = PAGE_SIZE - sgl[0].offset; - count -= sgl[0].length; - for (i=1; i < nr_pages ; i++) { - sg_set_page(&sgl[i], pages[i], - count < PAGE_SIZE ? count : PAGE_SIZE, 0);; - count -= PAGE_SIZE; - } - } - else { - sgl[0].length = count; - } + mdata->offset = uaddr & ~PAGE_MASK; + mdata->page_order = 0; + STbp->mapped_pages = pages; - kfree(pages); return nr_pages; - out_unmap: if (res > 0) { for (j=0; j < res; j++) @@ -4646,13 +4596,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa /* And unmap them... */ -static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, - int dirtied) +static int sgl_unmap_user_pages(struct st_buffer *STbp, + const unsigned int nr_pages, int dirtied) { int i; for (i=0; i < nr_pages; i++) { - struct page *page = sg_page(&sgl[i]); + struct page *page = STbp->mapped_pages[i]; if (dirtied) SetPageDirty(page); @@ -4661,6 +4611,8 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p */ page_cache_release(page); } + kfree(STbp->mapped_pages); + STbp->mapped_pages = NULL; return 0; } diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index b92712f9593..544dc6b1f54 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -29,6 +29,7 @@ struct st_request { int result; struct scsi_tape *stp; struct completion *waiting; + struct bio *bio; }; /* The tape buffer descriptor. */ @@ -44,20 +45,13 @@ struct st_buffer { int syscall_result; struct st_request *last_SRpnt; struct st_cmdstatus cmdstat; + struct page **reserved_pages; + struct page **mapped_pages; + struct rq_map_data map_data; unsigned char *b_data; unsigned short use_sg; /* zero or max number of s/g segments for this adapter */ unsigned short sg_segs; /* number of segments in s/g list */ - unsigned short orig_frp_segs; /* number of segments allocated at first try */ unsigned short frp_segs; /* number of buffer segments */ - unsigned int frp_sg_current; /* driver buffer length currently in s/g list */ - struct st_buf_fragment *frp; /* the allocated buffer fragment list */ - struct scatterlist sg[1]; /* MUST BE last item */ -}; - -/* The tape buffer fragment descriptor */ -struct st_buf_fragment { - struct page *page; - unsigned int length; }; /* The tape mode definition */ diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c index 3c4a300494a..a8d61a62522 100644 --- a/drivers/scsi/zalon.c +++ b/drivers/scsi/zalon.c @@ -137,8 +137,8 @@ zalon_probe(struct parisc_device *dev) goto fail; if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { - printk(KERN_ERR "%s: irq problem with %d, detaching\n ", - dev->dev.bus_id, dev->irq); + dev_printk(KERN_ERR, dev, "irq problem with %d, detaching\n ", + dev->irq); goto fail; } diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 1889a63ebc2..0d934bfbdd9 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2839,6 +2839,8 @@ int __init early_serial_setup(struct uart_port *port) p->flags = port->flags; p->mapbase = port->mapbase; p->private_data = port->private_data; + p->type = port->type; + p->line = port->line; set_io_from_upio(p); if (port->serial_in) diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b695ab3142d..3e525e38a5d 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -457,7 +457,7 @@ config SERIAL_SAMSUNG config SERIAL_SAMSUNG_UARTS int - depends on SERIAL_SAMSUNG + depends on ARM && PLAT_S3C default 2 if ARCH_S3C2400 default 4 if ARCH_S3C64XX || CPU_S3C2443 default 3 @@ -1320,13 +1320,30 @@ config SERIAL_NETX_CONSOLE config SERIAL_OF_PLATFORM tristate "Serial port on Open Firmware platform bus" depends on PPC_OF - depends on SERIAL_8250 + depends on SERIAL_8250 || SERIAL_OF_PLATFORM_NWPSERIAL help If you have a PowerPC based system that has serial ports on a platform specific bus, you should enable this option. Currently, only 8250 compatible ports are supported, but others can easily be added. +config SERIAL_OF_PLATFORM_NWPSERIAL + tristate "NWP serial port driver" + depends on PPC_OF && PPC_DCR + select SERIAL_OF_PLATFORM + select SERIAL_CORE_CONSOLE + select SERIAL_CORE + help + This driver supports the cell network processor nwp serial + device. + +config SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE + bool "Console on NWP serial port" + depends on SERIAL_OF_PLATFORM_NWPSERIAL=y + select SERIAL_CORE_CONSOLE + help + Support for Console on the NWP serial ports. + config SERIAL_QE tristate "Freescale QUICC Engine serial port support" depends on QUICC_ENGINE diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index dfe775ac45b..8844c0a0392 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -72,6 +72,7 @@ obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += of_serial.o +obj-$(CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL) += nwpserial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o obj-$(CONFIG_SERIAL_QE) += ucc_uart.o diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c index b7584ca55ad..e6390d02363 100644 --- a/drivers/serial/jsm/jsm_neo.c +++ b/drivers/serial/jsm/jsm_neo.c @@ -577,9 +577,6 @@ static void neo_parse_modem(struct jsm_channel *ch, u8 signals) jsm_printk(MSIGS, INFO, &ch->ch_bd->pci_dev, "neo_parse_modem: port: %d msignals: %x\n", ch->ch_portnum, msignals); - if (!ch) - return; - /* Scrub off lower bits. They signify delta's, which I don't care about */ /* Keep DDCD and DDSR though */ msignals &= 0xf8; diff --git a/drivers/serial/nwpserial.c b/drivers/serial/nwpserial.c new file mode 100644 index 00000000000..32f3eaf0d26 --- /dev/null +++ b/drivers/serial/nwpserial.c @@ -0,0 +1,475 @@ +/* + * Serial Port driver for a NWP uart device + * + * Copyright (C) 2008 IBM Corp., Benjamin Krill <ben@codiert.org> + * + * 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 <linux/init.h> +#include <linux/console.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/irqreturn.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> +#include <linux/of_device.h> +#include <linux/nwpserial.h> +#include <asm/prom.h> +#include <asm/dcr.h> + +#define NWPSERIAL_NR 2 + +#define NWPSERIAL_STATUS_RXVALID 0x1 +#define NWPSERIAL_STATUS_TXFULL 0x2 + +struct nwpserial_port { + struct uart_port port; + dcr_host_t dcr_host; + unsigned int ier; + unsigned int mcr; +}; + +static DEFINE_MUTEX(nwpserial_mutex); +static struct nwpserial_port nwpserial_ports[NWPSERIAL_NR]; + +static void wait_for_bits(struct nwpserial_port *up, int bits) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = dcr_read(up->dcr_host, UART_LSR); + + if (--tmout == 0) + break; + udelay(1); + } while ((status & bits) != bits); +} + +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE +static void nwpserial_console_putchar(struct uart_port *port, int c) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + /* check if tx buffer is full */ + wait_for_bits(up, UART_LSR_THRE); + dcr_write(up->dcr_host, UART_TX, c); + up->port.icount.tx++; +} + +static void +nwpserial_console_write(struct console *co, const char *s, unsigned int count) +{ + struct nwpserial_port *up = &nwpserial_ports[co->index]; + unsigned long flags; + int locked = 1; + + if (oops_in_progress) + locked = spin_trylock_irqsave(&up->port.lock, flags); + else + spin_lock_irqsave(&up->port.lock, flags); + + /* save and disable interrupt */ + up->ier = dcr_read(up->dcr_host, UART_IER); + dcr_write(up->dcr_host, UART_IER, up->ier & ~UART_IER_RDI); + + uart_console_write(&up->port, s, count, nwpserial_console_putchar); + + /* wait for transmitter to become emtpy */ + while ((dcr_read(up->dcr_host, UART_LSR) & UART_LSR_THRE) == 0) + cpu_relax(); + + /* restore interrupt state */ + dcr_write(up->dcr_host, UART_IER, up->ier); + + if (locked) + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static struct uart_driver nwpserial_reg; +static struct console nwpserial_console = { + .name = "ttySQ", + .write = nwpserial_console_write, + .device = uart_console_device, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &nwpserial_reg, +}; +#define NWPSERIAL_CONSOLE (&nwpserial_console) +#else +#define NWPSERIAL_CONSOLE NULL +#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ + +/**************************************************************************/ + +static int nwpserial_request_port(struct uart_port *port) +{ + return 0; +} + +static void nwpserial_release_port(struct uart_port *port) +{ + /* N/A */ +} + +static void nwpserial_config_port(struct uart_port *port, int flags) +{ + port->type = PORT_NWPSERIAL; +} + +static irqreturn_t nwpserial_interrupt(int irq, void *dev_id) +{ + struct nwpserial_port *up = dev_id; + struct tty_struct *tty = up->port.info->port.tty; + irqreturn_t ret; + unsigned int iir; + unsigned char ch; + + spin_lock(&up->port.lock); + + /* check if the uart was the interrupt source. */ + iir = dcr_read(up->dcr_host, UART_IIR); + if (!iir) { + ret = IRQ_NONE; + goto out; + } + + do { + up->port.icount.rx++; + ch = dcr_read(up->dcr_host, UART_RX); + if (up->port.ignore_status_mask != NWPSERIAL_STATUS_RXVALID) + tty_insert_flip_char(tty, ch, TTY_NORMAL); + } while (dcr_read(up->dcr_host, UART_RX) & UART_LSR_DR); + + tty_flip_buffer_push(tty); + ret = IRQ_HANDLED; + +out: + spin_unlock(&up->port.lock); + return ret; +} + +static int nwpserial_startup(struct uart_port *port) +{ + struct nwpserial_port *up; + int err; + + up = container_of(port, struct nwpserial_port, port); + + /* disable flow control by default */ + up->mcr = dcr_read(up->dcr_host, UART_MCR) & ~UART_MCR_AFE; + dcr_write(up->dcr_host, UART_MCR, up->mcr); + + /* register interrupt handler */ + err = request_irq(up->port.irq, nwpserial_interrupt, + IRQF_SHARED, "nwpserial", up); + if (err) + return err; + + /* enable interrupts */ + up->ier = UART_IER_RDI; + dcr_write(up->dcr_host, UART_IER, up->ier); + + /* enable receiving */ + up->port.ignore_status_mask &= ~NWPSERIAL_STATUS_RXVALID; + + return 0; +} + +static void nwpserial_shutdown(struct uart_port *port) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + + /* disable receiving */ + up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; + + /* disable interrupts from this port */ + up->ier = 0; + dcr_write(up->dcr_host, UART_IER, up->ier); + + /* free irq */ + free_irq(up->port.irq, port); +} + +static int nwpserial_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + return -EINVAL; +} + +static const char *nwpserial_type(struct uart_port *port) +{ + return port->type == PORT_NWPSERIAL ? "nwpserial" : NULL; +} + +static void nwpserial_set_termios(struct uart_port *port, + struct ktermios *termios, struct ktermios *old) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + + up->port.read_status_mask = NWPSERIAL_STATUS_RXVALID + | NWPSERIAL_STATUS_TXFULL; + + up->port.ignore_status_mask = 0; + /* ignore all characters if CREAD is not set */ + if ((termios->c_cflag & CREAD) == 0) + up->port.ignore_status_mask |= NWPSERIAL_STATUS_RXVALID; + + /* Copy back the old hardware settings */ + if (old) + tty_termios_copy_hw(termios, old); +} + +static void nwpserial_break_ctl(struct uart_port *port, int ctl) +{ + /* N/A */ +} + +static void nwpserial_enable_ms(struct uart_port *port) +{ + /* N/A */ +} + +static void nwpserial_stop_rx(struct uart_port *port) +{ + struct nwpserial_port *up; + up = container_of(port, struct nwpserial_port, port); + /* don't forward any more data (like !CREAD) */ + up->port.ignore_status_mask = NWPSERIAL_STATUS_RXVALID; +} + +static void nwpserial_putchar(struct nwpserial_port *up, unsigned char c) +{ + /* check if tx buffer is full */ + wait_for_bits(up, UART_LSR_THRE); + dcr_write(up->dcr_host, UART_TX, c); + up->port.icount.tx++; +} + +static void nwpserial_start_tx(struct uart_port *port) +{ + struct nwpserial_port *up; + struct circ_buf *xmit; + up = container_of(port, struct nwpserial_port, port); + xmit = &up->port.info->xmit; + + if (port->x_char) { + nwpserial_putchar(up, up->port.x_char); + port->x_char = 0; + } + + while (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port))) { + nwpserial_putchar(up, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + } +} + +static unsigned int nwpserial_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void nwpserial_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + /* N/A */ +} + +static void nwpserial_stop_tx(struct uart_port *port) +{ + /* N/A */ +} + +static unsigned int nwpserial_tx_empty(struct uart_port *port) +{ + struct nwpserial_port *up; + unsigned long flags; + int ret; + up = container_of(port, struct nwpserial_port, port); + + spin_lock_irqsave(&up->port.lock, flags); + ret = dcr_read(up->dcr_host, UART_LSR); + spin_unlock_irqrestore(&up->port.lock, flags); + + return ret & UART_LSR_TEMT ? TIOCSER_TEMT : 0; +} + +static struct uart_ops nwpserial_pops = { + .tx_empty = nwpserial_tx_empty, + .set_mctrl = nwpserial_set_mctrl, + .get_mctrl = nwpserial_get_mctrl, + .stop_tx = nwpserial_stop_tx, + .start_tx = nwpserial_start_tx, + .stop_rx = nwpserial_stop_rx, + .enable_ms = nwpserial_enable_ms, + .break_ctl = nwpserial_break_ctl, + .startup = nwpserial_startup, + .shutdown = nwpserial_shutdown, + .set_termios = nwpserial_set_termios, + .type = nwpserial_type, + .release_port = nwpserial_release_port, + .request_port = nwpserial_request_port, + .config_port = nwpserial_config_port, + .verify_port = nwpserial_verify_port, +}; + +static struct uart_driver nwpserial_reg = { + .owner = THIS_MODULE, + .driver_name = "nwpserial", + .dev_name = "ttySQ", + .major = TTY_MAJOR, + .minor = 68, + .nr = NWPSERIAL_NR, + .cons = NWPSERIAL_CONSOLE, +}; + +int nwpserial_register_port(struct uart_port *port) +{ + struct nwpserial_port *up = NULL; + int ret = -1; + int i; + static int first = 1; + int dcr_len; + int dcr_base; + struct device_node *dn; + + mutex_lock(&nwpserial_mutex); + + dn = to_of_device(port->dev)->node; + if (dn == NULL) + goto out; + + /* get dcr base. */ + dcr_base = dcr_resource_start(dn, 0); + + /* find matching entry */ + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.iobase == dcr_base) { + up = &nwpserial_ports[i]; + break; + } + + /* we didn't find a mtching entry, search for a free port */ + if (up == NULL) + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.type == PORT_UNKNOWN && + nwpserial_ports[i].port.iobase == 0) { + up = &nwpserial_ports[i]; + break; + } + + if (up == NULL) { + ret = -EBUSY; + goto out; + } + + if (first) + uart_register_driver(&nwpserial_reg); + first = 0; + + up->port.membase = port->membase; + up->port.irq = port->irq; + up->port.uartclk = port->uartclk; + up->port.fifosize = port->fifosize; + up->port.regshift = port->regshift; + up->port.iotype = port->iotype; + up->port.flags = port->flags; + up->port.mapbase = port->mapbase; + up->port.private_data = port->private_data; + + if (port->dev) + up->port.dev = port->dev; + + if (up->port.iobase != dcr_base) { + up->port.ops = &nwpserial_pops; + up->port.fifosize = 16; + + spin_lock_init(&up->port.lock); + + up->port.iobase = dcr_base; + dcr_len = dcr_resource_len(dn, 0); + + up->dcr_host = dcr_map(dn, dcr_base, dcr_len); + if (!DCR_MAP_OK(up->dcr_host)) { + printk(KERN_ERR "Cannot map DCR resources for NWPSERIAL"); + goto out; + } + } + + ret = uart_add_one_port(&nwpserial_reg, &up->port); + if (ret == 0) + ret = up->port.line; + +out: + mutex_unlock(&nwpserial_mutex); + + return ret; +} +EXPORT_SYMBOL(nwpserial_register_port); + +void nwpserial_unregister_port(int line) +{ + struct nwpserial_port *up = &nwpserial_ports[line]; + mutex_lock(&nwpserial_mutex); + uart_remove_one_port(&nwpserial_reg, &up->port); + + up->port.type = PORT_UNKNOWN; + + mutex_unlock(&nwpserial_mutex); +} +EXPORT_SYMBOL(nwpserial_unregister_port); + +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE +static int __init nwpserial_console_init(void) +{ + struct nwpserial_port *up = NULL; + struct device_node *dn; + const char *name; + int dcr_base; + int dcr_len; + int i; + + /* search for a free port */ + for (i = 0; i < NWPSERIAL_NR; i++) + if (nwpserial_ports[i].port.type == PORT_UNKNOWN) { + up = &nwpserial_ports[i]; + break; + } + + if (up == NULL) + return -1; + + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (name == NULL) + return -1; + + dn = of_find_node_by_path(name); + if (!dn) + return -1; + + spin_lock_init(&up->port.lock); + up->port.ops = &nwpserial_pops; + up->port.type = PORT_NWPSERIAL; + up->port.fifosize = 16; + + dcr_base = dcr_resource_start(dn, 0); + dcr_len = dcr_resource_len(dn, 0); + up->port.iobase = dcr_base; + + up->dcr_host = dcr_map(dn, dcr_base, dcr_len); + if (!DCR_MAP_OK(up->dcr_host)) { + printk("Cannot map DCR resources for SERIAL"); + return -1; + } + register_console(&nwpserial_console); + return 0; +} +console_initcall(nwpserial_console_init); +#endif /* CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL_CONSOLE */ diff --git a/drivers/serial/of_serial.c b/drivers/serial/of_serial.c index 8fa0ff561e9..a821e3a3d66 100644 --- a/drivers/serial/of_serial.c +++ b/drivers/serial/of_serial.c @@ -14,6 +14,7 @@ #include <linux/serial_core.h> #include <linux/serial_8250.h> #include <linux/of_platform.h> +#include <linux/nwpserial.h> #include <asm/prom.h> @@ -99,9 +100,16 @@ static int __devinit of_platform_serial_probe(struct of_device *ofdev, goto out; switch (port_type) { +#ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: ret = serial8250_register_port(&port); break; +#endif +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + case PORT_NWPSERIAL: + ret = nwpserial_register_port(&port); + break; +#endif default: /* need to add code for these */ case PORT_UNKNOWN: @@ -129,9 +137,16 @@ static int of_platform_serial_remove(struct of_device *ofdev) { struct of_serial_info *info = ofdev->dev.driver_data; switch (info->type) { +#ifdef CONFIG_SERIAL_8250 case PORT_8250 ... PORT_MAX_8250: serial8250_unregister_port(info->line); break; +#endif +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + case PORT_NWPSERIAL: + nwpserial_unregister_port(info->line); + break; +#endif default: /* need to add code for these */ break; @@ -148,6 +163,10 @@ static struct of_device_id __devinitdata of_platform_serial_table[] = { { .type = "serial", .compatible = "ns16450", .data = (void *)PORT_16450, }, { .type = "serial", .compatible = "ns16550", .data = (void *)PORT_16550, }, { .type = "serial", .compatible = "ns16750", .data = (void *)PORT_16750, }, +#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL + { .type = "serial", .compatible = "ibm,qpace-nwp-serial", + .data = (void *)PORT_NWPSERIAL, }, +#endif { .type = "serial", .data = (void *)PORT_UNKNOWN, }, { /* end of list */ }, }; diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index d8fc9b32fe3..c0916c7b217 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -279,6 +279,13 @@ static int pn_net_mtu(struct net_device *dev, int new_mtu) return err; } +static const struct net_device_ops pn_netdev_ops = { + .ndo_open = pn_net_open, + .ndo_stop = pn_net_close, + .ndo_start_xmit = pn_net_xmit, + .ndo_change_mtu = pn_net_mtu, +}; + static void pn_net_setup(struct net_device *dev) { dev->features = 0; @@ -290,12 +297,9 @@ static void pn_net_setup(struct net_device *dev) dev->addr_len = 1; dev->tx_queue_len = 1; + dev->netdev_ops = &pn_netdev_ops; dev->destructor = free_netdev; dev->header_ops = &phonet_header_ops; - dev->open = pn_net_open; - dev->stop = pn_net_close; - dev->hard_start_xmit = pn_net_xmit; /* mandatory */ - dev->change_mtu = pn_net_mtu; } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index d9739d52f8f..96d65ca06ec 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -716,6 +716,14 @@ static int __init get_ether_addr(const char *str, u8 *dev_addr) static struct eth_dev *the_dev; +static const struct net_device_ops eth_netdev_ops = { + .ndo_open = eth_open, + .ndo_stop = eth_stop, + .ndo_start_xmit = eth_start_xmit, + .ndo_change_mtu = ueth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; /** * gether_setup - initialize one ethernet-over-usb link @@ -764,12 +772,8 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) if (ethaddr) memcpy(ethaddr, dev->host_mac, ETH_ALEN); - net->change_mtu = ueth_change_mtu; - net->hard_start_xmit = eth_start_xmit; - net->open = eth_open; - net->stop = eth_stop; - /* watchdog_timeo, tx_timeout ... */ - /* set_multicast_list */ + net->netdev_ops = ð_netdev_ops; + SET_ETHTOOL_OPS(net, &ops); /* two kinds of host-initiated state changes: diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 01d0c70d60e..3cf41df302d 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -145,7 +145,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, static int ti_write_byte(struct ti_device *tdev, unsigned long addr, __u8 mask, __u8 byte); -static int ti_download_firmware(struct ti_device *tdev, int type); +static int ti_download_firmware(struct ti_device *tdev); /* circular buffer */ static struct circ_buf *ti_buf_alloc(void); @@ -176,9 +176,14 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[1+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[7+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { @@ -188,9 +193,14 @@ static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[] = { +static struct usb_device_id ti_id_table_combined[6+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_NO_FW_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_CDMA_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_PRODUCT_ID) }, + { USB_DEVICE(MTS_VENDOR_ID, MTS_EDGE_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, @@ -272,6 +282,9 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("ti_3410.fw"); MODULE_FIRMWARE("ti_5052.fw"); +MODULE_FIRMWARE("mts_cdma.fw"); +MODULE_FIRMWARE("mts_gsm.fw"); +MODULE_FIRMWARE("mts_edge.fw"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Enable debugging, 0=no, 1=yes"); @@ -304,21 +317,28 @@ MODULE_DEVICE_TABLE(usb, ti_id_table_combined); static int __init ti_init(void) { - int i, j; + int i, j, c; int ret; /* insert extra vendor and product ids */ + c = ARRAY_SIZE(ti_id_table_combined) - 2 * TI_EXTRA_VID_PID_COUNT - 1; j = ARRAY_SIZE(ti_id_table_3410) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++) { + for (i = 0; i < min(vendor_3410_count, product_3410_count); i++, j++, c++) { ti_id_table_3410[j].idVendor = vendor_3410[i]; ti_id_table_3410[j].idProduct = product_3410[i]; ti_id_table_3410[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; + ti_id_table_combined[c].idVendor = vendor_3410[i]; + ti_id_table_combined[c].idProduct = product_3410[i]; + ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } j = ARRAY_SIZE(ti_id_table_5052) - TI_EXTRA_VID_PID_COUNT - 1; - for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++) { + for (i = 0; i < min(vendor_5052_count, product_5052_count); i++, j++, c++) { ti_id_table_5052[j].idVendor = vendor_5052[i]; ti_id_table_5052[j].idProduct = product_5052[i]; ti_id_table_5052[j].match_flags = USB_DEVICE_ID_MATCH_DEVICE; + ti_id_table_combined[c].idVendor = vendor_5052[i]; + ti_id_table_combined[c].idProduct = product_5052[i]; + ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } ret = usb_serial_register(&ti_1port_device); @@ -390,11 +410,7 @@ static int ti_startup(struct usb_serial *serial) /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { - if (tdev->td_is_3410) - status = ti_download_firmware(tdev, 3410); - else - status = ti_download_firmware(tdev, 5052); - if (status) + if ((status = ti_download_firmware(tdev)) != 0) goto free_tdev; /* 3410 must be reset, 5052 resets itself */ @@ -1671,9 +1687,9 @@ static int ti_do_download(struct usb_device *dev, int pipe, return status; } -static int ti_download_firmware(struct ti_device *tdev, int type) +static int ti_download_firmware(struct ti_device *tdev) { - int status = -ENOMEM; + int status; int buffer_size; __u8 *buffer; struct usb_device *dev = tdev->td_serial->dev; @@ -1681,9 +1697,34 @@ static int ti_download_firmware(struct ti_device *tdev, int type) tdev->td_serial->port[0]->bulk_out_endpointAddress); const struct firmware *fw_p; char buf[32]; - sprintf(buf, "ti_usb-%d.bin", type); - if (request_firmware(&fw_p, buf, &dev->dev)) { + /* try ID specific firmware first, then try generic firmware */ + sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, + dev->descriptor.idProduct); + if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) { + buf[0] = '\0'; + if (dev->descriptor.idVendor == MTS_VENDOR_ID) { + switch (dev->descriptor.idProduct) { + case MTS_CDMA_PRODUCT_ID: + strcpy(buf, "mts_cdma.fw"); + break; + case MTS_GSM_PRODUCT_ID: + strcpy(buf, "mts_gsm.fw"); + break; + case MTS_EDGE_PRODUCT_ID: + strcpy(buf, "mts_edge.fw"); + break; + } + } + if (buf[0] == '\0') { + if (tdev->td_is_3410) + strcpy(buf, "ti_3410.fw"); + else + strcpy(buf, "ti_5052.fw"); + } + status = request_firmware(&fw_p, buf, &dev->dev); + } + if (status) { dev_err(&dev->dev, "%s - firmware not found\n", __func__); return -ENOENT; } @@ -1699,6 +1740,8 @@ static int ti_download_firmware(struct ti_device *tdev, int type) memset(buffer + fw_p->size, 0xff, buffer_size - fw_p->size); status = ti_do_download(dev, pipe, buffer, fw_p->size); kfree(buffer); + } else { + status = -ENOMEM; } release_firmware(fw_p); if (status) { diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index b5541bf991b..7e4752fbf23 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -34,6 +34,14 @@ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ +/* Multi-Tech vendor and product ids */ +#define MTS_VENDOR_ID 0x06E0 +#define MTS_GSM_NO_FW_PRODUCT_ID 0xF108 +#define MTS_CDMA_NO_FW_PRODUCT_ID 0xF109 +#define MTS_CDMA_PRODUCT_ID 0xF110 +#define MTS_GSM_PRODUCT_ID 0xF111 +#define MTS_EDGE_PRODUCT_ID 0xF112 + /* Commands */ #define TI_GET_VERSION 0x01 #define TI_GET_PORT_STATUS 0x02 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 080ade223d5..cfcfd5ab06c 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -511,9 +511,6 @@ static void usb_serial_port_work(struct work_struct *work) dbg("%s - port %d", __func__, port->number); - if (!port) - return; - tty = tty_port_tty_get(&port->port); if (!tty) return; diff --git a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h index 5f1b2951bb8..3421d3339d7 100644 --- a/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h +++ b/drivers/uwb/i1480/i1480u-wlp/i1480u-wlp.h @@ -221,7 +221,6 @@ struct i1480u { struct net_device *net_dev; spinlock_t lock; - struct net_device_stats stats; /* RX context handling */ struct sk_buff *rx_skb; @@ -271,7 +270,6 @@ extern int i1480u_stop(struct net_device *); extern int i1480u_hard_start_xmit(struct sk_buff *, struct net_device *); extern void i1480u_tx_timeout(struct net_device *); extern int i1480u_set_config(struct net_device *, struct ifmap *); -extern struct net_device_stats *i1480u_get_stats(struct net_device *); extern int i1480u_change_mtu(struct net_device *, int); extern void i1480u_uwb_notifs_cb(void *, struct uwb_dev *, enum uwb_notifs); diff --git a/drivers/uwb/i1480/i1480u-wlp/lc.c b/drivers/uwb/i1480/i1480u-wlp/lc.c index 049c05d4cc6..f272dfe54d4 100644 --- a/drivers/uwb/i1480/i1480u-wlp/lc.c +++ b/drivers/uwb/i1480/i1480u-wlp/lc.c @@ -181,6 +181,15 @@ error: } #endif +static const struct net_device_ops i1480u_netdev_ops = { + .ndo_open = i1480u_open, + .ndo_stop = i1480u_stop, + .ndo_start_xmit = i1480u_hard_start_xmit, + .ndo_tx_timeout = i1480u_tx_timeout, + .ndo_set_config = i1480u_set_config, + .ndo_change_mtu = i1480u_change_mtu, +}; + static int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) { @@ -235,13 +244,7 @@ int i1480u_add(struct i1480u *i1480u, struct usb_interface *iface) net_dev->features |= NETIF_F_HIGHDMA; net_dev->watchdog_timeo = 5*HZ; /* FIXME: a better default? */ - net_dev->open = i1480u_open; - net_dev->stop = i1480u_stop; - net_dev->hard_start_xmit = i1480u_hard_start_xmit; - net_dev->tx_timeout = i1480u_tx_timeout; - net_dev->get_stats = i1480u_get_stats; - net_dev->set_config = i1480u_set_config; - net_dev->change_mtu = i1480u_change_mtu; + net_dev->netdev_ops = &i1480u_netdev_ops; #ifdef i1480u_FLOW_CONTROL /* Notification endpoint setup (submitted when we open the device) */ diff --git a/drivers/uwb/i1480/i1480u-wlp/netdev.c b/drivers/uwb/i1480/i1480u-wlp/netdev.c index e3873ffb942..73055530e60 100644 --- a/drivers/uwb/i1480/i1480u-wlp/netdev.c +++ b/drivers/uwb/i1480/i1480u-wlp/netdev.c @@ -262,15 +262,6 @@ int i1480u_stop(struct net_device *net_dev) return 0; } - -/** Report statistics */ -struct net_device_stats *i1480u_get_stats(struct net_device *net_dev) -{ - struct i1480u *i1480u = netdev_priv(net_dev); - return &i1480u->stats; -} - - /** * * Change the interface config--we probably don't have to do anything. diff --git a/drivers/uwb/i1480/i1480u-wlp/rx.c b/drivers/uwb/i1480/i1480u-wlp/rx.c index 34f4cf9a7d3..25a2758beb6 100644 --- a/drivers/uwb/i1480/i1480u-wlp/rx.c +++ b/drivers/uwb/i1480/i1480u-wlp/rx.c @@ -167,7 +167,7 @@ do { \ do { \ if (printk_ratelimit()) \ dev_err(&i1480u->usb_iface->dev, msg); \ - i1480u->stats.rx_dropped++; \ + i1480u->net_dev->stats.rx_dropped++; \ } while (0) @@ -193,10 +193,8 @@ void i1480u_skb_deliver(struct i1480u *i1480u) if (!should_parse) goto out; i1480u->rx_skb->protocol = eth_type_trans(i1480u->rx_skb, net_dev); - i1480u->stats.rx_packets++; - i1480u->stats.rx_bytes += i1480u->rx_untd_pkt_size; - net_dev->last_rx = jiffies; - /* FIXME: flow control: check netif_rx() retval */ + net_dev->stats.rx_packets++; + net_dev->stats.rx_bytes += i1480u->rx_untd_pkt_size; netif_rx(i1480u->rx_skb); /* deliver */ out: diff --git a/drivers/uwb/i1480/i1480u-wlp/tx.c b/drivers/uwb/i1480/i1480u-wlp/tx.c index 39032cc3503..26bacc009c6 100644 --- a/drivers/uwb/i1480/i1480u-wlp/tx.c +++ b/drivers/uwb/i1480/i1480u-wlp/tx.c @@ -117,8 +117,8 @@ void i1480u_tx_cb(struct urb *urb) switch (urb->status) { case 0: spin_lock_irqsave(&i1480u->lock, flags); - i1480u->stats.tx_packets++; - i1480u->stats.tx_bytes += urb->actual_length; + net_dev->stats.tx_packets++; + net_dev->stats.tx_bytes += urb->actual_length; spin_unlock_irqrestore(&i1480u->lock, flags); break; case -ECONNRESET: /* Not an error, but a controlled situation; */ @@ -530,7 +530,7 @@ int i1480u_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev) return NETDEV_TX_OK; error: dev_kfree_skb_any(skb); - i1480u->stats.tx_dropped++; + net_dev->stats.tx_dropped++; out: return NETDEV_TX_OK; } diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e39e33e797d..be2b657546e 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_FB_DDC) += fb_ddc.o obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o # Hardware specific drivers go first -obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o +obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o @@ -72,7 +72,7 @@ obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o obj-$(CONFIG_FB_SGIVW) += sgivwfb.o obj-$(CONFIG_FB_ACORN) += acornfb.o -obj-$(CONFIG_FB_ATARI) += atafb.o c2p.o atafb_mfb.o \ +obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o obj-$(CONFIG_FB_MAC) += macfb.o obj-$(CONFIG_FB_HECUBA) += hecubafb.o diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c index 2ac52fd8cc1..4e046fed138 100644 --- a/drivers/video/amba-clcd.c +++ b/drivers/video/amba-clcd.c @@ -24,6 +24,7 @@ #include <linux/amba/bus.h> #include <linux/amba/clcd.h> #include <linux/clk.h> +#include <linux/hardirq.h> #include <asm/sizes.h> diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c index b8e9a8682f2..100f2366146 100644 --- a/drivers/video/amifb.c +++ b/drivers/video/amifb.c @@ -2159,9 +2159,9 @@ static void amifb_imageblit(struct fb_info *info, const struct fb_image *image) src += pitch; } } else { - c2p(info->screen_base, image->data, dx, dy, width, height, - par->next_line, par->next_plane, image->width, - info->var.bits_per_pixel); + c2p_planar(info->screen_base, image->data, dx, dy, width, + height, par->next_line, par->next_plane, + image->width, info->var.bits_per_pixel); } } diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c index 77eb8b34fbf..8058572a742 100644 --- a/drivers/video/atafb.c +++ b/drivers/video/atafb.c @@ -122,7 +122,6 @@ static struct atafb_par { void *screen_base; int yres_virtual; u_long next_line; - u_long next_plane; #if defined ATAFB_TT || defined ATAFB_STE union { struct { @@ -149,6 +148,7 @@ static struct atafb_par { short mono; short ste_mode; short bpp; + u32 pseudo_palette[16]; } falcon; #endif /* Nothing needed for external mode */ @@ -614,7 +614,7 @@ static int tt_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) fix->xpanstep = 0; fix->ypanstep = 1; fix->ywrapstep = 0; - fix->line_length = 0; + fix->line_length = par->next_line; fix->accel = FB_ACCEL_ATARIBLITT; return 0; } @@ -691,6 +691,7 @@ static int tt_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) return -EINVAL; par->yres_virtual = yres_virtual; par->screen_base = screen_base + var->yoffset * linelen; + par->next_line = linelen; return 0; } @@ -884,10 +885,6 @@ static int vdl_prescale[4][3] = { /* Default hsync timing [mon_type] in picoseconds */ static long h_syncs[4] = { 3000000, 4875000, 4000000, 4875000 }; -#ifdef FBCON_HAS_CFB16 -static u16 fbcon_cfb16_cmap[16]; -#endif - static inline int hxx_prescale(struct falcon_hw *hw) { return hw->ste_mode ? 16 @@ -918,7 +915,7 @@ static int falcon_encode_fix(struct fb_fix_screeninfo *fix, fix->visual = FB_VISUAL_TRUECOLOR; fix->xpanstep = 2; } - fix->line_length = 0; + fix->line_length = par->next_line; fix->accel = FB_ACCEL_ATARIBLITT; return 0; } @@ -1394,14 +1391,7 @@ set_screen_base: par->screen_base = screen_base + var->yoffset * linelen; par->hw.falcon.xoffset = 0; - // FIXME!!! sort of works, no crash - //par->next_line = linelen; - //par->next_plane = yres_virtual * linelen; par->next_line = linelen; - par->next_plane = 2; - // crashes - //par->next_plane = linelen; - //par->next_line = yres_virtual * linelen; return 0; } @@ -1735,10 +1725,10 @@ static int falcon_setcolreg(unsigned int regno, unsigned int red, (((red & 0xe000) >> 13) | ((red & 0x1000) >> 12) << 8) | (((green & 0xe000) >> 13) | ((green & 0x1000) >> 12) << 4) | ((blue & 0xe000) >> 13) | ((blue & 0x1000) >> 12); -#ifdef FBCON_HAS_CFB16 - fbcon_cfb16_cmap[regno] = ((red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11)); +#ifdef ATAFB_FALCON + ((u32 *)info->pseudo_palette)[regno] = ((red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11)); #endif } return 0; @@ -1852,7 +1842,7 @@ static int stste_encode_fix(struct fb_fix_screeninfo *fix, fix->ypanstep = 0; } fix->ywrapstep = 0; - fix->line_length = 0; + fix->line_length = par->next_line; fix->accel = FB_ACCEL_ATARIBLITT; return 0; } @@ -1910,6 +1900,7 @@ static int stste_decode_var(struct fb_var_screeninfo *var, return -EINVAL; par->yres_virtual = yres_virtual; par->screen_base = screen_base + var->yoffset * linelen; + par->next_line = linelen; return 0; } @@ -2169,7 +2160,7 @@ static int ext_encode_fix(struct fb_fix_screeninfo *fix, struct atafb_par *par) fix->xpanstep = 0; fix->ypanstep = 0; fix->ywrapstep = 0; - fix->line_length = 0; + fix->line_length = par->next_line; return 0; } @@ -2184,6 +2175,8 @@ static int ext_decode_var(struct fb_var_screeninfo *var, struct atafb_par *par) var->xoffset > 0 || var->yoffset > 0) return -EINVAL; + + par->next_line = external_xres_virtual * external_depth / 8; return 0; } @@ -2443,42 +2436,6 @@ static void atafb_set_disp(struct fb_info *info) atafb_get_fix(&info->fix, info); info->screen_base = (void *)info->fix.smem_start; - - switch (info->fix.type) { - case FB_TYPE_INTERLEAVED_PLANES: - switch (info->var.bits_per_pixel) { - case 2: - // display->dispsw = &fbcon_iplan2p2; - break; - case 4: - // display->dispsw = &fbcon_iplan2p4; - break; - case 8: - // display->dispsw = &fbcon_iplan2p8; - break; - } - break; - case FB_TYPE_PACKED_PIXELS: - switch (info->var.bits_per_pixel) { -#ifdef FBCON_HAS_MFB - case 1: - // display->dispsw = &fbcon_mfb; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - // display->dispsw = &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - // display->dispsw = &fbcon_cfb16; - // display->dispsw_data = fbcon_cfb16_cmap; - break; -#endif - } - break; - } } static int atafb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, @@ -2549,6 +2506,13 @@ static void atafb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) if (!rect->width || !rect->height) return; +#ifdef ATAFB_FALCON + if (info->var.bits_per_pixel == 16) { + cfb_fillrect(info, rect); + return; + } +#endif + /* * We could use hardware clipping but on many cards you get around * hardware clipping by writing to framebuffer directly. @@ -2583,6 +2547,13 @@ static void atafb_copyarea(struct fb_info *info, const struct fb_copyarea *area) u32 dx, dy, sx, sy, width, height; int rev_copy = 0; +#ifdef ATAFB_FALCON + if (info->var.bits_per_pixel == 16) { + cfb_copyarea(info, area); + return; + } +#endif + /* clip the destination */ x2 = area->dx + area->width; y2 = area->dy + area->height; @@ -2632,6 +2603,13 @@ static void atafb_imageblit(struct fb_info *info, const struct fb_image *image) const char *src; u32 dx, dy, width, height, pitch; +#ifdef ATAFB_FALCON + if (info->var.bits_per_pixel == 16) { + cfb_imageblit(info, image); + return; + } +#endif + /* * We could use hardware clipping but on many cards you get around * hardware clipping by writing to framebuffer directly like we are @@ -2676,10 +2654,9 @@ static void atafb_imageblit(struct fb_info *info, const struct fb_image *image) src += pitch; } } else { - // only used for logo; broken - c2p(info->screen_base, image->data, dx, dy, width, height, - par->next_line, par->next_plane, image->width, - info->var.bits_per_pixel); + c2p_iplan2(info->screen_base, image->data, dx, dy, width, + height, par->next_line, image->width, + info->var.bits_per_pixel); } } @@ -3098,8 +3075,7 @@ int __init atafb_setup(char *options) int __init atafb_init(void) { - int pad; - int detected_mode; + int pad, detected_mode, error; unsigned int defmode = 0; unsigned long mem_req; @@ -3139,8 +3115,12 @@ int __init atafb_init(void) printk("atafb_init: initializing Falcon hw\n"); fbhw = &falcon_switch; atafb_ops.fb_setcolreg = &falcon_setcolreg; - request_irq(IRQ_AUTO_4, falcon_vbl_switcher, IRQ_TYPE_PRIO, - "framebuffer/modeswitch", falcon_vbl_switcher); + error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, + IRQ_TYPE_PRIO, + "framebuffer/modeswitch", + falcon_vbl_switcher); + if (error) + return error; defmode = DEFMODE_F30; break; } @@ -3225,6 +3205,10 @@ int __init atafb_init(void) // tries to read from HW which may not be initialized yet // so set sane var first, then call atafb_set_par atafb_get_var(&fb_info.var, &fb_info); + +#ifdef ATAFB_FALCON + fb_info.pseudo_palette = current_par.hw.falcon.pseudo_palette; +#endif fb_info.flags = FBINFO_FLAG_DEFAULT; if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, atafb_modedb, diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 4a4dd9adc32..72facb9eb7d 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -52,11 +52,11 @@ config LCD_ILI9320 then say y to include a power driver for it. config LCD_TDO24M - tristate "Toppoly TDO24M LCD Panels support" + tristate "Toppoly TDO24M and TDO35S LCD Panels support" depends on LCD_CLASS_DEVICE && SPI_MASTER default n help - If you have a Toppoly TDO24M series LCD panel, say y here to + If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to include the support for it. config LCD_VGG2432A4 @@ -123,17 +123,14 @@ config BACKLIGHT_ATMEL_PWM To compile this driver as a module, choose M here: the module will be called atmel-pwm-bl. -config BACKLIGHT_CORGI - tristate "Generic (aka Sharp Corgi) Backlight Driver (DEPRECATED)" +config BACKLIGHT_GENERIC + tristate "Generic (aka Sharp Corgi) Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE - default n + default y help Say y to enable the generic platform backlight driver previously known as the Corgi backlight driver. If you have a Sharp Zaurus - SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n. - - Note: this driver is marked as deprecated, try enable SPI and - use the new corgi_lcd driver with integrated backlight control + SL-C7xx, SL-Cxx00 or SL-6000x say y. config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index 103427de670..363b3cb2f01 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o -obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o +obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index 0664fc03223..157057c79ca 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -40,6 +40,10 @@ static int fb_notifier_callback(struct notifier_block *self, if (!bd->ops->check_fb || bd->ops->check_fb(evdata->info)) { bd->props.fb_blank = *(int *)evdata->data; + if (bd->props.fb_blank == FB_BLANK_UNBLANK) + bd->props.state &= ~BL_CORE_FBBLANK; + else + bd->props.state |= BL_CORE_FBBLANK; backlight_update_status(bd); } mutex_unlock(&bd->ops_lock); @@ -80,20 +84,18 @@ static ssize_t backlight_show_power(struct device *dev, static ssize_t backlight_store_power(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int rc = -ENXIO; - char *endp; + int rc; struct backlight_device *bd = to_backlight_device(dev); - int power = simple_strtoul(buf, &endp, 0); - size_t size = endp - buf; + unsigned long power; - if (*endp && isspace(*endp)) - size++; - if (size != count) - return -EINVAL; + rc = strict_strtoul(buf, 0, &power); + if (rc) + return rc; + rc = -ENXIO; mutex_lock(&bd->ops_lock); if (bd->ops) { - pr_debug("backlight: set power to %d\n", power); + pr_debug("backlight: set power to %lu\n", power); if (bd->props.power != power) { bd->props.power = power; backlight_update_status(bd); @@ -116,28 +118,25 @@ static ssize_t backlight_show_brightness(struct device *dev, static ssize_t backlight_store_brightness(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - int rc = -ENXIO; - char *endp; + int rc; struct backlight_device *bd = to_backlight_device(dev); - int brightness = simple_strtoul(buf, &endp, 0); - size_t size = endp - buf; + unsigned long brightness; + + rc = strict_strtoul(buf, 0, &brightness); + if (rc) + return rc; - if (*endp && isspace(*endp)) - size++; - if (size != count) - return -EINVAL; + rc = -ENXIO; mutex_lock(&bd->ops_lock); if (bd->ops) { if (brightness > bd->props.max_brightness) rc = -EINVAL; else { - pr_debug("backlight: set brightness to %d\n", + pr_debug("backlight: set brightness to %lu\n", brightness); - if (bd->props.brightness != brightness) { - bd->props.brightness = brightness; - backlight_update_status(bd); - } + bd->props.brightness = brightness; + backlight_update_status(bd); rc = count; } } @@ -170,6 +169,34 @@ static ssize_t backlight_show_actual_brightness(struct device *dev, static struct class *backlight_class; +static int backlight_suspend(struct device *dev, pm_message_t state) +{ + struct backlight_device *bd = to_backlight_device(dev); + + if (bd->ops->options & BL_CORE_SUSPENDRESUME) { + mutex_lock(&bd->ops_lock); + bd->props.state |= BL_CORE_SUSPENDED; + backlight_update_status(bd); + mutex_unlock(&bd->ops_lock); + } + + return 0; +} + +static int backlight_resume(struct device *dev) +{ + struct backlight_device *bd = to_backlight_device(dev); + + if (bd->ops->options & BL_CORE_SUSPENDRESUME) { + mutex_lock(&bd->ops_lock); + bd->props.state &= ~BL_CORE_SUSPENDED; + backlight_update_status(bd); + mutex_unlock(&bd->ops_lock); + } + + return 0; +} + static void bl_device_release(struct device *dev) { struct backlight_device *bd = to_backlight_device(dev); @@ -286,6 +313,8 @@ static int __init backlight_class_init(void) } backlight_class->dev_attrs = bl_device_attributes; + backlight_class->suspend = backlight_suspend; + backlight_class->resume = backlight_resume; return 0; } diff --git a/drivers/video/backlight/corgi_bl.c b/drivers/video/backlight/corgi_bl.c deleted file mode 100644 index 4d4d037e3ec..00000000000 --- a/drivers/video/backlight/corgi_bl.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Backlight Driver for Sharp Zaurus Handhelds (various models) - * - * Copyright (c) 2004-2006 Richard Purdie - * - * Based on Sharp's 2.4 Backlight Driver - * - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <linux/fb.h> -#include <linux/backlight.h> - -static int corgibl_intensity; -static struct backlight_properties corgibl_data; -static struct backlight_device *corgi_backlight_device; -static struct generic_bl_info *bl_machinfo; - -static unsigned long corgibl_flags; -#define CORGIBL_SUSPENDED 0x01 -#define CORGIBL_BATTLOW 0x02 - -static int corgibl_send_intensity(struct backlight_device *bd) -{ - int intensity = bd->props.brightness; - - if (bd->props.power != FB_BLANK_UNBLANK) - intensity = 0; - if (bd->props.fb_blank != FB_BLANK_UNBLANK) - intensity = 0; - if (corgibl_flags & CORGIBL_SUSPENDED) - intensity = 0; - if (corgibl_flags & CORGIBL_BATTLOW) - intensity &= bl_machinfo->limit_mask; - - bl_machinfo->set_bl_intensity(intensity); - - corgibl_intensity = intensity; - - if (bl_machinfo->kick_battery) - bl_machinfo->kick_battery(); - - return 0; -} - -#ifdef CONFIG_PM -static int corgibl_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - corgibl_flags |= CORGIBL_SUSPENDED; - backlight_update_status(bd); - return 0; -} - -static int corgibl_resume(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - corgibl_flags &= ~CORGIBL_SUSPENDED; - backlight_update_status(bd); - return 0; -} -#else -#define corgibl_suspend NULL -#define corgibl_resume NULL -#endif - -static int corgibl_get_intensity(struct backlight_device *bd) -{ - return corgibl_intensity; -} - -/* - * Called when the battery is low to limit the backlight intensity. - * If limit==0 clear any limit, otherwise limit the intensity - */ -void corgibl_limit_intensity(int limit) -{ - if (limit) - corgibl_flags |= CORGIBL_BATTLOW; - else - corgibl_flags &= ~CORGIBL_BATTLOW; - backlight_update_status(corgi_backlight_device); -} -EXPORT_SYMBOL(corgibl_limit_intensity); - - -static struct backlight_ops corgibl_ops = { - .get_brightness = corgibl_get_intensity, - .update_status = corgibl_send_intensity, -}; - -static int corgibl_probe(struct platform_device *pdev) -{ - struct generic_bl_info *machinfo = pdev->dev.platform_data; - const char *name = "generic-bl"; - - bl_machinfo = machinfo; - if (!machinfo->limit_mask) - machinfo->limit_mask = -1; - - if (machinfo->name) - name = machinfo->name; - - corgi_backlight_device = backlight_device_register (name, - &pdev->dev, NULL, &corgibl_ops); - if (IS_ERR (corgi_backlight_device)) - return PTR_ERR (corgi_backlight_device); - - platform_set_drvdata(pdev, corgi_backlight_device); - - corgi_backlight_device->props.max_brightness = machinfo->max_intensity; - corgi_backlight_device->props.power = FB_BLANK_UNBLANK; - corgi_backlight_device->props.brightness = machinfo->default_intensity; - backlight_update_status(corgi_backlight_device); - - printk("Corgi Backlight Driver Initialized.\n"); - return 0; -} - -static int corgibl_remove(struct platform_device *pdev) -{ - struct backlight_device *bd = platform_get_drvdata(pdev); - - corgibl_data.power = 0; - corgibl_data.brightness = 0; - backlight_update_status(bd); - - backlight_device_unregister(bd); - - printk("Corgi Backlight Driver Unloaded\n"); - return 0; -} - -static struct platform_driver corgibl_driver = { - .probe = corgibl_probe, - .remove = corgibl_remove, - .suspend = corgibl_suspend, - .resume = corgibl_resume, - .driver = { - .name = "generic-bl", - }, -}; - -static int __init corgibl_init(void) -{ - return platform_driver_register(&corgibl_driver); -} - -static void __exit corgibl_exit(void) -{ - platform_driver_unregister(&corgibl_driver); -} - -module_init(corgibl_init); -module_exit(corgibl_exit); - -MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); -MODULE_DESCRIPTION("Corgi Backlight Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c index 26add889860..b9fe62b475c 100644 --- a/drivers/video/backlight/cr_bllcd.c +++ b/drivers/video/backlight/cr_bllcd.c @@ -259,22 +259,18 @@ static int __init cr_backlight_init(void) { int ret = platform_driver_register(&cr_backlight_driver); - if (!ret) { - crp = platform_device_alloc("cr_backlight", -1); - if (!crp) - return -ENOMEM; + if (ret) + return ret; - ret = platform_device_add(crp); - - if (ret) { - platform_device_put(crp); - platform_driver_unregister(&cr_backlight_driver); - } + crp = platform_device_register_simple("cr_backlight", -1, NULL, 0); + if (IS_ERR(crp)) { + platform_driver_unregister(&cr_backlight_driver); + return PTR_ERR(crp); } printk("Carillo Ranch Backlight Driver Initialized.\n"); - return ret; + return 0; } static void __exit cr_backlight_exit(void) diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c new file mode 100644 index 00000000000..6d27f62fdcd --- /dev/null +++ b/drivers/video/backlight/generic_bl.c @@ -0,0 +1,147 @@ +/* + * Generic Backlight Driver + * + * Copyright (c) 2004-2008 Richard Purdie + * + * 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 <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/mutex.h> +#include <linux/fb.h> +#include <linux/backlight.h> + +static int genericbl_intensity; +static struct backlight_device *generic_backlight_device; +static struct generic_bl_info *bl_machinfo; + +/* Flag to signal when the battery is low */ +#define GENERICBL_BATTLOW BL_CORE_DRIVER1 + +static int genericbl_send_intensity(struct backlight_device *bd) +{ + int intensity = bd->props.brightness; + + if (bd->props.power != FB_BLANK_UNBLANK) + intensity = 0; + if (bd->props.state & BL_CORE_FBBLANK) + intensity = 0; + if (bd->props.state & BL_CORE_SUSPENDED) + intensity = 0; + if (bd->props.state & GENERICBL_BATTLOW) + intensity &= bl_machinfo->limit_mask; + + bl_machinfo->set_bl_intensity(intensity); + + genericbl_intensity = intensity; + + if (bl_machinfo->kick_battery) + bl_machinfo->kick_battery(); + + return 0; +} + +static int genericbl_get_intensity(struct backlight_device *bd) +{ + return genericbl_intensity; +} + +/* + * Called when the battery is low to limit the backlight intensity. + * If limit==0 clear any limit, otherwise limit the intensity + */ +void corgibl_limit_intensity(int limit) +{ + struct backlight_device *bd = generic_backlight_device; + + mutex_lock(&bd->ops_lock); + if (limit) + bd->props.state |= GENERICBL_BATTLOW; + else + bd->props.state &= ~GENERICBL_BATTLOW; + backlight_update_status(generic_backlight_device); + mutex_unlock(&bd->ops_lock); +} +EXPORT_SYMBOL(corgibl_limit_intensity); + +static struct backlight_ops genericbl_ops = { + .options = BL_CORE_SUSPENDRESUME, + .get_brightness = genericbl_get_intensity, + .update_status = genericbl_send_intensity, +}; + +static int genericbl_probe(struct platform_device *pdev) +{ + struct generic_bl_info *machinfo = pdev->dev.platform_data; + const char *name = "generic-bl"; + struct backlight_device *bd; + + bl_machinfo = machinfo; + if (!machinfo->limit_mask) + machinfo->limit_mask = -1; + + if (machinfo->name) + name = machinfo->name; + + bd = backlight_device_register (name, + &pdev->dev, NULL, &genericbl_ops); + if (IS_ERR (bd)) + return PTR_ERR (bd); + + platform_set_drvdata(pdev, bd); + + bd->props.max_brightness = machinfo->max_intensity; + bd->props.power = FB_BLANK_UNBLANK; + bd->props.brightness = machinfo->default_intensity; + backlight_update_status(bd); + + generic_backlight_device = bd; + + printk("Generic Backlight Driver Initialized.\n"); + return 0; +} + +static int genericbl_remove(struct platform_device *pdev) +{ + struct backlight_device *bd = platform_get_drvdata(pdev); + + bd->props.power = 0; + bd->props.brightness = 0; + backlight_update_status(bd); + + backlight_device_unregister(bd); + + printk("Generic Backlight Driver Unloaded\n"); + return 0; +} + +static struct platform_driver genericbl_driver = { + .probe = genericbl_probe, + .remove = genericbl_remove, + .driver = { + .name = "generic-bl", + }, +}; + +static int __init genericbl_init(void) +{ + return platform_driver_register(&genericbl_driver); +} + +static void __exit genericbl_exit(void) +{ + platform_driver_unregister(&genericbl_driver); +} + +module_init(genericbl_init); +module_exit(genericbl_exit); + +MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>"); +MODULE_DESCRIPTION("Generic Backlight Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c index d4cfed0b26d..5be55a20d8c 100644 --- a/drivers/video/backlight/hp680_bl.c +++ b/drivers/video/backlight/hp680_bl.c @@ -151,19 +151,15 @@ static int __init hp680bl_init(void) int ret; ret = platform_driver_register(&hp680bl_driver); - if (!ret) { - hp680bl_device = platform_device_alloc("hp680-bl", -1); - if (!hp680bl_device) - return -ENOMEM; - - ret = platform_device_add(hp680bl_device); - - if (ret) { - platform_device_put(hp680bl_device); - platform_driver_unregister(&hp680bl_driver); - } + if (ret) + return ret; + hp680bl_device = platform_device_register_simple("hp680-bl", -1, + NULL, 0); + if (IS_ERR(hp680bl_device)) { + platform_driver_unregister(&hp680bl_driver); + return PTR_ERR(hp680bl_device); } - return ret; + return 0; } static void __exit hp680bl_exit(void) diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c index 06964af761c..65864c50045 100644 --- a/drivers/video/backlight/mbp_nvidia_bl.c +++ b/drivers/video/backlight/mbp_nvidia_bl.c @@ -70,6 +70,7 @@ static int mbp_get_intensity(struct backlight_device *bd) } static struct backlight_ops mbp_ops = { + .options = BL_CORE_SUSPENDRESUME, .get_brightness = mbp_get_intensity, .update_status = mbp_send_intensity, }; diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c index 15fb4d58b5b..9edaf24fd82 100644 --- a/drivers/video/backlight/progear_bl.c +++ b/drivers/video/backlight/progear_bl.c @@ -119,20 +119,16 @@ static int __init progearbl_init(void) { int ret = platform_driver_register(&progearbl_driver); - if (!ret) { - progearbl_device = platform_device_alloc("progear-bl", -1); - if (!progearbl_device) - return -ENOMEM; - - ret = platform_device_add(progearbl_device); - - if (ret) { - platform_device_put(progearbl_device); - platform_driver_unregister(&progearbl_driver); - } + if (ret) + return ret; + progearbl_device = platform_device_register_simple("progear-bl", -1, + NULL, 0); + if (IS_ERR(progearbl_device)) { + platform_driver_unregister(&progearbl_driver); + return PTR_ERR(progearbl_device); } - return ret; + return 0; } static void __exit progearbl_exit(void) diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c index 8427669162e..1dae7f8f3c6 100644 --- a/drivers/video/backlight/tdo24m.c +++ b/drivers/video/backlight/tdo24m.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/device.h> #include <linux/spi/spi.h> +#include <linux/spi/tdo24m.h> #include <linux/fb.h> #include <linux/lcd.h> @@ -31,6 +32,9 @@ struct tdo24m { struct spi_transfer xfer; uint8_t *buf; + int (*adj_mode)(struct tdo24m *lcd, int mode); + int color_invert; + int power; int mode; }; @@ -66,7 +70,7 @@ static uint32_t lcd_panel_off[] = { CMD_NULL, }; -static uint32_t lcd_vga_pass_through[] = { +static uint32_t lcd_vga_pass_through_tdo24m[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x80), CMD1(0xE1, 0x00), @@ -75,7 +79,7 @@ static uint32_t lcd_vga_pass_through[] = { CMD_NULL, }; -static uint32_t lcd_qvga_pass_through[] = { +static uint32_t lcd_qvga_pass_through_tdo24m[] = { CMD1(0xB0, 0x16), CMD1(0xBC, 0x81), CMD1(0xE1, 0x00), @@ -84,7 +88,7 @@ static uint32_t lcd_qvga_pass_through[] = { CMD_NULL, }; -static uint32_t lcd_vga_transfer[] = { +static uint32_t lcd_vga_transfer_tdo24m[] = { CMD1(0xcf, 0x02), /* Blanking period control (1) */ CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ CMD1(0xd1, 0x01), /* CKV timing control on/off */ @@ -110,6 +114,35 @@ static uint32_t lcd_qvga_transfer[] = { CMD_NULL, }; +static uint32_t lcd_vga_pass_through_tdo35s[] = { + CMD1(0xB0, 0x16), + CMD1(0xBC, 0x80), + CMD1(0xE1, 0x00), + CMD1(0x3B, 0x00), + CMD_NULL, +}; + +static uint32_t lcd_qvga_pass_through_tdo35s[] = { + CMD1(0xB0, 0x16), + CMD1(0xBC, 0x81), + CMD1(0xE1, 0x00), + CMD1(0x3B, 0x22), + CMD_NULL, +}; + +static uint32_t lcd_vga_transfer_tdo35s[] = { + CMD1(0xcf, 0x02), /* Blanking period control (1) */ + CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ + CMD1(0xd1, 0x01), /* CKV timing control on/off */ + CMD2(0xd2, 0x00, 0x1e), /* CKV 1,2 timing control */ + CMD2(0xd3, 0x14, 0x28), /* OEV timing control */ + CMD2(0xd4, 0x28, 0x64), /* ASW timing control (1) */ + CMD1(0xd5, 0x28), /* ASW timing control (2) */ + CMD0(0x21), /* Invert for normally black display */ + CMD0(0x29), /* Display on */ + CMD_NULL, +}; + static uint32_t lcd_panel_config[] = { CMD2(0xb8, 0xff, 0xf9), /* Output control */ CMD0(0x11), /* sleep out */ @@ -148,6 +181,8 @@ static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array) int nparams, err = 0; for (; *p != CMD_NULL; p++) { + if (!lcd->color_invert && *p == CMD0(0x21)) + continue; nparams = (*p >> 30) & 0x3; @@ -184,12 +219,33 @@ static int tdo24m_adj_mode(struct tdo24m *lcd, int mode) { switch (mode) { case MODE_VGA: - tdo24m_writes(lcd, lcd_vga_pass_through); + tdo24m_writes(lcd, lcd_vga_pass_through_tdo24m); tdo24m_writes(lcd, lcd_panel_config); - tdo24m_writes(lcd, lcd_vga_transfer); + tdo24m_writes(lcd, lcd_vga_transfer_tdo24m); break; case MODE_QVGA: - tdo24m_writes(lcd, lcd_qvga_pass_through); + tdo24m_writes(lcd, lcd_qvga_pass_through_tdo24m); + tdo24m_writes(lcd, lcd_panel_config); + tdo24m_writes(lcd, lcd_qvga_transfer); + break; + default: + return -EINVAL; + } + + lcd->mode = mode; + return 0; +} + +static int tdo35s_adj_mode(struct tdo24m *lcd, int mode) +{ + switch (mode) { + case MODE_VGA: + tdo24m_writes(lcd, lcd_vga_pass_through_tdo35s); + tdo24m_writes(lcd, lcd_panel_config); + tdo24m_writes(lcd, lcd_vga_transfer_tdo35s); + break; + case MODE_QVGA: + tdo24m_writes(lcd, lcd_qvga_pass_through_tdo35s); tdo24m_writes(lcd, lcd_panel_config); tdo24m_writes(lcd, lcd_qvga_transfer); break; @@ -213,7 +269,7 @@ static int tdo24m_power_on(struct tdo24m *lcd) if (err) goto out; - err = tdo24m_adj_mode(lcd, lcd->mode); + err = lcd->adj_mode(lcd, lcd->mode); out: return err; } @@ -262,7 +318,7 @@ static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m) if (lcd->mode == mode) return 0; - return tdo24m_adj_mode(lcd, mode); + return lcd->adj_mode(lcd, mode); } static struct lcd_ops tdo24m_ops = { @@ -276,8 +332,16 @@ static int __devinit tdo24m_probe(struct spi_device *spi) struct tdo24m *lcd; struct spi_message *m; struct spi_transfer *x; + struct tdo24m_platform_data *pdata; + enum tdo24m_model model; int err; + pdata = spi->dev.platform_data; + if (pdata) + model = pdata->model; + else + model = TDO24M; + spi->bits_per_word = 8; spi->mode = SPI_MODE_3; err = spi_setup(spi); @@ -306,6 +370,20 @@ static int __devinit tdo24m_probe(struct spi_device *spi) x->tx_buf = &lcd->buf[0]; spi_message_add_tail(x, m); + switch (model) { + case TDO24M: + lcd->color_invert = 1; + lcd->adj_mode = tdo24m_adj_mode; + break; + case TDO35S: + lcd->adj_mode = tdo35s_adj_mode; + lcd->color_invert = 0; + break; + default: + dev_err(&spi->dev, "Unsupported model"); + goto out_free; + } + lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev, lcd, &tdo24m_ops); if (IS_ERR(lcd->lcd_dev)) { diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c index 57a26649f1a..b7fbc75a62f 100644 --- a/drivers/video/backlight/tosa_lcd.c +++ b/drivers/video/backlight/tosa_lcd.c @@ -39,6 +39,7 @@ struct tosa_lcd_data { struct i2c_client *i2c; int lcd_power; + bool is_vga; }; static int tosa_tg_send(struct spi_device *spi, int adrs, uint8_t data) @@ -81,8 +82,12 @@ static void tosa_lcd_tg_init(struct tosa_lcd_data *data) static void tosa_lcd_tg_on(struct tosa_lcd_data *data) { struct spi_device *spi = data->spi; - const int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR; - tosa_tg_send(spi, TG_PNLCTL, value | TG_REG0_VQV); /* this depends on mode */ + int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR; + + if (data->is_vga) + value |= TG_REG0_VQV; + + tosa_tg_send(spi, TG_PNLCTL, value); /* TG LCD pannel power up */ tosa_tg_send(spi, TG_PINICTL,0x4); @@ -142,9 +147,25 @@ static int tosa_lcd_get_power(struct lcd_device *lcd) return data->lcd_power; } +static int tosa_lcd_set_mode(struct lcd_device *lcd, struct fb_videomode *mode) +{ + struct tosa_lcd_data *data = lcd_get_data(lcd); + + if (mode->xres == 320 || mode->yres == 320) + data->is_vga = false; + else + data->is_vga = true; + + if (POWER_IS_ON(data->lcd_power)) + tosa_lcd_tg_on(data); + + return 0; +} + static struct lcd_ops tosa_lcd_ops = { .set_power = tosa_lcd_set_power, .get_power = tosa_lcd_get_power, + .set_mode = tosa_lcd_set_mode, }; static int __devinit tosa_lcd_probe(struct spi_device *spi) @@ -156,6 +177,8 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi) if (!data) return -ENOMEM; + data->is_vga = true; /* defaut to VGA mode */ + /* * bits_per_word cannot be configured in platform data */ diff --git a/drivers/video/backlight/vgg2432a4.c b/drivers/video/backlight/vgg2432a4.c index 593c7687d54..8e653b8a6f1 100644 --- a/drivers/video/backlight/vgg2432a4.c +++ b/drivers/video/backlight/vgg2432a4.c @@ -137,7 +137,7 @@ static int vgg2432a4_lcd_init(struct ili9320 *lcd, ili9320_write(lcd, ILI9320_RGB_IF1, cfg->rgb_if1); ili9320_write(lcd, ILI9320_FRAMEMAKER, 0x0); - ili9320_write(lcd, ILI9320_RGB_IF2, ILI9320_RGBIF2_DPL); + ili9320_write(lcd, ILI9320_RGB_IF2, cfg->rgb_if2); ret = ili9320_write_regs(lcd, vgg_init1, ARRAY_SIZE(vgg_init1)); if (ret != 0) diff --git a/drivers/video/c2p.c b/drivers/video/c2p.c deleted file mode 100644 index 376bc07ff95..00000000000 --- a/drivers/video/c2p.c +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Fast C2P (Chunky-to-Planar) Conversion - * - * Copyright (C) 2003 Geert Uytterhoeven - * - * NOTES: - * - This code was inspired by Scout's C2P tutorial - * - It assumes to run on a big endian system - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ - -#include <linux/module.h> -#include <linux/string.h> -#include "c2p.h" - - - /* - * Basic transpose step - */ - -#define _transp(d, i1, i2, shift, mask) \ - do { \ - u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; \ - d[i1] ^= t; \ - d[i2] ^= t << shift; \ - } while (0) - -static inline u32 get_mask(int n) -{ - switch (n) { - case 1: - return 0x55555555; - break; - - case 2: - return 0x33333333; - break; - - case 4: - return 0x0f0f0f0f; - break; - - case 8: - return 0x00ff00ff; - break; - - case 16: - return 0x0000ffff; - break; - } - return 0; -} - -#define transp_nx1(d, n) \ - do { \ - u32 mask = get_mask(n); \ - /* First block */ \ - _transp(d, 0, 1, n, mask); \ - /* Second block */ \ - _transp(d, 2, 3, n, mask); \ - /* Third block */ \ - _transp(d, 4, 5, n, mask); \ - /* Fourth block */ \ - _transp(d, 6, 7, n, mask); \ - } while (0) - -#define transp_nx2(d, n) \ - do { \ - u32 mask = get_mask(n); \ - /* First block */ \ - _transp(d, 0, 2, n, mask); \ - _transp(d, 1, 3, n, mask); \ - /* Second block */ \ - _transp(d, 4, 6, n, mask); \ - _transp(d, 5, 7, n, mask); \ - } while (0) - -#define transp_nx4(d, n) \ - do { \ - u32 mask = get_mask(n); \ - _transp(d, 0, 4, n, mask); \ - _transp(d, 1, 5, n, mask); \ - _transp(d, 2, 6, n, mask); \ - _transp(d, 3, 7, n, mask); \ - } while (0) - -#define transp(d, n, m) transp_nx ## m(d, n) - - - /* - * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words - * containing - * - 32 8-bit chunky pixels on input - * - permuted planar data on output - */ - -static void c2p_8bpp(u32 d[8]) -{ - transp(d, 16, 4); - transp(d, 8, 2); - transp(d, 4, 1); - transp(d, 2, 4); - transp(d, 1, 2); -} - - - /* - * Array containing the permution indices of the planar data after c2p - */ - -static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 }; - - - /* - * Compose two values, using a bitmask as decision value - * This is equivalent to (a & mask) | (b & ~mask) - */ - -static inline unsigned long comp(unsigned long a, unsigned long b, - unsigned long mask) -{ - return ((a ^ b) & mask) ^ b; -} - - - /* - * Store a full block of planar data after c2p conversion - */ - -static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8]) -{ - int i; - - for (i = 0; i < bpp; i++, dst += dst_inc) - *(u32 *)dst = d[perm_c2p_8bpp[i]]; -} - - - /* - * Store a partial block of planar data after c2p conversion - */ - -static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp, - u32 d[8], u32 mask) -{ - int i; - - for (i = 0; i < bpp; i++, dst += dst_inc) - *(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask); -} - - - /* - * c2p - Copy 8-bit chunky image data to a planar frame buffer - * @dst: Starting address of the planar frame buffer - * @dx: Horizontal destination offset (in pixels) - * @dy: Vertical destination offset (in pixels) - * @width: Image width (in pixels) - * @height: Image height (in pixels) - * @dst_nextline: Frame buffer offset to the next line (in bytes) - * @dst_nextplane: Frame buffer offset to the next plane (in bytes) - * @src_nextline: Image offset to the next line (in bytes) - * @bpp: Bits per pixel of the planar frame buffer (1-8) - */ - -void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, - u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp) -{ - int dst_idx; - u32 d[8], first, last, w; - const u8 *c; - u8 *p; - - dst += dy*dst_nextline+(dx & ~31); - dst_idx = dx % 32; - first = ~0UL >> dst_idx; - last = ~(~0UL >> ((dst_idx+width) % 32)); - while (height--) { - c = src; - p = dst; - w = width; - if (dst_idx+width <= 32) { - /* Single destination word */ - first &= last; - memset(d, 0, sizeof(d)); - memcpy((u8 *)d+dst_idx, c, width); - c += width; - c2p_8bpp(d); - store_planar_masked(p, dst_nextplane, bpp, d, first); - p += 4; - } else { - /* Multiple destination words */ - w = width; - /* Leading bits */ - if (dst_idx) { - w = 32 - dst_idx; - memset(d, 0, dst_idx); - memcpy((u8 *)d+dst_idx, c, w); - c += w; - c2p_8bpp(d); - store_planar_masked(p, dst_nextplane, bpp, d, first); - p += 4; - w = width-w; - } - /* Main chunk */ - while (w >= 32) { - memcpy(d, c, 32); - c += 32; - c2p_8bpp(d); - store_planar(p, dst_nextplane, bpp, d); - p += 4; - w -= 32; - } - /* Trailing bits */ - w %= 32; - if (w > 0) { - memcpy(d, c, w); - memset((u8 *)d+w, 0, 32-w); - c2p_8bpp(d); - store_planar_masked(p, dst_nextplane, bpp, d, last); - } - } - src += src_nextline; - dst += dst_nextline; - } -} -EXPORT_SYMBOL_GPL(c2p); - -MODULE_LICENSE("GPL"); diff --git a/drivers/video/c2p.h b/drivers/video/c2p.h index c77cbf17e04..6c38d40427d 100644 --- a/drivers/video/c2p.h +++ b/drivers/video/c2p.h @@ -1,7 +1,7 @@ /* * Fast C2P (Chunky-to-Planar) Conversion * - * Copyright (C) 2003 Geert Uytterhoeven + * Copyright (C) 2003-2008 Geert Uytterhoeven * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive @@ -10,7 +10,10 @@ #include <linux/types.h> -extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height, - u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, - u32 bpp); +extern void c2p_planar(void *dst, const void *src, u32 dx, u32 dy, u32 width, + u32 height, u32 dst_nextline, u32 dst_nextplane, + u32 src_nextline, u32 bpp); +extern void c2p_iplan2(void *dst, const void *src, u32 dx, u32 dy, u32 width, + u32 height, u32 dst_nextline, u32 src_nextline, + u32 bpp); diff --git a/drivers/video/c2p_core.h b/drivers/video/c2p_core.h new file mode 100644 index 00000000000..e1035a865fb --- /dev/null +++ b/drivers/video/c2p_core.h @@ -0,0 +1,153 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003-2008 Geert Uytterhoeven + * + * NOTES: + * - This code was inspired by Scout's C2P tutorial + * - It assumes to run on a big endian system + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + + + /* + * Basic transpose step + */ + +static inline void _transp(u32 d[], unsigned int i1, unsigned int i2, + unsigned int shift, u32 mask) +{ + u32 t = (d[i1] ^ (d[i2] >> shift)) & mask; + + d[i1] ^= t; + d[i2] ^= t << shift; +} + + +extern void c2p_unsupported(void); + +static inline u32 get_mask(unsigned int n) +{ + switch (n) { + case 1: + return 0x55555555; + + case 2: + return 0x33333333; + + case 4: + return 0x0f0f0f0f; + + case 8: + return 0x00ff00ff; + + case 16: + return 0x0000ffff; + } + + c2p_unsupported(); + return 0; +} + + + /* + * Transpose operations on 8 32-bit words + */ + +static inline void transp8(u32 d[], unsigned int n, unsigned int m) +{ + u32 mask = get_mask(n); + + switch (m) { + case 1: + /* First n x 1 block */ + _transp(d, 0, 1, n, mask); + /* Second n x 1 block */ + _transp(d, 2, 3, n, mask); + /* Third n x 1 block */ + _transp(d, 4, 5, n, mask); + /* Fourth n x 1 block */ + _transp(d, 6, 7, n, mask); + return; + + case 2: + /* First n x 2 block */ + _transp(d, 0, 2, n, mask); + _transp(d, 1, 3, n, mask); + /* Second n x 2 block */ + _transp(d, 4, 6, n, mask); + _transp(d, 5, 7, n, mask); + return; + + case 4: + /* Single n x 4 block */ + _transp(d, 0, 4, n, mask); + _transp(d, 1, 5, n, mask); + _transp(d, 2, 6, n, mask); + _transp(d, 3, 7, n, mask); + return; + } + + c2p_unsupported(); +} + + + /* + * Transpose operations on 4 32-bit words + */ + +static inline void transp4(u32 d[], unsigned int n, unsigned int m) +{ + u32 mask = get_mask(n); + + switch (m) { + case 1: + /* First n x 1 block */ + _transp(d, 0, 1, n, mask); + /* Second n x 1 block */ + _transp(d, 2, 3, n, mask); + return; + + case 2: + /* Single n x 2 block */ + _transp(d, 0, 2, n, mask); + _transp(d, 1, 3, n, mask); + return; + } + + c2p_unsupported(); +} + + + /* + * Transpose operations on 4 32-bit words (reverse order) + */ + +static inline void transp4x(u32 d[], unsigned int n, unsigned int m) +{ + u32 mask = get_mask(n); + + switch (m) { + case 2: + /* Single n x 2 block */ + _transp(d, 2, 0, n, mask); + _transp(d, 3, 1, n, mask); + return; + } + + c2p_unsupported(); +} + + + /* + * Compose two values, using a bitmask as decision value + * This is equivalent to (a & mask) | (b & ~mask) + */ + +static inline u32 comp(u32 a, u32 b, u32 mask) +{ + return ((a ^ b) & mask) ^ b; +} diff --git a/drivers/video/c2p_iplan2.c b/drivers/video/c2p_iplan2.c new file mode 100644 index 00000000000..19156dc6158 --- /dev/null +++ b/drivers/video/c2p_iplan2.c @@ -0,0 +1,153 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003-2008 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/module.h> +#include <linux/string.h> + +#include <asm/unaligned.h> + +#include "c2p.h" +#include "c2p_core.h" + + + /* + * Perform a full C2P step on 16 8-bit pixels, stored in 4 32-bit words + * containing + * - 16 8-bit chunky pixels on input + * - permutated planar data (2 planes per 32-bit word) on output + */ + +static void c2p_16x8(u32 d[4]) +{ + transp4(d, 8, 2); + transp4(d, 1, 2); + transp4x(d, 16, 2); + transp4x(d, 2, 2); + transp4(d, 4, 1); +} + + + /* + * Array containing the permutation indices of the planar data after c2p + */ + +static const int perm_c2p_16x8[4] = { 1, 3, 0, 2 }; + + + /* + * Store a full block of iplan2 data after c2p conversion + */ + +static inline void store_iplan2(void *dst, u32 bpp, u32 d[4]) +{ + int i; + + for (i = 0; i < bpp/2; i++, dst += 4) + put_unaligned_be32(d[perm_c2p_16x8[i]], dst); +} + + + /* + * Store a partial block of iplan2 data after c2p conversion + */ + +static inline void store_iplan2_masked(void *dst, u32 bpp, u32 d[4], u32 mask) +{ + int i; + + for (i = 0; i < bpp/2; i++, dst += 4) + put_unaligned_be32(comp(d[perm_c2p_16x8[i]], + get_unaligned_be32(dst), mask), + dst); +} + + + /* + * c2p_iplan2 - Copy 8-bit chunky image data to an interleaved planar + * frame buffer with 2 bytes of interleave + * @dst: Starting address of the planar frame buffer + * @dx: Horizontal destination offset (in pixels) + * @dy: Vertical destination offset (in pixels) + * @width: Image width (in pixels) + * @height: Image height (in pixels) + * @dst_nextline: Frame buffer offset to the next line (in bytes) + * @src_nextline: Image offset to the next line (in bytes) + * @bpp: Bits per pixel of the planar frame buffer (2, 4, or 8) + */ + +void c2p_iplan2(void *dst, const void *src, u32 dx, u32 dy, u32 width, + u32 height, u32 dst_nextline, u32 src_nextline, u32 bpp) +{ + union { + u8 pixels[16]; + u32 words[4]; + } d; + u32 dst_idx, first, last, w; + const u8 *c; + void *p; + + dst += dy*dst_nextline+(dx & ~15)*bpp; + dst_idx = dx % 16; + first = 0xffffU >> dst_idx; + first |= first << 16; + last = 0xffffU ^ (0xffffU >> ((dst_idx+width) % 16)); + last |= last << 16; + while (height--) { + c = src; + p = dst; + w = width; + if (dst_idx+width <= 16) { + /* Single destination word */ + first &= last; + memset(d.pixels, 0, sizeof(d)); + memcpy(d.pixels+dst_idx, c, width); + c += width; + c2p_16x8(d.words); + store_iplan2_masked(p, bpp, d.words, first); + p += bpp*2; + } else { + /* Multiple destination words */ + w = width; + /* Leading bits */ + if (dst_idx) { + w = 16 - dst_idx; + memset(d.pixels, 0, dst_idx); + memcpy(d.pixels+dst_idx, c, w); + c += w; + c2p_16x8(d.words); + store_iplan2_masked(p, bpp, d.words, first); + p += bpp*2; + w = width-w; + } + /* Main chunk */ + while (w >= 16) { + memcpy(d.pixels, c, 16); + c += 16; + c2p_16x8(d.words); + store_iplan2(p, bpp, d.words); + p += bpp*2; + w -= 16; + } + /* Trailing bits */ + w %= 16; + if (w > 0) { + memcpy(d.pixels, c, w); + memset(d.pixels+w, 0, 16-w); + c2p_16x8(d.words); + store_iplan2_masked(p, bpp, d.words, last); + } + } + src += src_nextline; + dst += dst_nextline; + } +} +EXPORT_SYMBOL_GPL(c2p_iplan2); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/c2p_planar.c b/drivers/video/c2p_planar.c new file mode 100644 index 00000000000..ec7ac8526f0 --- /dev/null +++ b/drivers/video/c2p_planar.c @@ -0,0 +1,156 @@ +/* + * Fast C2P (Chunky-to-Planar) Conversion + * + * Copyright (C) 2003-2008 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#include <linux/module.h> +#include <linux/string.h> + +#include <asm/unaligned.h> + +#include "c2p.h" +#include "c2p_core.h" + + + /* + * Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words + * containing + * - 32 8-bit chunky pixels on input + * - permutated planar data (1 plane per 32-bit word) on output + */ + +static void c2p_32x8(u32 d[8]) +{ + transp8(d, 16, 4); + transp8(d, 8, 2); + transp8(d, 4, 1); + transp8(d, 2, 4); + transp8(d, 1, 2); +} + + + /* + * Array containing the permutation indices of the planar data after c2p + */ + +static const int perm_c2p_32x8[8] = { 7, 5, 3, 1, 6, 4, 2, 0 }; + + + /* + * Store a full block of planar data after c2p conversion + */ + +static inline void store_planar(void *dst, u32 dst_inc, u32 bpp, u32 d[8]) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + put_unaligned_be32(d[perm_c2p_32x8[i]], dst); +} + + + /* + * Store a partial block of planar data after c2p conversion + */ + +static inline void store_planar_masked(void *dst, u32 dst_inc, u32 bpp, + u32 d[8], u32 mask) +{ + int i; + + for (i = 0; i < bpp; i++, dst += dst_inc) + put_unaligned_be32(comp(d[perm_c2p_32x8[i]], + get_unaligned_be32(dst), mask), + dst); +} + + + /* + * c2p_planar - Copy 8-bit chunky image data to a planar frame buffer + * @dst: Starting address of the planar frame buffer + * @dx: Horizontal destination offset (in pixels) + * @dy: Vertical destination offset (in pixels) + * @width: Image width (in pixels) + * @height: Image height (in pixels) + * @dst_nextline: Frame buffer offset to the next line (in bytes) + * @dst_nextplane: Frame buffer offset to the next plane (in bytes) + * @src_nextline: Image offset to the next line (in bytes) + * @bpp: Bits per pixel of the planar frame buffer (1-8) + */ + +void c2p_planar(void *dst, const void *src, u32 dx, u32 dy, u32 width, + u32 height, u32 dst_nextline, u32 dst_nextplane, + u32 src_nextline, u32 bpp) +{ + union { + u8 pixels[32]; + u32 words[8]; + } d; + u32 dst_idx, first, last, w; + const u8 *c; + void *p; + + dst += dy*dst_nextline+(dx & ~31); + dst_idx = dx % 32; + first = 0xffffffffU >> dst_idx; + last = ~(0xffffffffU >> ((dst_idx+width) % 32)); + while (height--) { + c = src; + p = dst; + w = width; + if (dst_idx+width <= 32) { + /* Single destination word */ + first &= last; + memset(d.pixels, 0, sizeof(d)); + memcpy(d.pixels+dst_idx, c, width); + c += width; + c2p_32x8(d.words); + store_planar_masked(p, dst_nextplane, bpp, d.words, + first); + p += 4; + } else { + /* Multiple destination words */ + w = width; + /* Leading bits */ + if (dst_idx) { + w = 32 - dst_idx; + memset(d.pixels, 0, dst_idx); + memcpy(d.pixels+dst_idx, c, w); + c += w; + c2p_32x8(d.words); + store_planar_masked(p, dst_nextplane, bpp, + d.words, first); + p += 4; + w = width-w; + } + /* Main chunk */ + while (w >= 32) { + memcpy(d.pixels, c, 32); + c += 32; + c2p_32x8(d.words); + store_planar(p, dst_nextplane, bpp, d.words); + p += 4; + w -= 32; + } + /* Trailing bits */ + w %= 32; + if (w > 0) { + memcpy(d.pixels, c, w); + memset(d.pixels+w, 0, 32-w); + c2p_32x8(d.words); + store_planar_masked(p, dst_nextplane, bpp, + d.words, last); + } + } + src += src_nextline; + dst += dst_nextline; + } +} +EXPORT_SYMBOL_GPL(c2p_planar); + +MODULE_LICENSE("GPL"); diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 4bcff81b50e..1657b9608b0 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -78,13 +78,6 @@ #include <asm/fb.h> #include <asm/irq.h> #include <asm/system.h> -#ifdef CONFIG_ATARI -#include <asm/atariints.h> -#endif -#if defined(__mc68000__) -#include <asm/machdep.h> -#include <asm/setup.h> -#endif #include "fbcon.h" @@ -155,9 +148,6 @@ static int fbcon_set_origin(struct vc_data *); #define CURSOR_DRAW_DELAY (1) -/* # VBL ints between cursor state changes */ -#define ATARI_CURSOR_BLINK_RATE (42) - static int vbl_cursor_cnt; static int fbcon_cursor_noblink; @@ -403,20 +393,6 @@ static void fb_flashcursor(struct work_struct *work) release_console_sem(); } -#ifdef CONFIG_ATARI -static int cursor_blink_rate; -static irqreturn_t fb_vbl_handler(int irq, void *dev_id) -{ - struct fb_info *info = dev_id; - - if (vbl_cursor_cnt && --vbl_cursor_cnt == 0) { - schedule_work(&info->queue); - vbl_cursor_cnt = cursor_blink_rate; - } - return IRQ_HANDLED; -} -#endif - static void cursor_timer_handler(unsigned long dev_addr) { struct fb_info *info = (struct fb_info *) dev_addr; @@ -1017,15 +993,6 @@ static const char *fbcon_startup(void) info->var.yres, info->var.bits_per_pixel); -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) { - cursor_blink_rate = ATARI_CURSOR_BLINK_RATE; - (void)request_irq(IRQ_AUTO_4, fb_vbl_handler, - IRQ_TYPE_PRIO, "framebuffer vbl", - info); - } -#endif /* CONFIG_ATARI */ - fbcon_add_cursor_timer(info); fbcon_has_exited = 0; return display_desc; @@ -3454,11 +3421,6 @@ static void fbcon_exit(void) if (fbcon_has_exited) return; -#ifdef CONFIG_ATARI - if (MACH_IS_ATARI) - free_irq(IRQ_AUTO_4, fb_vbl_handler); -#endif - kfree((void *)softback_buf); softback_buf = 0UL; diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 90616822cd2..96d2f8e4c27 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -34,6 +34,12 @@ config W1_MASTER_DS2482 This driver can also be built as a module. If so, the module will be called ds2482. +config W1_MASTER_MXC + tristate "Freescale MXC 1-wire busmaster" + depends on W1 && ARCH_MXC + help + Say Y here to enable MXC 1-wire host + config W1_MASTER_DS1WM tristate "Maxim DS1WM 1-wire busmaster" depends on W1 && ARM && HAVE_CLK diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index bc4714a75f3..c5a3e96fcba 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o +obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o + obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c new file mode 100644 index 00000000000..b9d74d0b353 --- /dev/null +++ b/drivers/w1/masters/mxc_w1.c @@ -0,0 +1,211 @@ +/* + * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Luotao Fu, kernel@pengutronix.de + * + * 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 <linux/module.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include "../w1.h" +#include "../w1_int.h" +#include "../w1_log.h" + +/* According to the mx27 Datasheet the reset procedure should take up to about + * 1350us. We set the timeout to 500*100us = 50ms for sure */ +#define MXC_W1_RESET_TIMEOUT 500 + +/* + * MXC W1 Register offsets + */ +#define MXC_W1_CONTROL 0x00 +#define MXC_W1_TIME_DIVIDER 0x02 +#define MXC_W1_RESET 0x04 +#define MXC_W1_COMMAND 0x06 +#define MXC_W1_TXRX 0x08 +#define MXC_W1_INTERRUPT 0x0A +#define MXC_W1_INTERRUPT_EN 0x0C + +struct mxc_w1_device { + void __iomem *regs; + unsigned int clkdiv; + struct clk *clk; + struct w1_bus_master bus_master; +}; + +/* + * this is the low level routine to + * reset the device on the One Wire interface + * on the hardware + */ +static u8 mxc_w1_ds2_reset_bus(void *data) +{ + u8 reg_val; + unsigned int timeout_cnt = 0; + struct mxc_w1_device *dev = data; + + __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL)); + + while (1) { + reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL); + + if (((reg_val >> 7) & 0x1) == 0 || + timeout_cnt > MXC_W1_RESET_TIMEOUT) + break; + else + timeout_cnt++; + + udelay(100); + } + return (reg_val >> 7) & 0x1; +} + +/* + * this is the low level routine to read/write a bit on the One Wire + * interface on the hardware. It does write 0 if parameter bit is set + * to 0, otherwise a write 1/read. + */ +static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) +{ + struct mxc_w1_device *mdev = data; + void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL; + unsigned int timeout_cnt = 400; /* Takes max. 120us according to + * datasheet. + */ + + __raw_writeb((1 << (5 - bit)), ctrl_addr); + + while (timeout_cnt--) { + if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1)) + break; + + udelay(1); + } + + return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; +} + +static int __init mxc_w1_probe(struct platform_device *pdev) +{ + struct mxc_w1_device *mdev; + struct resource *res; + int err = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL); + if (!mdev) + return -ENOMEM; + + mdev->clk = clk_get(&pdev->dev, "owire_clk"); + if (!mdev->clk) { + err = -ENODEV; + goto failed_clk; + } + + mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; + + res = request_mem_region(res->start, resource_size(res), + "mxc_w1"); + if (!res) { + err = -EBUSY; + goto failed_req; + } + + mdev->regs = ioremap(res->start, resource_size(res)); + if (!mdev->regs) { + printk(KERN_ERR "Cannot map frame buffer registers\n"); + goto failed_ioremap; + } + + clk_enable(mdev->clk); + __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); + + mdev->bus_master.data = mdev; + mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; + mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; + + err = w1_add_master_device(&mdev->bus_master); + + if (err) + goto failed_add; + + platform_set_drvdata(pdev, mdev); + return 0; + +failed_add: + iounmap(mdev->regs); +failed_ioremap: + release_mem_region(res->start, resource_size(res)); +failed_req: + clk_put(mdev->clk); +failed_clk: + kfree(mdev); + return err; +} + +/* + * disassociate the w1 device from the driver + */ +static int mxc_w1_remove(struct platform_device *pdev) +{ + struct mxc_w1_device *mdev = platform_get_drvdata(pdev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + w1_remove_master_device(&mdev->bus_master); + + iounmap(mdev->regs); + release_mem_region(res->start, resource_size(res)); + clk_disable(mdev->clk); + clk_put(mdev->clk); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver mxc_w1_driver = { + .driver = { + .name = "mxc_w1", + }, + .probe = mxc_w1_probe, + .remove = mxc_w1_remove, +}; + +static int __init mxc_w1_init(void) +{ + return platform_driver_register(&mxc_w1_driver); +} + +static void mxc_w1_exit(void) +{ + platform_driver_unregister(&mxc_w1_driver); +} + +module_init(mxc_w1_init); +module_exit(mxc_w1_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Freescale Semiconductors Inc"); +MODULE_DESCRIPTION("Driver for One-Wire on MXC"); diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 97304bd83ec..d8a9709f344 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h @@ -210,6 +210,7 @@ u8 w1_read_8(struct w1_master *); int w1_reset_bus(struct w1_master *); u8 w1_calc_crc8(u8 *, int); void w1_write_block(struct w1_master *, const u8 *, int); +void w1_touch_block(struct w1_master *, u8 *, int); u8 w1_read_block(struct w1_master *, u8 *, int); int w1_reset_select_slave(struct w1_slave *sl); void w1_next_pullup(struct w1_master *, int); diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 5139c25ca96..442bd8bbd4a 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c @@ -238,7 +238,6 @@ EXPORT_SYMBOL_GPL(w1_read_8); * @param dev the master device * @param buf pointer to the data to write * @param len the number of bytes to write - * @return the byte read */ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) { @@ -256,6 +255,31 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) EXPORT_SYMBOL_GPL(w1_write_block); /** + * Touches a series of bytes. + * + * @param dev the master device + * @param buf pointer to the data to write + * @param len the number of bytes to write + */ +void w1_touch_block(struct w1_master *dev, u8 *buf, int len) +{ + int i, j; + u8 tmp; + + for (i = 0; i < len; ++i) { + tmp = 0; + for (j = 0; j < 8; ++j) { + if (j == 7) + w1_pre_write(dev); + tmp |= w1_touch_bit(dev, (buf[i] >> j) & 0x1) << j; + } + + buf[i] = tmp; + } +} +EXPORT_SYMBOL_GPL(w1_touch_block); + +/** * Reads a series of bytes. * * @param dev the master device diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 65c5ebd0787..fdf72851c57 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -47,21 +47,56 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) cn_netlink_send(m, 0, GFP_KERNEL); } -static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, - struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) +static void w1_send_slave(struct w1_master *dev, u64 rn) +{ + struct cn_msg *msg = dev->priv; + struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); + struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); + int avail; + + avail = dev->priv_size - cmd->len; + + if (avail > 8) { + u64 *data = (void *)(cmd + 1) + cmd->len; + + *data = rn; + cmd->len += 8; + hdr->len += 8; + msg->len += 8; + return; + } + + msg->ack++; + cn_netlink_send(msg, 0, GFP_KERNEL); + + msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); + hdr->len = sizeof(struct w1_netlink_cmd); + cmd->len = 0; +} + +static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, + unsigned int avail) { - dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", - __func__, dev->name, cmd->cmd, cmd->len); + struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); + struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); + int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH; - if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) - return -EINVAL; + dev->priv = msg; + dev->priv_size = avail; + + w1_search_devices(dev, search_type, w1_send_slave); + + msg->ack = 0; + cn_netlink_send(msg, 0, GFP_KERNEL); + + dev->priv = NULL; + dev->priv_size = 0; - w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); return 0; } -static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, - struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) +static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, + struct w1_netlink_cmd *cmd) { void *data; struct w1_netlink_msg *h; @@ -85,7 +120,8 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); cm->ack = msg->seq+1; - cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; + cm->len = sizeof(struct w1_netlink_msg) + + sizeof(struct w1_netlink_cmd) + cmd->len; h->len = sizeof(struct w1_netlink_cmd) + cmd->len; @@ -98,36 +134,178 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, return err; } -static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, +static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) { int err = 0; - dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", - __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, - cmd->cmd, cmd->len); + switch (cmd->cmd) { + case W1_CMD_TOUCH: + w1_touch_block(dev, cmd->data, cmd->len); + w1_send_read_reply(msg, hdr, cmd); + break; + case W1_CMD_READ: + w1_read_block(dev, cmd->data, cmd->len); + w1_send_read_reply(msg, hdr, cmd); + break; + case W1_CMD_WRITE: + w1_write_block(dev, cmd->data, cmd->len); + break; + default: + err = -EINVAL; + break; + } + + return err; +} + +static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, + struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) +{ + int err = -EINVAL; + struct cn_msg *msg; + struct w1_netlink_msg *hdr; + struct w1_netlink_cmd *cmd; + + msg = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->id = req_msg->id; + msg->seq = req_msg->seq; + msg->ack = 0; + msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); + + hdr = (struct w1_netlink_msg *)(msg + 1); + cmd = (struct w1_netlink_cmd *)(hdr + 1); + + hdr->type = W1_MASTER_CMD; + hdr->id = req_hdr->id; + hdr->len = sizeof(struct w1_netlink_cmd); + + cmd->cmd = req_cmd->cmd; + cmd->len = 0; switch (cmd->cmd) { - case W1_CMD_READ: - w1_read_block(sl->master, cmd->data, cmd->len); - w1_send_read_reply(sl, msg, hdr, cmd); - break; - case W1_CMD_WRITE: - w1_write_block(sl->master, cmd->data, cmd->len); - break; - case W1_CMD_SEARCH: - case W1_CMD_ALARM_SEARCH: - w1_search_process(sl->master, - (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); - break; - default: - err = -1; - break; + case W1_CMD_SEARCH: + case W1_CMD_ALARM_SEARCH: + err = w1_process_search_command(dev, msg, + PAGE_SIZE - msg->len - sizeof(struct cn_msg)); + break; + case W1_CMD_READ: + case W1_CMD_WRITE: + case W1_CMD_TOUCH: + err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); + break; + case W1_CMD_RESET: + err = w1_reset_bus(dev); + break; + default: + err = -EINVAL; + break; } + kfree(msg); return err; } +static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, + struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) +{ + dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", + __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, + sl->reg_num.crc, cmd->cmd, cmd->len); + + return w1_process_command_io(sl->master, msg, hdr, cmd); +} + +static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) +{ + struct w1_master *m; + struct cn_msg *cn; + struct w1_netlink_msg *w; + u32 *id; + + if (mcmd->type != W1_LIST_MASTERS) { + printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", + __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); + return -EPROTO; + } + + cn = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!cn) + return -ENOMEM; + + cn->id.idx = CN_W1_IDX; + cn->id.val = CN_W1_VAL; + + cn->seq = msg->seq; + cn->ack = 1; + cn->len = sizeof(struct w1_netlink_msg); + w = (struct w1_netlink_msg *)(cn + 1); + + w->type = W1_LIST_MASTERS; + w->status = 0; + w->len = 0; + id = (u32 *)(w + 1); + + mutex_lock(&w1_mlock); + list_for_each_entry(m, &w1_masters, w1_master_entry) { + if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { + cn_netlink_send(cn, 0, GFP_KERNEL); + cn->ack++; + cn->len = sizeof(struct w1_netlink_msg); + w->len = 0; + id = (u32 *)(w + 1); + } + + *id = m->id; + w->len += sizeof(*id); + cn->len += sizeof(*id); + id++; + } + cn->ack = 0; + cn_netlink_send(cn, 0, GFP_KERNEL); + mutex_unlock(&w1_mlock); + + kfree(cn); + return 0; +} + +static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, + struct w1_netlink_cmd *rcmd, int error) +{ + struct cn_msg *cmsg; + struct w1_netlink_msg *msg; + struct w1_netlink_cmd *cmd; + + cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); + if (!cmsg) + return -ENOMEM; + + msg = (struct w1_netlink_msg *)(cmsg + 1); + cmd = (struct w1_netlink_cmd *)(msg + 1); + + memcpy(cmsg, rcmsg, sizeof(*cmsg)); + cmsg->len = sizeof(*msg); + + memcpy(msg, rmsg, sizeof(*msg)); + msg->len = 0; + msg->status = (short)-error; + + if (rcmd) { + memcpy(cmd, rcmd, sizeof(*cmd)); + cmd->len = 0; + msg->len += sizeof(*cmd); + cmsg->len += sizeof(*cmd); + } + + error = cn_netlink_send(cmsg, 0, GFP_KERNEL); + kfree(cmsg); + + return error; +} + static void w1_cn_callback(void *data) { struct cn_msg *msg = data; @@ -144,6 +322,7 @@ static void w1_cn_callback(void *data) dev = NULL; sl = NULL; + cmd = NULL; memcpy(&id, m->id.id, sizeof(id)); #if 0 @@ -155,15 +334,15 @@ static void w1_cn_callback(void *data) break; } - if (!mlen) - goto out_cont; - if (m->type == W1_MASTER_CMD) { dev = w1_search_master_id(m->id.mst.id); } else if (m->type == W1_SLAVE_CMD) { sl = w1_search_slave(&id); if (sl) dev = sl->master; + } else { + err = w1_process_command_root(msg, m); + goto out_cont; } if (!dev) { @@ -171,6 +350,10 @@ static void w1_cn_callback(void *data) goto out_cont; } + err = 0; + if (!mlen) + goto out_cont; + mutex_lock(&dev->mutex); if (sl && w1_reset_select_slave(sl)) { @@ -187,9 +370,12 @@ static void w1_cn_callback(void *data) } if (sl) - w1_process_command_slave(sl, msg, m, cmd); + err = w1_process_command_slave(sl, msg, m, cmd); else - w1_process_command_master(dev, msg, m, cmd); + err = w1_process_command_master(dev, msg, m, cmd); + + w1_netlink_send_error(msg, m, cmd, err); + err = 0; cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); mlen -= cmd->len + sizeof(struct w1_netlink_cmd); @@ -200,6 +386,8 @@ out_up: atomic_dec(&sl->refcnt); mutex_unlock(&dev->mutex); out_cont: + if (!cmd || err) + w1_netlink_send_error(msg, m, cmd, err); msg->len -= sizeof(struct w1_netlink_msg) + m->len; m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); @@ -209,11 +397,6 @@ out_cont: if (err == -ENODEV) err = 0; } -#if 0 - if (err) { - printk("%s: malformed message. Dropping.\n", __func__); - } -#endif } int w1_init_netlink(void) diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 56122b9e929..27e950f935b 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h @@ -34,12 +34,13 @@ enum w1_netlink_message_types { W1_MASTER_REMOVE, W1_MASTER_CMD, W1_SLAVE_CMD, + W1_LIST_MASTERS, }; struct w1_netlink_msg { __u8 type; - __u8 reserved; + __u8 status; __u16 len; union { __u8 id[8]; @@ -51,10 +52,15 @@ struct w1_netlink_msg __u8 data[0]; }; -#define W1_CMD_READ 0x0 -#define W1_CMD_WRITE 0x1 -#define W1_CMD_SEARCH 0x2 -#define W1_CMD_ALARM_SEARCH 0x3 +enum w1_commands { + W1_CMD_READ = 0, + W1_CMD_WRITE, + W1_CMD_SEARCH, + W1_CMD_ALARM_SEARCH, + W1_CMD_TOUCH, + W1_CMD_RESET, + W1_CMD_MAX, +}; struct w1_netlink_cmd { diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ec68c741b56..3efa12f9ee5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -770,6 +770,12 @@ config TXX9_WDT # POWERPC Architecture +config GEF_WDT + tristate "GE Fanuc Watchdog Timer" + depends on GEF_SBC610 + ---help--- + Watchdog timer found in a number of GE Fanuc single board computers. + config MPC5200_WDT tristate "MPC5200 Watchdog Timer" depends on PPC_MPC52xx @@ -790,6 +796,14 @@ config MV64X60_WDT tristate "MV64X60 (Marvell Discovery) Watchdog Timer" depends on MV64X60 +config PIKA_WDT + tristate "PIKA FPGA Watchdog" + depends on WARP + default y + help + This enables the watchdog in the PIKA FPGA. Currently used on + the Warp platform. + config BOOKE_WDT bool "PowerPC Book-E Watchdog Timer" depends on BOOKE || 4xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index c19b866f5ed..806b3eb0853 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -111,9 +111,11 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o # PARISC Architecture # POWERPC Architecture +obj-$(CONFIG_GEF_WDT) += gef_wdt.o obj-$(CONFIG_MPC5200_WDT) += mpc5200_wdt.o obj-$(CONFIG_8xxx_WDT) += mpc8xxx_wdt.o obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o +obj-$(CONFIG_PIKA_WDT) += pika_wdt.o obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o # PPC64 Architecture diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c new file mode 100644 index 00000000000..f0c2b7a1a17 --- /dev/null +++ b/drivers/watchdog/gef_wdt.c @@ -0,0 +1,330 @@ +/* + * GE Fanuc watchdog userspace interface + * + * Author: Martyn Welch <martyn.welch@gefanuc.com> + * + * Copyright 2008 GE Fanuc Intelligent Platforms Embedded Systems, 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. + * + * Based on: mv64x60_wdt.c (MV64X60 watchdog userspace interface) + * Author: James Chapman <jchapman@katalix.com> + */ + +/* TODO: + * This driver does not provide support for the hardwares capability of sending + * an interrupt at a programmable threshold. + * + * This driver currently can only support 1 watchdog - there are 2 in the + * hardware that this driver supports. Thus one could be configured as a + * process-based watchdog (via /dev/watchdog), the second (using the interrupt + * capabilities) a kernel-based watchdog. + */ + +#include <linux/kernel.h> +#include <linux/compiler.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/io.h> +#include <linux/uaccess.h> + +#include <sysdev/fsl_soc.h> + +/* + * The watchdog configuration register contains a pair of 2-bit fields, + * 1. a reload field, bits 27-26, which triggers a reload of + * the countdown register, and + * 2. an enable field, bits 25-24, which toggles between + * enabling and disabling the watchdog timer. + * Bit 31 is a read-only field which indicates whether the + * watchdog timer is currently enabled. + * + * The low 24 bits contain the timer reload value. + */ +#define GEF_WDC_ENABLE_SHIFT 24 +#define GEF_WDC_SERVICE_SHIFT 26 +#define GEF_WDC_ENABLED_SHIFT 31 + +#define GEF_WDC_ENABLED_TRUE 1 +#define GEF_WDC_ENABLED_FALSE 0 + +/* Flags bits */ +#define GEF_WDOG_FLAG_OPENED 0 + +static unsigned long wdt_flags; +static int wdt_status; +static void __iomem *gef_wdt_regs; +static int gef_wdt_timeout; +static int gef_wdt_count; +static unsigned int bus_clk; +static char expect_close; +static DEFINE_SPINLOCK(gef_wdt_spinlock); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + + +static int gef_wdt_toggle_wdc(int enabled_predicate, int field_shift) +{ + u32 data; + u32 enabled; + int ret = 0; + + spin_lock(&gef_wdt_spinlock); + data = ioread32be(gef_wdt_regs); + enabled = (data >> GEF_WDC_ENABLED_SHIFT) & 1; + + /* only toggle the requested field if enabled state matches predicate */ + if ((enabled ^ enabled_predicate) == 0) { + /* We write a 1, then a 2 -- to the appropriate field */ + data = (1 << field_shift) | gef_wdt_count; + iowrite32be(data, gef_wdt_regs); + + data = (2 << field_shift) | gef_wdt_count; + iowrite32be(data, gef_wdt_regs); + ret = 1; + } + spin_unlock(&gef_wdt_spinlock); + + return ret; +} + +static void gef_wdt_service(void) +{ + gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE, + GEF_WDC_SERVICE_SHIFT); +} + +static void gef_wdt_handler_enable(void) +{ + if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_FALSE, + GEF_WDC_ENABLE_SHIFT)) { + gef_wdt_service(); + printk(KERN_NOTICE "gef_wdt: watchdog activated\n"); + } +} + +static void gef_wdt_handler_disable(void) +{ + if (gef_wdt_toggle_wdc(GEF_WDC_ENABLED_TRUE, + GEF_WDC_ENABLE_SHIFT)) + printk(KERN_NOTICE "gef_wdt: watchdog deactivated\n"); +} + +static void gef_wdt_set_timeout(unsigned int timeout) +{ + /* maximum bus cycle count is 0xFFFFFFFF */ + if (timeout > 0xFFFFFFFF / bus_clk) + timeout = 0xFFFFFFFF / bus_clk; + + /* Register only holds upper 24 bits, bit shifted into lower 24 */ + gef_wdt_count = (timeout * bus_clk) >> 8; + gef_wdt_timeout = timeout; +} + + +static ssize_t gef_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + if (len) { + if (!nowayout) { + size_t i; + + 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; + } + } + gef_wdt_service(); + } + + return len; +} + +static long gef_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int timeout; + int options; + void __user *argp = (void __user *)arg; + static struct watchdog_info info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | + WDIOF_KEEPALIVEPING, + .firmware_version = 0, + .identity = "GE Fanuc watchdog", + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &info, sizeof(info))) + return -EFAULT; + break; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + if (put_user(wdt_status, (int __user *)argp)) + return -EFAULT; + wdt_status &= ~WDIOF_KEEPALIVEPING; + break; + + case WDIOC_SETOPTIONS: + if (get_user(options, (int __user *)argp)) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) + gef_wdt_handler_disable(); + + if (options & WDIOS_ENABLECARD) + gef_wdt_handler_enable(); + break; + + case WDIOC_KEEPALIVE: + gef_wdt_service(); + wdt_status |= WDIOF_KEEPALIVEPING; + break; + + case WDIOC_SETTIMEOUT: + if (get_user(timeout, (int __user *)argp)) + return -EFAULT; + gef_wdt_set_timeout(timeout); + /* Fall through */ + + case WDIOC_GETTIMEOUT: + if (put_user(gef_wdt_timeout, (int __user *)argp)) + return -EFAULT; + break; + + default: + return -ENOTTY; + } + + return 0; +} + +static int gef_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags)) + return -EBUSY; + + if (nowayout) + __module_get(THIS_MODULE); + + gef_wdt_handler_enable(); + + return nonseekable_open(inode, file); +} + +static int gef_wdt_release(struct inode *inode, struct file *file) +{ + if (expect_close == 42) + gef_wdt_handler_disable(); + else { + printk(KERN_CRIT + "gef_wdt: unexpected close, not stopping timer!\n"); + gef_wdt_service(); + } + expect_close = 0; + + clear_bit(GEF_WDOG_FLAG_OPENED, &wdt_flags); + + return 0; +} + +static const struct file_operations gef_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = gef_wdt_write, + .unlocked_ioctl = gef_wdt_ioctl, + .open = gef_wdt_open, + .release = gef_wdt_release, +}; + +static struct miscdevice gef_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &gef_wdt_fops, +}; + + +static int __devinit gef_wdt_probe(struct of_device *dev, + const struct of_device_id *match) +{ + int timeout = 10; + u32 freq; + + bus_clk = 133; /* in MHz */ + + freq = fsl_get_sys_freq(); + if (freq > 0) + bus_clk = freq; + + /* Map devices registers into memory */ + gef_wdt_regs = of_iomap(dev->node, 0); + if (gef_wdt_regs == NULL) + return -ENOMEM; + + gef_wdt_set_timeout(timeout); + + gef_wdt_handler_disable(); /* in case timer was already running */ + + return misc_register(&gef_wdt_miscdev); +} + +static int __devexit gef_wdt_remove(struct platform_device *dev) +{ + misc_deregister(&gef_wdt_miscdev); + + gef_wdt_handler_disable(); + + iounmap(gef_wdt_regs); + + return 0; +} + +static const struct of_device_id gef_wdt_ids[] = { + { + .compatible = "gef,fpga-wdt", + }, + {}, +}; + +static struct of_platform_driver gef_wdt_driver = { + .owner = THIS_MODULE, + .name = "gef_wdt", + .match_table = gef_wdt_ids, + .probe = gef_wdt_probe, +}; + +static int __init gef_wdt_init(void) +{ + printk(KERN_INFO "GE Fanuc watchdog driver\n"); + return of_register_platform_driver(&gef_wdt_driver); +} + +static void __exit gef_wdt_exit(void) +{ + of_unregister_platform_driver(&gef_wdt_driver); +} + +module_init(gef_wdt_init); +module_exit(gef_wdt_exit); + +MODULE_AUTHOR("Martyn Welch <martyn.welch@gefanuc.com>"); +MODULE_DESCRIPTION("GE Fanuc watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_ALIAS("platform: gef_wdt"); diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c new file mode 100644 index 00000000000..2d22e996e99 --- /dev/null +++ b/drivers/watchdog/pika_wdt.c @@ -0,0 +1,301 @@ +/* + * PIKA FPGA based Watchdog Timer + * + * Copyright (c) 2008 PIKA Technologies + * Sean MacLennan <smaclennan@pikatech.com> + */ + +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/watchdog.h> +#include <linux/reboot.h> +#include <linux/jiffies.h> +#include <linux/timer.h> +#include <linux/bitops.h> +#include <linux/uaccess.h> +#include <linux/io.h> +#include <linux/of_platform.h> + +#define DRV_NAME "PIKA-WDT" +#define PFX DRV_NAME ": " + +/* Hardware timeout in seconds */ +#define WDT_HW_TIMEOUT 2 + +/* Timer heartbeat (500ms) */ +#define WDT_TIMEOUT (HZ/2) + +/* User land timeout */ +#define WDT_HEARTBEAT 15 +static int heartbeat = WDT_HEARTBEAT; +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. " + "(default = " __MODULE_STRING(WDT_HEARTBEAT) ")"); + +static int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " + "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static struct { + void __iomem *fpga; + unsigned long next_heartbeat; /* the next_heartbeat for the timer */ + unsigned long open; + char expect_close; + int bootstatus; + struct timer_list timer; /* The timer that pings the watchdog */ +} pikawdt_private; + +static struct watchdog_info ident = { + .identity = DRV_NAME, + .options = WDIOF_CARDRESET | + WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +/* + * Reload the watchdog timer. (ie, pat the watchdog) + */ +static inline void pikawdt_reset(void) +{ + /* -- FPGA: Reset Control Register (32bit R/W) (Offset: 0x14) -- + * Bit 7, WTCHDG_EN: When set to 1, the watchdog timer is enabled. + * Once enabled, it cannot be disabled. The watchdog can be + * kicked by performing any write access to the reset + * control register (this register). + * Bit 8-11, WTCHDG_TIMEOUT_SEC: Sets the watchdog timeout value in + * seconds. Valid ranges are 1 to 15 seconds. The value can + * be modified dynamically. + */ + unsigned reset = in_be32(pikawdt_private.fpga + 0x14); + /* enable with max timeout - 15 seconds */ + reset |= (1 << 7) + (WDT_HW_TIMEOUT << 8); + out_be32(pikawdt_private.fpga + 0x14, reset); +} + +/* + * Timer tick + */ +static void pikawdt_ping(unsigned long data) +{ + if (time_before(jiffies, pikawdt_private.next_heartbeat) || + (!nowayout && !pikawdt_private.open)) { + pikawdt_reset(); + mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT); + } else + printk(KERN_CRIT PFX "I will reset your machine !\n"); +} + + +static void pikawdt_keepalive(void) +{ + pikawdt_private.next_heartbeat = jiffies + heartbeat * HZ; +} + +static void pikawdt_start(void) +{ + pikawdt_keepalive(); + mod_timer(&pikawdt_private.timer, jiffies + WDT_TIMEOUT); +} + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int pikawdt_open(struct inode *inode, struct file *file) +{ + /* /dev/watchdog can only be opened once */ + if (test_and_set_bit(0, &pikawdt_private.open)) + return -EBUSY; + + pikawdt_start(); + + return nonseekable_open(inode, file); +} + +/* + * Close the watchdog device. + */ +static int pikawdt_release(struct inode *inode, struct file *file) +{ + /* stop internal ping */ + if (!pikawdt_private.expect_close) + del_timer(&pikawdt_private.timer); + + clear_bit(0, &pikawdt_private.open); + pikawdt_private.expect_close = 0; + return 0; +} + +/* + * Pat the watchdog whenever device is written to. + */ +static ssize_t pikawdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + if (!len) + return 0; + + /* Scan for magic character */ + if (!nowayout) { + size_t i; + + pikawdt_private.expect_close = 0; + + for (i = 0; i < len; i++) { + char c; + if (get_user(c, data + i)) + return -EFAULT; + if (c == 'V') { + pikawdt_private.expect_close = 42; + break; + } + } + } + + pikawdt_keepalive(); + + return len; +} + +/* + * Handle commands from user-space. + */ +static long pikawdt_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_value; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + return put_user(0, p); + + case WDIOC_GETBOOTSTATUS: + return put_user(pikawdt_private.bootstatus, p); + + case WDIOC_KEEPALIVE: + pikawdt_keepalive(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + + heartbeat = new_value; + pikawdt_keepalive(); + + return put_user(new_value, p); /* return current value */ + + case WDIOC_GETTIMEOUT: + return put_user(heartbeat, p); + } + return -ENOTTY; +} + + +static const struct file_operations pikawdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .open = pikawdt_open, + .release = pikawdt_release, + .write = pikawdt_write, + .unlocked_ioctl = pikawdt_ioctl, +}; + +static struct miscdevice pikawdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &pikawdt_fops, +}; + +static int __init pikawdt_init(void) +{ + struct device_node *np; + void __iomem *fpga; + static u32 post1; + int ret; + + np = of_find_compatible_node(NULL, NULL, "pika,fpga"); + if (np == NULL) { + printk(KERN_ERR PFX "Unable to find fpga.\n"); + return -ENOENT; + } + + pikawdt_private.fpga = of_iomap(np, 0); + of_node_put(np); + if (pikawdt_private.fpga == NULL) { + printk(KERN_ERR PFX "Unable to map fpga.\n"); + return -ENOMEM; + } + + ident.firmware_version = in_be32(pikawdt_private.fpga + 0x1c) & 0xffff; + + /* POST information is in the sd area. */ + np = of_find_compatible_node(NULL, NULL, "pika,fpga-sd"); + if (np == NULL) { + printk(KERN_ERR PFX "Unable to find fpga-sd.\n"); + ret = -ENOENT; + goto out; + } + + fpga = of_iomap(np, 0); + of_node_put(np); + if (fpga == NULL) { + printk(KERN_ERR PFX "Unable to map fpga-sd.\n"); + ret = -ENOMEM; + goto out; + } + + /* -- FPGA: POST Test Results Register 1 (32bit R/W) (Offset: 0x4040) -- + * Bit 31, WDOG: Set to 1 when the last reset was caused by a watchdog + * timeout. + */ + post1 = in_be32(fpga + 0x40); + if (post1 & 0x80000000) + pikawdt_private.bootstatus = WDIOF_CARDRESET; + + iounmap(fpga); + + setup_timer(&pikawdt_private.timer, pikawdt_ping, 0); + + ret = misc_register(&pikawdt_miscdev); + if (ret) { + printk(KERN_ERR PFX "Unable to register miscdev.\n"); + goto out; + } + + printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", + heartbeat, nowayout); + return 0; + +out: + iounmap(pikawdt_private.fpga); + return ret; +} + +static void __exit pikawdt_exit(void) +{ + misc_deregister(&pikawdt_miscdev); + + iounmap(pikawdt_private.fpga); +} + +module_init(pikawdt_init); +module_exit(pikawdt_exit); + +MODULE_AUTHOR("Sean MacLennan <smaclennan@pikatech.com>"); +MODULE_DESCRIPTION("PIKA FPGA based Watchdog Timer"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); + diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c index 2bc0d4d4b41..a2d2e8eb228 100644 --- a/drivers/watchdog/wm8350_wdt.c +++ b/drivers/watchdog/wm8350_wdt.c @@ -279,7 +279,7 @@ static struct miscdevice wm8350_wdt_miscdev = { .fops = &wm8350_wdt_fops, }; -static int wm8350_wdt_probe(struct platform_device *pdev) +static int __devinit wm8350_wdt_probe(struct platform_device *pdev) { struct wm8350 *wm8350 = platform_get_drvdata(pdev); @@ -296,7 +296,7 @@ static int wm8350_wdt_probe(struct platform_device *pdev) return misc_register(&wm8350_wdt_miscdev); } -static int __exit wm8350_wdt_remove(struct platform_device *pdev) +static int __devexit wm8350_wdt_remove(struct platform_device *pdev) { misc_deregister(&wm8350_wdt_miscdev); @@ -305,7 +305,7 @@ static int __exit wm8350_wdt_remove(struct platform_device *pdev) static struct platform_driver wm8350_wdt_driver = { .probe = wm8350_wdt_probe, - .remove = wm8350_wdt_remove, + .remove = __devexit_p(wm8350_wdt_remove), .driver = { .name = "wm8350-wdt", }, diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 4b75a16de00..526187c8a12 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -17,3 +17,27 @@ config XEN_SCRUB_PAGES is not accidentally visible to other domains. Is it more secure, but slightly less efficient. If in doubt, say yes. + +config XENFS + tristate "Xen filesystem" + depends on XEN + default y + help + The xen filesystem provides a way for domains to share + information with each other and with the hypervisor. + For example, by reading and writing the "xenbus" file, guests + may pass arbitrary information to the initial domain. + If in doubt, say yes. + +config XEN_COMPAT_XENFS + bool "Create compatibility mount point /proc/xen" + depends on XENFS + default y + help + The old xenstore userspace tools expect to find "xenbus" + under /proc/xen, but "xenbus" is now found at the root of the + xenfs filesystem. Selecting this causes the kernel to create + the compatibilty mount point /proc/xen if it is running on + a xen platform. + If in doubt, say yes. + diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index d2a8fdf0e19..ff8accc9e10 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -1,5 +1,7 @@ obj-y += grant-table.o features.o events.o manage.o obj-y += xenbus/ + obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += balloon.o +obj-$(CONFIG_XENFS) += xenfs/
\ No newline at end of file diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 9678b3e98c6..92a1ef80a28 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -136,7 +136,6 @@ EXPORT_SYMBOL_GPL(xenbus_watch_pathfmt); /** * xenbus_switch_state * @dev: xenbus device - * @xbt: transaction handle * @state: new state * * Advertise in the store a change of the given driver to the given new_state. @@ -267,7 +266,7 @@ EXPORT_SYMBOL_GPL(xenbus_dev_error); * @fmt: error message format * * Equivalent to xenbus_dev_error(dev, err, fmt, args), followed by - * xenbus_switch_state(dev, NULL, XenbusStateClosing) to schedule an orderly + * xenbus_switch_state(dev, XenbusStateClosing) to schedule an orderly * closedown of this driver and its peer. */ diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index b2a03184a24..773d1cf2328 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -40,6 +40,7 @@ #include <linux/ctype.h> #include <linux/fcntl.h> #include <linux/mm.h> +#include <linux/proc_fs.h> #include <linux/notifier.h> #include <linux/kthread.h> #include <linux/mutex.h> @@ -55,7 +56,10 @@ #include "xenbus_comms.h" #include "xenbus_probe.h" + int xen_store_evtchn; +EXPORT_SYMBOL(xen_store_evtchn); + struct xenstore_domain_interface *xen_store_interface; static unsigned long xen_store_mfn; @@ -166,6 +170,9 @@ static int read_backend_details(struct xenbus_device *xendev) return read_otherend_details(xendev, "backend-id", "backend"); } +static struct device_attribute xenbus_dev_attrs[] = { + __ATTR_NULL +}; /* Bus type for frontend drivers. */ static struct xen_bus_type xenbus_frontend = { @@ -174,12 +181,13 @@ static struct xen_bus_type xenbus_frontend = { .get_bus_id = frontend_bus_id, .probe = xenbus_probe_frontend, .bus = { - .name = "xen", - .match = xenbus_match, - .uevent = xenbus_uevent, - .probe = xenbus_dev_probe, - .remove = xenbus_dev_remove, - .shutdown = xenbus_dev_shutdown, + .name = "xen", + .match = xenbus_match, + .uevent = xenbus_uevent, + .probe = xenbus_dev_probe, + .remove = xenbus_dev_remove, + .shutdown = xenbus_dev_shutdown, + .dev_attrs = xenbus_dev_attrs, }, }; @@ -852,6 +860,14 @@ static int __init xenbus_probe_init(void) if (!xen_initial_domain()) xenbus_probe(NULL); +#ifdef CONFIG_XEN_COMPAT_XENFS + /* + * Create xenfs mountpoint in /proc for compatibility with + * utilities that expect to find "xenbus" under "/proc/xen". + */ + proc_mkdir("xen", NULL); +#endif + return 0; out_unreg_back: diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index 7f2f91c0e11..e325eab4724 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -184,6 +184,7 @@ void *xenbus_dev_request_and_reply(struct xsd_sockmsg *msg) return ret; } +EXPORT_SYMBOL(xenbus_dev_request_and_reply); /* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */ static void *xs_talkv(struct xenbus_transaction t, diff --git a/drivers/xen/xenfs/Makefile b/drivers/xen/xenfs/Makefile new file mode 100644 index 00000000000..25275c3bbdf --- /dev/null +++ b/drivers/xen/xenfs/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_XENFS) += xenfs.o + +xenfs-objs = super.o xenbus.o
\ No newline at end of file diff --git a/drivers/xen/xenfs/super.c b/drivers/xen/xenfs/super.c new file mode 100644 index 00000000000..515741a8e6b --- /dev/null +++ b/drivers/xen/xenfs/super.c @@ -0,0 +1,64 @@ +/* + * xenfs.c - a filesystem for passing info between the a domain and + * the hypervisor. + * + * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem + * and /proc/xen compatibility mount point. + * Turned xenfs into a loadable module. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/magic.h> + +#include "xenfs.h" + +#include <asm/xen/hypervisor.h> + +MODULE_DESCRIPTION("Xen filesystem"); +MODULE_LICENSE("GPL"); + +static int xenfs_fill_super(struct super_block *sb, void *data, int silent) +{ + static struct tree_descr xenfs_files[] = { + [2] = {"xenbus", &xenbus_file_ops, S_IRUSR|S_IWUSR}, + {""}, + }; + + return simple_fill_super(sb, XENFS_SUPER_MAGIC, xenfs_files); +} + +static int xenfs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + return get_sb_single(fs_type, flags, data, xenfs_fill_super, mnt); +} + +static struct file_system_type xenfs_type = { + .owner = THIS_MODULE, + .name = "xenfs", + .get_sb = xenfs_get_sb, + .kill_sb = kill_litter_super, +}; + +static int __init xenfs_init(void) +{ + if (xen_pv_domain()) + return register_filesystem(&xenfs_type); + + printk(KERN_INFO "XENFS: not registering filesystem on non-xen platform\n"); + return 0; +} + +static void __exit xenfs_exit(void) +{ + if (xen_pv_domain()) + unregister_filesystem(&xenfs_type); +} + +module_init(xenfs_init); +module_exit(xenfs_exit); + diff --git a/drivers/xen/xenfs/xenbus.c b/drivers/xen/xenfs/xenbus.c new file mode 100644 index 00000000000..875a4c59c59 --- /dev/null +++ b/drivers/xen/xenfs/xenbus.c @@ -0,0 +1,593 @@ +/* + * Driver giving user-space access to the kernel's xenbus connection + * to xenstore. + * + * Copyright (c) 2005, Christian Limpach + * Copyright (c) 2005, Rusty Russell, IBM Corporation + * + * 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; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this source file (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. + * + * Changes: + * 2008-10-07 Alex Zeffertt Replaced /proc/xen/xenbus with xenfs filesystem + * and /proc/xen compatibility mount point. + * Turned xenfs into a loadable module. + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/uio.h> +#include <linux/notifier.h> +#include <linux/wait.h> +#include <linux/fs.h> +#include <linux/poll.h> +#include <linux/mutex.h> +#include <linux/spinlock.h> +#include <linux/mount.h> +#include <linux/pagemap.h> +#include <linux/uaccess.h> +#include <linux/init.h> +#include <linux/namei.h> +#include <linux/string.h> + +#include "xenfs.h" +#include "../xenbus/xenbus_comms.h" + +#include <xen/xenbus.h> +#include <asm/xen/hypervisor.h> + +/* + * An element of a list of outstanding transactions, for which we're + * still waiting a reply. + */ +struct xenbus_transaction_holder { + struct list_head list; + struct xenbus_transaction handle; +}; + +/* + * A buffer of data on the queue. + */ +struct read_buffer { + struct list_head list; + unsigned int cons; + unsigned int len; + char msg[]; +}; + +struct xenbus_file_priv { + /* + * msgbuffer_mutex is held while partial requests are built up + * and complete requests are acted on. It therefore protects + * the "transactions" and "watches" lists, and the partial + * request length and buffer. + * + * reply_mutex protects the reply being built up to return to + * usermode. It nests inside msgbuffer_mutex but may be held + * alone during a watch callback. + */ + struct mutex msgbuffer_mutex; + + /* In-progress transactions */ + struct list_head transactions; + + /* Active watches. */ + struct list_head watches; + + /* Partial request. */ + unsigned int len; + union { + struct xsd_sockmsg msg; + char buffer[PAGE_SIZE]; + } u; + + /* Response queue. */ + struct mutex reply_mutex; + struct list_head read_buffers; + wait_queue_head_t read_waitq; + +}; + +/* Read out any raw xenbus messages queued up. */ +static ssize_t xenbus_file_read(struct file *filp, + char __user *ubuf, + size_t len, loff_t *ppos) +{ + struct xenbus_file_priv *u = filp->private_data; + struct read_buffer *rb; + unsigned i; + int ret; + + mutex_lock(&u->reply_mutex); + while (list_empty(&u->read_buffers)) { + mutex_unlock(&u->reply_mutex); + ret = wait_event_interruptible(u->read_waitq, + !list_empty(&u->read_buffers)); + if (ret) + return ret; + mutex_lock(&u->reply_mutex); + } + + rb = list_entry(u->read_buffers.next, struct read_buffer, list); + i = 0; + while (i < len) { + unsigned sz = min((unsigned)len - i, rb->len - rb->cons); + + ret = copy_to_user(ubuf + i, &rb->msg[rb->cons], sz); + + i += sz - ret; + rb->cons += sz - ret; + + if (ret != sz) { + if (i == 0) + i = -EFAULT; + goto out; + } + + /* Clear out buffer if it has been consumed */ + if (rb->cons == rb->len) { + list_del(&rb->list); + kfree(rb); + if (list_empty(&u->read_buffers)) + break; + rb = list_entry(u->read_buffers.next, + struct read_buffer, list); + } + } + +out: + mutex_unlock(&u->reply_mutex); + return i; +} + +/* + * Add a buffer to the queue. Caller must hold the appropriate lock + * if the queue is not local. (Commonly the caller will build up + * multiple queued buffers on a temporary local list, and then add it + * to the appropriate list under lock once all the buffers have een + * successfully allocated.) + */ +static int queue_reply(struct list_head *queue, const void *data, size_t len) +{ + struct read_buffer *rb; + + if (len == 0) + return 0; + + rb = kmalloc(sizeof(*rb) + len, GFP_KERNEL); + if (rb == NULL) + return -ENOMEM; + + rb->cons = 0; + rb->len = len; + + memcpy(rb->msg, data, len); + + list_add_tail(&rb->list, queue); + return 0; +} + +/* + * Free all the read_buffer s on a list. + * Caller must have sole reference to list. + */ +static void queue_cleanup(struct list_head *list) +{ + struct read_buffer *rb; + + while (!list_empty(list)) { + rb = list_entry(list->next, struct read_buffer, list); + list_del(list->next); + kfree(rb); + } +} + +struct watch_adapter { + struct list_head list; + struct xenbus_watch watch; + struct xenbus_file_priv *dev_data; + char *token; +}; + +static void free_watch_adapter(struct watch_adapter *watch) +{ + kfree(watch->watch.node); + kfree(watch->token); + kfree(watch); +} + +static struct watch_adapter *alloc_watch_adapter(const char *path, + const char *token) +{ + struct watch_adapter *watch; + + watch = kzalloc(sizeof(*watch), GFP_KERNEL); + if (watch == NULL) + goto out_fail; + + watch->watch.node = kstrdup(path, GFP_KERNEL); + if (watch->watch.node == NULL) + goto out_free; + + watch->token = kstrdup(token, GFP_KERNEL); + if (watch->token == NULL) + goto out_free; + + return watch; + +out_free: + free_watch_adapter(watch); + +out_fail: + return NULL; +} + +static void watch_fired(struct xenbus_watch *watch, + const char **vec, + unsigned int len) +{ + struct watch_adapter *adap; + struct xsd_sockmsg hdr; + const char *path, *token; + int path_len, tok_len, body_len, data_len = 0; + int ret; + LIST_HEAD(staging_q); + + adap = container_of(watch, struct watch_adapter, watch); + + path = vec[XS_WATCH_PATH]; + token = adap->token; + + path_len = strlen(path) + 1; + tok_len = strlen(token) + 1; + if (len > 2) + data_len = vec[len] - vec[2] + 1; + body_len = path_len + tok_len + data_len; + + hdr.type = XS_WATCH_EVENT; + hdr.len = body_len; + + mutex_lock(&adap->dev_data->reply_mutex); + + ret = queue_reply(&staging_q, &hdr, sizeof(hdr)); + if (!ret) + ret = queue_reply(&staging_q, path, path_len); + if (!ret) + ret = queue_reply(&staging_q, token, tok_len); + if (!ret && len > 2) + ret = queue_reply(&staging_q, vec[2], data_len); + + if (!ret) { + /* success: pass reply list onto watcher */ + list_splice_tail(&staging_q, &adap->dev_data->read_buffers); + wake_up(&adap->dev_data->read_waitq); + } else + queue_cleanup(&staging_q); + + mutex_unlock(&adap->dev_data->reply_mutex); +} + +static int xenbus_write_transaction(unsigned msg_type, + struct xenbus_file_priv *u) +{ + int rc, ret; + void *reply; + struct xenbus_transaction_holder *trans = NULL; + LIST_HEAD(staging_q); + + if (msg_type == XS_TRANSACTION_START) { + trans = kmalloc(sizeof(*trans), GFP_KERNEL); + if (!trans) { + rc = -ENOMEM; + goto out; + } + } + + reply = xenbus_dev_request_and_reply(&u->u.msg); + if (IS_ERR(reply)) { + kfree(trans); + rc = PTR_ERR(reply); + goto out; + } + + if (msg_type == XS_TRANSACTION_START) { + trans->handle.id = simple_strtoul(reply, NULL, 0); + + list_add(&trans->list, &u->transactions); + } else if (msg_type == XS_TRANSACTION_END) { + list_for_each_entry(trans, &u->transactions, list) + if (trans->handle.id == u->u.msg.tx_id) + break; + BUG_ON(&trans->list == &u->transactions); + list_del(&trans->list); + + kfree(trans); + } + + mutex_lock(&u->reply_mutex); + ret = queue_reply(&staging_q, &u->u.msg, sizeof(u->u.msg)); + if (!ret) + ret = queue_reply(&staging_q, reply, u->u.msg.len); + if (!ret) { + list_splice_tail(&staging_q, &u->read_buffers); + wake_up(&u->read_waitq); + } else { + queue_cleanup(&staging_q); + rc = ret; + } + mutex_unlock(&u->reply_mutex); + + kfree(reply); + +out: + return rc; +} + +static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) +{ + struct watch_adapter *watch, *tmp_watch; + char *path, *token; + int err, rc; + LIST_HEAD(staging_q); + + path = u->u.buffer + sizeof(u->u.msg); + token = memchr(path, 0, u->u.msg.len); + if (token == NULL) { + rc = -EILSEQ; + goto out; + } + token++; + + if (msg_type == XS_WATCH) { + watch = alloc_watch_adapter(path, token); + if (watch == NULL) { + rc = -ENOMEM; + goto out; + } + + watch->watch.callback = watch_fired; + watch->dev_data = u; + + err = register_xenbus_watch(&watch->watch); + if (err) { + free_watch_adapter(watch); + rc = err; + goto out; + } + list_add(&watch->list, &u->watches); + } else { + list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { + if (!strcmp(watch->token, token) && + !strcmp(watch->watch.node, path)) { + unregister_xenbus_watch(&watch->watch); + list_del(&watch->list); + free_watch_adapter(watch); + break; + } + } + } + + /* Success. Synthesize a reply to say all is OK. */ + { + struct { + struct xsd_sockmsg hdr; + char body[3]; + } __packed reply = { + { + .type = msg_type, + .len = sizeof(reply.body) + }, + "OK" + }; + + mutex_lock(&u->reply_mutex); + rc = queue_reply(&u->read_buffers, &reply, sizeof(reply)); + mutex_unlock(&u->reply_mutex); + } + +out: + return rc; +} + +static ssize_t xenbus_file_write(struct file *filp, + const char __user *ubuf, + size_t len, loff_t *ppos) +{ + struct xenbus_file_priv *u = filp->private_data; + uint32_t msg_type; + int rc = len; + int ret; + LIST_HEAD(staging_q); + + /* + * We're expecting usermode to be writing properly formed + * xenbus messages. If they write an incomplete message we + * buffer it up. Once it is complete, we act on it. + */ + + /* + * Make sure concurrent writers can't stomp all over each + * other's messages and make a mess of our partial message + * buffer. We don't make any attemppt to stop multiple + * writers from making a mess of each other's incomplete + * messages; we're just trying to guarantee our own internal + * consistency and make sure that single writes are handled + * atomically. + */ + mutex_lock(&u->msgbuffer_mutex); + + /* Get this out of the way early to avoid confusion */ + if (len == 0) + goto out; + + /* Can't write a xenbus message larger we can buffer */ + if ((len + u->len) > sizeof(u->u.buffer)) { + /* On error, dump existing buffer */ + u->len = 0; + rc = -EINVAL; + goto out; + } + + ret = copy_from_user(u->u.buffer + u->len, ubuf, len); + + if (ret == len) { + rc = -EFAULT; + goto out; + } + + /* Deal with a partial copy. */ + len -= ret; + rc = len; + + u->len += len; + + /* Return if we haven't got a full message yet */ + if (u->len < sizeof(u->u.msg)) + goto out; /* not even the header yet */ + + /* If we're expecting a message that's larger than we can + possibly send, dump what we have and return an error. */ + if ((sizeof(u->u.msg) + u->u.msg.len) > sizeof(u->u.buffer)) { + rc = -E2BIG; + u->len = 0; + goto out; + } + + if (u->len < (sizeof(u->u.msg) + u->u.msg.len)) + goto out; /* incomplete data portion */ + + /* + * OK, now we have a complete message. Do something with it. + */ + + msg_type = u->u.msg.type; + + switch (msg_type) { + case XS_TRANSACTION_START: + case XS_TRANSACTION_END: + case XS_DIRECTORY: + case XS_READ: + case XS_GET_PERMS: + case XS_RELEASE: + case XS_GET_DOMAIN_PATH: + case XS_WRITE: + case XS_MKDIR: + case XS_RM: + case XS_SET_PERMS: + /* Send out a transaction */ + ret = xenbus_write_transaction(msg_type, u); + break; + + case XS_WATCH: + case XS_UNWATCH: + /* (Un)Ask for some path to be watched for changes */ + ret = xenbus_write_watch(msg_type, u); + break; + + default: + ret = -EINVAL; + break; + } + if (ret != 0) + rc = ret; + + /* Buffered message consumed */ + u->len = 0; + + out: + mutex_unlock(&u->msgbuffer_mutex); + return rc; +} + +static int xenbus_file_open(struct inode *inode, struct file *filp) +{ + struct xenbus_file_priv *u; + + if (xen_store_evtchn == 0) + return -ENOENT; + + nonseekable_open(inode, filp); + + u = kzalloc(sizeof(*u), GFP_KERNEL); + if (u == NULL) + return -ENOMEM; + + INIT_LIST_HEAD(&u->transactions); + INIT_LIST_HEAD(&u->watches); + INIT_LIST_HEAD(&u->read_buffers); + init_waitqueue_head(&u->read_waitq); + + mutex_init(&u->reply_mutex); + mutex_init(&u->msgbuffer_mutex); + + filp->private_data = u; + + return 0; +} + +static int xenbus_file_release(struct inode *inode, struct file *filp) +{ + struct xenbus_file_priv *u = filp->private_data; + struct xenbus_transaction_holder *trans, *tmp; + struct watch_adapter *watch, *tmp_watch; + + /* + * No need for locking here because there are no other users, + * by definition. + */ + + list_for_each_entry_safe(trans, tmp, &u->transactions, list) { + xenbus_transaction_end(trans->handle, 1); + list_del(&trans->list); + kfree(trans); + } + + list_for_each_entry_safe(watch, tmp_watch, &u->watches, list) { + unregister_xenbus_watch(&watch->watch); + list_del(&watch->list); + free_watch_adapter(watch); + } + + kfree(u); + + return 0; +} + +static unsigned int xenbus_file_poll(struct file *file, poll_table *wait) +{ + struct xenbus_file_priv *u = file->private_data; + + poll_wait(file, &u->read_waitq, wait); + if (!list_empty(&u->read_buffers)) + return POLLIN | POLLRDNORM; + return 0; +} + +const struct file_operations xenbus_file_ops = { + .read = xenbus_file_read, + .write = xenbus_file_write, + .open = xenbus_file_open, + .release = xenbus_file_release, + .poll = xenbus_file_poll, +}; diff --git a/drivers/xen/xenfs/xenfs.h b/drivers/xen/xenfs/xenfs.h new file mode 100644 index 00000000000..51f08b2d0bf --- /dev/null +++ b/drivers/xen/xenfs/xenfs.h @@ -0,0 +1,6 @@ +#ifndef _XENFS_XENBUS_H +#define _XENFS_XENBUS_H + +extern const struct file_operations xenbus_file_ops; + +#endif /* _XENFS_XENBUS_H */ diff --git a/drivers/zorro/.gitignore b/drivers/zorro/.gitignore new file mode 100644 index 00000000000..34f980bd8ff --- /dev/null +++ b/drivers/zorro/.gitignore @@ -0,0 +1,2 @@ +devlist.h +gen-devlist diff --git a/drivers/zorro/zorro-sysfs.c b/drivers/zorro/zorro-sysfs.c index 5290552d2ef..1d2a772ea14 100644 --- a/drivers/zorro/zorro-sysfs.c +++ b/drivers/zorro/zorro-sysfs.c @@ -77,17 +77,21 @@ static struct bin_attribute zorro_config_attr = { .read = zorro_read_config, }; -void zorro_create_sysfs_dev_files(struct zorro_dev *z) +int zorro_create_sysfs_dev_files(struct zorro_dev *z) { struct device *dev = &z->dev; + int error; /* current configuration's attributes */ - device_create_file(dev, &dev_attr_id); - device_create_file(dev, &dev_attr_type); - device_create_file(dev, &dev_attr_serial); - device_create_file(dev, &dev_attr_slotaddr); - device_create_file(dev, &dev_attr_slotsize); - device_create_file(dev, &dev_attr_resource); - sysfs_create_bin_file(&dev->kobj, &zorro_config_attr); + if ((error = device_create_file(dev, &dev_attr_id)) || + (error = device_create_file(dev, &dev_attr_type)) || + (error = device_create_file(dev, &dev_attr_serial)) || + (error = device_create_file(dev, &dev_attr_slotaddr)) || + (error = device_create_file(dev, &dev_attr_slotsize)) || + (error = device_create_file(dev, &dev_attr_resource)) || + (error = sysfs_create_bin_file(&dev->kobj, &zorro_config_attr))) + return error; + + return 0; } diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index dff16d9767d..a1585d6f648 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -130,6 +130,7 @@ static int __init zorro_init(void) { struct zorro_dev *z; unsigned int i; + int error; if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(ZORRO)) return 0; @@ -140,7 +141,11 @@ static int __init zorro_init(void) /* Initialize the Zorro bus */ INIT_LIST_HEAD(&zorro_bus.devices); strcpy(zorro_bus.dev.bus_id, "zorro"); - device_register(&zorro_bus.dev); + error = device_register(&zorro_bus.dev); + if (error) { + pr_err("Zorro: Error registering zorro_bus\n"); + return error; + } /* Request the resources */ zorro_bus.num_resources = AMIGAHW_PRESENT(ZORRO3) ? 4 : 2; @@ -160,15 +165,19 @@ static int __init zorro_init(void) zorro_name_device(z); z->resource.name = z->name; if (request_resource(zorro_find_parent_resource(z), &z->resource)) - printk(KERN_ERR "Zorro: Address space collision on device %s " - "[%lx:%lx]\n", - z->name, (unsigned long)zorro_resource_start(z), - (unsigned long)zorro_resource_end(z)); + pr_err("Zorro: Address space collision on device %s %pR\n", + z->name, &z->resource); sprintf(z->dev.bus_id, "%02x", i); z->dev.parent = &zorro_bus.dev; z->dev.bus = &zorro_bus_type; - device_register(&z->dev); - zorro_create_sysfs_dev_files(z); + error = device_register(&z->dev); + if (error) { + pr_err("Zorro: Error registering device %s\n", z->name); + continue; + } + error = zorro_create_sysfs_dev_files(z); + if (error) + dev_err(&z->dev, "Error creating sysfs files\n"); } /* Mark all available Zorro II memory */ diff --git a/drivers/zorro/zorro.h b/drivers/zorro/zorro.h index 5c91adac4df..b682d5ccd63 100644 --- a/drivers/zorro/zorro.h +++ b/drivers/zorro/zorro.h @@ -1,4 +1,4 @@ extern void zorro_name_device(struct zorro_dev *z); -extern void zorro_create_sysfs_dev_files(struct zorro_dev *z); +extern int zorro_create_sysfs_dev_files(struct zorro_dev *z); |