diff options
Diffstat (limited to 'drivers')
933 files changed, 22633 insertions, 12431 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index ecb26b4f29a..c07f44f05f9 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -20,11 +20,12 @@ obj-y += acpi.o \ # All the builtin files are in the "acpi." module_param namespace. acpi-y += osl.o utils.o reboot.o acpi-y += atomicio.o +acpi-y += nvs.o # sleep related files acpi-y += wakeup.o acpi-y += sleep.o -acpi-$(CONFIG_ACPI_SLEEP) += proc.o nvs.o +acpi-$(CONFIG_ACPI_SLEEP) += proc.o # diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 301bd2d388a..0ca208b6dcf 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -8,41 +8,151 @@ ccflags-$(CONFIG_ACPI_DEBUG) += -DACPI_DEBUG_OUTPUT # use acpi.o to put all files here into acpi.o modparam namespace obj-y += acpi.o -acpi-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \ - dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \ - dsinit.o dsargs.o dscontrol.o dswload2.o +acpi-y := \ + dsargs.o \ + dscontrol.o \ + dsfield.o \ + dsinit.o \ + dsmethod.o \ + dsmthdat.o \ + dsobject.o \ + dsopcode.o \ + dsutils.o \ + dswexec.o \ + dswload.o \ + dswload2.o \ + dswscope.o \ + dswstate.o -acpi-y += evevent.o evregion.o evsci.o evxfevnt.o \ - evmisc.o evrgnini.o evxface.o evxfregn.o \ - evgpe.o evgpeblk.o evgpeinit.o evgpeutil.o evxfgpe.o evglock.o +acpi-y += \ + evevent.o \ + evgpe.o \ + evgpeblk.o \ + evgpeinit.o \ + evgpeutil.o \ + evglock.o \ + evmisc.o \ + evregion.o \ + evrgnini.o \ + evsci.o \ + evxface.o \ + evxfevnt.o \ + evxfgpe.o \ + evxfregn.o -acpi-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 exdebug.o +acpi-y += \ + exconfig.o \ + exconvrt.o \ + excreate.o \ + exdebug.o \ + exdump.o \ + exfield.o \ + exfldio.o \ + exmutex.o \ + exnames.o \ + exoparg1.o \ + exoparg2.o \ + exoparg3.o \ + exoparg6.o \ + exprep.o \ + exmisc.o \ + exregion.o \ + exresnte.o \ + exresolv.o \ + exresop.o \ + exstore.o \ + exstoren.o \ + exstorob.o \ + exsystem.o \ + exutils.o -acpi-y += hwacpi.o hwgpe.o hwregs.o hwsleep.o hwxface.o hwvalid.o hwpci.o +acpi-y += \ + hwacpi.o \ + hwgpe.o \ + hwpci.o \ + hwregs.o \ + hwsleep.o \ + hwvalid.o \ + hwxface.o acpi-$(ACPI_FUTURE_USAGE) += hwtimer.o -acpi-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 nsrepair.o nsrepair2.o +acpi-y += \ + nsaccess.o \ + nsalloc.o \ + nsdump.o \ + nseval.o \ + nsinit.o \ + nsload.o \ + nsnames.o \ + nsobject.o \ + nsparse.o \ + nspredef.o \ + nsrepair.o \ + nsrepair2.o \ + nssearch.o \ + nsutils.o \ + nswalk.o \ + nsxfeval.o \ + nsxfname.o \ + nsxfobj.o acpi-$(ACPI_FUTURE_USAGE) += nsdumpdv.o -acpi-y += psargs.o psparse.o psloop.o pstree.o pswalk.o \ - psopcode.o psscope.o psutils.o psxface.o +acpi-y += \ + psargs.o \ + psloop.o \ + psopcode.o \ + psparse.o \ + psscope.o \ + pstree.o \ + psutils.o \ + pswalk.o \ + psxface.o -acpi-y += rsaddr.o rscreate.o rsinfo.o rsio.o rslist.o rsmisc.o rsxface.o \ - rscalc.o rsirq.o rsmemory.o rsutils.o +acpi-y += \ + rsaddr.o \ + rscalc.o \ + rscreate.o \ + rsinfo.o \ + rsio.o \ + rsirq.o \ + rslist.o \ + rsmemory.o \ + rsmisc.o \ + rsserial.o \ + rsutils.o \ + rsxface.o acpi-$(ACPI_FUTURE_USAGE) += rsdump.o -acpi-y += tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o +acpi-y += \ + tbfadt.o \ + tbfind.o \ + tbinstal.o \ + tbutils.o \ + tbxface.o \ + tbxfroot.o -acpi-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 utlock.o utids.o \ - utosi.o utxferror.o utdecode.o +acpi-y += \ + utaddress.o \ + utalloc.o \ + utcopy.o \ + utdebug.o \ + utdecode.o \ + utdelete.o \ + uteval.o \ + utglobal.o \ + utids.o \ + utinit.o \ + utlock.o \ + utmath.o \ + utmisc.o \ + utmutex.o \ + utobject.o \ + utosi.o \ + utresrc.o \ + utstate.o \ + utxface.o \ + utxferror.o \ + utxfmutex.o diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index e0ba17f0a7c..a44bd424f9f 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acconfig.h b/drivers/acpi/acpica/acconfig.h index f895a244ca7..1f30af613e8 100644 --- a/drivers/acpi/acpica/acconfig.h +++ b/drivers/acpi/acpica/acconfig.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,6 +123,10 @@ #define ACPI_MAX_SLEEP 2000 /* Two seconds */ +/* Address Range lists are per-space_id (Memory and I/O only) */ + +#define ACPI_ADDRESS_RANGE_MAX 2 + /****************************************************************************** * * ACPI Specification constants (Do not change unless the specification changes) @@ -202,9 +206,10 @@ #define ACPI_RSDP_CHECKSUM_LENGTH 20 #define ACPI_RSDP_XCHECKSUM_LENGTH 36 -/* SMBus and IPMI bidirectional buffer size */ +/* SMBus, GSBus and IPMI bidirectional buffer size */ #define ACPI_SMBUS_BUFFER_SIZE 34 +#define ACPI_GSBUS_BUFFER_SIZE 34 #define ACPI_IPMI_BUFFER_SIZE 66 /* _sx_d and _sx_w control methods */ diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index eb0b1f8dee6..deaa8197956 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 2d1b7ffa377..5935ba6707e 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index bea3b489918..c53caa521a3 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -162,6 +162,7 @@ acpi_status acpi_ev_initialize_op_regions(void); acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + union acpi_operand_object *field_obj, u32 function, u32 region_offset, u32 bit_width, u64 *value); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 76dc02f1557..261fd5eb2b6 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -140,8 +140,19 @@ u32 acpi_gbl_trace_flags; acpi_name acpi_gbl_trace_method_name; u8 acpi_gbl_system_awake_and_running; +/* + * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning + * that the ACPI hardware is no longer required. A flag in the FADT indicates + * a reduced HW machine, and that flag is duplicated here for convenience. + */ +u8 acpi_gbl_reduced_hardware; + #endif +/* Do not disassemble buffers to resource descriptors */ + +ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_no_resource_disassembly, FALSE); + /***************************************************************************** * * Debug support @@ -207,7 +218,7 @@ ACPI_EXTERN struct acpi_rw_lock acpi_gbl_namespace_rw_lock; /***************************************************************************** * - * Mutual exlusion within ACPICA subsystem + * Mutual exclusion within ACPICA subsystem * ****************************************************************************/ @@ -295,6 +306,8 @@ ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present; ACPI_EXTERN u8 acpi_gbl_events_initialized; ACPI_EXTERN u8 acpi_gbl_osi_data; ACPI_EXTERN struct acpi_interface_info *acpi_gbl_supported_interfaces; +ACPI_EXTERN struct acpi_address_range + *acpi_gbl_address_range_list[ACPI_ADDRESS_RANGE_MAX]; #ifndef DEFINE_ACPI_GLOBALS diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index e7213beaafc..677793e938f 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 3731e1c34b8..eb308635da7 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -468,6 +468,8 @@ void acpi_ex_eisa_id_to_string(char *dest, u64 compressed_id); void acpi_ex_integer_to_string(char *dest, u64 value); +u8 acpi_is_valid_space_id(u8 space_id); + /* * exregion - default op_region handlers */ diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 5552125d834..3f24068837d 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,7 +53,7 @@ typedef u32 acpi_mutex_handle; /* Total number of aml opcodes defined */ -#define AML_NUM_OPCODES 0x7F +#define AML_NUM_OPCODES 0x81 /* Forward declarations */ @@ -249,12 +249,16 @@ struct acpi_create_field_info { struct acpi_namespace_node *field_node; struct acpi_namespace_node *register_node; struct acpi_namespace_node *data_register_node; + struct acpi_namespace_node *connection_node; + u8 *resource_buffer; u32 bank_value; u32 field_bit_position; u32 field_bit_length; + u16 resource_length; u8 field_flags; u8 attribute; u8 field_type; + u8 access_length; }; typedef @@ -315,7 +319,8 @@ struct acpi_name_info { /* * Used for ACPI_PTYPE1_FIXED, ACPI_PTYPE1_VAR, ACPI_PTYPE2, - * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT + * ACPI_PTYPE2_MIN, ACPI_PTYPE2_PKG_COUNT, ACPI_PTYPE2_COUNT, + * ACPI_PTYPE2_FIX_VAR */ struct acpi_package_info { u8 type; @@ -625,6 +630,15 @@ union acpi_generic_state { typedef acpi_status(*ACPI_EXECUTE_OP) (struct acpi_walk_state * walk_state); +/* Address Range info block */ + +struct acpi_address_range { + struct acpi_address_range *next; + struct acpi_namespace_node *region_node; + acpi_physical_address start_address; + acpi_physical_address end_address; +}; + /***************************************************************************** * * Parser typedefs and structs @@ -951,7 +965,7 @@ struct acpi_port_info { #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_FIXED_DMA 0x50 #define ACPI_RESOURCE_NAME_RESERVED_S2 0x58 #define ACPI_RESOURCE_NAME_RESERVED_S3 0x60 #define ACPI_RESOURCE_NAME_RESERVED_S4 0x68 @@ -973,7 +987,9 @@ struct acpi_port_info { #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 +#define ACPI_RESOURCE_NAME_GPIO 0x8C +#define ACPI_RESOURCE_NAME_SERIAL_BUS 0x8E +#define ACPI_RESOURCE_NAME_LARGE_MAX 0x8E /***************************************************************************** * diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index b7491ee1fba..ef338a96f5b 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 79a598c67fe..2c9e0f04952 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index 1055769f2f0..c065078ca83 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -254,6 +254,7 @@ ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_NOTIFY_INFO}; 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_length; /* For serial regions/fields */ struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and INDEX fields) */ @@ -261,7 +262,9 @@ struct acpi_object_field_common { /* COMMON FIELD (for BUFFER, REGION, BANK, and }; struct acpi_object_region_field { - ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO union acpi_operand_object *region_obj; /* Containing op_region object */ + ACPI_OBJECT_COMMON_HEADER ACPI_COMMON_FIELD_INFO u16 resource_length; + union acpi_operand_object *region_obj; /* Containing op_region object */ + u8 *resource_buffer; /* resource_template for serial regions/fields */ }; struct acpi_object_bank_field { @@ -358,6 +361,7 @@ typedef enum { */ struct acpi_object_extra { ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *method_REG; /* _REG method for this region (if any) */ + struct acpi_namespace_node *scope_node; void *region_context; /* Region-specific data */ u8 *aml_start; u32 aml_length; diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index bb2ccfad737..9440d053fbb 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -93,6 +93,7 @@ #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_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #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) @@ -164,6 +165,7 @@ #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_SERIALFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #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) @@ -223,6 +225,7 @@ #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_CONNECTFIELD_OP ARGI_INVALID_OPCODE #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) @@ -294,6 +297,7 @@ #define ARGI_RETURN_OP ARGI_INVALID_OPCODE #define ARGI_REVISION_OP ARG_NONE #define ARGI_SCOPE_OP ARGI_INVALID_OPCODE +#define ARGI_SERIALFIELD_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) diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 5ea1e06afa2..b725d780d34 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h index c445cca490e..bbb34c9be4e 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -94,6 +94,14 @@ * ACPI_PTYPE2_REV_FIXED: Revision at start, each subpackage is Fixed-length * (Used for _ART, _FPS) * + * ACPI_PTYPE2_FIX_VAR: Each subpackage consists of some fixed-length elements + * followed by an optional element + * object type + * count + * object type + * count = 0 (optional) + * (Used for _DLM) + * *****************************************************************************/ enum acpi_return_package_types { @@ -105,7 +113,8 @@ enum acpi_return_package_types { ACPI_PTYPE2_PKG_COUNT = 6, ACPI_PTYPE2_FIXED = 7, ACPI_PTYPE2_MIN = 8, - ACPI_PTYPE2_REV_FIXED = 9 + ACPI_PTYPE2_REV_FIXED = 9, + ACPI_PTYPE2_FIX_VAR = 10 }; #ifdef ACPI_CREATE_PREDEFINED_TABLE @@ -154,6 +163,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_AC8", 0, ACPI_RTYPE_INTEGER}}, {{"_AC9", 0, ACPI_RTYPE_INTEGER}}, {{"_ADR", 0, ACPI_RTYPE_INTEGER}}, + {{"_AEI", 0, ACPI_RTYPE_BUFFER}}, {{"_AL0", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -229,6 +239,13 @@ static const union acpi_predefined_info predefined_names[] = {{"_CID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Strs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING, 0,0}, 0,0}}, + {{"_CLS", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (3 Int) */ + {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}}, + + {{"_CPC", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints/Bufs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0, 0}, 0, + 0}}, + {{"_CRS", 0, ACPI_RTYPE_BUFFER}}, {{"_CRT", 0, ACPI_RTYPE_INTEGER}}, {{"_CSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n-1 Int) */ @@ -237,12 +254,21 @@ static const union acpi_predefined_info predefined_names[] = {{"_CST", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (1 Int(n), n Pkg (1 Buf/3 Int) */ {{{ACPI_PTYPE2_PKG_COUNT,ACPI_RTYPE_BUFFER, 1, ACPI_RTYPE_INTEGER}, 3,0}}, + {{"_CWS", 1, ACPI_RTYPE_INTEGER}}, {{"_DCK", 1, ACPI_RTYPE_INTEGER}}, {{"_DCS", 0, ACPI_RTYPE_INTEGER}}, {{"_DDC", 1, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER}}, {{"_DDN", 0, ACPI_RTYPE_STRING}}, + {{"_DEP", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_DGS", 0, ACPI_RTYPE_INTEGER}}, {{"_DIS", 0, 0}}, + + {{"_DLM", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (1 Ref, 0/1 Optional Buf/Ref) */ + {{{ACPI_PTYPE2_FIX_VAR, ACPI_RTYPE_REFERENCE, 1, + ACPI_RTYPE_REFERENCE | ACPI_RTYPE_BUFFER}, 0, 0}}, + {{"_DMA", 0, ACPI_RTYPE_BUFFER}}, {{"_DOD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Ints) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER, 0,0}, 0,0}}, @@ -262,6 +288,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_EJ3", 1, 0}}, {{"_EJ4", 1, 0}}, {{"_EJD", 0, ACPI_RTYPE_STRING}}, + {{"_EVT", 1, 0}}, {{"_FDE", 0, ACPI_RTYPE_BUFFER}}, {{"_FDI", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (16 Int) */ {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 16,0}, 0,0}}, @@ -281,14 +308,17 @@ static const union acpi_predefined_info predefined_names[] = {{{ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 3, 0}, 0, 0}}, {{"_GAI", 0, ACPI_RTYPE_INTEGER}}, + {{"_GCP", 0, ACPI_RTYPE_INTEGER}}, {{"_GHL", 0, ACPI_RTYPE_INTEGER}}, {{"_GLK", 0, ACPI_RTYPE_INTEGER}}, {{"_GPD", 0, ACPI_RTYPE_INTEGER}}, {{"_GPE", 0, ACPI_RTYPE_INTEGER}}, /* _GPE method, not _GPE scope */ + {{"_GRT", 0, ACPI_RTYPE_BUFFER}}, {{"_GSB", 0, ACPI_RTYPE_INTEGER}}, {{"_GTF", 0, ACPI_RTYPE_BUFFER}}, {{"_GTM", 0, ACPI_RTYPE_BUFFER}}, {{"_GTS", 1, 0}}, + {{"_GWS", 1, ACPI_RTYPE_INTEGER}}, {{"_HID", 0, ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING}}, {{"_HOT", 0, ACPI_RTYPE_INTEGER}}, {{"_HPP", 0, ACPI_RTYPE_PACKAGE}}, /* Fixed-length (4 Int) */ @@ -303,6 +333,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_HPX", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (var Ints) */ {{{ACPI_PTYPE2_MIN, ACPI_RTYPE_INTEGER, 5,0}, 0,0}}, + {{"_HRV", 0, ACPI_RTYPE_INTEGER}}, {{"_IFT", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ {{"_INI", 0, 0}}, {{"_IRC", 0, 0}}, @@ -361,6 +392,9 @@ static const union acpi_predefined_info predefined_names[] = {{"_PR3", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_PRE", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ + {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, + {{"_PRL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0}, 0, 0}}, @@ -391,6 +425,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_PSD", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Pkgs) each (5 Int) with count */ {{{ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER,0,0}, 0,0}}, + {{"_PSE", 1, 0}}, {{"_PSL", 0, ACPI_RTYPE_PACKAGE}}, /* Variable-length (Refs) */ {{{ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0,0}, 0,0}}, @@ -457,6 +492,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_SLI", 0, ACPI_RTYPE_BUFFER}}, {{"_SPD", 1, ACPI_RTYPE_INTEGER}}, {{"_SRS", 1, 0}}, + {{"_SRT", 1, ACPI_RTYPE_INTEGER}}, {{"_SRV", 0, ACPI_RTYPE_INTEGER}}, /* See IPMI spec */ {{"_SST", 1, 0}}, {{"_STA", 0, ACPI_RTYPE_INTEGER}}, @@ -464,6 +500,7 @@ static const union acpi_predefined_info predefined_names[] = {{"_STP", 2, ACPI_RTYPE_INTEGER}}, {{"_STR", 0, ACPI_RTYPE_BUFFER}}, {{"_STV", 2, ACPI_RTYPE_INTEGER}}, + {{"_SUB", 0, ACPI_RTYPE_STRING}}, {{"_SUN", 0, ACPI_RTYPE_INTEGER}}, {{"_SWS", 0, ACPI_RTYPE_INTEGER}}, {{"_TC1", 0, ACPI_RTYPE_INTEGER}}, diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index f08b55b7f3a..0347d099349 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -73,28 +73,40 @@ typedef const struct 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 +typedef enum { + ACPI_RSC_INITGET = 0, + ACPI_RSC_INITSET, + ACPI_RSC_FLAGINIT, + ACPI_RSC_1BITFLAG, + ACPI_RSC_2BITFLAG, + ACPI_RSC_3BITFLAG, + ACPI_RSC_ADDRESS, + ACPI_RSC_BITMASK, + ACPI_RSC_BITMASK16, + ACPI_RSC_COUNT, + ACPI_RSC_COUNT16, + ACPI_RSC_COUNT_GPIO_PIN, + ACPI_RSC_COUNT_GPIO_RES, + ACPI_RSC_COUNT_GPIO_VEN, + ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RSC_DATA8, + ACPI_RSC_EXIT_EQ, + ACPI_RSC_EXIT_LE, + ACPI_RSC_EXIT_NE, + ACPI_RSC_LENGTH, + ACPI_RSC_MOVE_GPIO_PIN, + ACPI_RSC_MOVE_GPIO_RES, + ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RSC_MOVE8, + ACPI_RSC_MOVE16, + ACPI_RSC_MOVE32, + ACPI_RSC_MOVE64, + ACPI_RSC_SET8, + ACPI_RSC_SOURCE, + ACPI_RSC_SOURCEX +} ACPI_RSCONVERT_OPCODES; /* Resource Conversion sub-opcodes */ @@ -106,6 +118,9 @@ typedef const 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) +/* + * Individual entry for the resource dump tables + */ typedef const struct acpi_rsdump_info { u8 opcode; u8 offset; @@ -116,20 +131,25 @@ typedef const struct 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 +typedef enum { + ACPI_RSD_TITLE = 0, + ACPI_RSD_1BITFLAG, + ACPI_RSD_2BITFLAG, + ACPI_RSD_3BITFLAG, + ACPI_RSD_ADDRESS, + ACPI_RSD_DWORDLIST, + ACPI_RSD_LITERAL, + ACPI_RSD_LONGLIST, + ACPI_RSD_SHORTLIST, + ACPI_RSD_SHORTLISTX, + ACPI_RSD_SOURCE, + ACPI_RSD_STRING, + ACPI_RSD_UINT8, + ACPI_RSD_UINT16, + ACPI_RSD_UINT32, + ACPI_RSD_UINT64, + ACPI_RSD_WORDLIST +} ACPI_RSDUMP_OPCODES; /* restore default alignment */ @@ -138,13 +158,18 @@ typedef const struct acpi_rsdump_info { /* Resource tables indexed by internal resource type */ extern const u8 acpi_gbl_aml_resource_sizes[]; +extern const u8 acpi_gbl_aml_resource_serial_bus_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 const u8 acpi_gbl_resource_struct_serial_bus_sizes[]; extern struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[]; +extern struct acpi_rsconvert_info + *acpi_gbl_convert_resource_serial_bus_dispatch[]; + struct acpi_vendor_walk_info { struct acpi_vendor_uuid *uuid; struct acpi_buffer *buffer; @@ -190,6 +215,10 @@ acpi_status acpi_rs_set_srs_method_data(struct acpi_namespace_node *node, struct acpi_buffer *ret_buffer); +acpi_status +acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer); + /* * rscalc */ @@ -293,6 +322,11 @@ 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[]; +extern struct acpi_rsconvert_info acpi_rs_convert_gpio[]; +extern struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[]; +extern struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[]; +extern struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[]; /* These resources require separate get/set tables */ @@ -310,6 +344,7 @@ extern struct acpi_rsconvert_info acpi_rs_set_vendor[]; * rsinfo */ extern struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[]; +extern struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[]; /* * rsdump @@ -331,6 +366,12 @@ 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[]; +extern struct acpi_rsdump_info acpi_rs_dump_gpio[]; +extern struct acpi_rsdump_info acpi_rs_dump_fixed_dma[]; +extern struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[]; +extern struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[]; #endif #endif /* __ACRESRC_H__ */ diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 1623b245dde..0404df605bc 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 967f08124eb..d5bec304c82 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 99c140d8e34..925ccf22101 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,7 @@ #define _ACUTILS_H extern const u8 acpi_gbl_resource_aml_sizes[]; +extern const u8 acpi_gbl_resource_aml_serial_bus_sizes[]; /* Strings used by the disassembler and debugger resource dump routines */ @@ -579,6 +580,24 @@ acpi_ut_create_list(char *list_name, #endif /* ACPI_DBG_TRACK_ALLOCATIONS */ /* + * utaddress - address range check + */ +acpi_status +acpi_ut_add_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + u32 length, struct acpi_namespace_node *region_node); + +void +acpi_ut_remove_address_range(acpi_adr_space_type space_id, + struct acpi_namespace_node *region_node); + +u32 +acpi_ut_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, u32 length, u8 warn); + +void acpi_ut_delete_address_lists(void); + +/* * utxferror - various error/warning output functions */ void ACPI_INTERNAL_VAR_XFACE diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 1077f17859e..905280fec0f 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -189,6 +189,14 @@ #define AML_LNOTEQUAL_OP (u16) 0x9293 /* + * Opcodes for "Field" operators + */ +#define AML_FIELD_OFFSET_OP (u8) 0x00 +#define AML_FIELD_ACCESS_OP (u8) 0x01 +#define AML_FIELD_CONNECTION_OP (u8) 0x02 /* ACPI 5.0 */ +#define AML_FIELD_EXT_ACCESS_OP (u8) 0x03 /* ACPI 5.0 */ + +/* * Internal opcodes * Use only "Unknown" AML opcodes, don't attempt to use * any valid ACPI ASCII values (A-Z, 0-9, '-') @@ -202,6 +210,8 @@ #define AML_INT_METHODCALL_OP (u16) 0x0035 #define AML_INT_RETURN_VALUE_OP (u16) 0x0036 #define AML_INT_EVAL_SUBTREE_OP (u16) 0x0037 +#define AML_INT_CONNECTION_OP (u16) 0x0038 +#define AML_INT_EXTACCESSFIELD_OP (u16) 0x0039 #define ARG_NONE 0x0 @@ -456,13 +466,16 @@ typedef enum { * 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_FIELD_ATTRIB_QUICK = 0x02, + AML_FIELD_ATTRIB_SEND_RCV = 0x04, + AML_FIELD_ATTRIB_BYTE = 0x06, + AML_FIELD_ATTRIB_WORD = 0x08, + AML_FIELD_ATTRIB_BLOCK = 0x0A, + AML_FIELD_ATTRIB_MULTIBYTE = 0x0B, + AML_FIELD_ATTRIB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_BLOCK_CALL = 0x0D, + AML_FIELD_ATTRIB_RAW_BYTES = 0x0E, + AML_FIELD_ATTRIB_RAW_PROCESS = 0x0F } AML_ACCESS_ATTRIBUTE; /* Bit fields in the AML method_flags byte */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index 59122cde247..7b2128f274e 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,29 +58,48 @@ #define ACPI_RESTAG_TYPESPECIFICATTRIBUTES "_ATT" #define ACPI_RESTAG_BASEADDRESS "_BAS" #define ACPI_RESTAG_BUSMASTER "_BM_" /* Master(1), Slave(0) */ +#define ACPI_RESTAG_DEBOUNCETIME "_DBT" #define ACPI_RESTAG_DECODE "_DEC" +#define ACPI_RESTAG_DEVICEPOLARITY "_DPL" #define ACPI_RESTAG_DMA "_DMA" #define ACPI_RESTAG_DMATYPE "_TYP" /* Compatible(0), A(1), B(2), F(3) */ +#define ACPI_RESTAG_DRIVESTRENGTH "_DRS" +#define ACPI_RESTAG_ENDIANNESS "_END" +#define ACPI_RESTAG_FLOWCONTROL "_FLC" #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_IORESTRICTION "_IOR" #define ACPI_RESTAG_LENGTH "_LEN" +#define ACPI_RESTAG_LINE "_LIN" #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_MODE "_MOD" +#define ACPI_RESTAG_PARITY "_PAR" +#define ACPI_RESTAG_PHASE "_PHA" +#define ACPI_RESTAG_PIN "_PIN" +#define ACPI_RESTAG_PINCONFIG "_PPI" +#define ACPI_RESTAG_POLARITY "_POL" #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_LENGTH_RX "_RXL" +#define ACPI_RESTAG_LENGTH_TX "_TXL" +#define ACPI_RESTAG_SLAVEMODE "_SLV" +#define ACPI_RESTAG_SPEED "_SPE" +#define ACPI_RESTAG_STOPBITS "_STB" #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) */ +#define ACPI_RESTAG_VENDORDATA "_VEN" /* Default sizes for "small" resource descriptors */ @@ -90,6 +109,7 @@ #define ASL_RDESC_END_DEPEND_SIZE 0x00 #define ASL_RDESC_IO_SIZE 0x07 #define ASL_RDESC_FIXED_IO_SIZE 0x03 +#define ASL_RDESC_FIXED_DMA_SIZE 0x05 #define ASL_RDESC_END_TAG_SIZE 0x01 struct asl_resource_node { @@ -164,6 +184,12 @@ struct aml_resource_end_tag { AML_RESOURCE_SMALL_HEADER_COMMON u8 checksum; }; +struct aml_resource_fixed_dma { + AML_RESOURCE_SMALL_HEADER_COMMON u16 request_lines; + u16 channels; + u8 width; +}; + /* * LARGE descriptors */ @@ -263,6 +289,110 @@ struct aml_resource_generic_register { u64 address; }; +/* Common descriptor for gpio_int and gpio_io (ACPI 5.0) */ + +struct aml_resource_gpio { + AML_RESOURCE_LARGE_HEADER_COMMON u8 revision_id; + u8 connection_type; + u16 flags; + u16 int_flags; + u8 pin_config; + u16 drive_strength; + u16 debounce_timeout; + u16 pin_table_offset; + u8 res_source_index; + u16 res_source_offset; + u16 vendor_offset; + u16 vendor_length; + /* + * Optional fields follow immediately: + * 1) PIN list (Words) + * 2) Resource Source String + * 3) Vendor Data bytes + */ +}; + +#define AML_RESOURCE_GPIO_REVISION 1 /* ACPI 5.0 */ + +/* Values for connection_type above */ + +#define AML_RESOURCE_GPIO_TYPE_INT 0 +#define AML_RESOURCE_GPIO_TYPE_IO 1 +#define AML_RESOURCE_MAX_GPIOTYPE 1 + +/* Common preamble for all serial descriptors (ACPI 5.0) */ + +#define AML_RESOURCE_SERIAL_COMMON \ + u8 revision_id; \ + u8 res_source_index; \ + u8 type; \ + u8 flags; \ + u16 type_specific_flags; \ + u8 type_revision_id; \ + u16 type_data_length; \ + +/* Values for the type field above */ + +#define AML_RESOURCE_I2C_SERIALBUSTYPE 1 +#define AML_RESOURCE_SPI_SERIALBUSTYPE 2 +#define AML_RESOURCE_UART_SERIALBUSTYPE 3 +#define AML_RESOURCE_MAX_SERIALBUSTYPE 3 +#define AML_RESOURCE_VENDOR_SERIALBUSTYPE 192 /* Vendor defined is 0xC0-0xFF (NOT SUPPORTED) */ + +struct aml_resource_common_serialbus { +AML_RESOURCE_LARGE_HEADER_COMMON AML_RESOURCE_SERIAL_COMMON}; + +struct aml_resource_i2c_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 connection_speed; + u16 slave_address; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_I2C_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_I2C_MIN_DATA_LEN 6 + +struct aml_resource_spi_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 connection_speed; + u8 data_bit_length; + u8 clock_phase; + u8 clock_polarity; + u16 device_selection; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_SPI_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_SPI_MIN_DATA_LEN 9 + +struct aml_resource_uart_serialbus { + AML_RESOURCE_LARGE_HEADER_COMMON + AML_RESOURCE_SERIAL_COMMON u32 default_baud_rate; + u16 rx_fifo_size; + u16 tx_fifo_size; + u8 parity; + u8 lines_enabled; + /* + * Optional fields follow immediately: + * 1) Vendor Data bytes + * 2) Resource Source String + */ +}; + +#define AML_RESOURCE_UART_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_TYPE_REVISION 1 /* ACPI 5.0 */ +#define AML_RESOURCE_UART_MIN_DATA_LEN 10 + /* restore default alignment */ #pragma pack() @@ -284,6 +414,7 @@ union aml_resource { struct aml_resource_end_dependent end_dpf; struct aml_resource_io io; struct aml_resource_fixed_io fixed_io; + struct aml_resource_fixed_dma fixed_dma; struct aml_resource_vendor_small vendor_small; struct aml_resource_end_tag end_tag; @@ -299,6 +430,11 @@ union aml_resource { struct aml_resource_address64 address64; struct aml_resource_extended_address64 ext_address64; struct aml_resource_extended_irq extended_irq; + struct aml_resource_gpio gpio; + struct aml_resource_i2c_serialbus i2c_serial_bus; + struct aml_resource_spi_serialbus spi_serial_bus; + struct aml_resource_uart_serialbus uart_serial_bus; + struct aml_resource_common_serialbus common_serial_bus; /* Utility overlays */ diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 8c7b99728aa..80eb1900297 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -250,6 +250,13 @@ acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc) status = acpi_ds_execute_arguments(node, node->parent, extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_ut_add_address_range(obj_desc->region.space_id, + obj_desc->region.address, + obj_desc->region.length, node); return_ACPI_STATUS(status); } @@ -384,8 +391,15 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc) /* Execute the argument AML */ - status = acpi_ds_execute_arguments(node, node->parent, + status = acpi_ds_execute_arguments(node, extra_desc->extra.scope_node, extra_desc->extra.aml_length, extra_desc->extra.aml_start); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_ut_add_address_range(obj_desc->region.space_id, + obj_desc->region.address, + obj_desc->region.length, node); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 26c49fff58d..effe4ca1133 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c index 34be60c0e44..cd243cf2cab 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -221,6 +221,7 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, { acpi_status status; u64 position; + union acpi_parse_object *child; ACPI_FUNCTION_TRACE_PTR(ds_get_field_names, info); @@ -232,10 +233,11 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, while (arg) { /* - * Three types of field elements are handled: - * 1) Offset - specifies a bit offset - * 2) access_as - changes the access mode - * 3) Name - Enters a new named field into the namespace + * Four types of field elements are handled: + * 1) Name - Enters a new named field into the namespace + * 2) Offset - specifies a bit offset + * 3) access_as - changes the access mode/attributes + * 4) Connection - Associate a resource template with the field */ switch (arg->common.aml_opcode) { case AML_INT_RESERVEDFIELD_OP: @@ -253,21 +255,70 @@ acpi_ds_get_field_names(struct acpi_create_field_info *info, break; case AML_INT_ACCESSFIELD_OP: - + case AML_INT_EXTACCESSFIELD_OP: /* - * Get a new access_type and access_attribute -- to be used for all - * field units that follow, until field end or another access_as - * keyword. + * Get new access_type, access_attribute, and access_length fields + * -- to be used for all field units that follow, until the + * end-of-field or another access_as keyword is encountered. + * NOTE. These three bytes are encoded in the integer value + * of the parseop for convenience. * * In field_flags, preserve the flag bits other than the - * ACCESS_TYPE bits + * ACCESS_TYPE bits. */ + + /* access_type (byte_acc, word_acc, etc.) */ + info->field_flags = (u8) ((info-> field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) | - ((u8) ((u32) arg->common.value.integer >> 8))); + ((u8)((u32)(arg->common.value.integer & 0x07)))); + + /* access_attribute (attrib_quick, attrib_byte, etc.) */ + + info->attribute = + (u8)((arg->common.value.integer >> 8) & 0xFF); + + /* access_length (for serial/buffer protocols) */ + + info->access_length = + (u8)((arg->common.value.integer >> 16) & 0xFF); + break; + + case AML_INT_CONNECTION_OP: + /* + * Clear any previous connection. New connection is used for all + * fields that follow, similar to access_as + */ + info->resource_buffer = NULL; + info->connection_node = NULL; - info->attribute = (u8) (arg->common.value.integer); + /* + * A Connection() is either an actual resource descriptor (buffer) + * or a named reference to a resource template + */ + child = arg->common.value.arg; + if (child->common.aml_opcode == AML_INT_BYTELIST_OP) { + info->resource_buffer = child->named.data; + info->resource_length = + (u16)child->named.value.integer; + } else { + /* Lookup the Connection() namepath, it should already exist */ + + status = acpi_ns_lookup(walk_state->scope_info, + child->common.value. + name, ACPI_TYPE_ANY, + ACPI_IMODE_EXECUTE, + ACPI_NS_DONT_OPEN_SCOPE, + walk_state, + &info->connection_node); + if (ACPI_FAILURE(status)) { + ACPI_ERROR_NAMESPACE(child->common. + value.name, + status); + return_ACPI_STATUS(status); + } + } break; case AML_INT_NAMEDFIELD_OP: @@ -374,6 +425,8 @@ acpi_ds_create_field(union acpi_parse_object *op, } } + ACPI_MEMSET(&info, 0, sizeof(struct acpi_create_field_info)); + /* Second arg is the field flags */ arg = arg->common.next; @@ -386,7 +439,6 @@ acpi_ds_create_field(union acpi_parse_object *op, info.region_node = region_node; status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); - return_ACPI_STATUS(status); } @@ -474,8 +526,8 @@ acpi_ds_init_field_objects(union acpi_parse_object *op, */ while (arg) { /* - * Ignore OFFSET and ACCESSAS terms here; we are only interested in the - * field names in order to enter them into the namespace. + * Ignore OFFSET/ACCESSAS/CONNECTION terms here; we are only interested + * in the field names in order to enter them into the namespace. */ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) { status = acpi_ns_lookup(walk_state->scope_info, @@ -651,6 +703,5 @@ acpi_ds_create_index_field(union acpi_parse_object *op, info.region_node = region_node; status = acpi_ds_get_field_names(&info, walk_state, arg->common.next); - return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index a7718bf2b9a..9e5ac7f780a 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 5d797751e20..00f5dab5bcc 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c index 905ce29a92e..b40bd507be5 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index f42e17e5c25..d7045ca3e32 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index c627a288e02..e5eff758510 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c index 2c477ce172f..1abcda31037 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c index fe40e4c6554..642f3c053e8 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 324acec1179..552aa3a50c8 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index 976318138c5..ae714772476 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c index 76a661fc1e0..9e9490a9cbf 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index a6c374ef991..c9c2ac13e7c 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c index d458b041e65..6729ebe2f1e 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -71,6 +71,12 @@ acpi_status acpi_ev_initialize_events(void) ACPI_FUNCTION_TRACE(ev_initialize_events); + /* If Hardware Reduced flag is set, there are no fixed events */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* * Initialize the Fixed and General Purpose Events. This is done prior to * enabling SCIs to prevent interrupts from occurring before the handlers @@ -111,6 +117,12 @@ acpi_status acpi_ev_install_xrupt_handlers(void) ACPI_FUNCTION_TRACE(ev_install_xrupt_handlers); + /* If Hardware Reduced flag is set, there is no ACPI h/w */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Install the SCI handler */ status = acpi_ev_install_sci_handler(); diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 56a562a1e5d..5e5683cb1f0 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,6 +70,12 @@ acpi_status acpi_ev_init_global_lock_handler(void) ACPI_FUNCTION_TRACE(ev_init_global_lock_handler); + /* If Hardware Reduced flag is set, there is no global lock */ + + if (acpi_gbl_reduced_hardware) { + return_ACPI_STATUS(AE_OK); + } + /* Attempt installation of the global lock handler */ status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL, diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index 65c79add3b1..9e88cb6fb25 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c index ca2c41a5331..be75339cd5d 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c index ce9aa9f9a97..adf7494da9d 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c index 80a81d0c4a8..25073932aa1 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c index d0b33184442..84966f41646 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index f0edf5c43c0..1b0180a1b79 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -329,6 +329,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) * FUNCTION: acpi_ev_address_space_dispatch * * PARAMETERS: region_obj - Internal region object + * field_obj - Corresponding field. Can be NULL. * Function - Read or Write operation * region_offset - Where in the region to read or write * bit_width - Field width in bits (8, 16, 32, or 64) @@ -344,6 +345,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) acpi_status acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, + union acpi_operand_object *field_obj, u32 function, u32 region_offset, u32 bit_width, u64 *value) { @@ -353,6 +355,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, union acpi_operand_object *handler_desc; union acpi_operand_object *region_obj2; void *region_context = NULL; + struct acpi_connection_info *context; ACPI_FUNCTION_TRACE(ev_address_space_dispatch); @@ -375,6 +378,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, return_ACPI_STATUS(AE_NOT_EXIST); } + context = handler_desc->address_space.context; + /* * It may be the case that the region has never been initialized. * Some types of regions require special init code @@ -404,8 +409,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, acpi_ex_exit_interpreter(); status = region_setup(region_obj, ACPI_REGION_ACTIVATE, - handler_desc->address_space.context, - ®ion_context); + context, ®ion_context); /* Re-enter the interpreter */ @@ -455,6 +459,25 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, acpi_ut_get_region_name(region_obj->region. space_id))); + /* + * Special handling for generic_serial_bus and general_purpose_io: + * There are three extra parameters that must be passed to the + * handler via the context: + * 1) Connection buffer, a resource template from Connection() op. + * 2) Length of the above buffer. + * 3) Actual access length from the access_as() op. + */ + if (((region_obj->region.space_id == ACPI_ADR_SPACE_GSBUS) || + (region_obj->region.space_id == ACPI_ADR_SPACE_GPIO)) && + context && field_obj) { + + /* Get the Connection (resource_template) buffer */ + + context->connection = field_obj->field.resource_buffer; + context->length = field_obj->field.resource_length; + context->access_length = field_obj->field.access_length; + } + if (!(handler_desc->address_space.handler_flags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) { /* @@ -469,7 +492,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, status = handler(function, (region_obj->region.address + region_offset), - bit_width, value, handler_desc->address_space.context, + bit_width, value, context, region_obj2->extra.region_context); if (ACPI_FAILURE(status)) { diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index 55a5d35ef34..819c17f5897 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c index 2ebd40e1a3e..26065c612e7 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index f4f523bf593..61944e89565 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 20516e59947..1768bbec100 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c index f06a3ee356b..33388fd69df 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index aee887e3ca5..6019208cd4b 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 745a42b401f..c86d44e41bc 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -297,9 +297,9 @@ acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) /* Bytewise reads */ for (i = 0; i < length; i++) { - status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, - region_offset, 8, - &value); + status = + acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ, + region_offset, 8, &value); if (ACPI_FAILURE(status)) { return status; } diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 74162a11817..e385436bd42 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 110711afada..3f5bc998c1c 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -267,7 +267,7 @@ acpi_status acpi_ex_create_mutex(struct acpi_walk_state *walk_state) * * PARAMETERS: aml_start - Pointer to the region declaration AML * aml_length - Max length of the declaration AML - * region_space - space_iD for the region + * space_id - Address space ID for the region * walk_state - Current state * * RETURN: Status @@ -279,7 +279,7 @@ acpi_status acpi_ex_create_mutex(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) + u8 space_id, struct acpi_walk_state *walk_state) { acpi_status status; union acpi_operand_object *obj_desc; @@ -304,16 +304,19 @@ acpi_ex_create_region(u8 * aml_start, * Space ID must be one of the predefined IDs, or in the user-defined * range */ - if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) && - (region_space < ACPI_USER_REGION_BEGIN) && - (region_space != ACPI_ADR_SPACE_DATA_TABLE)) { - ACPI_ERROR((AE_INFO, "Invalid AddressSpace type 0x%X", - region_space)); - return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + if (!acpi_is_valid_space_id(space_id)) { + /* + * Print an error message, but continue. We don't want to abort + * a table load for this exception. Instead, if the region is + * actually used at runtime, abort the executing method. + */ + ACPI_ERROR((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", + space_id)); } ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Region Type - %s (0x%X)\n", - acpi_ut_get_region_name(region_space), region_space)); + acpi_ut_get_region_name(space_id), space_id)); /* Create the region descriptor */ @@ -330,10 +333,16 @@ acpi_ex_create_region(u8 * aml_start, region_obj2 = obj_desc->common.next_object; region_obj2->extra.aml_start = aml_start; region_obj2->extra.aml_length = aml_length; + if (walk_state->scope_info) { + region_obj2->extra.scope_node = + walk_state->scope_info->scope.node; + } else { + region_obj2->extra.scope_node = node; + } /* Init the region from the operands */ - obj_desc->region.space_id = region_space; + obj_desc->region.space_id = space_id; obj_desc->region.address = 0; obj_desc->region.length = 0; obj_desc->region.node = node; diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index c7a2f1edd28..e211e9c1921 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 61b8c0e8b74..2a6ac0a3bc1 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -192,10 +192,13 @@ static struct acpi_exdump_info acpi_ex_dump_buffer_field[3] = { "Buffer Object"} }; -static struct acpi_exdump_info acpi_ex_dump_region_field[3] = { +static struct acpi_exdump_info acpi_ex_dump_region_field[5] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_region_field), NULL}, {ACPI_EXD_FIELD, 0, NULL}, - {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"} + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(field.access_length), "AccessLength"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.region_obj), "Region Object"}, + {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(field.resource_buffer), + "ResourceBuffer"} }; static struct acpi_exdump_info acpi_ex_dump_bank_field[5] = { diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index 0bde2230c02..dc092f5b35d 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -100,18 +100,25 @@ acpi_ex_read_data_from_field(struct acpi_walk_state *walk_state, (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS + || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus or IPMI read. We must create a buffer to hold + * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold * the data and then directly access the region handler. * - * Note: Smbus protocol value is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function */ if (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS) { length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_READ | (obj_desc->field.attribute << 16); + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + length = ACPI_GSBUS_BUFFER_SIZE; + function = + ACPI_READ | (obj_desc->field.attribute << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; @@ -248,21 +255,23 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS || obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS + || obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_IPMI)) { /* - * This is an SMBus or IPMI write. We will bypass the entire field + * This is an SMBus, GSBus or IPMI write. We will bypass the entire field * mechanism and handoff the buffer directly to the handler. For * these address spaces, the buffer is bi-directional; on a write, * return data is returned in the same buffer. * * Source must be a buffer of sufficient size: - * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE. + * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. * - * Note: SMBus protocol type is passed in upper 16-bits of Function + * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function */ if (source_desc->common.type != ACPI_TYPE_BUFFER) { ACPI_ERROR((AE_INFO, - "SMBus or IPMI write requires Buffer, found type %s", + "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", acpi_ut_get_object_type_name(source_desc))); return_ACPI_STATUS(AE_AML_OPERAND_TYPE); @@ -273,6 +282,11 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, length = ACPI_SMBUS_BUFFER_SIZE; function = ACPI_WRITE | (obj_desc->field.attribute << 16); + } else if (obj_desc->field.region_obj->region.space_id == + ACPI_ADR_SPACE_GSBUS) { + length = ACPI_GSBUS_BUFFER_SIZE; + function = + ACPI_WRITE | (obj_desc->field.attribute << 16); } else { /* IPMI */ length = ACPI_IPMI_BUFFER_SIZE; @@ -281,7 +295,7 @@ acpi_ex_write_data_to_field(union acpi_operand_object *source_desc, if (source_desc->buffer.length < length) { ACPI_ERROR((AE_INFO, - "SMBus or IPMI write requires Buffer of length %u, found length %u", + "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", length, source_desc->buffer.length)); return_ACPI_STATUS(AE_AML_BUFFER_LIMIT); diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index f915a7f3f92..149de45fdad 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -86,6 +86,7 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, { acpi_status status = AE_OK; union acpi_operand_object *rgn_desc; + u8 space_id; ACPI_FUNCTION_TRACE_U32(ex_setup_region, field_datum_byte_offset); @@ -101,6 +102,17 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, return_ACPI_STATUS(AE_AML_OPERAND_TYPE); } + space_id = rgn_desc->region.space_id; + + /* Validate the Space ID */ + + if (!acpi_is_valid_space_id(space_id)) { + ACPI_ERROR((AE_INFO, + "Invalid/unknown Address Space ID: 0x%2.2X", + space_id)); + return_ACPI_STATUS(AE_AML_INVALID_SPACE_ID); + } + /* * If the Region Address and Length have not been previously evaluated, * evaluate them now and save the results. @@ -119,11 +131,12 @@ acpi_ex_setup_region(union acpi_operand_object *obj_desc, } /* - * Exit now for SMBus or IPMI address space, it has a non-linear + * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear * address space and the request cannot be directly validated */ - if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS || - rgn_desc->region.space_id == ACPI_ADR_SPACE_IPMI) { + if (space_id == ACPI_ADR_SPACE_SMBUS || + space_id == ACPI_ADR_SPACE_GSBUS || + space_id == ACPI_ADR_SPACE_IPMI) { /* SMBus or IPMI has a non-linear address space */ @@ -271,11 +284,12 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, /* Invoke the appropriate address_space/op_region handler */ - status = - acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, - ACPI_MUL_8(obj_desc->common_field. - access_byte_width), - value); + status = acpi_ev_address_space_dispatch(rgn_desc, obj_desc, + function, region_offset, + ACPI_MUL_8(obj_desc-> + common_field. + access_byte_width), + value); if (ACPI_FAILURE(status)) { if (status == AE_NOT_IMPLEMENTED) { @@ -316,6 +330,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, static u8 acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) { + ACPI_FUNCTION_NAME(ex_register_overflow); if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) { /* @@ -330,6 +345,11 @@ acpi_ex_register_overflow(union acpi_operand_object *obj_desc, u64 value) * The Value is larger than the maximum value that can fit into * the register. */ + ACPI_ERROR((AE_INFO, + "Index value 0x%8.8X%8.8X overflows field width 0x%X", + ACPI_FORMAT_UINT64(value), + obj_desc->common_field.bit_length)); + return (TRUE); } diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 703d88ed0b3..0a089331034 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index be1c56ead65..60933e9dc3c 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c index 49ec049c157..fcc75fa27d3 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c index 236ead14b7f..9ba8c73cea1 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c index 2571b4a310f..879e8a277b9 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c index 1b48d9d28c9..71fcc65c9ff 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c index f4a2787e8e9..0786b865906 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c index cc95e200040..30157f5a12d 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,6 +47,7 @@ #include "acinterp.h" #include "amlcode.h" #include "acnamesp.h" +#include "acdispat.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exprep") @@ -455,6 +456,30 @@ acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info) obj_desc->field.region_obj = acpi_ns_get_attached_object(info->region_node); + /* Fields specific to generic_serial_bus fields */ + + obj_desc->field.access_length = info->access_length; + + if (info->connection_node) { + second_desc = info->connection_node->object; + if (!(second_desc->common.flags & AOPOBJ_DATA_VALID)) { + status = + acpi_ds_get_buffer_arguments(second_desc); + if (ACPI_FAILURE(status)) { + acpi_ut_delete_object_desc(obj_desc); + return_ACPI_STATUS(status); + } + } + + obj_desc->field.resource_buffer = + second_desc->buffer.pointer; + obj_desc->field.resource_length = + (u16)second_desc->buffer.length; + } else if (info->resource_buffer) { + obj_desc->field.resource_buffer = info->resource_buffer; + obj_desc->field.resource_length = info->resource_length; + } + /* Allow full data read from EC address space */ if ((obj_desc->field.region_obj->region.space_id == diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index f0d5e14f1f2..12d51df6d3b 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index 55997e46948..fa50e77e64a 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index db502cd7d93..6e335dc3452 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c index e3bb00ccdff..a67b1d925dd 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index c0c8842dd34..c6cf843cc4c 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c index a979017d56b..b35bed52e06 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c index dc665cc554d..65a45d8335c 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c index df66e7b686b..191a1294522 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c index 8ad93146dd3..eb6798ba8b5 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -435,4 +435,29 @@ void acpi_ex_integer_to_string(char *out_string, u64 value) } } +/******************************************************************************* + * + * FUNCTION: acpi_is_valid_space_id + * + * PARAMETERS: space_id - ID to be validated + * + * RETURN: TRUE if valid/supported ID. + * + * DESCRIPTION: Validate an operation region space_iD. + * + ******************************************************************************/ + +u8 acpi_is_valid_space_id(u8 space_id) +{ + + if ((space_id >= ACPI_NUM_PREDEFINED_REGIONS) && + (space_id < ACPI_USER_REGION_BEGIN) && + (space_id != ACPI_ADR_SPACE_DATA_TABLE) && + (space_id != ACPI_ADR_SPACE_FIXED_HARDWARE)) { + return (FALSE); + } + + return (TRUE); +} + #endif diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index fc380d3d45a..d21ec5f0b3a 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index f610d88a66b..1a6894afef7 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c index 050fd227951..1455ddcdc32 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 55accb7018b..4ea4eeb51bf 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -7,7 +7,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -269,16 +269,17 @@ acpi_status acpi_hw_clear_acpi_status(void) status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS, ACPI_BITMASK_ALL_FIXED_STATUS); - if (ACPI_FAILURE(status)) { - goto unlock_and_exit; - } + + acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); + + if (ACPI_FAILURE(status)) + goto exit; /* Clear the GPE Bits in all GPE registers in all GPE blocks */ status = acpi_ev_walk_gpe_list(acpi_hw_clear_gpe_block, NULL); - unlock_and_exit: - acpi_os_release_lock(acpi_gbl_hardware_lock, lock_flags); +exit: return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d52da307365..3c4a922a9fc 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 50d21c40b5c..d4973d9da9f 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c index 5f160587465..6e5c43a60bb 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -134,6 +134,8 @@ acpi_hw_validate_io_request(acpi_io_address address, u32 bit_width) /* Supported widths are 8/16/32 */ if ((bit_width != 8) && (bit_width != 16) && (bit_width != 32)) { + ACPI_ERROR((AE_INFO, + "Bad BitWidth parameter: %8.8X", bit_width)); return AE_BAD_PARAMETER; } diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index c2793a82f12..7bdbbcf35f8 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index d93172fd15a..61623f3f682 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index 1d0ef15d158..7c3d3ceb98b 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index b683cc2ff9d..b7f2b3be79a 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c index 2ed294b7a4d..30ea5bc53a7 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index c1bd02b1a05..f375cb82e32 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c index fd7c6380e29..9d84ec2f021 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index 5f7dc691c18..5cbf15ffe7d 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index d5fa520c3de..b20e7c8c3ff 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3bb8bf105ea..dd77a3ce6e5 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index b3234fa795b..ec7ba2d3463 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index c845c8089f3..bbe46a447d3 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -620,6 +620,7 @@ acpi_ns_check_package(struct acpi_predefined_data *data, case ACPI_PTYPE2_FIXED: case ACPI_PTYPE2_MIN: case ACPI_PTYPE2_COUNT: + case ACPI_PTYPE2_FIX_VAR: /* * These types all return a single Package that consists of a @@ -759,6 +760,34 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, } break; + case ACPI_PTYPE2_FIX_VAR: + /* + * Each subpackage has a fixed number of elements and an + * optional element + */ + expected_count = + package->ret_info.count1 + package->ret_info.count2; + if (sub_package->package.count < expected_count) { + goto package_too_small; + } + + status = + acpi_ns_check_package_elements(data, sub_elements, + package->ret_info. + object_type1, + package->ret_info. + count1, + package->ret_info. + object_type2, + sub_package->package. + count - + package->ret_info. + count1, 0); + if (ACPI_FAILURE(status)) { + return (status); + } + break; + case ACPI_PTYPE2_FIXED: /* Each sub-package has a fixed length */ diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index ac7b854b0bd..9c35d20eb52 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -634,6 +634,7 @@ acpi_ns_remove_null_elements(struct acpi_predefined_data *data, case ACPI_PTYPE2_FIXED: case ACPI_PTYPE2_MIN: case ACPI_PTYPE2_REV_FIXED: + case ACPI_PTYPE2_FIX_VAR: break; default: diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index 024c4f263f8..726bc8e687f 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -467,11 +467,12 @@ acpi_ns_repair_HID(struct acpi_predefined_data *data, } /* - * Copy and uppercase the string. From the ACPI specification: + * Copy and uppercase the string. From the ACPI 5.0 specification: * * A valid PNP ID must be of the form "AAA####" where A is an uppercase * letter and # is a hex digit. A valid ACPI ID must be of the form - * "ACPI####" where # is a hex digit. + * "NNNN####" where N is an uppercase letter or decimal digit, and + * # is a hex digit. */ for (dest = new_string->string.pointer; *source; dest++, source++) { *dest = (char)ACPI_TOUPPER(*source); diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 28b0d7a62b9..507043d6611 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index cb1b104a69a..a535b7afda5 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 345f0c3c6ad..f69895a5489 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index e7f016d1b22..71d15f61807 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 83bf9302430..af401c9c4df 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 57e6d825ed8..880a605cee2 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index e1fad0ee013..5ac36aba507 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -484,34 +484,54 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state *parser_state) { - u32 aml_offset = (u32) - ACPI_PTR_DIFF(parser_state->aml, - parser_state->aml_start); + u32 aml_offset; union acpi_parse_object *field; + union acpi_parse_object *arg = NULL; u16 opcode; u32 name; + u8 access_type; + u8 access_attribute; + u8 access_length; + u32 pkg_length; + u8 *pkg_end; + u32 buffer_length; ACPI_FUNCTION_TRACE(ps_get_next_field); + aml_offset = + (u32)ACPI_PTR_DIFF(parser_state->aml, parser_state->aml_start); + /* Determine field type */ switch (ACPI_GET8(parser_state->aml)) { - default: + case AML_FIELD_OFFSET_OP: - opcode = AML_INT_NAMEDFIELD_OP; + opcode = AML_INT_RESERVEDFIELD_OP; + parser_state->aml++; break; - case 0x00: + case AML_FIELD_ACCESS_OP: - opcode = AML_INT_RESERVEDFIELD_OP; + opcode = AML_INT_ACCESSFIELD_OP; parser_state->aml++; break; - case 0x01: + case AML_FIELD_CONNECTION_OP: - opcode = AML_INT_ACCESSFIELD_OP; + opcode = AML_INT_CONNECTION_OP; + parser_state->aml++; + break; + + case AML_FIELD_EXT_ACCESS_OP: + + opcode = AML_INT_EXTACCESSFIELD_OP; parser_state->aml++; break; + + default: + + opcode = AML_INT_NAMEDFIELD_OP; + break; } /* Allocate a new field op */ @@ -549,16 +569,111 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state break; case AML_INT_ACCESSFIELD_OP: + case AML_INT_EXTACCESSFIELD_OP: /* * Get access_type and access_attrib and merge into the field Op - * access_type is first operand, access_attribute is second + * access_type is first operand, access_attribute is second. stuff + * these bytes into the node integer value for convenience. */ - field->common.value.integer = - (((u32) ACPI_GET8(parser_state->aml) << 8)); + + /* Get the two bytes (Type/Attribute) */ + + access_type = ACPI_GET8(parser_state->aml); parser_state->aml++; - field->common.value.integer |= ACPI_GET8(parser_state->aml); + access_attribute = ACPI_GET8(parser_state->aml); parser_state->aml++; + + field->common.value.integer = (u8)access_type; + field->common.value.integer |= (u16)(access_attribute << 8); + + /* This opcode has a third byte, access_length */ + + if (opcode == AML_INT_EXTACCESSFIELD_OP) { + access_length = ACPI_GET8(parser_state->aml); + parser_state->aml++; + + field->common.value.integer |= + (u32)(access_length << 16); + } + break; + + case AML_INT_CONNECTION_OP: + + /* + * Argument for Connection operator can be either a Buffer + * (resource descriptor), or a name_string. + */ + if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { + parser_state->aml++; + + pkg_end = parser_state->aml; + pkg_length = + acpi_ps_get_next_package_length(parser_state); + pkg_end += pkg_length; + + if (parser_state->aml < pkg_end) { + + /* Non-empty list */ + + arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + if (!arg) { + return_PTR(NULL); + } + + /* Get the actual buffer length argument */ + + opcode = ACPI_GET8(parser_state->aml); + parser_state->aml++; + + switch (opcode) { + case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ + buffer_length = + ACPI_GET8(parser_state->aml); + parser_state->aml += 1; + break; + + case AML_WORD_OP: /* AML_WORDDATA_ARG */ + buffer_length = + ACPI_GET16(parser_state->aml); + parser_state->aml += 2; + break; + + case AML_DWORD_OP: /* AML_DWORDATA_ARG */ + buffer_length = + ACPI_GET32(parser_state->aml); + parser_state->aml += 4; + break; + + default: + buffer_length = 0; + break; + } + + /* Fill in bytelist data */ + + arg->named.value.size = buffer_length; + arg->named.data = parser_state->aml; + } + + /* Skip to End of byte data */ + + parser_state->aml = pkg_end; + } else { + arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + if (!arg) { + return_PTR(NULL); + } + + /* Get the Namestring argument */ + + arg->common.value.name = + acpi_ps_get_next_namestring(parser_state); + } + + /* Link the buffer/namestring to parent (CONNECTION_OP) */ + + acpi_ps_append_arg(field, arg); break; default: diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 01dd70d1de5..9547ad8a620 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index bed08de7528..a0226fdcf75 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -638,7 +638,16 @@ const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] = { /* 7E */ ACPI_OP("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, - AML_FLAGS_EXEC_0A_0T_1R) + AML_FLAGS_EXEC_0A_0T_1R), + +/* ACPI 5.0 opcodes */ + +/* 7F */ ACPI_OP("-ConnectField-", ARGP_CONNECTFIELD_OP, + ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS), +/* 80 */ ACPI_OP("-ExtAccessField-", ARGP_CONNECTFIELD_OP, + ARGI_CONNECTFIELD_OP, ACPI_TYPE_ANY, + AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0) /*! [End] no source code translation !*/ }; @@ -657,7 +666,7 @@ static const u8 acpi_gbl_short_op_index[256] = { /* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX, /* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D, -/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, +/* 0x38 */ 0x7F, 0x80, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, /* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, /* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, /* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 9bb0cbd37b5..2ff9c35a196 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c index a5faa1323a0..c872aa4b926 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c index f1464c03aa4..2b03cdbbe1c 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,6 +74,12 @@ union acpi_parse_object *acpi_ps_get_arg(union acpi_parse_object *op, u32 argn) ACPI_FUNCTION_ENTRY(); +/* + if (Op->Common.aml_opcode == AML_INT_CONNECTION_OP) + { + return (Op->Common.Value.Arg); + } +*/ /* Get the info structure for this opcode */ op_info = acpi_ps_get_opcode_info(op->common.aml_opcode); diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 7eda7850342..13bb131ae12 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c index 3312d6368bf..ab96cf47896 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 8086805d449..9d98c5ff66a 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c index 9e66f907842..a0305652394 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 3a8a89ec2ca..3c6df4b7eb2 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -313,6 +313,38 @@ acpi_rs_get_aml_length(struct acpi_resource * resource, acpi_size * size_needed) resource_source)); break; + case ACPI_RESOURCE_TYPE_GPIO: + + total_size = + (acpi_rs_length) (total_size + + (resource->data.gpio. + pin_table_length * 2) + + resource->data.gpio. + resource_source.string_length + + resource->data.gpio. + vendor_length); + + break; + + case ACPI_RESOURCE_TYPE_SERIAL_BUS: + + total_size = + acpi_gbl_aml_resource_serial_bus_sizes[resource-> + data. + common_serial_bus. + type]; + + total_size = (acpi_rs_length) (total_size + + resource->data. + i2c_serial_bus. + resource_source. + string_length + + resource->data. + i2c_serial_bus. + vendor_length); + + break; + default: break; } @@ -362,10 +394,11 @@ acpi_rs_get_list_length(u8 * aml_buffer, u32 extra_struct_bytes; u8 resource_index; u8 minimum_aml_resource_length; + union aml_resource *aml_resource; ACPI_FUNCTION_TRACE(rs_get_list_length); - *size_needed = 0; + *size_needed = ACPI_RS_SIZE_MIN; /* Minimum size is one end_tag */ end_aml = aml_buffer + aml_buffer_length; /* Walk the list of AML resource descriptors */ @@ -376,9 +409,15 @@ acpi_rs_get_list_length(u8 * aml_buffer, status = acpi_ut_validate_resource(aml_buffer, &resource_index); if (ACPI_FAILURE(status)) { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ return_ACPI_STATUS(status); } + aml_resource = (void *)aml_buffer; + /* Get the resource length and base (minimum) AML size */ resource_length = acpi_ut_get_resource_length(aml_buffer); @@ -422,10 +461,8 @@ acpi_rs_get_list_length(u8 * aml_buffer, case ACPI_RESOURCE_NAME_END_TAG: /* - * End Tag: - * This is the normal exit, add size of end_tag + * End Tag: This is the normal exit */ - *size_needed += ACPI_RS_SIZE_MIN; return_ACPI_STATUS(AE_OK); case ACPI_RESOURCE_NAME_ADDRESS32: @@ -457,6 +494,33 @@ acpi_rs_get_list_length(u8 * aml_buffer, minimum_aml_resource_length); break; + case ACPI_RESOURCE_NAME_GPIO: + + /* Vendor data is optional */ + + if (aml_resource->gpio.vendor_length) { + extra_struct_bytes += + aml_resource->gpio.vendor_offset - + aml_resource->gpio.pin_table_offset + + aml_resource->gpio.vendor_length; + } else { + extra_struct_bytes += + aml_resource->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + aml_resource->gpio.pin_table_offset; + } + break; + + case ACPI_RESOURCE_NAME_SERIAL_BUS: + + minimum_aml_resource_length = + acpi_gbl_resource_aml_serial_bus_sizes + [aml_resource->common_serial_bus.type]; + extra_struct_bytes += + aml_resource->common_serial_bus.resource_length - + minimum_aml_resource_length; + break; + default: break; } @@ -467,9 +531,18 @@ acpi_rs_get_list_length(u8 * aml_buffer, * Important: Round the size up for the appropriate alignment. This * is a requirement on IA64. */ - buffer_size = acpi_gbl_resource_struct_sizes[resource_index] + - extra_struct_bytes; - buffer_size = (u32) ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); + if (acpi_ut_get_resource_type(aml_buffer) == + ACPI_RESOURCE_NAME_SERIAL_BUS) { + buffer_size = + acpi_gbl_resource_struct_serial_bus_sizes + [aml_resource->common_serial_bus.type] + + extra_struct_bytes; + } else { + buffer_size = + acpi_gbl_resource_struct_sizes[resource_index] + + extra_struct_bytes; + } + buffer_size = (u32)ACPI_ROUND_UP_TO_NATIVE_WORD(buffer_size); *size_needed += buffer_size; diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 4ce6e1147e8..46d6eb38ae6 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,6 +51,70 @@ ACPI_MODULE_NAME("rscreate") /******************************************************************************* * + * FUNCTION: acpi_buffer_to_resource + * + * PARAMETERS: aml_buffer - Pointer to the resource byte stream + * aml_buffer_length - Length of the aml_buffer + * resource_ptr - Where the converted resource is returned + * + * RETURN: Status + * + * DESCRIPTION: Convert a raw AML buffer to a resource list + * + ******************************************************************************/ +acpi_status +acpi_buffer_to_resource(u8 *aml_buffer, + u16 aml_buffer_length, + struct acpi_resource **resource_ptr) +{ + acpi_status status; + acpi_size list_size_needed; + void *resource; + void *current_resource_ptr; + + /* + * Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag + * is not required here. + */ + + /* Get the required length for the converted resource */ + + status = acpi_rs_get_list_length(aml_buffer, aml_buffer_length, + &list_size_needed); + if (status == AE_AML_NO_RESOURCE_END_TAG) { + status = AE_OK; + } + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Allocate a buffer for the converted resource */ + + resource = ACPI_ALLOCATE_ZEROED(list_size_needed); + current_resource_ptr = resource; + if (!resource) { + return (AE_NO_MEMORY); + } + + /* Perform the AML-to-Resource conversion */ + + status = acpi_ut_walk_aml_resources(aml_buffer, aml_buffer_length, + acpi_rs_convert_aml_to_resources, + ¤t_resource_ptr); + if (status == AE_AML_NO_RESOURCE_END_TAG) { + status = AE_OK; + } + if (ACPI_FAILURE(status)) { + ACPI_FREE(resource); + } else { + *resource_ptr = resource; + } + + return (status); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_create_resource_list * * PARAMETERS: aml_buffer - Pointer to the resource byte stream @@ -66,9 +130,10 @@ ACPI_MODULE_NAME("rscreate") * of device resources. * ******************************************************************************/ + acpi_status acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer, - struct acpi_buffer *output_buffer) + struct acpi_buffer * output_buffer) { acpi_status status; diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 33db7520c74..b4c58113239 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,11 +61,13 @@ static void acpi_rs_out_integer64(char *title, u64 value); static void acpi_rs_out_title(char *title); -static void acpi_rs_dump_byte_list(u16 length, u8 * data); +static void acpi_rs_dump_byte_list(u16 length, u8 *data); -static void acpi_rs_dump_dword_list(u8 length, u32 * data); +static void acpi_rs_dump_word_list(u16 length, u16 *data); -static void acpi_rs_dump_short_byte_list(u8 length, u8 * data); +static void acpi_rs_dump_dword_list(u8 length, u32 *data); + +static void acpi_rs_dump_short_byte_list(u8 length, u8 *data); static void acpi_rs_dump_resource_source(struct acpi_resource_source *resource_source); @@ -309,6 +311,125 @@ struct acpi_rsdump_info acpi_rs_dump_generic_reg[6] = { {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(generic_reg.address), "Address", NULL} }; +struct acpi_rsdump_info acpi_rs_dump_gpio[16] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_gpio), "GPIO", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.revision_id), "RevisionId", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.connection_type), + "ConnectionType", acpi_gbl_ct_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.producer_consumer), + "ProducerConsumer", acpi_gbl_consume_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(gpio.pin_config), "PinConfig", + acpi_gbl_ppc_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.sharable), "Sharable", + acpi_gbl_shr_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.io_restriction), + "IoRestriction", acpi_gbl_ior_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(gpio.triggering), "Triggering", + acpi_gbl_he_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(gpio.polarity), "Polarity", + acpi_gbl_ll_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.drive_strength), "DriveStrength", + NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.debounce_timeout), + "DebounceTimeout", NULL}, + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(gpio.resource_source), + "ResourceSource", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.pin_table_length), + "PinTableLength", NULL}, + {ACPI_RSD_WORDLIST, ACPI_RSD_OFFSET(gpio.pin_table), "PinTable", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(gpio.vendor_length), "VendorLength", + NULL}, + {ACPI_RSD_SHORTLISTX, ACPI_RSD_OFFSET(gpio.vendor_data), "VendorData", + NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_fixed_dma[4] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_fixed_dma), + "FixedDma", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.request_lines), + "RequestLines", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(fixed_dma.channels), "Channels", + NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(fixed_dma.width), "TransferWidth", + acpi_gbl_dts_decode}, +}; + +#define ACPI_RS_DUMP_COMMON_SERIAL_BUS \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.revision_id), "RevisionId", NULL}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type), "Type", acpi_gbl_sbt_decode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.producer_consumer), "ProducerConsumer", acpi_gbl_consume_decode}, \ + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET (common_serial_bus.slave_mode), "SlaveMode", acpi_gbl_sm_decode}, \ + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET (common_serial_bus.type_revision_id), "TypeRevisionId", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.type_data_length), "TypeDataLength", NULL}, \ + {ACPI_RSD_SOURCE, ACPI_RSD_OFFSET (common_serial_bus.resource_source), "ResourceSource", NULL}, \ + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET (common_serial_bus.vendor_length), "VendorLength", NULL}, \ + {ACPI_RSD_SHORTLISTX,ACPI_RSD_OFFSET (common_serial_bus.vendor_data), "VendorData", NULL}, + +struct acpi_rsdump_info acpi_rs_dump_common_serial_bus[10] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_common_serial_bus), + "Common Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS +}; + +struct acpi_rsdump_info acpi_rs_dump_i2c_serial_bus[13] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_i2c_serial_bus), + "I2C Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(i2c_serial_bus. + access_mode), + "AccessMode", acpi_gbl_am_decode}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(i2c_serial_bus.connection_speed), + "ConnectionSpeed", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(i2c_serial_bus.slave_address), + "SlaveAddress", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_spi_serial_bus[17] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_spi_serial_bus), + "Spi Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_1BITFLAG, + ACPI_RSD_OFFSET(spi_serial_bus. + wire_mode), "WireMode", + acpi_gbl_wm_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(spi_serial_bus.device_polarity), + "DevicePolarity", acpi_gbl_dp_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.data_bit_length), + "DataBitLength", NULL}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_phase), + "ClockPhase", acpi_gbl_cph_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(spi_serial_bus.clock_polarity), + "ClockPolarity", acpi_gbl_cpo_decode}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(spi_serial_bus.device_selection), + "DeviceSelection", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(spi_serial_bus.connection_speed), + "ConnectionSpeed", NULL}, +}; + +struct acpi_rsdump_info acpi_rs_dump_uart_serial_bus[19] = { + {ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_uart_serial_bus), + "Uart Serial Bus", NULL}, + ACPI_RS_DUMP_COMMON_SERIAL_BUS {ACPI_RSD_2BITFLAG, + ACPI_RSD_OFFSET(uart_serial_bus. + flow_control), + "FlowControl", acpi_gbl_fc_decode}, + {ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.stop_bits), + "StopBits", acpi_gbl_sb_decode}, + {ACPI_RSD_3BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.data_bits), + "DataBits", acpi_gbl_bpb_decode}, + {ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(uart_serial_bus.endian), "Endian", + acpi_gbl_ed_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.parity), "Parity", + acpi_gbl_pt_decode}, + {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(uart_serial_bus.lines_enabled), + "LinesEnabled", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.rx_fifo_size), + "RxFifoSize", NULL}, + {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(uart_serial_bus.tx_fifo_size), + "TxFifoSize", NULL}, + {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(uart_serial_bus.default_baud_rate), + "ConnectionSpeed", NULL}, +}; + /* * Tables used for common address descriptor flag fields */ @@ -413,7 +534,14 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) /* Data items, 8/16/32/64 bit */ case ACPI_RSD_UINT8: - acpi_rs_out_integer8(name, ACPI_GET8(target)); + if (table->pointer) { + acpi_rs_out_string(name, ACPI_CAST_PTR(char, + table-> + pointer + [*target])); + } else { + acpi_rs_out_integer8(name, ACPI_GET8(target)); + } break; case ACPI_RSD_UINT16: @@ -444,6 +572,13 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) 0x03])); break; + case ACPI_RSD_3BITFLAG: + acpi_rs_out_string(name, ACPI_CAST_PTR(char, + table-> + pointer[*target & + 0x07])); + break; + case ACPI_RSD_SHORTLIST: /* * Short byte list (single line output) for DMA and IRQ resources @@ -456,6 +591,20 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) } break; + case ACPI_RSD_SHORTLISTX: + /* + * Short byte list (single line output) for GPIO vendor data + * Note: The list length is obtained from the previous table entry + */ + if (previous_target) { + acpi_rs_out_title(name); + acpi_rs_dump_short_byte_list(*previous_target, + * + (ACPI_CAST_INDIRECT_PTR + (u8, target))); + } + break; + case ACPI_RSD_LONGLIST: /* * Long byte list for Vendor resource data @@ -480,6 +629,18 @@ acpi_rs_dump_descriptor(void *resource, struct acpi_rsdump_info *table) } break; + case ACPI_RSD_WORDLIST: + /* + * Word list for GPIO Pin Table + * Note: The list length is obtained from the previous table entry + */ + if (previous_target) { + acpi_rs_dump_word_list(*previous_target, + *(ACPI_CAST_INDIRECT_PTR + (u16, target))); + } + break; + case ACPI_RSD_ADDRESS: /* * Common flags for all Address resources @@ -627,14 +788,20 @@ void acpi_rs_dump_resource_list(struct acpi_resource *resource_list) /* Dump the resource descriptor */ - acpi_rs_dump_descriptor(&resource_list->data, - acpi_gbl_dump_resource_dispatch[type]); + if (type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + acpi_rs_dump_descriptor(&resource_list->data, + acpi_gbl_dump_serial_bus_dispatch + [resource_list->data. + common_serial_bus.type]); + } else { + acpi_rs_dump_descriptor(&resource_list->data, + acpi_gbl_dump_resource_dispatch + [type]); + } /* Point to the next resource structure */ - resource_list = - ACPI_ADD_PTR(struct acpi_resource, resource_list, - resource_list->length); + resource_list = ACPI_NEXT_RESOURCE(resource_list); /* Exit when END_TAG descriptor is reached */ @@ -768,4 +935,13 @@ static void acpi_rs_dump_dword_list(u8 length, u32 * data) } } +static void acpi_rs_dump_word_list(u16 length, u16 *data) +{ + u16 i; + + for (i = 0; i < length; i++) { + acpi_os_printf("%25s%2.2X : %4.4X\n", "Word", i, data[i]); + } +} + #endif diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index f9ea60872aa..a9fa5158200 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -76,7 +76,10 @@ struct acpi_rsconvert_info *acpi_gbl_set_resource_dispatch[] = { acpi_rs_convert_address64, /* 0x0D, ACPI_RESOURCE_TYPE_ADDRESS64 */ acpi_rs_convert_ext_address64, /* 0x0E, ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ acpi_rs_convert_ext_irq, /* 0x0F, ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ - acpi_rs_convert_generic_reg /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_convert_generic_reg, /* 0x10, ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_convert_gpio, /* 0x11, ACPI_RESOURCE_TYPE_GPIO */ + acpi_rs_convert_fixed_dma, /* 0x12, ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* 0x13, ACPI_RESOURCE_TYPE_SERIAL_BUS - Use subtype table below */ }; /* Dispatch tables for AML-to-resource (Get Resource) conversion functions */ @@ -94,7 +97,7 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_end_dpf, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */ acpi_rs_convert_io, /* 0x08, ACPI_RESOURCE_NAME_IO */ acpi_rs_convert_fixed_io, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO */ - NULL, /* 0x0A, Reserved */ + acpi_rs_convert_fixed_dma, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */ NULL, /* 0x0B, Reserved */ NULL, /* 0x0C, Reserved */ NULL, /* 0x0D, Reserved */ @@ -114,7 +117,19 @@ struct acpi_rsconvert_info *acpi_gbl_get_resource_dispatch[] = { acpi_rs_convert_address16, /* 0x08, ACPI_RESOURCE_NAME_ADDRESS16 */ acpi_rs_convert_ext_irq, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_IRQ */ acpi_rs_convert_address64, /* 0x0A, ACPI_RESOURCE_NAME_ADDRESS64 */ - acpi_rs_convert_ext_address64 /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ + acpi_rs_convert_ext_address64, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS64 */ + acpi_rs_convert_gpio, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */ + NULL, /* 0x0D, Reserved */ + NULL, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS - Use subtype table below */ +}; + +/* Subtype table for serial_bus -- I2C, SPI, and UART */ + +struct acpi_rsconvert_info *acpi_gbl_convert_resource_serial_bus_dispatch[] = { + NULL, + acpi_rs_convert_i2c_serial_bus, + acpi_rs_convert_spi_serial_bus, + acpi_rs_convert_uart_serial_bus, }; #ifdef ACPI_FUTURE_USAGE @@ -140,6 +155,16 @@ struct acpi_rsdump_info *acpi_gbl_dump_resource_dispatch[] = { acpi_rs_dump_ext_address64, /* ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ acpi_rs_dump_ext_irq, /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ acpi_rs_dump_generic_reg, /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + acpi_rs_dump_gpio, /* ACPI_RESOURCE_TYPE_GPIO */ + acpi_rs_dump_fixed_dma, /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + NULL, /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ +}; + +struct acpi_rsdump_info *acpi_gbl_dump_serial_bus_dispatch[] = { + NULL, + acpi_rs_dump_i2c_serial_bus, /* AML_RESOURCE_I2C_BUS_TYPE */ + acpi_rs_dump_spi_serial_bus, /* AML_RESOURCE_SPI_BUS_TYPE */ + acpi_rs_dump_uart_serial_bus, /* AML_RESOURCE_UART_BUS_TYPE */ }; #endif @@ -166,7 +191,10 @@ const u8 acpi_gbl_aml_resource_sizes[] = { sizeof(struct aml_resource_address64), /* ACPI_RESOURCE_TYPE_ADDRESS64 */ sizeof(struct aml_resource_extended_address64), /*ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 */ sizeof(struct aml_resource_extended_irq), /* ACPI_RESOURCE_TYPE_EXTENDED_IRQ */ - sizeof(struct aml_resource_generic_register) /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + sizeof(struct aml_resource_generic_register), /* ACPI_RESOURCE_TYPE_GENERIC_REGISTER */ + sizeof(struct aml_resource_gpio), /* ACPI_RESOURCE_TYPE_GPIO */ + sizeof(struct aml_resource_fixed_dma), /* ACPI_RESOURCE_TYPE_FIXED_DMA */ + sizeof(struct aml_resource_common_serialbus), /* ACPI_RESOURCE_TYPE_SERIAL_BUS */ }; const u8 acpi_gbl_resource_struct_sizes[] = { @@ -182,7 +210,7 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE_MIN, ACPI_RS_SIZE(struct acpi_resource_io), ACPI_RS_SIZE(struct acpi_resource_fixed_io), - 0, + ACPI_RS_SIZE(struct acpi_resource_fixed_dma), 0, 0, 0, @@ -202,5 +230,21 @@ const u8 acpi_gbl_resource_struct_sizes[] = { ACPI_RS_SIZE(struct acpi_resource_address16), ACPI_RS_SIZE(struct acpi_resource_extended_irq), ACPI_RS_SIZE(struct acpi_resource_address64), - ACPI_RS_SIZE(struct acpi_resource_extended_address64) + ACPI_RS_SIZE(struct acpi_resource_extended_address64), + ACPI_RS_SIZE(struct acpi_resource_gpio), + ACPI_RS_SIZE(struct acpi_resource_common_serialbus) +}; + +const u8 acpi_gbl_aml_resource_serial_bus_sizes[] = { + 0, + sizeof(struct aml_resource_i2c_serialbus), + sizeof(struct aml_resource_spi_serialbus), + sizeof(struct aml_resource_uart_serialbus), +}; + +const u8 acpi_gbl_resource_struct_serial_bus_sizes[] = { + 0, + ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), + ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), + ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), }; diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 0c7efef008b..f6a081057a2 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c index 50b8ad21116..e23a9ec248c 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -264,3 +264,34 @@ struct acpi_rsconvert_info acpi_rs_convert_dma[6] = { AML_OFFSET(dma.dma_channel_mask), ACPI_RS_OFFSET(data.dma.channel_count)} }; + +/******************************************************************************* + * + * acpi_rs_convert_fixed_dma + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_fixed_dma[4] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_FIXED_DMA, + ACPI_RS_SIZE(struct acpi_resource_fixed_dma), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_fixed_dma)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_FIXED_DMA, + sizeof(struct aml_resource_fixed_dma), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * request_lines + * Channels + */ + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.fixed_dma.request_lines), + AML_OFFSET(fixed_dma.request_lines), + 2}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.fixed_dma.width), + AML_OFFSET(fixed_dma.width), + 1}, + +}; diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 1bfcef736c5..9be129f5d6f 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,6 +70,8 @@ acpi_rs_convert_aml_to_resources(u8 * aml, struct acpi_resource **resource_ptr = ACPI_CAST_INDIRECT_PTR(struct acpi_resource, context); struct acpi_resource *resource; + union aml_resource *aml_resource; + struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_aml_to_resources); @@ -84,14 +86,37 @@ acpi_rs_convert_aml_to_resources(u8 * aml, "Misaligned resource pointer %p", resource)); } + /* Get the appropriate conversion info table */ + + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (acpi_ut_get_resource_type(aml) == ACPI_RESOURCE_NAME_SERIAL_BUS) { + if (aml_resource->common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE) { + conversion_table = NULL; + } else { + /* This is an I2C, SPI, or UART serial_bus descriptor */ + + conversion_table = + acpi_gbl_convert_resource_serial_bus_dispatch + [aml_resource->common_serial_bus.type]; + } + } else { + conversion_table = + acpi_gbl_get_resource_dispatch[resource_index]; + } + + if (!conversion_table) { + ACPI_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource_index)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } + /* Convert the AML byte stream resource to a local resource struct */ status = - acpi_rs_convert_aml_to_resource(resource, - ACPI_CAST_PTR(union aml_resource, - aml), - acpi_gbl_get_resource_dispatch - [resource_index]); + acpi_rs_convert_aml_to_resource(resource, aml_resource, + conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert AML resource (Type 0x%X)", @@ -106,7 +131,7 @@ acpi_rs_convert_aml_to_resources(u8 * aml, /* Point to the next structure in the output buffer */ - *resource_ptr = ACPI_ADD_PTR(void, resource, resource->length); + *resource_ptr = ACPI_NEXT_RESOURCE(resource); return_ACPI_STATUS(AE_OK); } @@ -135,6 +160,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, { u8 *aml = output_buffer; u8 *end_aml = output_buffer + aml_size_needed; + struct acpi_rsconvert_info *conversion_table; acpi_status status; ACPI_FUNCTION_TRACE(rs_convert_resources_to_aml); @@ -154,11 +180,34 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Perform the conversion */ - status = acpi_rs_convert_resource_to_aml(resource, ACPI_CAST_PTR(union - aml_resource, - aml), - acpi_gbl_set_resource_dispatch - [resource->type]); + if (resource->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + if (resource->data.common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE) { + conversion_table = NULL; + } else { + /* This is an I2C, SPI, or UART serial_bus descriptor */ + + conversion_table = + acpi_gbl_convert_resource_serial_bus_dispatch + [resource->data.common_serial_bus.type]; + } + } else { + conversion_table = + acpi_gbl_set_resource_dispatch[resource->type]; + } + + if (!conversion_table) { + ACPI_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource->type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } + + status = acpi_rs_convert_resource_to_aml(resource, + ACPI_CAST_PTR(union + aml_resource, + aml), + conversion_table); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Could not convert resource (type 0x%X) to AML", @@ -192,9 +241,7 @@ acpi_rs_convert_resources_to_aml(struct acpi_resource *resource, /* Point to the next input resource descriptor */ - resource = - ACPI_ADD_PTR(struct acpi_resource, resource, - resource->length); + resource = ACPI_NEXT_RESOURCE(resource); } /* Completed buffer, but did not find an end_tag resource descriptor */ diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 7cc6d8625f1..4fd611ad02b 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c index 410264b22a2..8073b371cc7 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -83,6 +83,10 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ACPI_FUNCTION_TRACE(rs_convert_aml_to_resource); + if (!info) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + if (((acpi_size) resource) & 0x3) { /* Each internal resource struct is expected to be 32-bit aligned */ @@ -101,7 +105,6 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, * table length (# of table entries) */ count = INIT_TABLE_LENGTH(info); - while (count) { /* * Source is the external AML byte stream buffer, @@ -145,6 +148,14 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, ((ACPI_GET8(source) >> info->value) & 0x03); break; + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8(destination) = (u8) + ((ACPI_GET8(source) >> info->value) & 0x07); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); @@ -163,6 +174,69 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, (info->value * (item_count - 1)); break; + case ACPI_RSC_COUNT_GPIO_PIN: + + target = ACPI_ADD_PTR(void, aml, info->value); + item_count = ACPI_GET16(target) - ACPI_GET16(source); + + resource->length = resource->length + item_count; + item_count = item_count / 2; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + item_count = ACPI_GET8(source); + ACPI_SET8(destination) = (u8)item_count; + + resource->length = resource->length + + (info->value * item_count); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + + /* + * Vendor data is optional (length/offset may both be zero) + * Examine vendor data length field first + */ + target = ACPI_ADD_PTR(void, aml, (info->value + 2)); + if (ACPI_GET16(target)) { + + /* Use vendor offset to get resource source length */ + + target = ACPI_ADD_PTR(void, aml, info->value); + item_count = + ACPI_GET16(target) - ACPI_GET16(source); + } else { + /* No vendor data to worry about */ + + item_count = aml->large_header.resource_length + + sizeof(struct aml_resource_large_header) - + ACPI_GET16(source); + } + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + item_count = ACPI_GET16(source) - info->value; + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + item_count = (aml_resource_length + + sizeof(struct aml_resource_large_header)) + - ACPI_GET16(source) - info->value; + + resource->length = resource->length + item_count; + ACPI_SET16(destination) = item_count; + break; + case ACPI_RSC_LENGTH: resource->length = resource->length + info->value; @@ -183,6 +257,72 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, info->opcode); break; + case ACPI_RSC_MOVE_GPIO_PIN: + + /* Generate and set the PIN data pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count * 2)); + *(u16 **)destination = ACPI_CAST_PTR(u16, target); + + /* Copy the PIN data */ + + source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Generate and set the resource_source string pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the resource_source string */ + + source = ACPI_ADD_PTR(void, aml, ACPI_GET16(source)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + /* Generate and set the Vendor Data pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the Vendor Data */ + + source = ACPI_ADD_PTR(void, aml, info->value); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + /* Generate and set the resource_source string pointer */ + + target = (char *)ACPI_ADD_PTR(void, resource, + (resource->length - + item_count)); + *(u8 **)destination = ACPI_CAST_PTR(u8, target); + + /* Copy the resource_source string */ + + source = + ACPI_ADD_PTR(void, aml, + (ACPI_GET16(source) + info->value)); + acpi_rs_move_data(target, source, item_count, + info->opcode); + break; + case ACPI_RSC_SET8: ACPI_MEMSET(destination, info->aml_offset, info->value); @@ -219,13 +359,18 @@ acpi_rs_convert_aml_to_resource(struct acpi_resource *resource, * Optional resource_source (Index and String). This is the more * complicated case used by the Interrupt() macro */ - target = - ACPI_ADD_PTR(char, resource, - info->aml_offset + (item_count * 4)); + target = ACPI_ADD_PTR(char, resource, + info->aml_offset + + (item_count * 4)); resource->length += acpi_rs_get_resource_source(aml_resource_length, - (acpi_rs_length) (((item_count - 1) * sizeof(u32)) + info->value), destination, aml, target); + (acpi_rs_length) + (((item_count - + 1) * sizeof(u32)) + + info->value), + destination, aml, + target); break; case ACPI_RSC_BITMASK: @@ -327,6 +472,7 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, { void *source = NULL; void *destination; + char *target; acpi_rsdesc_size aml_length = 0; u8 count; u16 temp16 = 0; @@ -334,6 +480,10 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, ACPI_FUNCTION_TRACE(rs_convert_resource_to_aml); + if (!info) { + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + /* * First table entry must be ACPI_RSC_INITxxx and must contain the * table length (# of table entries) @@ -383,6 +533,14 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, ((ACPI_GET8(source) & 0x03) << info->value); break; + case ACPI_RSC_3BITFLAG: + /* + * Mask and shift the flag bits + */ + ACPI_SET8(destination) |= (u8) + ((ACPI_GET8(source) & 0x07) << info->value); + break; + case ACPI_RSC_COUNT: item_count = ACPI_GET8(source); @@ -400,6 +558,63 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, acpi_rs_set_resource_length(aml_length, aml); break; + case ACPI_RSC_COUNT_GPIO_PIN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)aml_length; + + aml_length = (u16)(aml_length + item_count * 2); + target = ACPI_ADD_PTR(void, aml, info->value); + ACPI_SET16(target) = (u16)aml_length; + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_GPIO_VEN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)item_count; + + aml_length = + (u16)(aml_length + (info->value * item_count)); + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_GPIO_RES: + + /* Set resource source string length */ + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = (u16)aml_length; + + /* Compute offset for the Vendor Data */ + + aml_length = (u16)(aml_length + item_count); + target = ACPI_ADD_PTR(void, aml, info->value); + + /* Set vendor offset only if there is vendor data */ + + if (resource->data.gpio.vendor_length) { + ACPI_SET16(target) = (u16)aml_length; + } + + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_SERIAL_VEN: + + item_count = ACPI_GET16(source); + ACPI_SET16(destination) = item_count + info->value; + aml_length = (u16)(aml_length + item_count); + acpi_rs_set_resource_length(aml_length, aml); + break; + + case ACPI_RSC_COUNT_SERIAL_RES: + + item_count = ACPI_GET16(source); + aml_length = (u16)(aml_length + item_count); + acpi_rs_set_resource_length(aml_length, aml); + break; + case ACPI_RSC_LENGTH: acpi_rs_set_resource_length(info->value, aml); @@ -417,6 +632,48 @@ acpi_rs_convert_resource_to_aml(struct acpi_resource *resource, info->opcode); break; + case ACPI_RSC_MOVE_GPIO_PIN: + + destination = (char *)ACPI_ADD_PTR(void, aml, + ACPI_GET16 + (destination)); + source = *(u16 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_GPIO_RES: + + /* Used for both resource_source string and vendor_data */ + + destination = (char *)ACPI_ADD_PTR(void, aml, + ACPI_GET16 + (destination)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_VEN: + + destination = (char *)ACPI_ADD_PTR(void, aml, + (aml_length - + item_count)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + + case ACPI_RSC_MOVE_SERIAL_RES: + + destination = (char *)ACPI_ADD_PTR(void, aml, + (aml_length - + item_count)); + source = *(u8 **)source; + acpi_rs_move_data(destination, source, item_count, + info->opcode); + break; + case ACPI_RSC_ADDRESS: /* Set the Resource Type, General Flags, and Type-Specific Flags */ diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c new file mode 100644 index 00000000000..9aa5e689b44 --- /dev/null +++ b/drivers/acpi/acpica/rsserial.c @@ -0,0 +1,441 @@ +/******************************************************************************* + * + * Module Name: rsserial - GPIO/serial_bus resource descriptors + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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 "acresrc.h" + +#define _COMPONENT ACPI_RESOURCES +ACPI_MODULE_NAME("rsserial") + +/******************************************************************************* + * + * acpi_rs_convert_gpio + * + ******************************************************************************/ +struct acpi_rsconvert_info acpi_rs_convert_gpio[17] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_GPIO, + ACPI_RS_SIZE(struct acpi_resource_gpio), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_gpio)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_GPIO, + sizeof(struct aml_resource_gpio), + 0}, + + /* + * These fields are contiguous in both the source and destination: + * revision_id + * connection_type + */ + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.revision_id), + AML_OFFSET(gpio.revision_id), + 2}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.producer_consumer), + AML_OFFSET(gpio.flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.sharable), + AML_OFFSET(gpio.int_flags), + 3}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.io_restriction), + AML_OFFSET(gpio.int_flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.gpio.triggering), + AML_OFFSET(gpio.int_flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.gpio.polarity), + AML_OFFSET(gpio.int_flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.pin_config), + AML_OFFSET(gpio.pin_config), + 1}, + + /* + * These fields are contiguous in both the source and destination: + * drive_strength + * debounce_timeout + */ + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.gpio.drive_strength), + AML_OFFSET(gpio.drive_strength), + 2}, + + /* Pin Table */ + + {ACPI_RSC_COUNT_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table_length), + AML_OFFSET(gpio.pin_table_offset), + AML_OFFSET(gpio.res_source_offset)}, + + {ACPI_RSC_MOVE_GPIO_PIN, ACPI_RS_OFFSET(data.gpio.pin_table), + AML_OFFSET(gpio.pin_table_offset), + 0}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.gpio.resource_source.index), + AML_OFFSET(gpio.res_source_index), + 1}, + + {ACPI_RSC_COUNT_GPIO_RES, + ACPI_RS_OFFSET(data.gpio.resource_source.string_length), + AML_OFFSET(gpio.res_source_offset), + AML_OFFSET(gpio.vendor_offset)}, + + {ACPI_RSC_MOVE_GPIO_RES, + ACPI_RS_OFFSET(data.gpio.resource_source.string_ptr), + AML_OFFSET(gpio.res_source_offset), + 0}, + + /* Vendor Data */ + + {ACPI_RSC_COUNT_GPIO_VEN, ACPI_RS_OFFSET(data.gpio.vendor_length), + AML_OFFSET(gpio.vendor_length), + 1}, + + {ACPI_RSC_MOVE_GPIO_RES, ACPI_RS_OFFSET(data.gpio.vendor_data), + AML_OFFSET(gpio.vendor_offset), + 0}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_i2c_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_i2c_serial_bus[16] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_i2c_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_i2c_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_i2c_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_I2C_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_i2c_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* I2C bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.i2c_serial_bus.access_mode), + AML_OFFSET(i2c_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.i2c_serial_bus.connection_speed), + AML_OFFSET(i2c_serial_bus.connection_speed), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.i2c_serial_bus.slave_address), + AML_OFFSET(i2c_serial_bus.slave_address), + 1}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_spi_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_spi_serial_bus[20] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_spi_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_spi_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_spi_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_SPI_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_spi_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* Spi bus type specific */ + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.wire_mode), + AML_OFFSET(spi_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.spi_serial_bus.device_polarity), + AML_OFFSET(spi_serial_bus.type_specific_flags), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.data_bit_length), + AML_OFFSET(spi_serial_bus.data_bit_length), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_phase), + AML_OFFSET(spi_serial_bus.clock_phase), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.spi_serial_bus.clock_polarity), + AML_OFFSET(spi_serial_bus.clock_polarity), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.spi_serial_bus.device_selection), + AML_OFFSET(spi_serial_bus.device_selection), + 1}, + + {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.spi_serial_bus.connection_speed), + AML_OFFSET(spi_serial_bus.connection_speed), + 1}, +}; + +/******************************************************************************* + * + * acpi_rs_convert_uart_serial_bus + * + ******************************************************************************/ + +struct acpi_rsconvert_info acpi_rs_convert_uart_serial_bus[22] = { + {ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_SERIAL_BUS, + ACPI_RS_SIZE(struct acpi_resource_uart_serialbus), + ACPI_RSC_TABLE_SIZE(acpi_rs_convert_uart_serial_bus)}, + + {ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_SERIAL_BUS, + sizeof(struct aml_resource_uart_serialbus), + 0}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.revision_id), + AML_OFFSET(common_serial_bus.revision_id), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.common_serial_bus.type), + AML_OFFSET(common_serial_bus.type), + 1}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.common_serial_bus.slave_mode), + AML_OFFSET(common_serial_bus.flags), + 0}, + + {ACPI_RSC_1BITFLAG, + ACPI_RS_OFFSET(data.common_serial_bus.producer_consumer), + AML_OFFSET(common_serial_bus.flags), + 1}, + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.type_revision_id), + AML_OFFSET(common_serial_bus.type_revision_id), + 1}, + + {ACPI_RSC_MOVE16, + ACPI_RS_OFFSET(data.common_serial_bus.type_data_length), + AML_OFFSET(common_serial_bus.type_data_length), + 1}, + + /* Vendor data */ + + {ACPI_RSC_COUNT_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_length), + AML_OFFSET(common_serial_bus.type_data_length), + AML_RESOURCE_UART_MIN_DATA_LEN}, + + {ACPI_RSC_MOVE_SERIAL_VEN, + ACPI_RS_OFFSET(data.common_serial_bus.vendor_data), + 0, + sizeof(struct aml_resource_uart_serialbus)}, + + /* Resource Source */ + + {ACPI_RSC_MOVE8, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.index), + AML_OFFSET(common_serial_bus.res_source_index), + 1}, + + {ACPI_RSC_COUNT_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_length), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + {ACPI_RSC_MOVE_SERIAL_RES, + ACPI_RS_OFFSET(data.common_serial_bus.resource_source.string_ptr), + AML_OFFSET(common_serial_bus.type_data_length), + sizeof(struct aml_resource_common_serialbus)}, + + /* Uart bus type specific */ + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.flow_control), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 0}, + + {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.stop_bits), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 2}, + + {ACPI_RSC_3BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.data_bits), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 4}, + + {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.uart_serial_bus.endian), + AML_OFFSET(uart_serial_bus.type_specific_flags), + 7}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.parity), + AML_OFFSET(uart_serial_bus.parity), + 1}, + + {ACPI_RSC_MOVE8, ACPI_RS_OFFSET(data.uart_serial_bus.lines_enabled), + AML_OFFSET(uart_serial_bus.lines_enabled), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.rx_fifo_size), + AML_OFFSET(uart_serial_bus.rx_fifo_size), + 1}, + + {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.uart_serial_bus.tx_fifo_size), + AML_OFFSET(uart_serial_bus.tx_fifo_size), + 1}, + + {ACPI_RSC_MOVE32, + ACPI_RS_OFFSET(data.uart_serial_bus.default_baud_rate), + AML_OFFSET(uart_serial_bus.default_baud_rate), + 1}, +}; diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index 231811e5693..433a375deb9 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -144,6 +144,9 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) * since there are no alignment or endian issues */ case ACPI_RSC_MOVE8: + case ACPI_RSC_MOVE_GPIO_RES: + case ACPI_RSC_MOVE_SERIAL_VEN: + case ACPI_RSC_MOVE_SERIAL_RES: ACPI_MEMCPY(destination, source, item_count); return; @@ -153,6 +156,7 @@ acpi_rs_move_data(void *destination, void *source, u16 item_count, u8 move_type) * misaligned memory transfers */ case ACPI_RSC_MOVE16: + case ACPI_RSC_MOVE_GPIO_PIN: ACPI_MOVE_16_TO_16(&ACPI_CAST_PTR(u16, destination)[i], &ACPI_CAST_PTR(u16, source)[i]); break; @@ -590,6 +594,56 @@ acpi_rs_get_prs_method_data(struct acpi_namespace_node *node, /******************************************************************************* * + * FUNCTION: acpi_rs_get_aei_method_data + * + * PARAMETERS: Node - Device node + * ret_buffer - Pointer to a buffer structure for the + * results + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the _AEI value of an object + * contained in an object specified by the handle passed in + * + * If the function fails an appropriate status will be returned + * and the contents of the callers buffer is undefined. + * + ******************************************************************************/ + +acpi_status +acpi_rs_get_aei_method_data(struct acpi_namespace_node *node, + struct acpi_buffer *ret_buffer) +{ + union acpi_operand_object *obj_desc; + acpi_status status; + + ACPI_FUNCTION_TRACE(rs_get_aei_method_data); + + /* Parameters guaranteed valid by caller */ + + /* Execute the method, no parameters */ + + status = acpi_ut_evaluate_object(node, METHOD_NAME__AEI, + ACPI_BTYPE_BUFFER, &obj_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* + * Make the call to create a resource linked list from the + * byte stream buffer that comes back from the _CRS method + * execution. + */ + status = acpi_rs_create_resource_list(obj_desc, ret_buffer); + + /* On exit, we must delete the object returned by evaluate_object */ + + acpi_ut_remove_reference(obj_desc); + return_ACPI_STATUS(status); +} + +/******************************************************************************* + * * FUNCTION: acpi_rs_get_method_data * * PARAMETERS: Handle - Handle to the containing object diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index fe86b37b16c..f58c098c7ae 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -307,6 +307,46 @@ acpi_set_current_resources(acpi_handle device_handle, ACPI_EXPORT_SYMBOL(acpi_set_current_resources) +/******************************************************************************* + * + * FUNCTION: acpi_get_event_resources + * + * PARAMETERS: device_handle - Handle to the device object for the + * device we are getting resources + * in_buffer - Pointer to a buffer containing the + * resources to be set for the device + * + * RETURN: Status + * + * DESCRIPTION: This function is called to get the event resources for a + * specific device. The caller must first acquire a handle for + * the desired device. The resource data is passed to the routine + * the buffer pointed to by the in_buffer variable. Uses the + * _AEI method. + * + ******************************************************************************/ +acpi_status +acpi_get_event_resources(acpi_handle device_handle, + struct acpi_buffer *ret_buffer) +{ + acpi_status status; + struct acpi_namespace_node *node; + + ACPI_FUNCTION_TRACE(acpi_get_event_resources); + + /* Validate parameters then dispatch to internal routine */ + + status = acpi_rs_validate_parameters(device_handle, ret_buffer, &node); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + status = acpi_rs_get_aei_method_data(node, ret_buffer); + return_ACPI_STATUS(status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_event_resources) + /****************************************************************************** * * FUNCTION: acpi_resource_to_address64 @@ -486,8 +526,9 @@ acpi_rs_match_vendor_resource(struct acpi_resource *resource, void *context) * * PARAMETERS: device_handle - Handle to the device object for the * device we are querying - * Name - Method name of the resources we want - * (METHOD_NAME__CRS or METHOD_NAME__PRS) + * Name - Method name of the resources we want. + * (METHOD_NAME__CRS, METHOD_NAME__PRS, or + * METHOD_NAME__AEI) * user_function - Called for each resource * Context - Passed to user_function * @@ -514,11 +555,12 @@ acpi_walk_resources(acpi_handle device_handle, if (!device_handle || !user_function || !name || (!ACPI_COMPARE_NAME(name, METHOD_NAME__CRS) && - !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS))) { + !ACPI_COMPARE_NAME(name, METHOD_NAME__PRS) && + !ACPI_COMPARE_NAME(name, METHOD_NAME__AEI))) { return_ACPI_STATUS(AE_BAD_PARAMETER); } - /* Get the _CRS or _PRS resource list */ + /* Get the _CRS/_PRS/_AEI resource list */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; status = acpi_rs_get_method_data(device_handle, name, &buffer); diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 6f5588e62c0..c5d870406f4 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -63,14 +63,15 @@ static void acpi_tb_setup_fadt_registers(void); typedef struct acpi_fadt_info { char *name; - u8 address64; - u8 address32; - u8 length; + u16 address64; + u16 address32; + u16 length; u8 default_length; u8 type; } acpi_fadt_info; +#define ACPI_FADT_OPTIONAL 0 #define ACPI_FADT_REQUIRED 1 #define ACPI_FADT_SEPARATE_LENGTH 2 @@ -87,7 +88,7 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(pm1b_event_block), ACPI_FADT_OFFSET(pm1_event_length), ACPI_PM1_REGISTER_WIDTH * 2, /* Enable + Status register */ - 0}, + ACPI_FADT_OPTIONAL}, {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block), @@ -101,7 +102,7 @@ static struct acpi_fadt_info fadt_info_table[] = { ACPI_FADT_OFFSET(pm1b_control_block), ACPI_FADT_OFFSET(pm1_control_length), ACPI_PM1_REGISTER_WIDTH, - 0}, + ACPI_FADT_OPTIONAL}, {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block), @@ -139,7 +140,7 @@ static struct acpi_fadt_info fadt_info_table[] = { typedef struct acpi_fadt_pm_info { struct acpi_generic_address *target; - u8 source; + u16 source; u8 register_num; } acpi_fadt_pm_info; @@ -253,8 +254,13 @@ void acpi_tb_parse_fadt(u32 table_index) acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); - acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, - ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS); + /* If Hardware Reduced flag is set, there is no FACS */ + + if (!acpi_gbl_reduced_hardware) { + acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT. + Xfacs, ACPI_SIG_FACS, + ACPI_TABLE_INDEX_FACS); + } } /******************************************************************************* @@ -277,12 +283,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) { /* * Check if the FADT is larger than the largest table that we expect - * (the ACPI 2.0/3.0 version). If so, truncate the table, and issue + * (the ACPI 5.0 version). If so, truncate the table, and issue * a warning. */ if (length > sizeof(struct acpi_table_fadt)) { ACPI_WARNING((AE_INFO, - "FADT (revision %u) is longer than ACPI 2.0 version, " + "FADT (revision %u) is longer than ACPI 5.0 version, " "truncating length %u to %u", table->revision, length, (u32)sizeof(struct acpi_table_fadt))); @@ -297,6 +303,13 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) ACPI_MEMCPY(&acpi_gbl_FADT, table, ACPI_MIN(length, sizeof(struct acpi_table_fadt))); + /* Take a copy of the Hardware Reduced flag */ + + acpi_gbl_reduced_hardware = FALSE; + if (acpi_gbl_FADT.flags & ACPI_FADT_HW_REDUCED) { + acpi_gbl_reduced_hardware = TRUE; + } + /* Convert the local copy of the FADT to the common internal format */ acpi_tb_convert_fadt(); @@ -502,6 +515,12 @@ static void acpi_tb_validate_fadt(void) acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt; } + /* If Hardware Reduced flag is set, we are all done */ + + if (acpi_gbl_reduced_hardware) { + return; + } + /* Examine all of the 64-bit extended address fields (X fields) */ for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index a55cb2bb5ab..4903e36ea75 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 62365f6075d..1aecf7baa4e 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 0f2d395feab..09ca39e1433 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -135,6 +135,13 @@ acpi_status acpi_tb_initialize_facs(void) { acpi_status status; + /* If Hardware Reduced flag is set, there is no FACS */ + + if (acpi_gbl_reduced_hardware) { + acpi_gbl_FACS = NULL; + return (AE_OK); + } + status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index e7d13f5d3f2..abcc6412c24 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c index 7eb6c6cc1ed..4258f647ca3 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c new file mode 100644 index 00000000000..67932aebe6d --- /dev/null +++ b/drivers/acpi/acpica/utaddress.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Module Name: utaddress - op_region address range check + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utaddress") + +/******************************************************************************* + * + * FUNCTION: acpi_ut_add_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - op_region start address + * Length - op_region length + * region_node - op_region namespace node + * + * RETURN: Status + * + * DESCRIPTION: Add the Operation Region address range to the global list. + * The only supported Space IDs are Memory and I/O. Called when + * the op_region address/length operands are fully evaluated. + * + * MUTEX: Locks the namespace + * + * NOTE: Because this interface is only called when an op_region argument + * list is evaluated, there cannot be any duplicate region_nodes. + * Duplicate Address/Length values are allowed, however, so that multiple + * address conflicts can be detected. + * + ******************************************************************************/ +acpi_status +acpi_ut_add_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + u32 length, struct acpi_namespace_node *region_node) +{ + struct acpi_address_range *range_info; + acpi_status status; + + ACPI_FUNCTION_TRACE(ut_add_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_ACPI_STATUS(AE_OK); + } + + /* Allocate/init a new info block, add it to the appropriate list */ + + range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range)); + if (!range_info) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + range_info->start_address = address; + range_info->end_address = (address + length - 1); + range_info->region_node = region_node; + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + ACPI_FREE(range_info); + return_ACPI_STATUS(status); + } + + range_info->next = acpi_gbl_address_range_list[space_id]; + acpi_gbl_address_range_list[space_id] = range_info; + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "\nAdded [%4.4s] address range: 0x%p-0x%p\n", + acpi_ut_get_node_name(range_info->region_node), + ACPI_CAST_PTR(void, address), + ACPI_CAST_PTR(void, range_info->end_address))); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_remove_address_range + * + * PARAMETERS: space_id - Address space ID + * region_node - op_region namespace node + * + * RETURN: None + * + * DESCRIPTION: Remove the Operation Region from the global list. The only + * supported Space IDs are Memory and I/O. Called when an + * op_region is deleted. + * + * MUTEX: Assumes the namespace is locked + * + ******************************************************************************/ + +void +acpi_ut_remove_address_range(acpi_adr_space_type space_id, + struct acpi_namespace_node *region_node) +{ + struct acpi_address_range *range_info; + struct acpi_address_range *prev; + + ACPI_FUNCTION_TRACE(ut_remove_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_VOID; + } + + /* Get the appropriate list head and check the list */ + + range_info = prev = acpi_gbl_address_range_list[space_id]; + while (range_info) { + if (range_info->region_node == region_node) { + if (range_info == prev) { /* Found at list head */ + acpi_gbl_address_range_list[space_id] = + range_info->next; + } else { + prev->next = range_info->next; + } + + ACPI_DEBUG_PRINT((ACPI_DB_NAMES, + "\nRemoved [%4.4s] address range: 0x%p-0x%p\n", + acpi_ut_get_node_name(range_info-> + region_node), + ACPI_CAST_PTR(void, + range_info-> + start_address), + ACPI_CAST_PTR(void, + range_info-> + end_address))); + + ACPI_FREE(range_info); + return_VOID; + } + + prev = range_info; + range_info = range_info->next; + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_check_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - Start address + * Length - Length of address range + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. Zero is always + * returned for Space IDs other than Memory or I/O. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. The only supported + * Space IDs are Memory and I/O. + * + * MUTEX: Assumes the namespace is locked. + * + ******************************************************************************/ + +u32 +acpi_ut_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, u32 length, u8 warn) +{ + struct acpi_address_range *range_info; + acpi_physical_address end_address; + char *pathname; + u32 overlap_count = 0; + + ACPI_FUNCTION_TRACE(ut_check_address_range); + + if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && + (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { + return_UINT32(0); + } + + range_info = acpi_gbl_address_range_list[space_id]; + end_address = address + length - 1; + + /* Check entire list for all possible conflicts */ + + while (range_info) { + /* + * Check if the requested Address/Length overlaps this address_range. + * Four cases to consider: + * + * 1) Input address/length is contained completely in the address range + * 2) Input address/length overlaps range at the range start + * 3) Input address/length overlaps range at the range end + * 4) Input address/length completely encompasses the range + */ + if ((address <= range_info->end_address) && + (end_address >= range_info->start_address)) { + + /* Found an address range overlap */ + + overlap_count++; + if (warn) { /* Optional warning message */ + pathname = + acpi_ns_get_external_pathname(range_info-> + region_node); + + ACPI_WARNING((AE_INFO, + "0x%p-0x%p %s conflicts with Region %s %d", + ACPI_CAST_PTR(void, address), + ACPI_CAST_PTR(void, end_address), + acpi_ut_get_region_name(space_id), + pathname, overlap_count)); + ACPI_FREE(pathname); + } + } + + range_info = range_info->next; + } + + return_UINT32(overlap_count); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_delete_address_lists + * + * PARAMETERS: None + * + * RETURN: None + * + * DESCRIPTION: Delete all global address range lists (called during + * subsystem shutdown). + * + ******************************************************************************/ + +void acpi_ut_delete_address_lists(void) +{ + struct acpi_address_range *next; + struct acpi_address_range *range_info; + int i; + + /* Delete all elements in all address range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { + next = acpi_gbl_address_range_list[i]; + + while (next) { + range_info = next; + next = range_info->next; + ACPI_FREE(range_info); + } + + acpi_gbl_address_range_list[i] = NULL; + } +} diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 0a697351cf6..9982d2ea66f 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index aded299a2fa..3317c0a406e 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index a1f8d7509e6..a0998a88631 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c index 8b087e2d64f..d42ede5260c 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -171,7 +171,9 @@ const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] = { "SMBus", "SystemCMOS", "PCIBARTarget", - "IPMI" + "IPMI", + "GeneralPurposeIo", + "GenericSerialBus" }; char *acpi_ut_get_region_name(u8 space_id) diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 31f5a7832ef..2a6c3e18369 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -215,11 +215,14 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object)); - /* Invalidate the region address/length via the host OS */ - - acpi_os_invalidate_address(object->region.space_id, - object->region.address, - (acpi_size) object->region.length); + /* + * Update address_range list. However, only permanent regions + * are installed in this list. (Not created within a method) + */ + if (!(object->region.node->flags & ANOBJ_TEMPORARY)) { + acpi_ut_remove_address_range(object->region.space_id, + object->region.node); + } second_desc = acpi_ns_get_secondary_object(object); if (second_desc) { diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 18f73c9d10b..479f32b3341 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c index ffba0a39c3e..4153584cf52 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -264,6 +264,12 @@ acpi_status acpi_ut_init_globals(void) return_ACPI_STATUS(status); } + /* Address Range lists */ + + for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { + acpi_gbl_address_range_list[i] = NULL; + } + /* Mutex locked flags */ for (i = 0; i < ACPI_NUM_MUTEX; i++) { diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index b679ea69354..c92eb1d9378 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 191b6828cce..8359c0c5dc9 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,6 +92,7 @@ static void acpi_ut_terminate(void) gpe_xrupt_info = next_gpe_xrupt_info; } + acpi_ut_delete_address_lists(); return_VOID; } diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index f6bb75c6faf..155fd786d0f 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c index ce481da9bb4..2491a552b0e 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index c33a852d4f4..86f19db74e0 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 7d797e2baec..43174df3312 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -293,14 +293,10 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) { - acpi_thread_id this_thread_id; - ACPI_FUNCTION_NAME(ut_release_mutex); - this_thread_id = acpi_os_get_thread_id(); - ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %u releasing Mutex [%s]\n", - (u32)this_thread_id, + (u32)acpi_os_get_thread_id(), acpi_ut_get_mutex_name(mutex_id))); if (mutex_id > ACPI_MAX_MUTEX) { @@ -329,7 +325,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) * the ACPI subsystem code. */ for (i = mutex_id; i < ACPI_NUM_MUTEX; i++) { - if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { + if (acpi_gbl_mutex_info[i].thread_id == + acpi_os_get_thread_id()) { if (i == mutex_id) { continue; } diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 188340a017b..b112744fc9a 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c index 1fb10cb8f11..2360cf70c18 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c index 6ffd3a8bdaa..9d441ea7030 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,7 @@ #include <acpi/acpi.h> #include "accommon.h" -#include "amlresrc.h" +#include "acresrc.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utresrc") @@ -154,6 +154,138 @@ const char *acpi_gbl_typ_decode[] = { "TypeF" }; +const char *acpi_gbl_ppc_decode[] = { + "PullDefault", + "PullUp", + "PullDown", + "PullNone" +}; + +const char *acpi_gbl_ior_decode[] = { + "IoRestrictionNone", + "IoRestrictionInputOnly", + "IoRestrictionOutputOnly", + "IoRestrictionNoneAndPreserve" +}; + +const char *acpi_gbl_dts_decode[] = { + "Width8bit", + "Width16bit", + "Width32bit", + "Width64bit", + "Width128bit", + "Width256bit", +}; + +/* GPIO connection type */ + +const char *acpi_gbl_ct_decode[] = { + "Interrupt", + "I/O" +}; + +/* Serial bus type */ + +const char *acpi_gbl_sbt_decode[] = { + "/* UNKNOWN serial bus type */", + "I2C", + "SPI", + "UART" +}; + +/* I2C serial bus access mode */ + +const char *acpi_gbl_am_decode[] = { + "AddressingMode7Bit", + "AddressingMode10Bit" +}; + +/* I2C serial bus slave mode */ + +const char *acpi_gbl_sm_decode[] = { + "ControllerInitiated", + "DeviceInitiated" +}; + +/* SPI serial bus wire mode */ + +const char *acpi_gbl_wm_decode[] = { + "FourWireMode", + "ThreeWireMode" +}; + +/* SPI serial clock phase */ + +const char *acpi_gbl_cph_decode[] = { + "ClockPhaseFirst", + "ClockPhaseSecond" +}; + +/* SPI serial bus clock polarity */ + +const char *acpi_gbl_cpo_decode[] = { + "ClockPolarityLow", + "ClockPolarityHigh" +}; + +/* SPI serial bus device polarity */ + +const char *acpi_gbl_dp_decode[] = { + "PolarityLow", + "PolarityHigh" +}; + +/* UART serial bus endian */ + +const char *acpi_gbl_ed_decode[] = { + "LittleEndian", + "BigEndian" +}; + +/* UART serial bus bits per byte */ + +const char *acpi_gbl_bpb_decode[] = { + "DataBitsFive", + "DataBitsSix", + "DataBitsSeven", + "DataBitsEight", + "DataBitsNine", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */", + "/* UNKNOWN Bits per byte */" +}; + +/* UART serial bus stop bits */ + +const char *acpi_gbl_sb_decode[] = { + "StopBitsNone", + "StopBitsOne", + "StopBitsOnePlusHalf", + "StopBitsTwo" +}; + +/* UART serial bus flow control */ + +const char *acpi_gbl_fc_decode[] = { + "FlowControlNone", + "FlowControlHardware", + "FlowControlXON", + "/* UNKNOWN flow control keyword */" +}; + +/* UART serial bus parity type */ + +const char *acpi_gbl_pt_decode[] = { + "ParityTypeNone", + "ParityTypeEven", + "ParityTypeOdd", + "ParityTypeMark", + "ParityTypeSpace", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */", + "/* UNKNOWN parity keyword */" +}; + #endif /* @@ -173,7 +305,7 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent), ACPI_AML_SIZE_SMALL(struct aml_resource_io), ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io), - 0, + ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma), 0, 0, 0, @@ -193,7 +325,17 @@ const u8 acpi_gbl_resource_aml_sizes[] = { ACPI_AML_SIZE_LARGE(struct aml_resource_address16), ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq), ACPI_AML_SIZE_LARGE(struct aml_resource_address64), - ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64) + ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64), + ACPI_AML_SIZE_LARGE(struct aml_resource_gpio), + 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus), +}; + +const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = { + 0, + ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus), + ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus), }; /* @@ -209,35 +351,49 @@ static const u8 acpi_gbl_resource_types[] = { 0, 0, 0, - ACPI_SMALL_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_SMALL_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - 0, + ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */ + ACPI_FIXED_LENGTH, /* 05 DMA */ + ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */ + ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */ + ACPI_FIXED_LENGTH, /* 08 IO */ + ACPI_FIXED_LENGTH, /* 09 fixed_iO */ + ACPI_FIXED_LENGTH, /* 0_a fixed_dMA */ 0, 0, 0, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, + ACPI_VARIABLE_LENGTH, /* 0_e vendor_short */ + ACPI_FIXED_LENGTH, /* 0_f end_tag */ /* Large descriptors */ 0, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, + ACPI_FIXED_LENGTH, /* 01 Memory24 */ + ACPI_FIXED_LENGTH, /* 02 generic_register */ 0, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_FIXED_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_VARIABLE_LENGTH, - ACPI_FIXED_LENGTH + ACPI_VARIABLE_LENGTH, /* 04 vendor_long */ + ACPI_FIXED_LENGTH, /* 05 Memory32 */ + ACPI_FIXED_LENGTH, /* 06 memory32_fixed */ + ACPI_VARIABLE_LENGTH, /* 07 Dword* address */ + ACPI_VARIABLE_LENGTH, /* 08 Word* address */ + ACPI_VARIABLE_LENGTH, /* 09 extended_iRQ */ + ACPI_VARIABLE_LENGTH, /* 0_a Qword* address */ + ACPI_FIXED_LENGTH, /* 0_b Extended* address */ + ACPI_VARIABLE_LENGTH, /* 0_c Gpio* */ + 0, + ACPI_VARIABLE_LENGTH /* 0_e *serial_bus */ }; +/* + * For the i_aSL compiler/disassembler, we don't want any error messages + * because the disassembler uses the resource validation code to determine + * if Buffer objects are actually Resource Templates. + */ +#ifdef ACPI_ASL_COMPILER +#define ACPI_RESOURCE_ERROR(plist) +#else +#define ACPI_RESOURCE_ERROR(plist) ACPI_ERROR(plist) +#endif + /******************************************************************************* * * FUNCTION: acpi_ut_walk_aml_resources @@ -265,6 +421,7 @@ acpi_ut_walk_aml_resources(u8 * aml, u8 resource_index; u32 length; u32 offset = 0; + u8 end_tag[2] = { 0x79, 0x00 }; ACPI_FUNCTION_TRACE(ut_walk_aml_resources); @@ -286,6 +443,10 @@ acpi_ut_walk_aml_resources(u8 * aml, status = acpi_ut_validate_resource(aml, &resource_index); if (ACPI_FAILURE(status)) { + /* + * Exit on failure. Cannot continue because the descriptor length + * may be bogus also. + */ return_ACPI_STATUS(status); } @@ -300,7 +461,7 @@ acpi_ut_walk_aml_resources(u8 * aml, user_function(aml, length, offset, resource_index, context); if (ACPI_FAILURE(status)) { - return (status); + return_ACPI_STATUS(status); } } @@ -333,7 +494,19 @@ acpi_ut_walk_aml_resources(u8 * aml, /* Did not find an end_tag descriptor */ - return (AE_AML_NO_RESOURCE_END_TAG); + if (user_function) { + + /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */ + + (void)acpi_ut_validate_resource(end_tag, &resource_index); + status = + user_function(end_tag, 2, offset, resource_index, context); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } /******************************************************************************* @@ -354,6 +527,7 @@ acpi_ut_walk_aml_resources(u8 * aml, acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) { + union aml_resource *aml_resource; u8 resource_type; u8 resource_index; acpi_rs_length resource_length; @@ -375,7 +549,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Verify the large resource type (name) against the max */ if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) { - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; } /* @@ -392,15 +566,17 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3); } - /* Check validity of the resource type, zero indicates name is invalid */ - + /* + * Check validity of the resource type, via acpi_gbl_resource_types. Zero + * indicates an invalid resource. + */ if (!acpi_gbl_resource_types[resource_index]) { - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; } /* - * 2) Validate the resource_length field. This ensures that the length - * is at least reasonable, and guarantees that it is non-zero. + * Validate the resource_length field. This ensures that the length + * is at least reasonable, and guarantees that it is non-zero. */ resource_length = acpi_ut_get_resource_length(aml); minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index]; @@ -413,7 +589,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Fixed length resource, length must match exactly */ if (resource_length != minimum_resource_length) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -422,7 +598,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Variable length resource, length must be at least the minimum */ if (resource_length < minimum_resource_length) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -432,7 +608,7 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) if ((resource_length > minimum_resource_length) || (resource_length < (minimum_resource_length - 1))) { - return (AE_AML_BAD_RESOURCE_LENGTH); + goto bad_resource_length; } break; @@ -440,7 +616,23 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) /* Shouldn't happen (because of validation earlier), but be sure */ - return (AE_AML_INVALID_RESOURCE_TYPE); + goto invalid_resource; + } + + aml_resource = ACPI_CAST_PTR(union aml_resource, aml); + if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) { + + /* Validate the bus_type field */ + + if ((aml_resource->common_serial_bus.type == 0) || + (aml_resource->common_serial_bus.type > + AML_RESOURCE_MAX_SERIALBUSTYPE)) { + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X", + aml_resource->common_serial_bus. + type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + } } /* Optionally return the resource table index */ @@ -450,6 +642,22 @@ acpi_status acpi_ut_validate_resource(void *aml, u8 * return_index) } return (AE_OK); + + invalid_resource: + + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid/unsupported resource descriptor: Type 0x%2.2X", + resource_type)); + return (AE_AML_INVALID_RESOURCE_TYPE); + + bad_resource_length: + + ACPI_RESOURCE_ERROR((AE_INFO, + "Invalid resource descriptor length: Type " + "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X", + resource_type, resource_length, + minimum_resource_length)); + return (AE_AML_BAD_RESOURCE_LENGTH); } /******************************************************************************* diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index 30c21e1a936..4267477c279 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 420ebfe08c7..644e8c8ebc4 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include "acnamesp.h" #include "acdebug.h" #include "actables.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utxface") @@ -640,4 +641,41 @@ acpi_status acpi_install_interface_handler(acpi_interface_handler handler) } ACPI_EXPORT_SYMBOL(acpi_install_interface_handler) + +/***************************************************************************** + * + * FUNCTION: acpi_check_address_range + * + * PARAMETERS: space_id - Address space ID + * Address - Start address + * Length - Length + * Warn - TRUE if warning on overlap desired + * + * RETURN: Count of the number of conflicts detected. + * + * DESCRIPTION: Check if the input address range overlaps any of the + * ASL operation region address ranges. + * + ****************************************************************************/ +u32 +acpi_check_address_range(acpi_adr_space_type space_id, + acpi_physical_address address, + acpi_size length, u8 warn) +{ + u32 overlaps; + acpi_status status; + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + return (0); + } + + overlaps = acpi_ut_check_address_range(space_id, address, + (u32)length, warn); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (overlaps); +} + +ACPI_EXPORT_SYMBOL(acpi_check_address_range) #endif /* !ACPI_ASL_COMPILER */ diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index 8d0245ec431..52b568af181 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2011, Intel Corp. + * Copyright (C) 2000 - 2012, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c new file mode 100644 index 00000000000..1427d191d15 --- /dev/null +++ b/drivers/acpi/acpica/utxfmutex.c @@ -0,0 +1,187 @@ +/******************************************************************************* + * + * Module Name: utxfmutex - external AML mutex access functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2012, 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" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utxfmutex") + +/* Local prototypes */ +static acpi_status +acpi_ut_get_mutex_object(acpi_handle handle, + acpi_string pathname, + union acpi_operand_object **ret_obj); + +/******************************************************************************* + * + * FUNCTION: acpi_ut_get_mutex_object + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * ret_obj - Where the mutex object is returned + * + * RETURN: Status + * + * DESCRIPTION: Get an AML mutex object. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +static acpi_status +acpi_ut_get_mutex_object(acpi_handle handle, + acpi_string pathname, + union acpi_operand_object **ret_obj) +{ + struct acpi_namespace_node *mutex_node; + union acpi_operand_object *mutex_obj; + acpi_status status; + + /* Parameter validation */ + + if (!ret_obj || (!handle && !pathname)) { + return (AE_BAD_PARAMETER); + } + + /* Get a the namespace node for the mutex */ + + mutex_node = handle; + if (pathname != NULL) { + status = acpi_get_handle(handle, pathname, + ACPI_CAST_PTR(acpi_handle, + &mutex_node)); + if (ACPI_FAILURE(status)) { + return (status); + } + } + + /* Ensure that we actually have a Mutex object */ + + if (!mutex_node || (mutex_node->type != ACPI_TYPE_MUTEX)) { + return (AE_TYPE); + } + + /* Get the low-level mutex object */ + + mutex_obj = acpi_ns_get_attached_object(mutex_node); + if (!mutex_obj) { + return (AE_NULL_OBJECT); + } + + *ret_obj = mutex_obj; + return (AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_acquire_mutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * Timeout - Max time to wait for the lock (millisec) + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +acpi_status +acpi_acquire_mutex(acpi_handle handle, acpi_string pathname, u16 timeout) +{ + acpi_status status; + union acpi_operand_object *mutex_obj; + + /* Get the low-level mutex associated with Handle:Pathname */ + + status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Acquire the OS mutex */ + + status = acpi_os_acquire_mutex(mutex_obj->mutex.os_mutex, timeout); + return (status); +} + +/******************************************************************************* + * + * FUNCTION: acpi_release_mutex + * + * PARAMETERS: Handle - Mutex or prefix handle (optional) + * Pathname - Mutex pathname (optional) + * + * RETURN: Status + * + * DESCRIPTION: Release an AML mutex. This is a device driver interface to + * AML mutex objects, and allows for transaction locking between + * drivers and AML code. The mutex node is pointed to by + * Handle:Pathname. Either Handle or Pathname can be NULL, but + * not both. + * + ******************************************************************************/ + +acpi_status acpi_release_mutex(acpi_handle handle, acpi_string pathname) +{ + acpi_status status; + union acpi_operand_object *mutex_obj; + + /* Get the low-level mutex associated with Handle:Pathname */ + + status = acpi_ut_get_mutex_object(handle, pathname, &mutex_obj); + if (ACPI_FAILURE(status)) { + return (status); + } + + /* Release the OS mutex */ + + acpi_os_release_mutex(mutex_obj->mutex.os_mutex); + return (AE_OK); +} diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 61540360d5c..e45350cb6ac 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -34,13 +34,13 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/acpi_io.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/kref.h> #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/debugfs.h> -#include <acpi/atomicio.h> #include "apei-internal.h" @@ -70,7 +70,7 @@ int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val) { int rc; - rc = acpi_atomic_read(val, &entry->register_region); + rc = apei_read(val, &entry->register_region); if (rc) return rc; *val >>= entry->register_region.bit_offset; @@ -116,13 +116,13 @@ int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val) val <<= entry->register_region.bit_offset; if (entry->flags & APEI_EXEC_PRESERVE_REGISTER) { u64 valr = 0; - rc = acpi_atomic_read(&valr, &entry->register_region); + rc = apei_read(&valr, &entry->register_region); if (rc) return rc; valr &= ~(entry->mask << entry->register_region.bit_offset); val |= valr; } - rc = acpi_atomic_write(val, &entry->register_region); + rc = apei_write(val, &entry->register_region); return rc; } @@ -243,7 +243,7 @@ static int pre_map_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - return acpi_pre_map_gar(&entry->register_region); + return acpi_os_map_generic_address(&entry->register_region); return 0; } @@ -276,7 +276,7 @@ static int post_unmap_gar_callback(struct apei_exec_context *ctx, u8 ins = entry->instruction; if (ctx->ins_table[ins].flags & APEI_EXEC_INS_ACCESS_REGISTER) - acpi_post_unmap_gar(&entry->register_region); + acpi_os_unmap_generic_address(&entry->register_region); return 0; } @@ -421,6 +421,17 @@ static int apei_resources_merge(struct apei_resources *resources1, return 0; } +int apei_resources_add(struct apei_resources *resources, + unsigned long start, unsigned long size, + bool iomem) +{ + if (iomem) + return apei_res_add(&resources->iomem, start, size); + else + return apei_res_add(&resources->ioport, start, size); +} +EXPORT_SYMBOL_GPL(apei_resources_add); + /* * EINJ has two groups of GARs (EINJ table entry and trigger table * entry), so common resources are subtracted from the trigger table @@ -438,8 +449,19 @@ int apei_resources_sub(struct apei_resources *resources1, } EXPORT_SYMBOL_GPL(apei_resources_sub); +static int apei_get_nvs_callback(__u64 start, __u64 size, void *data) +{ + struct apei_resources *resources = data; + return apei_res_add(&resources->iomem, start, size); +} + +static int apei_get_nvs_resources(struct apei_resources *resources) +{ + return acpi_nvs_for_each_region(apei_get_nvs_callback, resources); +} + /* - * IO memory/port rersource management mechanism is used to check + * IO memory/port resource management mechanism is used to check * whether memory/port area used by GARs conflicts with normal memory * or IO memory/port of devices. */ @@ -448,21 +470,35 @@ int apei_resources_request(struct apei_resources *resources, { struct apei_res *res, *res_bak = NULL; struct resource *r; + struct apei_resources nvs_resources; int rc; rc = apei_resources_sub(resources, &apei_resources_all); if (rc) return rc; + /* + * Some firmware uses ACPI NVS region, that has been marked as + * busy, so exclude it from APEI resources to avoid false + * conflict. + */ + apei_resources_init(&nvs_resources); + rc = apei_get_nvs_resources(&nvs_resources); + if (rc) + goto res_fini; + rc = apei_resources_sub(resources, &nvs_resources); + if (rc) + goto res_fini; + rc = -EINVAL; list_for_each_entry(res, &resources->iomem, list) { r = request_mem_region(res->start, res->end - res->start, desc); if (!r) { pr_err(APEI_PFX - "Can not request iomem region <%016llx-%016llx> for GARs.\n", + "Can not request [mem %#010llx-%#010llx] for %s registers\n", (unsigned long long)res->start, - (unsigned long long)res->end); + (unsigned long long)res->end - 1, desc); res_bak = res; goto err_unmap_iomem; } @@ -472,9 +508,9 @@ int apei_resources_request(struct apei_resources *resources, r = request_region(res->start, res->end - res->start, desc); if (!r) { pr_err(APEI_PFX - "Can not request ioport region <%016llx-%016llx> for GARs.\n", + "Can not request [io %#06llx-%#06llx] for %s registers\n", (unsigned long long)res->start, - (unsigned long long)res->end); + (unsigned long long)res->end - 1, desc); res_bak = res; goto err_unmap_ioport; } @@ -500,6 +536,8 @@ err_unmap_iomem: break; release_mem_region(res->start, res->end - res->start); } +res_fini: + apei_resources_fini(&nvs_resources); return rc; } EXPORT_SYMBOL_GPL(apei_resources_request); @@ -553,6 +591,96 @@ static int apei_check_gar(struct acpi_generic_address *reg, u64 *paddr) return 0; } +/* read GAR in interrupt (including NMI) or process context */ +int apei_read(u64 *val, struct acpi_generic_address *reg) +{ + int rc; + u64 address; + u32 tmp, width = reg->bit_width; + acpi_status status; + + rc = apei_check_gar(reg, &address); + if (rc) + return rc; + + if (width == 64) + width = 32; /* Break into two 32-bit transfers */ + + *val = 0; + switch(reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_os_read_memory((acpi_physical_address) + address, &tmp, width); + if (ACPI_FAILURE(status)) + return -EIO; + *val = tmp; + + if (reg->bit_width == 64) { + /* Read the top 32 bits */ + status = acpi_os_read_memory((acpi_physical_address) + (address + 4), &tmp, 32); + if (ACPI_FAILURE(status)) + return -EIO; + *val |= ((u64)tmp << 32); + } + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_os_read_port(address, (u32 *)val, reg->bit_width); + if (ACPI_FAILURE(status)) + return -EIO; + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(apei_read); + +/* write GAR in interrupt (including NMI) or process context */ +int apei_write(u64 val, struct acpi_generic_address *reg) +{ + int rc; + u64 address; + u32 width = reg->bit_width; + acpi_status status; + + rc = apei_check_gar(reg, &address); + if (rc) + return rc; + + if (width == 64) + width = 32; /* Break into two 32-bit transfers */ + + switch (reg->space_id) { + case ACPI_ADR_SPACE_SYSTEM_MEMORY: + status = acpi_os_write_memory((acpi_physical_address) + address, ACPI_LODWORD(val), + width); + if (ACPI_FAILURE(status)) + return -EIO; + + if (reg->bit_width == 64) { + status = acpi_os_write_memory((acpi_physical_address) + (address + 4), + ACPI_HIDWORD(val), 32); + if (ACPI_FAILURE(status)) + return -EIO; + } + break; + case ACPI_ADR_SPACE_SYSTEM_IO: + status = acpi_os_write_port(address, val, reg->bit_width); + if (ACPI_FAILURE(status)) + return -EIO; + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(apei_write); + static int collect_res_callback(struct apei_exec_context *ctx, struct acpi_whea_header *entry, void *data) diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index f57050e7a5e..cca240a3303 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -68,6 +68,9 @@ static inline int apei_exec_run_optional(struct apei_exec_context *ctx, u8 actio /* IP has been set in instruction function */ #define APEI_EXEC_SET_IP 1 +int apei_read(u64 *val, struct acpi_generic_address *reg); +int apei_write(u64 val, struct acpi_generic_address *reg); + int __apei_exec_read_register(struct acpi_whea_header *entry, u64 *val); int __apei_exec_write_register(struct acpi_whea_header *entry, u64 val); int apei_exec_read_register(struct apei_exec_context *ctx, @@ -95,6 +98,9 @@ static inline void apei_resources_init(struct apei_resources *resources) } void apei_resources_fini(struct apei_resources *resources); +int apei_resources_add(struct apei_resources *resources, + unsigned long start, unsigned long size, + bool iomem); int apei_resources_sub(struct apei_resources *resources1, struct apei_resources *resources2); int apei_resources_request(struct apei_resources *resources, diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index 589b96c3870..5b898d4dda9 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -43,6 +43,42 @@ #define FIRMWARE_TIMEOUT (1 * NSEC_PER_MSEC) /* + * ACPI version 5 provides a SET_ERROR_TYPE_WITH_ADDRESS action. + */ +static int acpi5; + +struct set_error_type_with_address { + u32 type; + u32 vendor_extension; + u32 flags; + u32 apicid; + u64 memory_address; + u64 memory_address_range; + u32 pcie_sbdf; +}; +enum { + SETWA_FLAGS_APICID = 1, + SETWA_FLAGS_MEM = 2, + SETWA_FLAGS_PCIE_SBDF = 4, +}; + +/* + * Vendor extensions for platform specific operations + */ +struct vendor_error_type_extension { + u32 length; + u32 pcie_sbdf; + u16 vendor_id; + u16 device_id; + u8 rev_id; + u8 reserved[3]; +}; + +static u32 vendor_flags; +static struct debugfs_blob_wrapper vendor_blob; +static char vendor_dev[64]; + +/* * Some BIOSes allow parameters to the SET_ERROR_TYPE entries in the * EINJ table through an unpublished extension. Use with caution as * most will ignore the parameter and make their own choice of address @@ -103,7 +139,14 @@ static struct apei_exec_ins_type einj_ins_type[] = { */ static DEFINE_MUTEX(einj_mutex); -static struct einj_parameter *einj_param; +static void *einj_param; + +#ifndef readq +static inline __u64 readq(volatile void __iomem *addr) +{ + return ((__u64)readl(addr+4) << 32) + readl(addr); +} +#endif #ifndef writeq static inline void writeq(__u64 val, volatile void __iomem *addr) @@ -158,10 +201,31 @@ static int einj_timedout(u64 *t) return 0; } -static u64 einj_get_parameter_address(void) +static void check_vendor_extension(u64 paddr, + struct set_error_type_with_address *v5param) +{ + int offset = readl(&v5param->vendor_extension); + struct vendor_error_type_extension *v; + u32 sbdf; + + if (!offset) + return; + v = ioremap(paddr + offset, sizeof(*v)); + if (!v) + return; + sbdf = readl(&v->pcie_sbdf); + sprintf(vendor_dev, "%x:%x:%x.%x vendor_id=%x device_id=%x rev_id=%x\n", + sbdf >> 24, (sbdf >> 16) & 0xff, + (sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7, + readw(&v->vendor_id), readw(&v->device_id), + readb(&v->rev_id)); + iounmap(v); +} + +static void *einj_get_parameter_address(void) { int i; - u64 paddr = 0; + u64 paddrv4 = 0, paddrv5 = 0; struct acpi_whea_header *entry; entry = EINJ_TAB_ENTRY(einj_tab); @@ -170,12 +234,40 @@ static u64 einj_get_parameter_address(void) entry->instruction == ACPI_EINJ_WRITE_REGISTER && entry->register_region.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - memcpy(&paddr, &entry->register_region.address, - sizeof(paddr)); + memcpy(&paddrv4, &entry->register_region.address, + sizeof(paddrv4)); + if (entry->action == ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS && + entry->instruction == ACPI_EINJ_WRITE_REGISTER && + entry->register_region.space_id == + ACPI_ADR_SPACE_SYSTEM_MEMORY) + memcpy(&paddrv5, &entry->register_region.address, + sizeof(paddrv5)); entry++; } + if (paddrv5) { + struct set_error_type_with_address *v5param; + + v5param = ioremap(paddrv5, sizeof(*v5param)); + if (v5param) { + acpi5 = 1; + check_vendor_extension(paddrv5, v5param); + return v5param; + } + } + if (paddrv4) { + struct einj_parameter *v4param; + + v4param = ioremap(paddrv4, sizeof(*v4param)); + if (!v4param) + return 0; + if (readq(&v4param->reserved1) || readq(&v4param->reserved2)) { + iounmap(v4param); + return 0; + } + return v4param; + } - return paddr; + return 0; } /* do sanity check to trigger table */ @@ -194,8 +286,29 @@ static int einj_check_trigger_header(struct acpi_einj_trigger *trigger_tab) return 0; } +static struct acpi_generic_address *einj_get_trigger_parameter_region( + struct acpi_einj_trigger *trigger_tab, u64 param1, u64 param2) +{ + int i; + struct acpi_whea_header *entry; + + entry = (struct acpi_whea_header *) + ((char *)trigger_tab + sizeof(struct acpi_einj_trigger)); + for (i = 0; i < trigger_tab->entry_count; i++) { + if (entry->action == ACPI_EINJ_TRIGGER_ERROR && + entry->instruction == ACPI_EINJ_WRITE_REGISTER_VALUE && + entry->register_region.space_id == + ACPI_ADR_SPACE_SYSTEM_MEMORY && + (entry->register_region.address & param2) == (param1 & param2)) + return &entry->register_region; + entry++; + } + + return NULL; +} /* Execute instructions in trigger error action table */ -static int __einj_error_trigger(u64 trigger_paddr) +static int __einj_error_trigger(u64 trigger_paddr, u32 type, + u64 param1, u64 param2) { struct acpi_einj_trigger *trigger_tab = NULL; struct apei_exec_context trigger_ctx; @@ -204,14 +317,16 @@ static int __einj_error_trigger(u64 trigger_paddr) struct resource *r; u32 table_size; int rc = -EIO; + struct acpi_generic_address *trigger_param_region = NULL; r = request_mem_region(trigger_paddr, sizeof(*trigger_tab), "APEI EINJ Trigger Table"); if (!r) { pr_err(EINJ_PFX - "Can not request iomem region <%016llx-%016llx> for Trigger table.\n", + "Can not request [mem %#010llx-%#010llx] for Trigger table\n", (unsigned long long)trigger_paddr, - (unsigned long long)trigger_paddr+sizeof(*trigger_tab)); + (unsigned long long)trigger_paddr + + sizeof(*trigger_tab) - 1); goto out; } trigger_tab = ioremap_cache(trigger_paddr, sizeof(*trigger_tab)); @@ -232,9 +347,9 @@ static int __einj_error_trigger(u64 trigger_paddr) "APEI EINJ Trigger Table"); if (!r) { pr_err(EINJ_PFX -"Can not request iomem region <%016llx-%016llx> for Trigger Table Entry.\n", - (unsigned long long)trigger_paddr+sizeof(*trigger_tab), - (unsigned long long)trigger_paddr + table_size); +"Can not request [mem %#010llx-%#010llx] for Trigger Table Entry\n", + (unsigned long long)trigger_paddr + sizeof(*trigger_tab), + (unsigned long long)trigger_paddr + table_size - 1); goto out_rel_header; } iounmap(trigger_tab); @@ -255,6 +370,30 @@ static int __einj_error_trigger(u64 trigger_paddr) rc = apei_resources_sub(&trigger_resources, &einj_resources); if (rc) goto out_fini; + /* + * Some firmware will access target address specified in + * param1 to trigger the error when injecting memory error. + * This will cause resource conflict with regular memory. So + * remove it from trigger table resources. + */ + if (param_extension && (type & 0x0038) && param2) { + struct apei_resources addr_resources; + apei_resources_init(&addr_resources); + trigger_param_region = einj_get_trigger_parameter_region( + trigger_tab, param1, param2); + if (trigger_param_region) { + rc = apei_resources_add(&addr_resources, + trigger_param_region->address, + trigger_param_region->bit_width/8, true); + if (rc) + goto out_fini; + rc = apei_resources_sub(&trigger_resources, + &addr_resources); + } + apei_resources_fini(&addr_resources); + if (rc) + goto out_fini; + } rc = apei_resources_request(&trigger_resources, "APEI EINJ Trigger"); if (rc) goto out_fini; @@ -293,12 +432,56 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) if (rc) return rc; apei_exec_ctx_set_input(&ctx, type); - rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); - if (rc) - return rc; - if (einj_param) { - writeq(param1, &einj_param->param1); - writeq(param2, &einj_param->param2); + if (acpi5) { + struct set_error_type_with_address *v5param = einj_param; + + writel(type, &v5param->type); + if (type & 0x80000000) { + switch (vendor_flags) { + case SETWA_FLAGS_APICID: + writel(param1, &v5param->apicid); + break; + case SETWA_FLAGS_MEM: + writeq(param1, &v5param->memory_address); + writeq(param2, &v5param->memory_address_range); + break; + case SETWA_FLAGS_PCIE_SBDF: + writel(param1, &v5param->pcie_sbdf); + break; + } + writel(vendor_flags, &v5param->flags); + } else { + switch (type) { + case ACPI_EINJ_PROCESSOR_CORRECTABLE: + case ACPI_EINJ_PROCESSOR_UNCORRECTABLE: + case ACPI_EINJ_PROCESSOR_FATAL: + writel(param1, &v5param->apicid); + writel(SETWA_FLAGS_APICID, &v5param->flags); + break; + case ACPI_EINJ_MEMORY_CORRECTABLE: + case ACPI_EINJ_MEMORY_UNCORRECTABLE: + case ACPI_EINJ_MEMORY_FATAL: + writeq(param1, &v5param->memory_address); + writeq(param2, &v5param->memory_address_range); + writel(SETWA_FLAGS_MEM, &v5param->flags); + break; + case ACPI_EINJ_PCIX_CORRECTABLE: + case ACPI_EINJ_PCIX_UNCORRECTABLE: + case ACPI_EINJ_PCIX_FATAL: + writel(param1, &v5param->pcie_sbdf); + writel(SETWA_FLAGS_PCIE_SBDF, &v5param->flags); + break; + } + } + } else { + rc = apei_exec_run(&ctx, ACPI_EINJ_SET_ERROR_TYPE); + if (rc) + return rc; + if (einj_param) { + struct einj_parameter *v4param = einj_param; + writeq(param1, &v4param->param1); + writeq(param2, &v4param->param2); + } } rc = apei_exec_run(&ctx, ACPI_EINJ_EXECUTE_OPERATION); if (rc) @@ -324,7 +507,7 @@ static int __einj_error_inject(u32 type, u64 param1, u64 param2) if (rc) return rc; trigger_paddr = apei_exec_ctx_get_output(&ctx); - rc = __einj_error_trigger(trigger_paddr); + rc = __einj_error_trigger(trigger_paddr, type, param1, param2); if (rc) return rc; rc = apei_exec_run_optional(&ctx, ACPI_EINJ_END_OPERATION); @@ -408,15 +591,25 @@ static int error_type_set(void *data, u64 val) { int rc; u32 available_error_type = 0; + u32 tval, vendor; + + /* + * Vendor defined types have 0x80000000 bit set, and + * are not enumerated by ACPI_EINJ_GET_ERROR_TYPE + */ + vendor = val & 0x80000000; + tval = val & 0x7fffffff; /* Only one error type can be specified */ - if (val & (val - 1)) - return -EINVAL; - rc = einj_get_available_error_type(&available_error_type); - if (rc) - return rc; - if (!(val & available_error_type)) + if (tval & (tval - 1)) return -EINVAL; + if (!vendor) { + rc = einj_get_available_error_type(&available_error_type); + if (rc) + return rc; + if (!(val & available_error_type)) + return -EINVAL; + } error_type = val; return 0; @@ -455,7 +648,6 @@ static int einj_check_table(struct acpi_table_einj *einj_tab) static int __init einj_init(void) { int rc; - u64 param_paddr; acpi_status status; struct dentry *fentry; struct apei_exec_context ctx; @@ -465,10 +657,9 @@ static int __init einj_init(void) status = acpi_get_table(ACPI_SIG_EINJ, 0, (struct acpi_table_header **)&einj_tab); - if (status == AE_NOT_FOUND) { - pr_info(EINJ_PFX "Table is not found!\n"); + if (status == AE_NOT_FOUND) return -ENODEV; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(EINJ_PFX "Failed to get table, %s\n", msg); return -EINVAL; @@ -509,23 +700,30 @@ static int __init einj_init(void) rc = apei_exec_pre_map_gars(&ctx); if (rc) goto err_release; - if (param_extension) { - param_paddr = einj_get_parameter_address(); - if (param_paddr) { - einj_param = ioremap(param_paddr, sizeof(*einj_param)); - rc = -ENOMEM; - if (!einj_param) - goto err_unmap; - fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param1); - if (!fentry) - goto err_unmap; - fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, - einj_debug_dir, &error_param2); - if (!fentry) - goto err_unmap; - } else - pr_warn(EINJ_PFX "Parameter extension is not supported.\n"); + + einj_param = einj_get_parameter_address(); + if ((param_extension || acpi5) && einj_param) { + fentry = debugfs_create_x64("param1", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param1); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x64("param2", S_IRUSR | S_IWUSR, + einj_debug_dir, &error_param2); + if (!fentry) + goto err_unmap; + } + + if (vendor_dev[0]) { + vendor_blob.data = vendor_dev; + vendor_blob.size = strlen(vendor_dev); + fentry = debugfs_create_blob("vendor", S_IRUSR, + einj_debug_dir, &vendor_blob); + if (!fentry) + goto err_unmap; + fentry = debugfs_create_x32("vendor_flags", S_IRUSR | S_IWUSR, + einj_debug_dir, &vendor_flags); + if (!fentry) + goto err_unmap; } pr_info(EINJ_PFX "Error INJection is initialized.\n"); diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 127408069ca..8e8d786c5d2 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -932,7 +932,8 @@ static int erst_check_table(struct acpi_table_erst *erst_tab) static int erst_open_pstore(struct pstore_info *psi); static int erst_close_pstore(struct pstore_info *psi); static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi); + struct timespec *time, char **buf, + struct pstore_info *psi); static int erst_writer(enum pstore_type_id type, u64 *id, unsigned int part, size_t size, struct pstore_info *psi); static int erst_clearer(enum pstore_type_id type, u64 id, @@ -986,17 +987,23 @@ static int erst_close_pstore(struct pstore_info *psi) } static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi) + struct timespec *time, char **buf, + struct pstore_info *psi) { int rc; ssize_t len = 0; u64 record_id; - struct cper_pstore_record *rcd = (struct cper_pstore_record *) - (erst_info.buf - sizeof(*rcd)); + struct cper_pstore_record *rcd; + size_t rcd_len = sizeof(*rcd) + erst_info.bufsize; if (erst_disable) return -ENODEV; + rcd = kmalloc(rcd_len, GFP_KERNEL); + if (!rcd) { + rc = -ENOMEM; + goto out; + } skip: rc = erst_get_record_id_next(&reader_pos, &record_id); if (rc) @@ -1004,22 +1011,27 @@ skip: /* no more record */ if (record_id == APEI_ERST_INVALID_RECORD_ID) { - rc = -1; + rc = -EINVAL; goto out; } - len = erst_read(record_id, &rcd->hdr, sizeof(*rcd) + - erst_info.bufsize); + len = erst_read(record_id, &rcd->hdr, rcd_len); /* The record may be cleared by others, try read next record */ if (len == -ENOENT) goto skip; - else if (len < 0) { - rc = -1; + else if (len < sizeof(*rcd)) { + rc = -EIO; goto out; } if (uuid_le_cmp(rcd->hdr.creator_id, CPER_CREATOR_PSTORE) != 0) goto skip; + *buf = kmalloc(len, GFP_KERNEL); + if (*buf == NULL) { + rc = -ENOMEM; + goto out; + } + memcpy(*buf, rcd->data, len - sizeof(*rcd)); *id = record_id; if (uuid_le_cmp(rcd->sec_hdr.section_type, CPER_SECTION_TYPE_DMESG) == 0) @@ -1037,6 +1049,7 @@ skip: time->tv_nsec = 0; out: + kfree(rcd); return (rc < 0) ? rc : (len - sizeof(*rcd)); } @@ -1112,10 +1125,9 @@ static int __init erst_init(void) status = acpi_get_table(ACPI_SIG_ERST, 0, (struct acpi_table_header **)&erst_tab); - if (status == AE_NOT_FOUND) { - pr_info(ERST_PFX "Table is not found!\n"); + if (status == AE_NOT_FOUND) goto err; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(ERST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index b8e08cb67a1..b3207e16670 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/acpi_io.h> #include <linux/io.h> #include <linux/interrupt.h> #include <linux/timer.h> @@ -45,8 +46,9 @@ #include <linux/irq_work.h> #include <linux/llist.h> #include <linux/genalloc.h> +#include <linux/pci.h> +#include <linux/aer.h> #include <acpi/apei.h> -#include <acpi/atomicio.h> #include <acpi/hed.h> #include <asm/mce.h> #include <asm/tlbflush.h> @@ -299,7 +301,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) if (!ghes) return ERR_PTR(-ENOMEM); ghes->generic = generic; - rc = acpi_pre_map_gar(&generic->error_status_address); + rc = acpi_os_map_generic_address(&generic->error_status_address); if (rc) goto err_free; error_block_length = generic->error_block_length; @@ -319,7 +321,7 @@ static struct ghes *ghes_new(struct acpi_hest_generic *generic) return ghes; err_unmap: - acpi_post_unmap_gar(&generic->error_status_address); + acpi_os_unmap_generic_address(&generic->error_status_address); err_free: kfree(ghes); return ERR_PTR(rc); @@ -328,7 +330,7 @@ err_free: static void ghes_fini(struct ghes *ghes) { kfree(ghes->estatus); - acpi_post_unmap_gar(&ghes->generic->error_status_address); + acpi_os_unmap_generic_address(&ghes->generic->error_status_address); } enum { @@ -399,7 +401,7 @@ static int ghes_read_estatus(struct ghes *ghes, int silent) u32 len; int rc; - rc = acpi_atomic_read(&buf_paddr, &g->error_status_address); + rc = apei_read(&buf_paddr, &g->error_status_address); if (rc) { if (!silent && printk_ratelimit()) pr_warning(FW_WARN GHES_PFX @@ -476,6 +478,27 @@ static void ghes_do_proc(const struct acpi_hest_generic_status *estatus) } #endif } +#ifdef CONFIG_ACPI_APEI_PCIEAER + else if (!uuid_le_cmp(*(uuid_le *)gdata->section_type, + CPER_SEC_PCIE)) { + struct cper_sec_pcie *pcie_err; + pcie_err = (struct cper_sec_pcie *)(gdata+1); + if (sev == GHES_SEV_RECOVERABLE && + sec_sev == GHES_SEV_RECOVERABLE && + pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && + pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { + unsigned int devfn; + int aer_severity; + devfn = PCI_DEVFN(pcie_err->device_id.device, + pcie_err->device_id.function); + aer_severity = cper_severity_to_aer(sev); + aer_recover_queue(pcie_err->device_id.segment, + pcie_err->device_id.bus, + devfn, aer_severity); + } + + } +#endif } } @@ -483,16 +506,22 @@ static void __ghes_print_estatus(const char *pfx, const struct acpi_hest_generic *generic, const struct acpi_hest_generic_status *estatus) { + static atomic_t seqno; + unsigned int curr_seqno; + char pfx_seq[64]; + if (pfx == NULL) { if (ghes_severity(estatus->error_severity) <= GHES_SEV_CORRECTED) - pfx = KERN_WARNING HW_ERR; + pfx = KERN_WARNING; else - pfx = KERN_ERR HW_ERR; + pfx = KERN_ERR; } + curr_seqno = atomic_inc_return(&seqno); + snprintf(pfx_seq, sizeof(pfx_seq), "%s{%u}" HW_ERR, pfx, curr_seqno); printk("%s""Hardware error from APEI Generic Hardware Error Source: %d\n", - pfx, generic->header.source_id); - apei_estatus_print(pfx, estatus); + pfx_seq, generic->header.source_id); + apei_estatus_print(pfx_seq, estatus); } static int ghes_print_estatus(const char *pfx, @@ -711,26 +740,34 @@ static int ghes_notify_sci(struct notifier_block *this, return ret; } +static struct llist_node *llist_nodes_reverse(struct llist_node *llnode) +{ + struct llist_node *next, *tail = NULL; + + while (llnode) { + next = llnode->next; + llnode->next = tail; + tail = llnode; + llnode = next; + } + + return tail; +} + static void ghes_proc_in_irq(struct irq_work *irq_work) { - struct llist_node *llnode, *next, *tail = NULL; + struct llist_node *llnode, *next; struct ghes_estatus_node *estatus_node; struct acpi_hest_generic *generic; struct acpi_hest_generic_status *estatus; u32 len, node_len; + llnode = llist_del_all(&ghes_estatus_llist); /* * Because the time order of estatus in list is reversed, * revert it back to proper order. */ - llnode = llist_del_all(&ghes_estatus_llist); - while (llnode) { - next = llnode->next; - llnode->next = tail; - tail = llnode; - llnode = next; - } - llnode = tail; + llnode = llist_nodes_reverse(llnode); while (llnode) { next = llnode->next; estatus_node = llist_entry(llnode, struct ghes_estatus_node, @@ -750,6 +787,32 @@ static void ghes_proc_in_irq(struct irq_work *irq_work) } } +static void ghes_print_queued_estatus(void) +{ + struct llist_node *llnode; + struct ghes_estatus_node *estatus_node; + struct acpi_hest_generic *generic; + struct acpi_hest_generic_status *estatus; + u32 len, node_len; + + llnode = llist_del_all(&ghes_estatus_llist); + /* + * Because the time order of estatus in list is reversed, + * revert it back to proper order. + */ + llnode = llist_nodes_reverse(llnode); + while (llnode) { + estatus_node = llist_entry(llnode, struct ghes_estatus_node, + llnode); + estatus = GHES_ESTATUS_FROM_NODE(estatus_node); + len = apei_estatus_len(estatus); + node_len = GHES_ESTATUS_NODE_LEN(len); + generic = estatus_node->generic; + ghes_print_estatus(NULL, generic, estatus); + llnode = llnode->next; + } +} + static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) { struct ghes *ghes, *ghes_global = NULL; @@ -775,7 +838,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs) if (sev_global >= GHES_SEV_PANIC) { oops_begin(); - __ghes_print_estatus(KERN_EMERG HW_ERR, ghes_global->generic, + ghes_print_queued_estatus(); + __ghes_print_estatus(KERN_EMERG, ghes_global->generic, ghes_global->estatus); /* reboot to log the error! */ if (panic_timeout == 0) diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 05fee06f4d6..f709269d493 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -221,10 +221,9 @@ void __init acpi_hest_init(void) status = acpi_get_table(ACPI_SIG_HEST, 0, (struct acpi_table_header **)&hest_tab); - if (status == AE_NOT_FOUND) { - pr_info(HEST_PFX "Table not found.\n"); + if (status == AE_NOT_FOUND) goto err; - } else if (ACPI_FAILURE(status)) { + else if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); pr_err(HEST_PFX "Failed to get table, %s\n", msg); rc = -EINVAL; diff --git a/drivers/acpi/atomicio.c b/drivers/acpi/atomicio.c index 04ae1c88c03..d4a5b3d3657 100644 --- a/drivers/acpi/atomicio.c +++ b/drivers/acpi/atomicio.c @@ -32,6 +32,8 @@ #include <linux/rculist.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/mm.h> +#include <linux/highmem.h> #include <acpi/atomicio.h> #define ACPI_PFX "ACPI: " @@ -76,7 +78,7 @@ static void __iomem *__acpi_ioremap_fast(phys_addr_t paddr, { struct acpi_iomap *map; - map = __acpi_find_iomap(paddr, size); + map = __acpi_find_iomap(paddr, size/8); if (map) return map->vaddr + (paddr - map->paddr); else @@ -97,6 +99,37 @@ static void __iomem *__acpi_try_ioremap(phys_addr_t paddr, return NULL; } +#ifndef CONFIG_IA64 +#define should_use_kmap(pfn) page_is_ram(pfn) +#else +/* ioremap will take care of cache attributes */ +#define should_use_kmap(pfn) 0 +#endif + +static void __iomem *acpi_map(phys_addr_t pg_off, unsigned long pg_sz) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (should_use_kmap(pfn)) { + if (pg_sz > PAGE_SIZE) + return NULL; + return (void __iomem __force *)kmap(pfn_to_page(pfn)); + } else + return ioremap(pg_off, pg_sz); +} + +static void acpi_unmap(phys_addr_t pg_off, void __iomem *vaddr) +{ + unsigned long pfn; + + pfn = pg_off >> PAGE_SHIFT; + if (page_is_ram(pfn)) + kunmap(pfn_to_page(pfn)); + else + iounmap(vaddr); +} + /* * Used to pre-map the specified IO memory area. First try to find * whether the area is already pre-mapped, if it is, increase the @@ -119,7 +152,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, pg_off = paddr & PAGE_MASK; pg_sz = ((paddr + size + PAGE_SIZE - 1) & PAGE_MASK) - pg_off; - vaddr = ioremap(pg_off, pg_sz); + vaddr = acpi_map(pg_off, pg_sz); if (!vaddr) return NULL; map = kmalloc(sizeof(*map), GFP_KERNEL); @@ -135,7 +168,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, vaddr = __acpi_try_ioremap(paddr, size); if (vaddr) { spin_unlock_irqrestore(&acpi_iomaps_lock, flags); - iounmap(map->vaddr); + acpi_unmap(pg_off, map->vaddr); kfree(map); return vaddr; } @@ -144,7 +177,7 @@ static void __iomem *acpi_pre_map(phys_addr_t paddr, return map->vaddr + (paddr - map->paddr); err_unmap: - iounmap(vaddr); + acpi_unmap(pg_off, vaddr); return NULL; } @@ -177,7 +210,7 @@ static void acpi_post_unmap(phys_addr_t paddr, unsigned long size) return; synchronize_rcu(); - iounmap(map->vaddr); + acpi_unmap(map->paddr, map->vaddr); kfree(map); } @@ -260,6 +293,21 @@ int acpi_post_unmap_gar(struct acpi_generic_address *reg) } EXPORT_SYMBOL_GPL(acpi_post_unmap_gar); +#ifdef readq +static inline u64 read64(const volatile void __iomem *addr) +{ + return readq(addr); +} +#else +static inline u64 read64(const volatile void __iomem *addr) +{ + u64 l, h; + l = readl(addr); + h = readl(addr+4); + return l | (h << 32); +} +#endif + /* * Can be used in atomic (including NMI) or process context. RCU read * lock can only be released after the IO memory area accessing. @@ -280,11 +328,9 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width) case 32: *val = readl(addr); break; -#ifdef readq case 64: - *val = readq(addr); + *val = read64(addr); break; -#endif default: return -EINVAL; } @@ -293,6 +339,19 @@ static int acpi_atomic_read_mem(u64 paddr, u64 *val, u32 width) return 0; } +#ifdef writeq +static inline void write64(u64 val, volatile void __iomem *addr) +{ + writeq(val, addr); +} +#else +static inline void write64(u64 val, volatile void __iomem *addr) +{ + writel(val, addr); + writel(val>>32, addr+4); +} +#endif + static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width) { void __iomem *addr; @@ -309,11 +368,9 @@ static int acpi_atomic_write_mem(u64 paddr, u64 val, u32 width) case 32: writel(val, addr); break; -#ifdef writeq case 64: - writeq(val, addr); + write64(val, addr); break; -#endif default: return -EINVAL; } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 437ddbf0c49..9ecec98bc76 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -911,10 +911,7 @@ void __init acpi_early_init(void) } #endif - status = - acpi_enable_subsystem(~ - (ACPI_NO_HARDWARE_INIT | - ACPI_NO_ACPI_ENABLE)); + status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to enable ACPI\n"); goto error0; @@ -935,8 +932,7 @@ static int __init acpi_bus_init(void) acpi_os_initialize1(); - status = - acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE); + status = acpi_enable_subsystem(ACPI_NO_ACPI_ENABLE); if (ACPI_FAILURE(status)) { printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n"); diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 3b5c3189fd9..e56f3be7b07 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -45,6 +45,8 @@ static int pxm_to_node_map[MAX_PXM_DOMAINS] static int node_to_pxm_map[MAX_NUMNODES] = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; +unsigned char acpi_srat_revision __initdata; + int pxm_to_node(int pxm) { if (pxm < 0) @@ -255,9 +257,13 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header, static int __init acpi_parse_srat(struct acpi_table_header *table) { + struct acpi_table_srat *srat; if (!table) return -EINVAL; + srat = (struct acpi_table_srat *)table; + acpi_srat_revision = srat->header.revision; + /* Real work done in acpi_table_parse_srat below. */ return 0; diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 096787b43c9..7a2035fa8c7 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -15,6 +15,56 @@ #include <linux/acpi_io.h> #include <acpi/acpiosxf.h> +/* ACPI NVS regions, APEI may use it */ + +struct nvs_region { + __u64 phys_start; + __u64 size; + struct list_head node; +}; + +static LIST_HEAD(nvs_region_list); + +#ifdef CONFIG_ACPI_SLEEP +static int suspend_nvs_register(unsigned long start, unsigned long size); +#else +static inline int suspend_nvs_register(unsigned long a, unsigned long b) +{ + return 0; +} +#endif + +int acpi_nvs_register(__u64 start, __u64 size) +{ + struct nvs_region *region; + + region = kmalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return -ENOMEM; + region->phys_start = start; + region->size = size; + list_add_tail(®ion->node, &nvs_region_list); + + return suspend_nvs_register(start, size); +} + +int acpi_nvs_for_each_region(int (*func)(__u64 start, __u64 size, void *data), + void *data) +{ + int rc; + struct nvs_region *region; + + list_for_each_entry(region, &nvs_region_list, node) { + rc = func(region->phys_start, region->size, data); + if (rc) + return rc; + } + + return 0; +} + + +#ifdef CONFIG_ACPI_SLEEP /* * Platforms, like ACPI, may want us to save some memory used by them during * suspend and to restore the contents of this memory during the subsequent @@ -41,7 +91,7 @@ static LIST_HEAD(nvs_list); * things so that the data from page-aligned addresses in this region will * be copied into separate RAM pages. */ -int suspend_nvs_register(unsigned long start, unsigned long size) +static int suspend_nvs_register(unsigned long start, unsigned long size) { struct nvs_page *entry, *next; @@ -159,3 +209,4 @@ void suspend_nvs_restore(void) if (entry->data) memcpy(entry->kaddr, entry->data, entry->size); } +#endif diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index f31c5c5f1b7..fcc12d842bc 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -83,19 +83,6 @@ static struct workqueue_struct *kacpi_notify_wq; struct workqueue_struct *kacpi_hotplug_wq; EXPORT_SYMBOL(kacpi_hotplug_wq); -struct acpi_res_list { - resource_size_t start; - resource_size_t end; - acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ - char name[5]; /* only can have a length of 4 chars, make use of this - one instead of res->name, no need to kalloc then */ - struct list_head resource_list; - int count; -}; - -static LIST_HEAD(resource_list_head); -static DEFINE_SPINLOCK(acpi_res_lock); - /* * This list of permanent mappings is for memory that may be accessed from * interrupt context, where we can't do the ioremap(). @@ -166,17 +153,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported) return supported; } -static void __init acpi_request_region (struct acpi_generic_address *addr, +static void __init acpi_request_region (struct acpi_generic_address *gas, unsigned int length, char *desc) { - if (!addr->address || !length) + u64 addr; + + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !length) return; /* Resources are never freed */ - if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) - request_region(addr->address, length, desc); - else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - request_mem_region(addr->address, length, desc); + if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) + request_region(addr, length, desc); + else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + request_mem_region(addr, length, desc); } static int __init acpi_reserve_resources(void) @@ -427,35 +418,42 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) __acpi_unmap_table(virt, size); } -static int acpi_os_map_generic_address(struct acpi_generic_address *addr) +int acpi_os_map_generic_address(struct acpi_generic_address *gas) { + u64 addr; void __iomem *virt; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return 0; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return -EINVAL; - virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); + virt = acpi_os_map_memory(addr, gas->bit_width / 8); if (!virt) return -EIO; return 0; } +EXPORT_SYMBOL(acpi_os_map_generic_address); -static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) +void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) { + u64 addr; struct acpi_ioremap *map; - if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) return; - if (!addr->address || !addr->bit_width) + /* Handle possible alignment issues */ + memcpy(&addr, &gas->address, sizeof(addr)); + if (!addr || !gas->bit_width) return; mutex_lock(&acpi_ioremap_lock); - map = acpi_map_lookup(addr->address, addr->bit_width / 8); + map = acpi_map_lookup(addr, gas->bit_width / 8); if (!map) { mutex_unlock(&acpi_ioremap_lock); return; @@ -465,6 +463,7 @@ static void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) acpi_os_map_cleanup(map); } +EXPORT_SYMBOL(acpi_os_unmap_generic_address); #ifdef ACPI_FUTURE_USAGE acpi_status @@ -1278,44 +1277,28 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); * drivers */ int acpi_check_resource_conflict(const struct resource *res) { - struct acpi_res_list *res_list_elem; - int ioport = 0, clash = 0; + acpi_adr_space_type space_id; + acpi_size length; + u8 warn = 0; + int clash = 0; if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) return 0; if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) return 0; - ioport = res->flags & IORESOURCE_IO; - - spin_lock(&acpi_res_lock); - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - if (ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_IO)) - continue; - if (!ioport && (res_list_elem->resource_type - != ACPI_ADR_SPACE_SYSTEM_MEMORY)) - continue; + if (res->flags & IORESOURCE_IO) + space_id = ACPI_ADR_SPACE_SYSTEM_IO; + else + space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; - if (res->end < res_list_elem->start - || res_list_elem->end < res->start) - continue; - clash = 1; - break; - } - spin_unlock(&acpi_res_lock); + length = res->end - res->start + 1; + if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) + warn = 1; + clash = acpi_check_address_range(space_id, res->start, length, warn); if (clash) { if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { - printk(KERN_WARNING "ACPI: resource %s %pR" - " conflicts with ACPI region %s " - "[%s 0x%zx-0x%zx]\n", - res->name, res, res_list_elem->name, - (res_list_elem->resource_type == - ACPI_ADR_SPACE_SYSTEM_IO) ? "io" : "mem", - (size_t) res_list_elem->start, - (size_t) res_list_elem->end); if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) printk(KERN_NOTICE "ACPI: This conflict may" " cause random problems and system" @@ -1467,155 +1450,6 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) kmem_cache_free(cache, object); return (AE_OK); } - -static inline int acpi_res_list_add(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * The Region(addr,len) already exist in the list, - * just increase the count - */ - - res_list_elem->count++; - return 0; - } - } - - res->count = 1; - list_add(&res->resource_list, &resource_list_head); - return 1; -} - -static inline void acpi_res_list_del(struct acpi_res_list *res) -{ - struct acpi_res_list *res_list_elem; - - list_for_each_entry(res_list_elem, &resource_list_head, - resource_list) { - - if (res->resource_type == res_list_elem->resource_type && - res->start == res_list_elem->start && - res->end == res_list_elem->end) { - - /* - * If the res count is decreased to 0, - * remove and free it - */ - - if (--res_list_elem->count == 0) { - list_del(&res_list_elem->resource_list); - kfree(res_list_elem); - } - return; - } - } -} - -acpi_status -acpi_os_invalidate_address( - u8 space_id, - acpi_physical_address address, - acpi_size length) -{ - struct acpi_res_list res; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res.start = address; - res.end = address + length - 1; - res.resource_type = space_id; - spin_lock(&acpi_res_lock); - acpi_res_list_del(&res); - spin_unlock(&acpi_res_lock); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} - -/****************************************************************************** - * - * FUNCTION: acpi_os_validate_address - * - * PARAMETERS: space_id - ACPI space ID - * address - Physical address - * length - Address length - * - * RETURN: AE_OK if address/length is valid for the space_id. Otherwise, - * should return AE_AML_ILLEGAL_ADDRESS. - * - * DESCRIPTION: Validate a system address via the host OS. Used to validate - * the addresses accessed by AML operation regions. - * - *****************************************************************************/ - -acpi_status -acpi_os_validate_address ( - u8 space_id, - acpi_physical_address address, - acpi_size length, - char *name) -{ - struct acpi_res_list *res; - int added; - if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) - return AE_OK; - - switch (space_id) { - case ACPI_ADR_SPACE_SYSTEM_IO: - case ACPI_ADR_SPACE_SYSTEM_MEMORY: - /* Only interference checks against SystemIO and SystemMemory - are needed */ - res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); - if (!res) - return AE_OK; - /* ACPI names are fixed to 4 bytes, still better use strlcpy */ - strlcpy(res->name, name, 5); - res->start = address; - res->end = address + length - 1; - res->resource_type = space_id; - spin_lock(&acpi_res_lock); - added = acpi_res_list_add(res); - spin_unlock(&acpi_res_lock); - pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " - "name: %s\n", added ? "Added" : "Already exist", - (space_id == ACPI_ADR_SPACE_SYSTEM_IO) - ? "SystemIO" : "System Memory", - (unsigned long long)res->start, - (unsigned long long)res->end, - res->name); - if (!added) - kfree(res); - break; - case ACPI_ADR_SPACE_PCI_CONFIG: - case ACPI_ADR_SPACE_EC: - case ACPI_ADR_SPACE_SMBUS: - case ACPI_ADR_SPACE_CMOS: - case ACPI_ADR_SPACE_PCI_BAR_TARGET: - case ACPI_ADR_SPACE_DATA_TABLE: - case ACPI_ADR_SPACE_FIXED_HARDWARE: - break; - } - return AE_OK; -} #endif acpi_status __init acpi_os_initialize(void) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 3a0428e8435..c850de4c9a1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -173,8 +173,30 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) apic_id = map_mat_entry(handle, type, acpi_id); if (apic_id == -1) apic_id = map_madt_entry(type, acpi_id); - if (apic_id == -1) - return apic_id; + if (apic_id == -1) { + /* + * On UP processor, there is no _MAT or MADT table. + * So above apic_id is always set to -1. + * + * BIOS may define multiple CPU handles even for UP processor. + * For example, + * + * Scope (_PR) + * { + * Processor (CPU0, 0x00, 0x00000410, 0x06) {} + * Processor (CPU1, 0x01, 0x00000410, 0x06) {} + * Processor (CPU2, 0x02, 0x00000410, 0x06) {} + * Processor (CPU3, 0x03, 0x00000410, 0x06) {} + * } + * + * Ignores apic_id and always return 0 for CPU0's handle. + * Return -1 for other CPU's handle. + */ + if (acpi_id == 0) + return acpi_id; + else + return apic_id; + } #ifdef CONFIG_SMP for_each_possible_cpu(i) { diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index a4e0f1ba604..b9cbd9b0945 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -82,7 +82,7 @@ MODULE_LICENSE("GPL"); static int acpi_processor_add(struct acpi_device *device); static int acpi_processor_remove(struct acpi_device *device, int type); static void acpi_processor_notify(struct acpi_device *device, u32 event); -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr); static int acpi_processor_handle_eject(struct acpi_processor *pr); @@ -324,10 +324,8 @@ static int acpi_processor_get_info(struct acpi_device *device) * they are physically not present. */ if (pr->id == -1) { - if (ACPI_FAILURE - (acpi_processor_hotadd_init(pr->handle, &pr->id))) { + if (ACPI_FAILURE(acpi_processor_hotadd_init(pr))) return -ENODEV; - } } /* * On some boxes several processors use the same processor bus id. @@ -426,7 +424,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr, 0); - acpi_processor_cst_has_changed(pr); + acpi_processor_hotplug(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } @@ -503,8 +501,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) acpi_processor_get_throttling_info(pr); acpi_processor_get_limit_info(pr); - - if (cpuidle_get_driver() == &acpi_idle_driver) + if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) acpi_processor_power_init(pr, device); pr->cdev = thermal_cooling_device_register("Processor", device, @@ -540,6 +537,7 @@ err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); err_power_exit: acpi_processor_power_exit(pr, device); + sysfs_remove_link(&device->dev.kobj, "sysdev"); err_free_cpumask: free_cpumask_var(pr->throttling.shared_cpu_map); @@ -721,18 +719,19 @@ processor_walk_namespace_cb(acpi_handle handle, return (AE_OK); } -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) { + acpi_handle handle = pr->handle; if (!is_processor_present(handle)) { return AE_ERROR; } - if (acpi_map_lsapic(handle, p_cpu)) + if (acpi_map_lsapic(handle, &pr->id)) return AE_ERROR; - if (arch_register_cpu(*p_cpu)) { - acpi_unmap_lsapic(*p_cpu); + if (arch_register_cpu(pr->id)) { + acpi_unmap_lsapic(pr->id); return AE_ERROR; } @@ -749,7 +748,7 @@ static int acpi_processor_handle_eject(struct acpi_processor *pr) return (0); } #else -static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu) +static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr) { return AE_ERROR; } @@ -800,17 +799,9 @@ static int __init acpi_processor_init(void) memset(&errata, 0, sizeof(errata)); - if (!cpuidle_register_driver(&acpi_idle_driver)) { - printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", - acpi_idle_driver.name); - } else { - printk(KERN_DEBUG "ACPI: acpi_idle yielding to %s\n", - cpuidle_get_driver()->name); - } - result = acpi_bus_register_driver(&acpi_processor_driver); if (result < 0) - goto out_cpuidle; + return result; acpi_processor_install_hotplug_notify(); @@ -821,11 +812,6 @@ static int __init acpi_processor_init(void) acpi_processor_throttling_init(); return 0; - -out_cpuidle: - cpuidle_unregister_driver(&acpi_idle_driver); - - return result; } static void __exit acpi_processor_exit(void) @@ -841,8 +827,6 @@ static void __exit acpi_processor_exit(void) acpi_bus_unregister_driver(&acpi_processor_driver); - cpuidle_unregister_driver(&acpi_idle_driver); - return; } diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 9b88f9828d8..0e8e2de2ed3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -224,7 +224,6 @@ static void lapic_timer_state_broadcast(struct acpi_processor *pr, /* * Suspend / resume control */ -static int acpi_idle_suspend; static u32 saved_bm_rld; static void acpi_idle_bm_rld_save(void) @@ -243,21 +242,13 @@ static void acpi_idle_bm_rld_restore(void) int acpi_processor_suspend(struct acpi_device * device, pm_message_t state) { - if (acpi_idle_suspend == 1) - return 0; - acpi_idle_bm_rld_save(); - acpi_idle_suspend = 1; return 0; } int acpi_processor_resume(struct acpi_device * device) { - if (acpi_idle_suspend == 0) - return 0; - acpi_idle_bm_rld_restore(); - acpi_idle_suspend = 0; return 0; } @@ -741,66 +732,65 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) /** * acpi_idle_enter_c1 - enters an ACPI C1 state-type * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver containing cpuidle state info + * @index: index of target state * * This is equivalent to the HALT instruction. */ static int acpi_idle_enter_c1(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { ktime_t kt1, kt2; s64 idle_time; struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; + return -EINVAL; local_irq_disable(); - /* Do not access any ACPI IO ports in suspend path */ - if (acpi_idle_suspend) { - local_irq_enable(); - cpu_relax(); - return 0; - } - lapic_timer_state_broadcast(pr, cx, 1); kt1 = ktime_get_real(); acpi_idle_do_entry(cx); kt2 = ktime_get_real(); idle_time = ktime_to_us(ktime_sub(kt2, kt1)); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + local_irq_enable(); cx->usage++; lapic_timer_state_broadcast(pr, cx, 0); - return idle_time; + return index; } /** * acpi_idle_enter_simple - enters an ACPI state without BM handling * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver with cpuidle state information + * @index: the index of suggested state */ static int acpi_idle_enter_simple(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; - - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + return -EINVAL; local_irq_disable(); @@ -815,7 +805,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -837,6 +827,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -848,7 +841,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } static int c3_cpu_count; @@ -857,37 +850,37 @@ static DEFINE_RAW_SPINLOCK(c3_lock); /** * acpi_idle_enter_bm - enters C3 with proper BM handling * @dev: the target CPU - * @state: the state data + * @drv: cpuidle driver containing state data + * @index: the index of suggested state * * If BM is detected, the deepest non-C3 idle state is entered instead. */ static int acpi_idle_enter_bm(struct cpuidle_device *dev, - struct cpuidle_state *state) + struct cpuidle_driver *drv, int index) { struct acpi_processor *pr; - struct acpi_processor_cx *cx = cpuidle_get_statedata(state); + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); ktime_t kt1, kt2; s64 idle_time_ns; s64 idle_time; pr = __this_cpu_read(processors); + dev->last_residency = 0; if (unlikely(!pr)) - return 0; - - if (acpi_idle_suspend) - return(acpi_idle_enter_c1(dev, state)); + return -EINVAL; if (!cx->bm_sts_skip && acpi_idle_bm_check()) { - if (dev->safe_state) { - dev->last_state = dev->safe_state; - return dev->safe_state->enter(dev, dev->safe_state); + if (drv->safe_state_index >= 0) { + return drv->states[drv->safe_state_index].enter(dev, + drv, drv->safe_state_index); } else { local_irq_disable(); acpi_safe_halt(); local_irq_enable(); - return 0; + return -EINVAL; } } @@ -904,7 +897,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, if (unlikely(need_resched())) { current_thread_info()->status |= TS_POLLING; local_irq_enable(); - return 0; + return -EINVAL; } } @@ -954,6 +947,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, idle_time = idle_time_ns; do_div(idle_time, NSEC_PER_USEC); + /* Update device last_residency*/ + dev->last_residency = (int)idle_time; + /* Tell the scheduler how much we idled: */ sched_clock_idle_wakeup_event(idle_time_ns); @@ -965,7 +961,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev, lapic_timer_state_broadcast(pr, cx, 0); cx->time += idle_time; - return idle_time; + return index; } struct cpuidle_driver acpi_idle_driver = { @@ -974,14 +970,16 @@ struct cpuidle_driver acpi_idle_driver = { }; /** - * acpi_processor_setup_cpuidle - prepares and configures CPUIDLE + * acpi_processor_setup_cpuidle_cx - prepares and configures CPUIDLE + * device i.e. per-cpu data + * * @pr: the ACPI processor */ -static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) +static int acpi_processor_setup_cpuidle_cx(struct acpi_processor *pr) { int i, count = CPUIDLE_DRIVER_STATE_START; struct acpi_processor_cx *cx; - struct cpuidle_state *state; + struct cpuidle_state_usage *state_usage; struct cpuidle_device *dev = &pr->power.dev; if (!pr->flags.power_setup_done) @@ -992,9 +990,62 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) } dev->cpu = pr->id; + + if (max_cstate == 0) + max_cstate = 1; + + for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { + cx = &pr->power.states[i]; + state_usage = &dev->states_usage[count]; + + if (!cx->valid) + continue; + +#ifdef CONFIG_HOTPLUG_CPU + if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && + !pr->flags.has_cst && + !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) + continue; +#endif + + cpuidle_set_statedata(state_usage, cx); + + count++; + if (count == CPUIDLE_STATE_MAX) + break; + } + + dev->state_count = count; + + if (!count) + return -EINVAL; + + return 0; +} + +/** + * acpi_processor_setup_cpuidle states- prepares and configures cpuidle + * global state data i.e. idle routines + * + * @pr: the ACPI processor + */ +static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) +{ + int i, count = CPUIDLE_DRIVER_STATE_START; + struct acpi_processor_cx *cx; + struct cpuidle_state *state; + struct cpuidle_driver *drv = &acpi_idle_driver; + + if (!pr->flags.power_setup_done) + return -EINVAL; + + if (pr->flags.power == 0) + return -EINVAL; + + drv->safe_state_index = -1; for (i = 0; i < CPUIDLE_STATE_MAX; i++) { - dev->states[i].name[0] = '\0'; - dev->states[i].desc[0] = '\0'; + drv->states[i].name[0] = '\0'; + drv->states[i].desc[0] = '\0'; } if (max_cstate == 0) @@ -1002,7 +1053,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) { cx = &pr->power.states[i]; - state = &dev->states[count]; if (!cx->valid) continue; @@ -1013,8 +1063,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) continue; #endif - cpuidle_set_statedata(state, cx); + state = &drv->states[count]; snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN); state->exit_latency = cx->latency; @@ -1027,13 +1077,13 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_c1; - dev->safe_state = state; + drv->safe_state_index = count; break; case ACPI_STATE_C2: state->flags |= CPUIDLE_FLAG_TIME_VALID; state->enter = acpi_idle_enter_simple; - dev->safe_state = state; + drv->safe_state_index = count; break; case ACPI_STATE_C3: @@ -1049,7 +1099,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) break; } - dev->state_count = count; + drv->state_count = count; if (!count) return -EINVAL; @@ -1057,7 +1107,7 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) return 0; } -int acpi_processor_cst_has_changed(struct acpi_processor *pr) +int acpi_processor_hotplug(struct acpi_processor *pr) { int ret = 0; @@ -1078,7 +1128,7 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); + acpi_processor_setup_cpuidle_cx(pr); ret = cpuidle_enable_device(&pr->power.dev); } cpuidle_resume_and_unlock(); @@ -1086,10 +1136,72 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) return ret; } +int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + int cpu; + struct acpi_processor *_pr; + + if (disabled_by_idle_boot_param()) + return 0; + + if (!pr) + return -EINVAL; + + if (nocst) + return -ENODEV; + + if (!pr->flags.power_setup_done) + return -ENODEV; + + /* + * FIXME: Design the ACPI notification to make it once per + * system instead of once per-cpu. This condition is a hack + * to make the code that updates C-States be called once. + */ + + if (smp_processor_id() == 0 && + cpuidle_get_driver() == &acpi_idle_driver) { + + cpuidle_pause_and_lock(); + /* Protect against cpu-hotplug */ + get_online_cpus(); + + /* Disable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + cpuidle_disable_device(&_pr->power.dev); + } + + /* Populate Updated C-state information */ + acpi_processor_setup_cpuidle_states(pr); + + /* Enable all cpuidle devices */ + for_each_online_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr || !_pr->flags.power_setup_done) + continue; + acpi_processor_get_power_info(_pr); + if (_pr->flags.power) { + acpi_processor_setup_cpuidle_cx(_pr); + cpuidle_enable_device(&_pr->power.dev); + } + } + put_online_cpus(); + cpuidle_resume_and_unlock(); + } + + return 0; +} + +static int acpi_processor_registered; + int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { acpi_status status = 0; + int retval; static int first_run; if (disabled_by_idle_boot_param()) @@ -1126,9 +1238,26 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, * platforms that only support C1. */ if (pr->flags.power) { - acpi_processor_setup_cpuidle(pr); - if (cpuidle_register_device(&pr->power.dev)) - return -EIO; + /* Register acpi_idle_driver if not already registered */ + if (!acpi_processor_registered) { + acpi_processor_setup_cpuidle_states(pr); + retval = cpuidle_register_driver(&acpi_idle_driver); + if (retval) + return retval; + printk(KERN_DEBUG "ACPI: %s registered with cpuidle\n", + acpi_idle_driver.name); + } + /* Register per-cpu cpuidle_device. Cpuidle driver + * must already be registered before registering device + */ + acpi_processor_setup_cpuidle_cx(pr); + retval = cpuidle_register_device(&pr->power.dev); + if (retval) { + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + return retval; + } + acpi_processor_registered++; } return 0; } @@ -1139,8 +1268,13 @@ int acpi_processor_power_exit(struct acpi_processor *pr, if (disabled_by_idle_boot_param()) return 0; - cpuidle_unregister_device(&pr->power.dev); - pr->flags.power_setup_done = 0; + if (pr->flags.power) { + cpuidle_unregister_device(&pr->power.dev); + acpi_processor_registered--; + if (acpi_processor_registered == 0) + cpuidle_unregister_driver(&acpi_idle_driver); + } + pr->flags.power_setup_done = 0; return 0; } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 449c556274c..8ab80bafe3f 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1062,13 +1062,12 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id) if (!id) return; - id->id = kmalloc(strlen(dev_id) + 1, GFP_KERNEL); + id->id = kstrdup(dev_id, GFP_KERNEL); if (!id->id) { kfree(id); return; } - strcpy(id->id, dev_id); list_add_tail(&id->list, &device->pnp.ids); } diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index c538d0ef10f..9f66181c814 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -706,11 +706,23 @@ static void __exit interrupt_stats_exit(void) return; } +static ssize_t +acpi_show_profile(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", acpi_gbl_FADT.preferred_profile); +} + +static const struct device_attribute pm_profile_attr = + __ATTR(pm_profile, S_IRUGO, acpi_show_profile, NULL); + int __init acpi_sysfs_init(void) { int result; result = acpi_tables_sysfs_init(); - + if (result) + return result; + result = sysfs_create_file(acpi_kobj, &pm_profile_attr.attr); return result; } diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 6bdedd7cca2..cf047c406d9 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -820,7 +820,7 @@ config PATA_PLATFORM config PATA_OF_PLATFORM tristate "OpenFirmware platform device PATA support" - depends on PATA_PLATFORM && OF + depends on PATA_PLATFORM && OF && OF_IRQ help This option enables support for generic directly connected ATA devices commonly found on embedded systems with OpenFirmware diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index fb7b90b0592..cf26222a93c 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -390,6 +390,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { /* Promise */ { PCI_VDEVICE(PROMISE, 0x3f20), board_ahci }, /* PDC42819 */ + /* Asmedia */ + { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1061 */ + /* Generic, PCI class code for AHCI */ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 004f2ce3dc7..43b875810d1 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -65,9 +65,9 @@ static struct scsi_host_template ahci_platform_sht = { static int __init ahci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ahci_platform_data *pdata = dev->platform_data; + struct ahci_platform_data *pdata = dev_get_platdata(dev); const struct platform_device_id *id = platform_get_device_id(pdev); - struct ata_port_info pi = ahci_port_info[id->driver_data]; + struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0]; const struct ata_port_info *ppi[] = { &pi, NULL }; struct ahci_host_priv *hpriv; struct ata_host *host; @@ -191,7 +191,7 @@ err0: static int __devexit ahci_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct ahci_platform_data *pdata = dev->platform_data; + struct ahci_platform_data *pdata = dev_get_platdata(dev); struct ata_host *host = dev_get_drvdata(dev); ata_host_detach(host); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index f22957c2769..a9b28203800 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -2883,7 +2883,7 @@ int ata_eh_reset(struct ata_link *link, int classify, sata_scr_read(link, SCR_STATUS, &sstatus)) rc = -ERESTART; - if (rc == -ERESTART || try >= max_tries) { + if (try >= max_tries) { /* * Thaw host port even if reset failed, so that the port * can be retried on the next phy event. This risks @@ -2909,6 +2909,16 @@ int ata_eh_reset(struct ata_link *link, int classify, ata_eh_acquire(ap); } + /* + * While disks spinup behind PMP, some controllers fail sending SRST. + * They need to be reset - as well as the PMP - before retrying. + */ + if (rc == -ERESTART) { + if (ata_is_host_link(link)) + ata_eh_thaw_port(ap); + goto out; + } + if (try == max_tries - 1) { sata_down_spd_limit(link, 0); if (slave) diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 104462dbc52..21b80c555c6 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -389,12 +389,9 @@ static void sata_pmp_quirks(struct ata_port *ap) /* link reports offline after LPM */ link->flags |= ATA_LFLAG_NO_LPM; - /* Class code report is unreliable and SRST - * times out under certain configurations. - */ + /* Class code report is unreliable. */ if (link->pmp < 5) - link->flags |= ATA_LFLAG_NO_SRST | - ATA_LFLAG_ASSUME_ATA; + link->flags |= ATA_LFLAG_ASSUME_ATA; /* port 5 is for SEMB device and it doesn't like SRST */ if (link->pmp == 5) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 72a9770ac42..2a5412e7e9c 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1217,6 +1217,10 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) /** * __ata_change_queue_depth - helper for ata_scsi_change_queue_depth + * @ap: ATA port to which the device change the queue depth + * @sdev: SCSI device to configure queue depth for + * @queue_depth: new queue depth + * @reason: calling context * * libsas and libata have different approaches for associating a sdev to * its ata_port. diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 63d53277d6a..4cadfa28f94 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -2533,10 +2533,12 @@ static int ata_pci_init_one(struct pci_dev *pdev, if (rc) goto out; +#ifdef CONFIG_ATA_BMDMA if (bmdma) /* prepare and activate BMDMA host */ rc = ata_pci_bmdma_prepare_host(pdev, ppi, &host); else +#endif /* prepare and activate SFF host */ rc = ata_pci_sff_prepare_host(pdev, ppi, &host); if (rc) @@ -2544,10 +2546,12 @@ static int ata_pci_init_one(struct pci_dev *pdev, host->private_data = host_priv; host->flags |= hflags; +#ifdef CONFIG_ATA_BMDMA if (bmdma) { pci_set_master(pdev); rc = ata_pci_sff_activate_host(host, ata_bmdma_interrupt, sht); } else +#endif rc = ata_pci_sff_activate_host(host, ata_sff_interrupt, sht); out: if (rc == 0) diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c index a72ab0dde4e..2a472c5bb7d 100644 --- a/drivers/ata/pata_of_platform.c +++ b/drivers/ata/pata_of_platform.c @@ -52,7 +52,7 @@ static int __devinit pata_of_platform_probe(struct platform_device *ofdev) } ret = of_irq_to_resource(dn, 0, &irq_res); - if (ret == NO_IRQ) + if (!ret) irq_res.start = irq_res.end = 0; else irq_res.flags = 0; diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index 447d9c05fb5..95ec435f0eb 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -104,7 +104,7 @@ static const struct ata_port_info sis_port_info = { }; MODULE_AUTHOR("Uwe Koziolek"); -MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller"); +MODULE_DESCRIPTION("low-level driver for Silicon Integrated Systems SATA controller"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/base/core.c b/drivers/base/core.c index 82c865452c7..919daa7cd5b 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -22,6 +22,7 @@ #include <linux/kallsyms.h> #include <linux/mutex.h> #include <linux/async.h> +#include <linux/pm_runtime.h> #include "base.h" #include "power/power.h" @@ -1743,6 +1744,10 @@ void device_shutdown(void) list_del_init(&dev->kobj.entry); spin_unlock(&devices_kset->list_lock); + /* Don't allow any more runtime suspends */ + pm_runtime_get_noresume(dev); + pm_runtime_barrier(dev); + if (dev->bus && dev->bus->shutdown) { dev_dbg(dev, "shutdown\n"); dev->bus->shutdown(dev); diff --git a/drivers/base/node.c b/drivers/base/node.c index 793f796c4da..5693ecee9a4 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -127,12 +127,13 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_WRITEBACK)), nid, K(node_page_state(nid, NR_FILE_PAGES)), nid, K(node_page_state(nid, NR_FILE_MAPPED)), - nid, K(node_page_state(nid, NR_ANON_PAGES) #ifdef CONFIG_TRANSPARENT_HUGEPAGE + nid, K(node_page_state(nid, NR_ANON_PAGES) + node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR + HPAGE_PMD_NR), +#else + nid, K(node_page_state(nid, NR_ANON_PAGES)), #endif - ), nid, K(node_page_state(nid, NR_SHMEM)), nid, node_page_state(nid, NR_KERNEL_STACK) * THREAD_SIZE / 1024, @@ -143,13 +144,14 @@ static ssize_t node_read_meminfo(struct sys_device * dev, nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) + node_page_state(nid, NR_SLAB_UNRECLAIMABLE)), nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)), - nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) #ifdef CONFIG_TRANSPARENT_HUGEPAGE + nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE)) , nid, K(node_page_state(nid, NR_ANON_TRANSPARENT_HUGEPAGES) * - HPAGE_PMD_NR) + HPAGE_PMD_NR)); +#else + nid, K(node_page_state(nid, NR_SLAB_UNRECLAIMABLE))); #endif - ); n += hugetlb_report_node_meminfo(nid, buf + n); return n; } diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index 5f0f85d5c57..428e55e012d 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -229,7 +229,8 @@ int pm_clk_suspend(struct device *dev) list_for_each_entry_reverse(ce, &psd->clock_list, node) { if (ce->status < PCE_STATUS_ERROR) { - clk_disable(ce->clk); + if (ce->status == PCE_STATUS_ENABLED) + clk_disable(ce->clk); ce->status = PCE_STATUS_ACQUIRED; } } diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 7fa098464da..c3d2dfcf438 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -920,7 +920,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) End: if (!error) { dev->power.is_suspended = true; - if (dev->power.wakeup_path && dev->parent) + if (dev->power.wakeup_path + && dev->parent && !dev->parent->power.ignore_children) dev->parent->power.wakeup_path = true; } diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 434a6c01167..95706fa24c7 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -669,7 +669,7 @@ struct srcu_notifier_head *opp_get_notifier(struct device *dev) struct device_opp *dev_opp = find_device_opp(dev); if (IS_ERR(dev_opp)) - return ERR_PTR(PTR_ERR(dev_opp)); /* matching type */ + return ERR_CAST(dev_opp); /* matching type */ return &dev_opp->head; } diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 30a94eadc20..86de6c50fc4 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -212,11 +212,9 @@ int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, if (!dev || !req) /*guard against callers passing in null */ return -EINVAL; - if (dev_pm_qos_request_active(req)) { - WARN(1, KERN_ERR "dev_pm_qos_add_request() called for already " - "added request\n"); + if (WARN(dev_pm_qos_request_active(req), + "%s() called for already added request\n", __func__)) return -EINVAL; - } req->dev = dev; @@ -271,11 +269,9 @@ int dev_pm_qos_update_request(struct dev_pm_qos_request *req, if (!req) /*guard against callers passing in null */ return -EINVAL; - if (!dev_pm_qos_request_active(req)) { - WARN(1, KERN_ERR "dev_pm_qos_update_request() called for " - "unknown object\n"); + if (WARN(!dev_pm_qos_request_active(req), + "%s() called for unknown object\n", __func__)) return -EINVAL; - } mutex_lock(&dev_pm_qos_mtx); @@ -312,11 +308,9 @@ int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) if (!req) /*guard against callers passing in null */ return -EINVAL; - if (!dev_pm_qos_request_active(req)) { - WARN(1, KERN_ERR "dev_pm_qos_remove_request() called for " - "unknown object\n"); + if (WARN(!dev_pm_qos_request_active(req), + "%s() called for unknown object\n", __func__)) return -EINVAL; - } mutex_lock(&dev_pm_qos_mtx); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 486f94ef24d..587cce57ada 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/delay.h> @@ -2600,6 +2601,8 @@ static int fill_cmd(ctlr_info_t *h, CommandList_struct *c, __u8 cmd, void *buff, c->Request.Timeout = 0; c->Request.CDB[0] = BMIC_WRITE; c->Request.CDB[6] = BMIC_CACHE_FLUSH; + c->Request.CDB[7] = (size >> 8) & 0xFF; + c->Request.CDB[8] = size & 0xFF; break; case TEST_UNIT_READY: c->Request.CDBLen = 6; @@ -4319,6 +4322,10 @@ static int __devinit cciss_pci_init(ctlr_info_t *h) dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); return -ENODEV; } + + pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); + err = pci_enable_device(h->pdev); if (err) { dev_warn(&h->pdev->dev, "Unable to Enable PCI device\n"); @@ -4875,7 +4882,7 @@ static int cciss_request_irq(ctlr_info_t *h, { if (h->msix_vector || h->msi_vector) { if (!request_irq(h->intr[h->intr_mode], msixhandler, - IRQF_DISABLED, h->devname, h)) + 0, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get msi irq %d" " for %s\n", h->intr[h->intr_mode], @@ -4884,7 +4891,7 @@ static int cciss_request_irq(ctlr_info_t *h, } if (!request_irq(h->intr[h->intr_mode], intxhandler, - IRQF_DISABLED, h->devname, h)) + IRQF_SHARED, h->devname, h)) return 0; dev_err(&h->pdev->dev, "Unable to get irq %d for %s\n", h->intr[h->intr_mode], h->devname); @@ -5158,6 +5165,7 @@ reinit_after_soft_reset: h->cciss_max_sectors = 8192; rebuild_lun_table(h, 1, 0); + cciss_engage_scsi(h); h->busy_initializing = 0; return 1; diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c index 951a4e33b92..e820b68d2f6 100644 --- a/drivers/block/cciss_scsi.c +++ b/drivers/block/cciss_scsi.c @@ -1720,5 +1720,6 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd) /* If no tape support, then these become defined out of existence */ #define cciss_scsi_setup(cntl_num) +#define cciss_engage_scsi(h) #endif /* CONFIG_CISS_SCSI_TAPE */ diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 3d806820280..1e888c9e85b 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -161,17 +161,19 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { &xor_funcs }; -static loff_t get_loop_size(struct loop_device *lo, struct file *file) +static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) { - loff_t size, offset, loopsize; + loff_t size, loopsize; /* Compute loopsize in bytes */ size = i_size_read(file->f_mapping->host); - offset = lo->lo_offset; loopsize = size - offset; - if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize) - loopsize = lo->lo_sizelimit; + /* offset is beyond i_size, wierd but possible */ + if (loopsize < 0) + return 0; + if (sizelimit > 0 && sizelimit < loopsize) + loopsize = sizelimit; /* * Unfortunately, if we want to do I/O on the device, * the number of 512-byte sectors has to fit into a sector_t. @@ -179,17 +181,25 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file) return loopsize >> 9; } +static loff_t get_loop_size(struct loop_device *lo, struct file *file) +{ + return get_size(lo->lo_offset, lo->lo_sizelimit, file); +} + static int -figure_loop_size(struct loop_device *lo) +figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit) { - loff_t size = get_loop_size(lo, lo->lo_backing_file); + loff_t size = get_size(offset, sizelimit, lo->lo_backing_file); sector_t x = (sector_t)size; if (unlikely((loff_t)x != size)) return -EFBIG; - + if (lo->lo_offset != offset) + lo->lo_offset = offset; + if (lo->lo_sizelimit != sizelimit) + lo->lo_sizelimit = sizelimit; set_capacity(lo->lo_disk, x); - return 0; + return 0; } static inline int @@ -372,7 +382,8 @@ do_lo_receive(struct loop_device *lo, if (retval < 0) return retval; - + if (retval != bvec->bv_len) + return -EIO; return 0; } @@ -411,7 +422,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) /* * We use punch hole to reclaim the free space used by the - * image a.k.a. discard. However we do support discard if + * image a.k.a. discard. However we do not support discard if * encryption is enabled, because it may give an attacker * useful information. */ @@ -786,7 +797,7 @@ static void loop_config_discard(struct loop_device *lo) } q->limits.discard_granularity = inode->i_sb->s_blocksize; - q->limits.discard_alignment = inode->i_sb->s_blocksize; + q->limits.discard_alignment = 0; q->limits.max_discard_sectors = UINT_MAX >> 9; q->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); @@ -1058,9 +1069,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) { - lo->lo_offset = info->lo_offset; - lo->lo_sizelimit = info->lo_sizelimit; - if (figure_loop_size(lo)) + if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) return -EFBIG; } loop_config_discard(lo); @@ -1246,7 +1255,7 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev) err = -ENXIO; if (unlikely(lo->lo_state != Lo_bound)) goto out; - err = figure_loop_size(lo); + err = figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit); if (unlikely(err)) goto out; sec = get_capacity(lo->lo_disk); @@ -1284,13 +1293,19 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, goto out_unlocked; break; case LOOP_SET_STATUS: - err = loop_set_status_old(lo, (struct loop_info __user *) arg); + err = -EPERM; + if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) + err = loop_set_status_old(lo, + (struct loop_info __user *)arg); break; case LOOP_GET_STATUS: err = loop_get_status_old(lo, (struct loop_info __user *) arg); break; case LOOP_SET_STATUS64: - err = loop_set_status64(lo, (struct loop_info64 __user *) arg); + err = -EPERM; + if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) + err = loop_set_status64(lo, + (struct loop_info64 __user *) arg); break; case LOOP_GET_STATUS64: err = loop_get_status64(lo, (struct loop_info64 __user *) arg); diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 6b9a2000d56..a79fb4f7ff6 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -630,6 +630,7 @@ static ssize_t pg_read(struct file *filp, char __user *buf, size_t count, loff_t if (dev->status & 0x10) return -ETIME; + memset(&hdr, 0, sizeof(hdr)); hdr.magic = PG_MAGIC; hdr.dlen = dev->dlen; copy = 0; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 65cc424359b..148ab944378 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -183,10 +183,6 @@ static LIST_HEAD(rbd_client_list); /* clients */ static int __rbd_init_snaps_header(struct rbd_device *rbd_dev); static void rbd_dev_release(struct device *dev); -static ssize_t rbd_snap_rollback(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t size); static ssize_t rbd_snap_add(struct device *dev, struct device_attribute *attr, const char *buf, @@ -461,6 +457,10 @@ static int rbd_header_from_disk(struct rbd_image_header *header, u32 snap_count = le32_to_cpu(ondisk->snap_count); int ret = -ENOMEM; + if (memcmp(ondisk, RBD_HEADER_TEXT, sizeof(RBD_HEADER_TEXT))) { + return -ENXIO; + } + init_rwsem(&header->snap_rwsem); header->snap_names_len = le64_to_cpu(ondisk->snap_names_len); header->snapc = kmalloc(sizeof(struct ceph_snap_context) + @@ -1356,32 +1356,6 @@ fail: } /* - * Request sync osd rollback - */ -static int rbd_req_sync_rollback_obj(struct rbd_device *dev, - u64 snapid, - const char *obj) -{ - struct ceph_osd_req_op *ops; - int ret = rbd_create_rw_ops(&ops, 1, CEPH_OSD_OP_ROLLBACK, 0); - if (ret < 0) - return ret; - - ops[0].snap.snapid = snapid; - - ret = rbd_req_sync_op(dev, NULL, - CEPH_NOSNAP, - 0, - CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, - ops, - 1, obj, 0, 0, NULL, NULL, NULL); - - rbd_destroy_ops(ops); - - return ret; -} - -/* * Request sync osd read */ static int rbd_req_sync_exec(struct rbd_device *dev, @@ -1610,8 +1584,13 @@ static int rbd_read_header(struct rbd_device *rbd_dev, goto out_dh; rc = rbd_header_from_disk(header, dh, snap_count, GFP_KERNEL); - if (rc < 0) + if (rc < 0) { + if (rc == -ENXIO) { + pr_warning("unrecognized header format" + " for image %s", rbd_dev->obj); + } goto out_dh; + } if (snap_count != header->total_snaps) { snap_count = header->total_snaps; @@ -1882,7 +1861,6 @@ static DEVICE_ATTR(name, S_IRUGO, rbd_name_show, NULL); static DEVICE_ATTR(refresh, S_IWUSR, NULL, rbd_image_refresh); static DEVICE_ATTR(current_snap, S_IRUGO, rbd_snap_show, NULL); static DEVICE_ATTR(create_snap, S_IWUSR, NULL, rbd_snap_add); -static DEVICE_ATTR(rollback_snap, S_IWUSR, NULL, rbd_snap_rollback); static struct attribute *rbd_attrs[] = { &dev_attr_size.attr, @@ -1893,7 +1871,6 @@ static struct attribute *rbd_attrs[] = { &dev_attr_current_snap.attr, &dev_attr_refresh.attr, &dev_attr_create_snap.attr, - &dev_attr_rollback_snap.attr, NULL }; @@ -2424,64 +2401,6 @@ err_unlock: return ret; } -static ssize_t rbd_snap_rollback(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct rbd_device *rbd_dev = dev_to_rbd(dev); - int ret; - u64 snapid; - u64 cur_ofs; - char *seg_name = NULL; - char *snap_name = kmalloc(count + 1, GFP_KERNEL); - ret = -ENOMEM; - if (!snap_name) - return ret; - - /* parse snaps add command */ - snprintf(snap_name, count, "%s", buf); - seg_name = kmalloc(RBD_MAX_SEG_NAME_LEN + 1, GFP_NOIO); - if (!seg_name) - goto done; - - mutex_lock_nested(&ctl_mutex, SINGLE_DEPTH_NESTING); - - ret = snap_by_name(&rbd_dev->header, snap_name, &snapid, NULL); - if (ret < 0) - goto done_unlock; - - dout("snapid=%lld\n", snapid); - - cur_ofs = 0; - while (cur_ofs < rbd_dev->header.image_size) { - cur_ofs += rbd_get_segment(&rbd_dev->header, - rbd_dev->obj, - cur_ofs, (u64)-1, - seg_name, NULL); - dout("seg_name=%s\n", seg_name); - - ret = rbd_req_sync_rollback_obj(rbd_dev, snapid, seg_name); - if (ret < 0) - pr_warning("could not roll back obj %s err=%d\n", - seg_name, ret); - } - - ret = __rbd_update_snaps(rbd_dev); - if (ret < 0) - goto done_unlock; - - ret = count; - -done_unlock: - mutex_unlock(&ctl_mutex); -done: - kfree(seg_name); - kfree(snap_name); - - return ret; -} - static struct bus_attribute rbd_bus_attrs[] = { __ATTR(add, S_IWUSR, NULL, rbd_add), __ATTR(remove, S_IWUSR, NULL, rbd_remove), diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index ae3e167e17a..89ddab127e3 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -16,6 +16,8 @@ * handle GCR disks */ +#undef DEBUG + #include <linux/stddef.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -36,13 +38,11 @@ #include <asm/machdep.h> #include <asm/pmac_feature.h> -static DEFINE_MUTEX(swim3_mutex); -static struct request_queue *swim3_queue; -static struct gendisk *disks[2]; -static struct request *fd_req; - #define MAX_FLOPPIES 2 +static DEFINE_MUTEX(swim3_mutex); +static struct gendisk *disks[MAX_FLOPPIES]; + enum swim_state { idle, locating, @@ -177,7 +177,6 @@ struct swim3 { struct floppy_state { enum swim_state state; - spinlock_t lock; struct swim3 __iomem *swim3; /* hardware registers */ struct dbdma_regs __iomem *dma; /* DMA controller registers */ int swim3_intr; /* interrupt number for SWIM3 */ @@ -204,8 +203,20 @@ struct floppy_state { int wanted; struct macio_dev *mdev; char dbdma_cmd_space[5 * sizeof(struct dbdma_cmd)]; + int index; + struct request *cur_req; }; +#define swim3_err(fmt, arg...) dev_err(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) +#define swim3_warn(fmt, arg...) dev_warn(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) +#define swim3_info(fmt, arg...) dev_info(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) + +#ifdef DEBUG +#define swim3_dbg(fmt, arg...) dev_dbg(&fs->mdev->ofdev.dev, "[fd%d] " fmt, fs->index, arg) +#else +#define swim3_dbg(fmt, arg...) do { } while(0) +#endif + static struct floppy_state floppy_states[MAX_FLOPPIES]; static int floppy_count = 0; static DEFINE_SPINLOCK(swim3_lock); @@ -224,17 +235,8 @@ static unsigned short write_postamble[] = { 0, 0, 0, 0, 0, 0 }; -static void swim3_select(struct floppy_state *fs, int sel); -static void swim3_action(struct floppy_state *fs, int action); -static int swim3_readbit(struct floppy_state *fs, int bit); -static void do_fd_request(struct request_queue * q); -static void start_request(struct floppy_state *fs); -static void set_timeout(struct floppy_state *fs, int nticks, - void (*proc)(unsigned long)); -static void scan_track(struct floppy_state *fs); static void seek_track(struct floppy_state *fs, int n); static void init_dma(struct dbdma_cmd *cp, int cmd, void *buf, int count); -static void setup_transfer(struct floppy_state *fs); static void act(struct floppy_state *fs); static void scan_timeout(unsigned long data); static void seek_timeout(unsigned long data); @@ -254,18 +256,21 @@ static unsigned int floppy_check_events(struct gendisk *disk, unsigned int clearing); static int floppy_revalidate(struct gendisk *disk); -static bool swim3_end_request(int err, unsigned int nr_bytes) +static bool swim3_end_request(struct floppy_state *fs, int err, unsigned int nr_bytes) { - if (__blk_end_request(fd_req, err, nr_bytes)) - return true; + struct request *req = fs->cur_req; + int rc; - fd_req = NULL; - return false; -} + swim3_dbg(" end request, err=%d nr_bytes=%d, cur_req=%p\n", + err, nr_bytes, req); -static bool swim3_end_request_cur(int err) -{ - return swim3_end_request(err, blk_rq_cur_bytes(fd_req)); + if (err) + nr_bytes = blk_rq_cur_bytes(req); + rc = __blk_end_request(req, err, nr_bytes); + if (rc) + return true; + fs->cur_req = NULL; + return false; } static void swim3_select(struct floppy_state *fs, int sel) @@ -303,50 +308,53 @@ static int swim3_readbit(struct floppy_state *fs, int bit) return (stat & DATA) == 0; } -static void do_fd_request(struct request_queue * q) -{ - int i; - - for(i=0; i<floppy_count; i++) { - struct floppy_state *fs = &floppy_states[i]; - if (fs->mdev->media_bay && - check_media_bay(fs->mdev->media_bay) != MB_FD) - continue; - start_request(fs); - } -} - static void start_request(struct floppy_state *fs) { struct request *req; unsigned long x; + swim3_dbg("start request, initial state=%d\n", fs->state); + if (fs->state == idle && fs->wanted) { fs->state = available; wake_up(&fs->wait); return; } while (fs->state == idle) { - if (!fd_req) { - fd_req = blk_fetch_request(swim3_queue); - if (!fd_req) + swim3_dbg("start request, idle loop, cur_req=%p\n", fs->cur_req); + if (!fs->cur_req) { + fs->cur_req = blk_fetch_request(disks[fs->index]->queue); + swim3_dbg(" fetched request %p\n", fs->cur_req); + if (!fs->cur_req) break; } - req = fd_req; -#if 0 - printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", - req->rq_disk->disk_name, req->cmd, - (long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer); - printk(" errors=%d current_nr_sectors=%u\n", - req->errors, blk_rq_cur_sectors(req)); + req = fs->cur_req; + + if (fs->mdev->media_bay && + check_media_bay(fs->mdev->media_bay) != MB_FD) { + swim3_dbg("%s", " media bay absent, dropping req\n"); + swim3_end_request(fs, -ENODEV, 0); + continue; + } + +#if 0 /* This is really too verbose */ + swim3_dbg("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n", + req->rq_disk->disk_name, req->cmd, + (long)blk_rq_pos(req), blk_rq_sectors(req), + req->buffer); + swim3_dbg(" errors=%d current_nr_sectors=%u\n", + req->errors, blk_rq_cur_sectors(req)); #endif if (blk_rq_pos(req) >= fs->total_secs) { - swim3_end_request_cur(-EIO); + swim3_dbg(" pos out of bounds (%ld, max is %ld)\n", + (long)blk_rq_pos(req), (long)fs->total_secs); + swim3_end_request(fs, -EIO, 0); continue; } if (fs->ejected) { - swim3_end_request_cur(-EIO); + swim3_dbg("%s", " disk ejected\n"); + swim3_end_request(fs, -EIO, 0); continue; } @@ -354,7 +362,8 @@ static void start_request(struct floppy_state *fs) if (fs->write_prot < 0) fs->write_prot = swim3_readbit(fs, WRITE_PROT); if (fs->write_prot) { - swim3_end_request_cur(-EIO); + swim3_dbg("%s", " try to write, disk write protected\n"); + swim3_end_request(fs, -EIO, 0); continue; } } @@ -369,7 +378,6 @@ static void start_request(struct floppy_state *fs) x = ((long)blk_rq_pos(req)) % fs->secpercyl; fs->head = x / fs->secpertrack; fs->req_sector = x % fs->secpertrack + 1; - fd_req = req; fs->state = do_transfer; fs->retries = 0; @@ -377,12 +385,14 @@ static void start_request(struct floppy_state *fs) } } +static void do_fd_request(struct request_queue * q) +{ + start_request(q->queuedata); +} + static void set_timeout(struct floppy_state *fs, int nticks, void (*proc)(unsigned long)) { - unsigned long flags; - - spin_lock_irqsave(&fs->lock, flags); if (fs->timeout_pending) del_timer(&fs->timeout); fs->timeout.expires = jiffies + nticks; @@ -390,7 +400,6 @@ static void set_timeout(struct floppy_state *fs, int nticks, fs->timeout.data = (unsigned long) fs; add_timer(&fs->timeout); fs->timeout_pending = 1; - spin_unlock_irqrestore(&fs->lock, flags); } static inline void scan_track(struct floppy_state *fs) @@ -442,40 +451,45 @@ static inline void setup_transfer(struct floppy_state *fs) struct swim3 __iomem *sw = fs->swim3; struct dbdma_cmd *cp = fs->dma_cmd; struct dbdma_regs __iomem *dr = fs->dma; + struct request *req = fs->cur_req; - if (blk_rq_cur_sectors(fd_req) <= 0) { - printk(KERN_ERR "swim3: transfer 0 sectors?\n"); + if (blk_rq_cur_sectors(req) <= 0) { + swim3_warn("%s", "Transfer 0 sectors ?\n"); return; } - if (rq_data_dir(fd_req) == WRITE) + if (rq_data_dir(req) == WRITE) n = 1; else { n = fs->secpertrack - fs->req_sector + 1; - if (n > blk_rq_cur_sectors(fd_req)) - n = blk_rq_cur_sectors(fd_req); + if (n > blk_rq_cur_sectors(req)) + n = blk_rq_cur_sectors(req); } + + swim3_dbg(" setup xfer at sect %d (of %d) head %d for %d\n", + fs->req_sector, fs->secpertrack, fs->head, n); + fs->scount = n; swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0); out_8(&sw->sector, fs->req_sector); out_8(&sw->nsect, n); out_8(&sw->gap3, 0); out_le32(&dr->cmdptr, virt_to_bus(cp)); - if (rq_data_dir(fd_req) == WRITE) { + if (rq_data_dir(req) == WRITE) { /* Set up 3 dma commands: write preamble, data, postamble */ init_dma(cp, OUTPUT_MORE, write_preamble, sizeof(write_preamble)); ++cp; - init_dma(cp, OUTPUT_MORE, fd_req->buffer, 512); + init_dma(cp, OUTPUT_MORE, req->buffer, 512); ++cp; init_dma(cp, OUTPUT_LAST, write_postamble, sizeof(write_postamble)); } else { - init_dma(cp, INPUT_LAST, fd_req->buffer, n * 512); + init_dma(cp, INPUT_LAST, req->buffer, n * 512); } ++cp; out_le16(&cp->command, DBDMA_STOP); out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); in_8(&sw->error); out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); - if (rq_data_dir(fd_req) == WRITE) + if (rq_data_dir(req) == WRITE) out_8(&sw->control_bis, WRITE_SECTORS); in_8(&sw->intr); out_le32(&dr->control, (RUN << 16) | RUN); @@ -488,12 +502,16 @@ static inline void setup_transfer(struct floppy_state *fs) static void act(struct floppy_state *fs) { for (;;) { + swim3_dbg(" act loop, state=%d, req_cyl=%d, cur_cyl=%d\n", + fs->state, fs->req_cyl, fs->cur_cyl); + switch (fs->state) { case idle: return; /* XXX shouldn't get here */ case locating: if (swim3_readbit(fs, TRACK_ZERO)) { + swim3_dbg("%s", " locate track 0\n"); fs->cur_cyl = 0; if (fs->req_cyl == 0) fs->state = do_transfer; @@ -511,7 +529,7 @@ static void act(struct floppy_state *fs) break; } if (fs->req_cyl == fs->cur_cyl) { - printk("whoops, seeking 0\n"); + swim3_warn("%s", "Whoops, seeking 0\n"); fs->state = do_transfer; break; } @@ -527,7 +545,9 @@ static void act(struct floppy_state *fs) case do_transfer: if (fs->cur_cyl != fs->req_cyl) { if (fs->retries > 5) { - swim3_end_request_cur(-EIO); + swim3_err("Wrong cylinder in transfer, want: %d got %d\n", + fs->req_cyl, fs->cur_cyl); + swim3_end_request(fs, -EIO, 0); fs->state = idle; return; } @@ -542,7 +562,7 @@ static void act(struct floppy_state *fs) return; default: - printk(KERN_ERR"swim3: unknown state %d\n", fs->state); + swim3_err("Unknown state %d\n", fs->state); return; } } @@ -552,59 +572,75 @@ static void scan_timeout(unsigned long data) { struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; + unsigned long flags; + + swim3_dbg("* scan timeout, state=%d\n", fs->state); + spin_lock_irqsave(&swim3_lock, flags); fs->timeout_pending = 0; out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); fs->cur_cyl = -1; if (fs->retries > 5) { - swim3_end_request_cur(-EIO); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); } else { fs->state = jogging; act(fs); } + spin_unlock_irqrestore(&swim3_lock, flags); } static void seek_timeout(unsigned long data) { struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; + unsigned long flags; + + swim3_dbg("* seek timeout, state=%d\n", fs->state); + spin_lock_irqsave(&swim3_lock, flags); fs->timeout_pending = 0; out_8(&sw->control_bic, DO_SEEK); out_8(&sw->select, RELAX); out_8(&sw->intr_enable, 0); - printk(KERN_ERR "swim3: seek timeout\n"); - swim3_end_request_cur(-EIO); + swim3_err("%s", "Seek timeout\n"); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); + spin_unlock_irqrestore(&swim3_lock, flags); } static void settle_timeout(unsigned long data) { struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; + unsigned long flags; + + swim3_dbg("* settle timeout, state=%d\n", fs->state); + spin_lock_irqsave(&swim3_lock, flags); fs->timeout_pending = 0; if (swim3_readbit(fs, SEEK_COMPLETE)) { out_8(&sw->select, RELAX); fs->state = locating; act(fs); - return; + goto unlock; } out_8(&sw->select, RELAX); if (fs->settle_time < 2*HZ) { ++fs->settle_time; set_timeout(fs, 1, settle_timeout); - return; + goto unlock; } - printk(KERN_ERR "swim3: seek settle timeout\n"); - swim3_end_request_cur(-EIO); + swim3_err("%s", "Seek settle timeout\n"); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); + unlock: + spin_unlock_irqrestore(&swim3_lock, flags); } static void xfer_timeout(unsigned long data) @@ -612,8 +648,12 @@ static void xfer_timeout(unsigned long data) struct floppy_state *fs = (struct floppy_state *) data; struct swim3 __iomem *sw = fs->swim3; struct dbdma_regs __iomem *dr = fs->dma; + unsigned long flags; int n; + swim3_dbg("* xfer timeout, state=%d\n", fs->state); + + spin_lock_irqsave(&swim3_lock, flags); fs->timeout_pending = 0; out_le32(&dr->control, RUN << 16); /* We must wait a bit for dbdma to stop */ @@ -622,12 +662,13 @@ static void xfer_timeout(unsigned long data) out_8(&sw->intr_enable, 0); out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION); out_8(&sw->select, RELAX); - printk(KERN_ERR "swim3: timeout %sing sector %ld\n", - (rq_data_dir(fd_req)==WRITE? "writ": "read"), - (long)blk_rq_pos(fd_req)); - swim3_end_request_cur(-EIO); + swim3_err("Timeout %sing sector %ld\n", + (rq_data_dir(fs->cur_req)==WRITE? "writ": "read"), + (long)blk_rq_pos(fs->cur_req)); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); + spin_unlock_irqrestore(&swim3_lock, flags); } static irqreturn_t swim3_interrupt(int irq, void *dev_id) @@ -638,12 +679,17 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) int stat, resid; struct dbdma_regs __iomem *dr; struct dbdma_cmd *cp; + unsigned long flags; + struct request *req = fs->cur_req; + + swim3_dbg("* interrupt, state=%d\n", fs->state); + spin_lock_irqsave(&swim3_lock, flags); intr = in_8(&sw->intr); err = (intr & ERROR_INTR)? in_8(&sw->error): 0; if ((intr & ERROR_INTR) && fs->state != do_transfer) - printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n", - fs->state, rq_data_dir(fd_req), intr, err); + swim3_err("Non-transfer error interrupt: state=%d, dir=%x, intr=%x, err=%x\n", + fs->state, rq_data_dir(req), intr, err); switch (fs->state) { case locating: if (intr & SEEN_SECTOR) { @@ -653,10 +699,10 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) del_timer(&fs->timeout); fs->timeout_pending = 0; if (sw->ctrack == 0xff) { - printk(KERN_ERR "swim3: seen sector but cyl=ff?\n"); + swim3_err("%s", "Seen sector but cyl=ff?\n"); fs->cur_cyl = -1; if (fs->retries > 5) { - swim3_end_request_cur(-EIO); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); } else { @@ -668,8 +714,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) fs->cur_cyl = sw->ctrack; fs->cur_sector = sw->csect; if (fs->expect_cyl != -1 && fs->expect_cyl != fs->cur_cyl) - printk(KERN_ERR "swim3: expected cyl %d, got %d\n", - fs->expect_cyl, fs->cur_cyl); + swim3_err("Expected cyl %d, got %d\n", + fs->expect_cyl, fs->cur_cyl); fs->state = do_transfer; act(fs); } @@ -704,7 +750,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) fs->timeout_pending = 0; dr = fs->dma; cp = fs->dma_cmd; - if (rq_data_dir(fd_req) == WRITE) + if (rq_data_dir(req) == WRITE) ++cp; /* * Check that the main data transfer has finished. @@ -729,31 +775,32 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) if (intr & ERROR_INTR) { n = fs->scount - 1 - resid / 512; if (n > 0) { - blk_update_request(fd_req, 0, n << 9); + blk_update_request(req, 0, n << 9); fs->req_sector += n; } if (fs->retries < 5) { ++fs->retries; act(fs); } else { - printk("swim3: error %sing block %ld (err=%x)\n", - rq_data_dir(fd_req) == WRITE? "writ": "read", - (long)blk_rq_pos(fd_req), err); - swim3_end_request_cur(-EIO); + swim3_err("Error %sing block %ld (err=%x)\n", + rq_data_dir(req) == WRITE? "writ": "read", + (long)blk_rq_pos(req), err); + swim3_end_request(fs, -EIO, 0); fs->state = idle; } } else { if ((stat & ACTIVE) == 0 || resid != 0) { /* musta been an error */ - printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid); - printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n", - fs->state, rq_data_dir(fd_req), intr, err); - swim3_end_request_cur(-EIO); + swim3_err("fd dma error: stat=%x resid=%d\n", stat, resid); + swim3_err(" state=%d, dir=%x, intr=%x, err=%x\n", + fs->state, rq_data_dir(req), intr, err); + swim3_end_request(fs, -EIO, 0); fs->state = idle; start_request(fs); break; } - if (swim3_end_request(0, fs->scount << 9)) { + fs->retries = 0; + if (swim3_end_request(fs, 0, fs->scount << 9)) { fs->req_sector += fs->scount; if (fs->req_sector > fs->secpertrack) { fs->req_sector -= fs->secpertrack; @@ -770,8 +817,9 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id) start_request(fs); break; default: - printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state); + swim3_err("Don't know what to do in state %d\n", fs->state); } + spin_unlock_irqrestore(&swim3_lock, flags); return IRQ_HANDLED; } @@ -781,26 +829,31 @@ static void fd_dma_interrupt(int irq, void *dev_id) } */ +/* Called under the mutex to grab exclusive access to a drive */ static int grab_drive(struct floppy_state *fs, enum swim_state state, int interruptible) { unsigned long flags; - spin_lock_irqsave(&fs->lock, flags); - if (fs->state != idle) { + swim3_dbg("%s", "-> grab drive\n"); + + spin_lock_irqsave(&swim3_lock, flags); + if (fs->state != idle && fs->state != available) { ++fs->wanted; while (fs->state != available) { + spin_unlock_irqrestore(&swim3_lock, flags); if (interruptible && signal_pending(current)) { --fs->wanted; - spin_unlock_irqrestore(&fs->lock, flags); return -EINTR; } interruptible_sleep_on(&fs->wait); + spin_lock_irqsave(&swim3_lock, flags); } --fs->wanted; } fs->state = state; - spin_unlock_irqrestore(&fs->lock, flags); + spin_unlock_irqrestore(&swim3_lock, flags); + return 0; } @@ -808,10 +861,12 @@ static void release_drive(struct floppy_state *fs) { unsigned long flags; - spin_lock_irqsave(&fs->lock, flags); + swim3_dbg("%s", "-> release drive\n"); + + spin_lock_irqsave(&swim3_lock, flags); fs->state = idle; start_request(fs); - spin_unlock_irqrestore(&fs->lock, flags); + spin_unlock_irqrestore(&swim3_lock, flags); } static int fd_eject(struct floppy_state *fs) @@ -966,6 +1021,7 @@ static int floppy_release(struct gendisk *disk, fmode_t mode) { struct floppy_state *fs = disk->private_data; struct swim3 __iomem *sw = fs->swim3; + mutex_lock(&swim3_mutex); if (fs->ref_count > 0 && --fs->ref_count == 0) { swim3_action(fs, MOTOR_OFF); @@ -1031,30 +1087,48 @@ static const struct block_device_operations floppy_fops = { .revalidate_disk= floppy_revalidate, }; +static void swim3_mb_event(struct macio_dev* mdev, int mb_state) +{ + struct floppy_state *fs = macio_get_drvdata(mdev); + struct swim3 __iomem *sw = fs->swim3; + + if (!fs) + return; + if (mb_state != MB_FD) + return; + + /* Clear state */ + out_8(&sw->intr_enable, 0); + in_8(&sw->intr); + in_8(&sw->error); +} + static int swim3_add_device(struct macio_dev *mdev, int index) { struct device_node *swim = mdev->ofdev.dev.of_node; struct floppy_state *fs = &floppy_states[index]; int rc = -EBUSY; + /* Do this first for message macros */ + memset(fs, 0, sizeof(*fs)); + fs->mdev = mdev; + fs->index = index; + /* Check & Request resources */ if (macio_resource_count(mdev) < 2) { - printk(KERN_WARNING "ifd%d: no address for %s\n", - index, swim->full_name); + swim3_err("%s", "No address in device-tree\n"); return -ENXIO; } - if (macio_irq_count(mdev) < 2) { - printk(KERN_WARNING "fd%d: no intrs for device %s\n", - index, swim->full_name); + if (macio_irq_count(mdev) < 1) { + swim3_err("%s", "No interrupt in device-tree\n"); + return -ENXIO; } if (macio_request_resource(mdev, 0, "swim3 (mmio)")) { - printk(KERN_ERR "fd%d: can't request mmio resource for %s\n", - index, swim->full_name); + swim3_err("%s", "Can't request mmio resource\n"); return -EBUSY; } if (macio_request_resource(mdev, 1, "swim3 (dma)")) { - printk(KERN_ERR "fd%d: can't request dma resource for %s\n", - index, swim->full_name); + swim3_err("%s", "Can't request dma resource\n"); macio_release_resource(mdev, 0); return -EBUSY; } @@ -1063,22 +1137,18 @@ static int swim3_add_device(struct macio_dev *mdev, int index) if (mdev->media_bay == NULL) pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); - memset(fs, 0, sizeof(*fs)); - spin_lock_init(&fs->lock); fs->state = idle; fs->swim3 = (struct swim3 __iomem *) ioremap(macio_resource_start(mdev, 0), 0x200); if (fs->swim3 == NULL) { - printk("fd%d: couldn't map registers for %s\n", - index, swim->full_name); + swim3_err("%s", "Couldn't map mmio registers\n"); rc = -ENOMEM; goto out_release; } fs->dma = (struct dbdma_regs __iomem *) ioremap(macio_resource_start(mdev, 1), 0x200); if (fs->dma == NULL) { - printk("fd%d: couldn't map DMA for %s\n", - index, swim->full_name); + swim3_err("%s", "Couldn't map dma registers\n"); iounmap(fs->swim3); rc = -ENOMEM; goto out_release; @@ -1090,31 +1160,25 @@ static int swim3_add_device(struct macio_dev *mdev, int index) fs->secpercyl = 36; fs->secpertrack = 18; fs->total_secs = 2880; - fs->mdev = mdev; init_waitqueue_head(&fs->wait); fs->dma_cmd = (struct dbdma_cmd *) DBDMA_ALIGN(fs->dbdma_cmd_space); memset(fs->dma_cmd, 0, 2 * sizeof(struct dbdma_cmd)); st_le16(&fs->dma_cmd[1].command, DBDMA_STOP); + if (mdev->media_bay == NULL || check_media_bay(mdev->media_bay) == MB_FD) + swim3_mb_event(mdev, MB_FD); + if (request_irq(fs->swim3_intr, swim3_interrupt, 0, "SWIM3", fs)) { - printk(KERN_ERR "fd%d: couldn't request irq %d for %s\n", - index, fs->swim3_intr, swim->full_name); + swim3_err("%s", "Couldn't request interrupt\n"); pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 0); goto out_unmap; return -EBUSY; } -/* - if (request_irq(fs->dma_intr, fd_dma_interrupt, 0, "SWIM3-dma", fs)) { - printk(KERN_ERR "Couldn't get irq %d for SWIM3 DMA", - fs->dma_intr); - return -EBUSY; - } -*/ init_timer(&fs->timeout); - printk(KERN_INFO "fd%d: SWIM3 floppy controller %s\n", floppy_count, + swim3_info("SWIM3 floppy controller %s\n", mdev->media_bay ? "in media bay" : ""); return 0; @@ -1132,41 +1196,42 @@ static int swim3_add_device(struct macio_dev *mdev, int index) static int __devinit swim3_attach(struct macio_dev *mdev, const struct of_device_id *match) { - int i, rc; struct gendisk *disk; + int index, rc; + + index = floppy_count++; + if (index >= MAX_FLOPPIES) + return -ENXIO; /* Add the drive */ - rc = swim3_add_device(mdev, floppy_count); + rc = swim3_add_device(mdev, index); if (rc) return rc; + /* Now register that disk. Same comment about failure handling */ + disk = disks[index] = alloc_disk(1); + if (disk == NULL) + return -ENOMEM; + disk->queue = blk_init_queue(do_fd_request, &swim3_lock); + if (disk->queue == NULL) { + put_disk(disk); + return -ENOMEM; + } + disk->queue->queuedata = &floppy_states[index]; - /* Now create the queue if not there yet */ - if (swim3_queue == NULL) { + if (index == 0) { /* If we failed, there isn't much we can do as the driver is still * too dumb to remove the device, just bail out */ if (register_blkdev(FLOPPY_MAJOR, "fd")) return 0; - swim3_queue = blk_init_queue(do_fd_request, &swim3_lock); - if (swim3_queue == NULL) { - unregister_blkdev(FLOPPY_MAJOR, "fd"); - return 0; - } } - /* Now register that disk. Same comment about failure handling */ - i = floppy_count++; - disk = disks[i] = alloc_disk(1); - if (disk == NULL) - return 0; - disk->major = FLOPPY_MAJOR; - disk->first_minor = i; + disk->first_minor = index; disk->fops = &floppy_fops; - disk->private_data = &floppy_states[i]; - disk->queue = swim3_queue; + disk->private_data = &floppy_states[index]; disk->flags |= GENHD_FL_REMOVABLE; - sprintf(disk->disk_name, "fd%d", i); + sprintf(disk->disk_name, "fd%d", index); set_capacity(disk, 2880); add_disk(disk); @@ -1194,6 +1259,9 @@ static struct macio_driver swim3_driver = .of_match_table = swim3_match, }, .probe = swim3_attach, +#ifdef CONFIG_PMAC_MEDIABAY + .mediabay_event = swim3_mb_event, +#endif #if 0 .suspend = swim3_suspend, .resume = swim3_resume, diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 11b41fd40c2..5ccf142ef0b 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -188,7 +188,7 @@ config BT_MRVL The core driver to support Marvell Bluetooth devices. This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787. + Marvell Bluetooth devices, such as 8688/8787/8797. Say Y here to compile Marvell Bluetooth driver into the kernel or say M to compile it as module. @@ -201,8 +201,8 @@ config BT_MRVL_SDIO The driver for Marvell Bluetooth chipsets with SDIO interface. This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787 chipsets are - supported. + devices with SDIO interface. Currently SD8688/SD8787/SD8797 + chipsets are supported. Say Y here to compile support for Marvell BT-over-SDIO driver into the kernel or say M to compile it as module. diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index db7cb8111fb..106beb194f3 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -105,7 +105,7 @@ static int ath3k_load_firmware(struct usb_device *udev, pipe = usb_sndctrlpipe(udev, 0); - send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); + send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; @@ -176,7 +176,7 @@ static int ath3k_load_fwfile(struct usb_device *udev, count = firmware->size; - send_buf = kmalloc(BULK_SIZE, GFP_ATOMIC); + send_buf = kmalloc(BULK_SIZE, GFP_KERNEL); if (!send_buf) { BT_ERR("Can't allocate memory chunk for firmware"); return -ENOMEM; diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index 8b1b643a519..54952ab800b 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -24,6 +24,7 @@ #include <linux/module.h> +#include <linux/atomic.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> @@ -65,6 +66,7 @@ struct bcm203x_data { unsigned long state; struct work_struct work; + atomic_t shutdown; struct urb *urb; unsigned char *buffer; @@ -97,6 +99,7 @@ static void bcm203x_complete(struct urb *urb) data->state = BCM203X_SELECT_MEMORY; + /* use workqueue to have a small delay */ schedule_work(&data->work); break; @@ -155,7 +158,10 @@ static void bcm203x_work(struct work_struct *work) struct bcm203x_data *data = container_of(work, struct bcm203x_data, work); - if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) + if (atomic_read(&data->shutdown)) + return; + + if (usb_submit_urb(data->urb, GFP_KERNEL) < 0) BT_ERR("Can't submit URB"); } @@ -243,6 +249,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id usb_set_intfdata(intf, data); + /* use workqueue to have a small delay */ schedule_work(&data->work); return 0; @@ -254,6 +261,9 @@ static void bcm203x_disconnect(struct usb_interface *intf) BT_DBG("intf %p", intf); + atomic_inc(&data->shutdown); + cancel_work_sync(&data->work); + usb_kill_urb(data->urb); usb_set_intfdata(intf, NULL); diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 005919ab043..61b591470a9 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -568,22 +568,23 @@ static int bfusb_load_firmware(struct bfusb_data *data, BT_INFO("BlueFRITZ! USB loading firmware"); + buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_KERNEL); + if (!buf) { + BT_ERR("Can't allocate memory chunk for firmware"); + return -ENOMEM; + } + pipe = usb_sndctrlpipe(data->udev, 0); if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) { BT_ERR("Can't change to loading configuration"); + kfree(buf); return -EBUSY; } data->udev->toggle[0] = data->udev->toggle[1] = 0; - buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); - if (!buf) { - BT_ERR("Can't allocate memory chunk for firmware"); - return -ENOMEM; - } - pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep); while (count) { diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 9ef48167e2c..27b74b0d547 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -65,7 +65,7 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_8688 = { .io_port_1 = 0x01, .io_port_2 = 0x02, }; -static const struct btmrvl_sdio_card_reg btmrvl_reg_8787 = { +static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = { .cfg = 0x00, .host_int_mask = 0x02, .host_intstatus = 0x03, @@ -92,7 +92,14 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8688 = { static const struct btmrvl_sdio_device btmrvl_sdio_sd8787 = { .helper = NULL, .firmware = "mrvl/sd8787_uapsta.bin", - .reg = &btmrvl_reg_8787, + .reg = &btmrvl_reg_87xx, + .sd_blksz_fw_dl = 256, +}; + +static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = { + .helper = NULL, + .firmware = "mrvl/sd8797_uapsta.bin", + .reg = &btmrvl_reg_87xx, .sd_blksz_fw_dl = 256, }; @@ -103,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8787 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + /* Marvell SD8797 Bluetooth device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), + .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, { } /* Terminating entry */ }; @@ -1076,3 +1086,4 @@ MODULE_LICENSE("GPL v2"); MODULE_FIRMWARE("sd8688_helper.bin"); MODULE_FIRMWARE("sd8688.bin"); MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin"); +MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin"); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f9b726091ad..eabc437ce50 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -100,6 +100,9 @@ static struct usb_device_id btusb_table[] = { /* Canyon CN-BTU1 with HID interfaces */ { USB_DEVICE(0x0c10, 0x0000) }, + /* Broadcom BCM20702A0 */ + { USB_DEVICE(0x413c, 0x8197) }, + { } /* Terminating entry */ }; @@ -774,9 +777,8 @@ skip_waking: usb_mark_last_busy(data->udev); } - usb_free_urb(urb); - done: + usb_free_urb(urb); return err; } diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 66cd0b8096c..c92424ca1a5 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1186,10 +1186,11 @@ static void gen6_cleanup(void) /* Certain Gen5 chipsets require require idling the GPU before * unmapping anything from the GTT when VT-d is enabled. */ -extern int intel_iommu_gfx_mapped; static inline int needs_idle_maps(void) { +#ifdef CONFIG_INTEL_IOMMU const unsigned short gpu_devid = intel_private.pcidev->device; + extern int intel_iommu_gfx_mapped; /* Query intel_iommu to see if we need the workaround. Presumably that * was loaded first. @@ -1198,7 +1199,7 @@ static inline int needs_idle_maps(void) gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && intel_iommu_gfx_mapped) return 1; - +#endif return 0; } @@ -1236,7 +1237,7 @@ static int i9xx_setup(void) intel_private.gtt_bus_addr = reg_addr + gtt_offset; } - if (needs_idle_maps()); + if (needs_idle_maps()) intel_private.base.do_idle_maps = 1; intel_i9xx_setup_flush(); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index c2917ffad2c..34767a6d7f4 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -139,6 +139,8 @@ #define IPMI_WDOG_SET_TIMER 0x24 #define IPMI_WDOG_GET_TIMER 0x25 +#define IPMI_WDOG_TIMER_NOT_INIT_RESP 0x80 + /* These are here until the real ones get into the watchdog.h interface. */ #ifndef WDIOC_GETTIMEOUT #define WDIOC_GETTIMEOUT _IOW(WATCHDOG_IOCTL_BASE, 20, int) @@ -596,6 +598,7 @@ static int ipmi_heartbeat(void) struct kernel_ipmi_msg msg; int rv; struct ipmi_system_interface_addr addr; + int timeout_retries = 0; if (ipmi_ignore_heartbeat) return 0; @@ -616,6 +619,7 @@ static int ipmi_heartbeat(void) mutex_lock(&heartbeat_lock); +restart: atomic_set(&heartbeat_tofree, 2); /* @@ -653,7 +657,33 @@ static int ipmi_heartbeat(void) /* Wait for the heartbeat to be sent. */ wait_for_completion(&heartbeat_wait); - if (heartbeat_recv_msg.msg.data[0] != 0) { + if (heartbeat_recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) { + timeout_retries++; + if (timeout_retries > 3) { + printk(KERN_ERR PFX ": Unable to restore the IPMI" + " watchdog's settings, giving up.\n"); + rv = -EIO; + goto out_unlock; + } + + /* + * The timer was not initialized, that means the BMC was + * probably reset and lost the watchdog information. Attempt + * to restore the timer's info. Note that we still hold + * the heartbeat lock, to keep a heartbeat from happening + * in this process, so must say no heartbeat to avoid a + * deadlock on this mutex. + */ + rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB); + if (rv) { + printk(KERN_ERR PFX ": Unable to send the command to" + " set the watchdog's settings, giving up.\n"); + goto out_unlock; + } + + /* We might need a new heartbeat, so do it now */ + goto restart; + } else if (heartbeat_recv_msg.msg.data[0] != 0) { /* * Got an error in the heartbeat response. It was already * reported in ipmi_wdog_msg_handler, but we should return @@ -662,6 +692,7 @@ static int ipmi_heartbeat(void) rv = -EINVAL; } +out_unlock: mutex_unlock(&heartbeat_lock); return rv; @@ -922,11 +953,15 @@ static struct miscdevice ipmi_wdog_miscdev = { static void ipmi_wdog_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) { - if (msg->msg.data[0] != 0) { + if (msg->msg.cmd == IPMI_WDOG_RESET_TIMER && + msg->msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) + printk(KERN_INFO PFX "response: The IPMI controller appears" + " to have been reset, will attempt to reinitialize" + " the watchdog timer\n"); + else if (msg->msg.data[0] != 0) printk(KERN_ERR PFX "response: Error %x on cmd %x\n", msg->msg.data[0], msg->msg.cmd); - } ipmi_free_recv_msg(msg); } diff --git a/drivers/char/random.c b/drivers/char/random.c index 63e19ba56bb..6035ab8d5ef 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -941,7 +941,7 @@ void get_random_bytes(void *buf, int nbytes) if (!arch_get_random_long(&v)) break; - memcpy(buf, &v, chunk); + memcpy(p, &v, chunk); p += chunk; nbytes -= chunk; } diff --git a/drivers/cpufreq/db8500-cpufreq.c b/drivers/cpufreq/db8500-cpufreq.c index edaa987621e..f5002015d82 100644 --- a/drivers/cpufreq/db8500-cpufreq.c +++ b/drivers/cpufreq/db8500-cpufreq.c @@ -109,7 +109,7 @@ static unsigned int db8500_cpufreq_getspeed(unsigned int cpu) static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) { - int res; + int i, res; BUILD_BUG_ON(ARRAY_SIZE(idx2opp) + 1 != ARRAY_SIZE(freq_table)); @@ -120,8 +120,8 @@ static int __cpuinit db8500_cpufreq_init(struct cpufreq_policy *policy) freq_table[3].frequency = 1000000; } pr_info("db8500-cpufreq : Available frequencies:\n"); - while (freq_table[i].frequency != CPUFREQ_TABLE_END) - pr_info(" %d Mhz\n", freq_table[i++].frequency/1000); + for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) + pr_info(" %d Mhz\n", freq_table[i].frequency/1000); /* get policy fields based on the table */ res = cpufreq_frequency_table_cpuinfo(policy, freq_table); diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index becd6d99203..06ce2680d00 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -62,8 +62,9 @@ static int __cpuidle_register_device(struct cpuidle_device *dev); int cpuidle_idle_call(void) { struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices); + struct cpuidle_driver *drv = cpuidle_get_driver(); struct cpuidle_state *target_state; - int next_state; + int next_state, entered_state; if (off) return -ENODEV; @@ -84,45 +85,36 @@ int cpuidle_idle_call(void) hrtimer_peek_ahead_timers(); #endif - /* - * Call the device's prepare function before calling the - * governor's select function. ->prepare gives the device's - * cpuidle driver a chance to update any dynamic information - * of its cpuidle states for the current idle period, e.g. - * state availability, latencies, residencies, etc. - */ - if (dev->prepare) - dev->prepare(dev); - /* ask the governor for the next state */ - next_state = cpuidle_curr_governor->select(dev); + next_state = cpuidle_curr_governor->select(drv, dev); if (need_resched()) { local_irq_enable(); return 0; } - target_state = &dev->states[next_state]; - - /* enter the state and update stats */ - dev->last_state = target_state; + target_state = &drv->states[next_state]; trace_power_start(POWER_CSTATE, next_state, dev->cpu); trace_cpu_idle(next_state, dev->cpu); - dev->last_residency = target_state->enter(dev, target_state); + entered_state = target_state->enter(dev, drv, next_state); trace_power_end(dev->cpu); trace_cpu_idle(PWR_EVENT_EXIT, dev->cpu); - if (dev->last_state) - target_state = dev->last_state; - - target_state->time += (unsigned long long)dev->last_residency; - target_state->usage++; + if (entered_state >= 0) { + /* Update cpuidle counters */ + /* This can be moved to within driver enter routine + * but that results in multiple copies of same code. + */ + dev->states_usage[entered_state].time += + (unsigned long long)dev->last_residency; + dev->states_usage[entered_state].usage++; + } /* give the governor an opportunity to reflect on the outcome */ if (cpuidle_curr_governor->reflect) - cpuidle_curr_governor->reflect(dev); + cpuidle_curr_governor->reflect(dev, entered_state); return 0; } @@ -173,11 +165,11 @@ void cpuidle_resume_and_unlock(void) EXPORT_SYMBOL_GPL(cpuidle_resume_and_unlock); #ifdef CONFIG_ARCH_HAS_CPU_RELAX -static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) +static int poll_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { ktime_t t1, t2; s64 diff; - int ret; t1 = ktime_get(); local_irq_enable(); @@ -189,15 +181,14 @@ static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st) if (diff > INT_MAX) diff = INT_MAX; - ret = (int) diff; - return ret; + dev->last_residency = (int) diff; + + return index; } -static void poll_idle_init(struct cpuidle_device *dev) +static void poll_idle_init(struct cpuidle_driver *drv) { - struct cpuidle_state *state = &dev->states[0]; - - cpuidle_set_statedata(state, NULL); + struct cpuidle_state *state = &drv->states[0]; snprintf(state->name, CPUIDLE_NAME_LEN, "POLL"); snprintf(state->desc, CPUIDLE_DESC_LEN, "CPUIDLE CORE POLL IDLE"); @@ -208,7 +199,7 @@ static void poll_idle_init(struct cpuidle_device *dev) state->enter = poll_idle; } #else -static void poll_idle_init(struct cpuidle_device *dev) {} +static void poll_idle_init(struct cpuidle_driver *drv) {} #endif /* CONFIG_ARCH_HAS_CPU_RELAX */ /** @@ -235,21 +226,20 @@ int cpuidle_enable_device(struct cpuidle_device *dev) return ret; } - poll_idle_init(dev); + poll_idle_init(cpuidle_get_driver()); if ((ret = cpuidle_add_state_sysfs(dev))) return ret; if (cpuidle_curr_governor->enable && - (ret = cpuidle_curr_governor->enable(dev))) + (ret = cpuidle_curr_governor->enable(cpuidle_get_driver(), dev))) goto fail_sysfs; for (i = 0; i < dev->state_count; i++) { - dev->states[i].usage = 0; - dev->states[i].time = 0; + dev->states_usage[i].usage = 0; + dev->states_usage[i].time = 0; } dev->last_residency = 0; - dev->last_state = NULL; smp_wmb(); @@ -283,7 +273,7 @@ void cpuidle_disable_device(struct cpuidle_device *dev) dev->enabled = 0; if (cpuidle_curr_governor->disable) - cpuidle_curr_governor->disable(dev); + cpuidle_curr_governor->disable(cpuidle_get_driver(), dev); cpuidle_remove_state_sysfs(dev); enabled_devices--; @@ -311,26 +301,6 @@ static int __cpuidle_register_device(struct cpuidle_device *dev) init_completion(&dev->kobj_unregister); - /* - * cpuidle driver should set the dev->power_specified bit - * before registering the device if the driver provides - * power_usage numbers. - * - * For those devices whose ->power_specified is not set, - * we fill in power_usage with decreasing values as the - * cpuidle code has an implicit assumption that state Cn - * uses less power than C(n-1). - * - * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned - * an power value of -1. So we use -2, -3, etc, for other - * c-states. - */ - if (!dev->power_specified) { - int i; - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) - dev->states[i].power_usage = -1 - i; - } - per_cpu(cpuidle_devices, dev->cpu) = dev; list_add(&dev->device_list, &cpuidle_detected_devices); if ((ret = cpuidle_add_sysfs(sys_dev))) { diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 3f7e3cedd13..284d7af5a9c 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -17,6 +17,30 @@ static struct cpuidle_driver *cpuidle_curr_driver; DEFINE_SPINLOCK(cpuidle_driver_lock); +static void __cpuidle_register_driver(struct cpuidle_driver *drv) +{ + int i; + /* + * cpuidle driver should set the drv->power_specified bit + * before registering if the driver provides + * power_usage numbers. + * + * If power_specified is not set, + * we fill in power_usage with decreasing values as the + * cpuidle code has an implicit assumption that state Cn + * uses less power than C(n-1). + * + * With CONFIG_ARCH_HAS_CPU_RELAX, C0 is already assigned + * an power value of -1. So we use -2, -3, etc, for other + * c-states. + */ + if (!drv->power_specified) { + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) + drv->states[i].power_usage = -1 - i; + } +} + + /** * cpuidle_register_driver - registers a driver * @drv: the driver @@ -34,6 +58,7 @@ int cpuidle_register_driver(struct cpuidle_driver *drv) spin_unlock(&cpuidle_driver_lock); return -EBUSY; } + __cpuidle_register_driver(drv); cpuidle_curr_driver = drv; spin_unlock(&cpuidle_driver_lock); diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index 3b8fce20f02..b6a09ea859b 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -60,9 +60,11 @@ static inline void ladder_do_selection(struct ladder_device *ldev, /** * ladder_select_state - selects the next state to enter + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_select_state(struct cpuidle_device *dev) +static int ladder_select_state(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct ladder_device *ldev = &__get_cpu_var(ladder_devices); struct ladder_device_state *last_state; @@ -77,15 +79,17 @@ static int ladder_select_state(struct cpuidle_device *dev) last_state = &ldev->states[last_idx]; - if (dev->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) - last_residency = cpuidle_get_last_residency(dev) - dev->states[last_idx].exit_latency; + if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) { + last_residency = cpuidle_get_last_residency(dev) - \ + drv->states[last_idx].exit_latency; + } else last_residency = last_state->threshold.promotion_time + 1; /* consider promotion */ - if (last_idx < dev->state_count - 1 && + if (last_idx < drv->state_count - 1 && last_residency > last_state->threshold.promotion_time && - dev->states[last_idx + 1].exit_latency <= latency_req) { + drv->states[last_idx + 1].exit_latency <= latency_req) { last_state->stats.promotion_count++; last_state->stats.demotion_count = 0; if (last_state->stats.promotion_count >= last_state->threshold.promotion_count) { @@ -96,11 +100,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /* consider demotion */ if (last_idx > CPUIDLE_DRIVER_STATE_START && - dev->states[last_idx].exit_latency > latency_req) { + drv->states[last_idx].exit_latency > latency_req) { int i; for (i = last_idx - 1; i > CPUIDLE_DRIVER_STATE_START; i--) { - if (dev->states[i].exit_latency <= latency_req) + if (drv->states[i].exit_latency <= latency_req) break; } ladder_do_selection(ldev, last_idx, i); @@ -123,9 +127,11 @@ static int ladder_select_state(struct cpuidle_device *dev) /** * ladder_enable_device - setup for the governor + * @drv: cpuidle driver * @dev: the CPU */ -static int ladder_enable_device(struct cpuidle_device *dev) +static int ladder_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { int i; struct ladder_device *ldev = &per_cpu(ladder_devices, dev->cpu); @@ -134,8 +140,8 @@ static int ladder_enable_device(struct cpuidle_device *dev) ldev->last_state_idx = CPUIDLE_DRIVER_STATE_START; - for (i = 0; i < dev->state_count; i++) { - state = &dev->states[i]; + for (i = 0; i < drv->state_count; i++) { + state = &drv->states[i]; lstate = &ldev->states[i]; lstate->stats.promotion_count = 0; @@ -144,7 +150,7 @@ static int ladder_enable_device(struct cpuidle_device *dev) lstate->threshold.promotion_count = PROMOTION_COUNT; lstate->threshold.demotion_count = DEMOTION_COUNT; - if (i < dev->state_count - 1) + if (i < drv->state_count - 1) lstate->threshold.promotion_time = state->exit_latency; if (i > 0) lstate->threshold.demotion_time = state->exit_latency; @@ -153,11 +159,24 @@ static int ladder_enable_device(struct cpuidle_device *dev) return 0; } +/** + * ladder_reflect - update the correct last_state_idx + * @dev: the CPU + * @index: the index of actual state entered + */ +static void ladder_reflect(struct cpuidle_device *dev, int index) +{ + struct ladder_device *ldev = &__get_cpu_var(ladder_devices); + if (index > 0) + ldev->last_state_idx = index; +} + static struct cpuidle_governor ladder_governor = { .name = "ladder", .rating = 10, .enable = ladder_enable_device, .select = ladder_select_state, + .reflect = ladder_reflect, .owner = THIS_MODULE, }; diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index 00275244ce2..ad0952601ae 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -183,7 +183,7 @@ static inline int performance_multiplier(void) static DEFINE_PER_CPU(struct menu_device, menu_devices); -static void menu_update(struct cpuidle_device *dev); +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev); /* This implements DIV_ROUND_CLOSEST but avoids 64 bit division */ static u64 div_round64(u64 dividend, u32 divisor) @@ -229,9 +229,10 @@ static void detect_repeating_patterns(struct menu_device *data) /** * menu_select - selects the next idle state to enter + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static int menu_select(struct cpuidle_device *dev) +static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); @@ -241,7 +242,7 @@ static int menu_select(struct cpuidle_device *dev) struct timespec t; if (data->needs_update) { - menu_update(dev); + menu_update(drv, dev); data->needs_update = 0; } @@ -286,11 +287,9 @@ static int menu_select(struct cpuidle_device *dev) * Find the idle state with the lowest power while satisfying * our constraints. */ - for (i = CPUIDLE_DRIVER_STATE_START; i < dev->state_count; i++) { - struct cpuidle_state *s = &dev->states[i]; + for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) { + struct cpuidle_state *s = &drv->states[i]; - if (s->flags & CPUIDLE_FLAG_IGNORE) - continue; if (s->target_residency > data->predicted_us) continue; if (s->exit_latency > latency_req) @@ -311,26 +310,30 @@ static int menu_select(struct cpuidle_device *dev) /** * menu_reflect - records that data structures need update * @dev: the CPU + * @index: the index of actual entered state * * NOTE: it's important to be fast here because this operation will add to * the overall exit latency. */ -static void menu_reflect(struct cpuidle_device *dev) +static void menu_reflect(struct cpuidle_device *dev, int index) { struct menu_device *data = &__get_cpu_var(menu_devices); - data->needs_update = 1; + data->last_state_idx = index; + if (index >= 0) + data->needs_update = 1; } /** * menu_update - attempts to guess what happened after entry + * @drv: cpuidle driver containing state data * @dev: the CPU */ -static void menu_update(struct cpuidle_device *dev) +static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = &__get_cpu_var(menu_devices); int last_idx = data->last_state_idx; unsigned int last_idle_us = cpuidle_get_last_residency(dev); - struct cpuidle_state *target = &dev->states[last_idx]; + struct cpuidle_state *target = &drv->states[last_idx]; unsigned int measured_us; u64 new_factor; @@ -384,9 +387,11 @@ static void menu_update(struct cpuidle_device *dev) /** * menu_enable_device - scans a CPU's states and does setup + * @drv: cpuidle driver * @dev: the CPU */ -static int menu_enable_device(struct cpuidle_device *dev) +static int menu_enable_device(struct cpuidle_driver *drv, + struct cpuidle_device *dev) { struct menu_device *data = &per_cpu(menu_devices, dev->cpu); diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c index be7917ec40c..1e756e160dc 100644 --- a/drivers/cpuidle/sysfs.c +++ b/drivers/cpuidle/sysfs.c @@ -216,7 +216,8 @@ static struct kobj_type ktype_cpuidle = { struct cpuidle_state_attr { struct attribute attr; - ssize_t (*show)(struct cpuidle_state *, char *); + ssize_t (*show)(struct cpuidle_state *, \ + struct cpuidle_state_usage *, char *); ssize_t (*store)(struct cpuidle_state *, const char *, size_t); }; @@ -224,19 +225,22 @@ struct cpuidle_state_attr { static struct cpuidle_state_attr attr_##_name = __ATTR(_name, 0444, show, NULL) #define define_show_state_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ return sprintf(buf, "%u\n", state->_name);\ } #define define_show_state_ull_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ - return sprintf(buf, "%llu\n", state->_name);\ + return sprintf(buf, "%llu\n", state_usage->_name);\ } #define define_show_state_str_function(_name) \ -static ssize_t show_state_##_name(struct cpuidle_state *state, char *buf) \ +static ssize_t show_state_##_name(struct cpuidle_state *state, \ + struct cpuidle_state_usage *state_usage, char *buf) \ { \ if (state->_name[0] == '\0')\ return sprintf(buf, "<null>\n");\ @@ -269,16 +273,18 @@ static struct attribute *cpuidle_state_default_attrs[] = { #define kobj_to_state_obj(k) container_of(k, struct cpuidle_state_kobj, kobj) #define kobj_to_state(k) (kobj_to_state_obj(k)->state) +#define kobj_to_state_usage(k) (kobj_to_state_obj(k)->state_usage) #define attr_to_stateattr(a) container_of(a, struct cpuidle_state_attr, attr) static ssize_t cpuidle_state_show(struct kobject * kobj, struct attribute * attr ,char * buf) { int ret = -EIO; struct cpuidle_state *state = kobj_to_state(kobj); + struct cpuidle_state_usage *state_usage = kobj_to_state_usage(kobj); struct cpuidle_state_attr * cattr = attr_to_stateattr(attr); if (cattr->show) - ret = cattr->show(state, buf); + ret = cattr->show(state, state_usage, buf); return ret; } @@ -316,13 +322,15 @@ int cpuidle_add_state_sysfs(struct cpuidle_device *device) { int i, ret = -ENOMEM; struct cpuidle_state_kobj *kobj; + struct cpuidle_driver *drv = cpuidle_get_driver(); /* state statistics */ for (i = 0; i < device->state_count; i++) { kobj = kzalloc(sizeof(struct cpuidle_state_kobj), GFP_KERNEL); if (!kobj) goto error_state; - kobj->state = &device->states[i]; + kobj->state = &drv->states[i]; + kobj->state_usage = &device->states_usage[i]; init_completion(&kobj->kobj_unregister); ret = kobject_init_and_add(&kobj->kobj, &ktype_state_cpuidle, &device->kobj, diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 5c6f56f2144..dcd8babae9e 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -343,11 +343,13 @@ static void mv_process_hash_current(int first_block) else op.config |= CFG_MID_FRAG; - writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); - writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); - writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); - writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); - writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); + if (first_block) { + writel(req_ctx->state[0], cpg->reg + DIGEST_INITIAL_VAL_A); + writel(req_ctx->state[1], cpg->reg + DIGEST_INITIAL_VAL_B); + writel(req_ctx->state[2], cpg->reg + DIGEST_INITIAL_VAL_C); + writel(req_ctx->state[3], cpg->reg + DIGEST_INITIAL_VAL_D); + writel(req_ctx->state[4], cpg->reg + DIGEST_INITIAL_VAL_E); + } } memcpy(cpg->sram + SRAM_CONFIG, &op, sizeof(struct sec_accel_config)); diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig index 643b055ed3c..8f049103708 100644 --- a/drivers/devfreq/Kconfig +++ b/drivers/devfreq/Kconfig @@ -1,36 +1,29 @@ -config ARCH_HAS_DEVFREQ - bool - depends on ARCH_HAS_OPP - help - Denotes that the architecture supports DEVFREQ. If the architecture - supports multiple OPP entries per device and the frequency of the - devices with OPPs may be altered dynamically, the architecture - supports DEVFREQ. - menuconfig PM_DEVFREQ bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support" - depends on PM_OPP && ARCH_HAS_DEVFREQ help - With OPP support, a device may have a list of frequencies and - voltages available. DEVFREQ, a generic DVFS framework can be - registered for a device with OPP support in order to let the - governor provided to DEVFREQ choose an operating frequency - based on the OPP's list and the policy given with DEVFREQ. + A device may have a list of frequencies and voltages available. + devfreq, a generic DVFS framework can be registered for a device + in order to let the governor provided to devfreq choose an + operating frequency based on the device driver's policy. - Each device may have its own governor and policy. DEVFREQ can + Each device may have its own governor and policy. Devfreq can reevaluate the device state periodically and/or based on the - OPP list changes (each frequency/voltage pair in OPP may be - disabled or enabled). + notification to "nb", a notifier block, of devfreq. - Like some CPUs with CPUFREQ, a device may have multiple clocks. + Like some CPUs with CPUfreq, a device may have multiple clocks. However, because the clock frequencies of a single device are - determined by the single device's state, an instance of DEVFREQ + determined by the single device's state, an instance of devfreq is attached to a single device and returns a "representative" - clock frequency from the OPP of the device, which is also attached - to a device by 1-to-1. The device registering DEVFREQ takes the - responsiblity to "interpret" the frequency listed in OPP and + clock frequency of the device, which is also attached + to a device by 1-to-1. The device registering devfreq takes the + responsiblity to "interpret" the representative frequency and to set its every clock accordingly with the "target" callback - given to DEVFREQ. + given to devfreq. + + When OPP is used with the devfreq device, it is recommended to + register devfreq's nb to the OPP's notifier head. If OPP is + used with the devfreq device, you may use OPP helper + functions defined in devfreq.h. if PM_DEVFREQ diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index 5d15b812377..59d24e9cb8c 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -15,7 +15,9 @@ #include <linux/errno.h> #include <linux/err.h> #include <linux/init.h> +#include <linux/module.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/opp.h> #include <linux/devfreq.h> #include <linux/workqueue.h> @@ -416,10 +418,14 @@ out: */ int devfreq_remove_device(struct devfreq *devfreq) { + bool central_polling; + if (!devfreq) return -EINVAL; - if (!devfreq->governor->no_central_polling) { + central_polling = !devfreq->governor->no_central_polling; + + if (central_polling) { mutex_lock(&devfreq_list_lock); while (wait_remove_device == devfreq) { mutex_unlock(&devfreq_list_lock); @@ -431,7 +437,7 @@ int devfreq_remove_device(struct devfreq *devfreq) mutex_lock(&devfreq->lock); _remove_devfreq(devfreq, false); /* it unlocks devfreq->lock */ - if (!devfreq->governor->no_central_polling) + if (central_polling) mutex_unlock(&devfreq_list_lock); return 0; diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index ab8f469f5cf..5a99bb3f255 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -124,7 +124,7 @@ config MV_XOR config MX3_IPU bool "MX3x Image Processing Unit support" - depends on ARCH_MX3 + depends on SOC_IMX31 ||Â SOC_IMX35 select DMA_ENGINE default y help @@ -216,7 +216,7 @@ config PCH_DMA config IMX_SDMA tristate "i.MX SDMA support" - depends on ARCH_MX25 || ARCH_MX3 || ARCH_MX5 + depends on ARCH_MX25 || SOC_IMX31 ||Â SOC_IMX35 || ARCH_MX5 select DMA_ENGINE help Support the i.MX SDMA engine. This engine is integrated into diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 8af8e864a9c..73464a62adf 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -1128,7 +1128,7 @@ static struct of_device_id mpc85xx_mc_err_of_match[] = { { .compatible = "fsl,p1020-memory-controller", }, { .compatible = "fsl,p1021-memory-controller", }, { .compatible = "fsl,p2020-memory-controller", }, - { .compatible = "fsl,p4080-memory-controller", }, + { .compatible = "fsl,qoriq-memory-controller", }, {}, }; MODULE_DEVICE_TABLE(of, mpc85xx_mc_err_of_match); diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index bcb1126e3d0..153980be4ee 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -585,14 +585,12 @@ int dmi_name_in_serial(const char *str) } /** - * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. + * dmi_name_in_vendors - Check if string is in the DMI system or board vendor name * @str: Case sensitive Name */ int dmi_name_in_vendors(const char *str) { - static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, - DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; + static int fields[] = { DMI_SYS_VENDOR, DMI_BOARD_VENDOR, DMI_NONE }; int i; for (i = 0; fields[i] != DMI_NONE; i++) { int f = fields[i]; diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index 8370f72d87f..b0a81173a26 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c @@ -457,7 +457,8 @@ static int efi_pstore_close(struct pstore_info *psi) } static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, - struct timespec *timespec, struct pstore_info *psi) + struct timespec *timespec, + char **buf, struct pstore_info *psi) { efi_guid_t vendor = LINUX_EFI_CRASH_GUID; struct efivars *efivars = psi->data; @@ -478,7 +479,11 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, timespec->tv_nsec = 0; get_var_data_locked(efivars, &efivars->walk_entry->var); size = efivars->walk_entry->var.DataSize; - memcpy(psi->buf, efivars->walk_entry->var.Data, size); + *buf = kmalloc(size, GFP_KERNEL); + if (*buf == NULL) + return -ENOMEM; + memcpy(*buf, efivars->walk_entry->var.Data, + size); efivars->walk_entry = list_entry(efivars->walk_entry->list.next, struct efivar_entry, list); return size; @@ -576,7 +581,8 @@ static int efi_pstore_close(struct pstore_info *psi) } static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, - struct timespec *time, struct pstore_info *psi) + struct timespec *timespec, + char **buf, struct pstore_info *psi) { return -1; } diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index c811cb10790..2cce44a1d7d 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -746,6 +746,37 @@ static void __exit ibft_exit(void) ibft_cleanup(); } +#ifdef CONFIG_ACPI +static const struct { + char *sign; +} ibft_signs[] = { + /* + * One spec says "IBFT", the other says "iBFT". We have to check + * for both. + */ + { ACPI_SIG_IBFT }, + { "iBFT" }, +}; + +static void __init acpi_find_ibft_region(void) +{ + int i; + struct acpi_table_header *table = NULL; + + if (acpi_disabled) + return; + + for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) { + acpi_get_table(ibft_signs[i].sign, 0, &table); + ibft_addr = (struct acpi_table_ibft *)table; + } +} +#else +static void __init acpi_find_ibft_region(void) +{ +} +#endif + /* * ibft_init() - creates sysfs tree entries for the iBFT data. */ @@ -753,9 +784,16 @@ static int __init ibft_init(void) { int rc = 0; + /* + As on UEFI systems the setup_arch()/find_ibft_region() + is called before ACPI tables are parsed and it only does + legacy finding. + */ + if (!ibft_addr) + acpi_find_ibft_region(); + if (ibft_addr) { - printk(KERN_INFO "iBFT detected at 0x%llx.\n", - (u64)isa_virt_to_bus(ibft_addr)); + pr_info("iBFT detected.\n"); rc = ibft_check_device(); if (rc) diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c index bfe723266fd..4da4eb9ae92 100644 --- a/drivers/firmware/iscsi_ibft_find.c +++ b/drivers/firmware/iscsi_ibft_find.c @@ -45,13 +45,6 @@ EXPORT_SYMBOL_GPL(ibft_addr); static const struct { char *sign; } ibft_signs[] = { -#ifdef CONFIG_ACPI - /* - * One spec says "IBFT", the other says "iBFT". We have to check - * for both. - */ - { ACPI_SIG_IBFT }, -#endif { "iBFT" }, { "BIFT" }, /* Broadcom iSCSI Offload */ }; @@ -62,14 +55,6 @@ static const struct { #define VGA_MEM 0xA0000 /* VGA buffer */ #define VGA_SIZE 0x20000 /* 128kB */ -#ifdef CONFIG_ACPI -static int __init acpi_find_ibft(struct acpi_table_header *header) -{ - ibft_addr = (struct acpi_table_ibft *)header; - return 0; -} -#endif /* CONFIG_ACPI */ - static int __init find_ibft_in_mem(void) { unsigned long pos; @@ -94,6 +79,7 @@ static int __init find_ibft_in_mem(void) * the table cannot be valid. */ if (pos + len <= (IBFT_END-1)) { ibft_addr = (struct acpi_table_ibft *)virt; + pr_info("iBFT found at 0x%lx.\n", pos); goto done; } } @@ -108,20 +94,12 @@ done: */ unsigned long __init find_ibft_region(unsigned long *sizep) { -#ifdef CONFIG_ACPI - int i; -#endif ibft_addr = NULL; -#ifdef CONFIG_ACPI - for (i = 0; i < ARRAY_SIZE(ibft_signs) && !ibft_addr; i++) - acpi_table_parse(ibft_signs[i].sign, acpi_find_ibft); -#endif /* CONFIG_ACPI */ - /* iBFT 1.03 section 1.4.3.1 mandates that UEFI machines will * only use ACPI for this */ - if (!ibft_addr && !efi_enabled) + if (!efi_enabled) find_ibft_in_mem(); if (ibft_addr) { diff --git a/drivers/firmware/sigma.c b/drivers/firmware/sigma.c index f10fc521951..1eedb6f7fda 100644 --- a/drivers/firmware/sigma.c +++ b/drivers/firmware/sigma.c @@ -14,13 +14,34 @@ #include <linux/module.h> #include <linux/sigma.h> -/* Return: 0==OK, <0==error, =1 ==no more actions */ +static size_t sigma_action_size(struct sigma_action *sa) +{ + size_t payload = 0; + + switch (sa->instr) { + case SIGMA_ACTION_WRITEXBYTES: + case SIGMA_ACTION_WRITESINGLE: + case SIGMA_ACTION_WRITESAFELOAD: + payload = sigma_action_len(sa); + break; + default: + break; + } + + payload = ALIGN(payload, 2); + + return payload + sizeof(struct sigma_action); +} + +/* + * Returns a negative error value in case of an error, 0 if processing of + * the firmware should be stopped after this action, 1 otherwise. + */ static int -process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) +process_sigma_action(struct i2c_client *client, struct sigma_action *sa) { - struct sigma_action *sa = (void *)(ssfw->fw->data + ssfw->pos); size_t len = sigma_action_len(sa); - int ret = 0; + int ret; pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, sa->instr, sa->addr, len); @@ -29,44 +50,50 @@ process_sigma_action(struct i2c_client *client, struct sigma_firmware *ssfw) case SIGMA_ACTION_WRITEXBYTES: case SIGMA_ACTION_WRITESINGLE: case SIGMA_ACTION_WRITESAFELOAD: - if (ssfw->fw->size < ssfw->pos + len) - return -EINVAL; ret = i2c_master_send(client, (void *)&sa->addr, len); if (ret < 0) return -EINVAL; break; - case SIGMA_ACTION_DELAY: - ret = 0; udelay(len); len = 0; break; - case SIGMA_ACTION_END: - return 1; - + return 0; default: return -EINVAL; } - /* when arrive here ret=0 or sent data */ - ssfw->pos += sigma_action_size(sa, len); - return ssfw->pos == ssfw->fw->size; + return 1; } static int process_sigma_actions(struct i2c_client *client, struct sigma_firmware *ssfw) { - pr_debug("%s: processing %p\n", __func__, ssfw); + struct sigma_action *sa; + size_t size; + int ret; + + while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { + sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); + + size = sigma_action_size(sa); + ssfw->pos += size; + if (ssfw->pos > ssfw->fw->size || size == 0) + break; + + ret = process_sigma_action(client, sa); - while (1) { - int ret = process_sigma_action(client, ssfw); pr_debug("%s: action returned %i\n", __func__, ret); - if (ret == 1) - return 0; - else if (ret) + + if (ret <= 0) return ret; } + + if (ssfw->pos != ssfw->fw->size) + return -EINVAL; + + return 0; } int process_sigma_firmware(struct i2c_client *client, const char *name) @@ -89,16 +116,24 @@ int process_sigma_firmware(struct i2c_client *client, const char *name) /* then verify the header */ ret = -EINVAL; - if (fw->size < sizeof(*ssfw_head)) + + /* + * Reject too small or unreasonable large files. The upper limit has been + * chosen a bit arbitrarily, but it should be enough for all practical + * purposes and having the limit makes it easier to avoid integer + * overflows later in the loading process. + */ + if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) goto done; ssfw_head = (void *)fw->data; if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) goto done; - crc = crc32(0, fw->data, fw->size); + crc = crc32(0, fw->data + sizeof(*ssfw_head), + fw->size - sizeof(*ssfw_head)); pr_debug("%s: crc=%x\n", __func__, crc); - if (crc != ssfw_head->crc) + if (crc != le32_to_cpu(ssfw_head->crc)) goto done; ssfw.pos = sizeof(*ssfw_head); diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index dbcb0bcfd8d..4e018d6a763 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -18,7 +18,7 @@ obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o -obj-$(CONFIG_MACH_KS8695) += gpio-ks8695.o +obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o obj-$(CONFIG_GPIO_LANGWELL) += gpio-langwell.o obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 038f5eb8b13..f8ce29ef9f8 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -22,7 +22,6 @@ #include <linux/mfd/da9052/da9052.h> #include <linux/mfd/da9052/reg.h> #include <linux/mfd/da9052/pdata.h> -#include <linux/mfd/da9052/gpio.h> #define DA9052_INPUT 1 #define DA9052_OUTPUT_OPENDRAIN 2 @@ -43,6 +42,9 @@ #define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0 #define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F #define DA9052_GPIO_NIBBLE_SHIFT 4 +#define DA9052_IRQ_GPI0 16 +#define DA9052_GPIO_ODD_SHIFT 7 +#define DA9052_GPIO_EVEN_SHIFT 3 struct da9052_gpio { struct da9052 *da9052; @@ -104,33 +106,26 @@ static int da9052_gpio_get(struct gpio_chip *gc, unsigned offset) static void da9052_gpio_set(struct gpio_chip *gc, unsigned offset, int value) { struct da9052_gpio *gpio = to_da9052_gpio(gc); - unsigned char register_value = 0; int ret; if (da9052_gpio_port_odd(offset)) { - if (value) { - register_value = DA9052_GPIO_ODD_PORT_MODE; ret = da9052_reg_update(gpio->da9052, (offset >> 1) + DA9052_GPIO_0_1_REG, DA9052_GPIO_ODD_PORT_MODE, - register_value); + value << DA9052_GPIO_ODD_SHIFT); if (ret != 0) dev_err(gpio->da9052->dev, "Failed to updated gpio odd reg,%d", ret); - } } else { - if (value) { - register_value = DA9052_GPIO_EVEN_PORT_MODE; ret = da9052_reg_update(gpio->da9052, (offset >> 1) + DA9052_GPIO_0_1_REG, DA9052_GPIO_EVEN_PORT_MODE, - register_value); + value << DA9052_GPIO_EVEN_SHIFT); if (ret != 0) dev_err(gpio->da9052->dev, "Failed to updated gpio even reg,%d", ret); - } } } @@ -201,9 +196,9 @@ static struct gpio_chip reference_gp __devinitdata = { .direction_input = da9052_gpio_direction_input, .direction_output = da9052_gpio_direction_output, .to_irq = da9052_gpio_to_irq, - .can_sleep = 1; - .ngpio = 16; - .base = -1; + .can_sleep = 1, + .ngpio = 16, + .base = -1, }; static int __devinit da9052_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index ea8e7386925..461958fc226 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -332,6 +332,34 @@ static void ioh_irq_mask(struct irq_data *d) &chip->reg->regs[chip->ch].imask); } +static void ioh_irq_disable(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + unsigned long flags; + u32 ien; + + spin_lock_irqsave(&chip->spinlock, flags); + ien = ioread32(&chip->reg->regs[chip->ch].ien); + ien &= ~(1 << (d->irq - chip->irq_base)); + iowrite32(ien, &chip->reg->regs[chip->ch].ien); + spin_unlock_irqrestore(&chip->spinlock, flags); +} + +static void ioh_irq_enable(struct irq_data *d) +{ + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); + struct ioh_gpio *chip = gc->private; + unsigned long flags; + u32 ien; + + spin_lock_irqsave(&chip->spinlock, flags); + ien = ioread32(&chip->reg->regs[chip->ch].ien); + ien |= 1 << (d->irq - chip->irq_base); + iowrite32(ien, &chip->reg->regs[chip->ch].ien); + spin_unlock_irqrestore(&chip->spinlock, flags); +} + static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) { struct ioh_gpio *chip = dev_id; @@ -339,7 +367,7 @@ static irqreturn_t ioh_gpio_handler(int irq, void *dev_id) int i, j; int ret = IRQ_NONE; - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++, chip++) { reg_val = ioread32(&chip->reg->regs[i].istatus); for (j = 0; j < num_ports[i]; j++) { if (reg_val & BIT(j)) { @@ -370,6 +398,8 @@ static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip, ct->chip.irq_mask = ioh_irq_mask; ct->chip.irq_unmask = ioh_irq_unmask; ct->chip.irq_set_type = ioh_irq_type; + ct->chip.irq_disable = ioh_irq_disable; + ct->chip.irq_enable = ioh_irq_enable; irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE, IRQ_NOREQUEST | IRQ_NOPROBE, 0); diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index ec3fcf0a7e1..5cd04b65c55 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -132,6 +132,15 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return 0; } +static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + /* GPIO 28..31 are input only on MPC5121 */ + if (gpio >= 28) + return -EINVAL; + + return mpc8xxx_gpio_dir_out(gc, gpio, val); +} + static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -340,11 +349,10 @@ static void __init mpc8xxx_add_controller(struct device_node *np) mm_gc->save_regs = mpc8xxx_gpio_save_regs; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = mpc8xxx_gpio_dir_out; - if (of_device_is_compatible(np, "fsl,mpc8572-gpio")) - gc->get = mpc8572_gpio_get; - else - gc->get = mpc8xxx_gpio_get; + gc->direction_output = of_device_is_compatible(np, "fsl,mpc5121-gpio") ? + mpc5121_gpio_dir_out : mpc8xxx_gpio_dir_out; + gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ? + mpc8572_gpio_get : mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; gc->to_irq = mpc8xxx_gpio_to_irq; diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 0e49d87f6c6..0b056297917 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -148,13 +148,17 @@ static int _get_gpio_dataout(struct gpio_bank *bank, int gpio) return (__raw_readl(reg) & GPIO_BIT(bank, gpio)) != 0; } -#define MOD_REG_BIT(reg, bit_mask, set) \ -do { \ - int l = __raw_readl(base + reg); \ - if (set) l |= bit_mask; \ - else l &= ~bit_mask; \ - __raw_writel(l, base + reg); \ -} while(0) +static inline void _gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set) +{ + int l = __raw_readl(base + reg); + + if (set) + l |= mask; + else + l &= ~mask; + + __raw_writel(l, base + reg); +} /** * _set_gpio_debounce - low level gpio debounce time @@ -210,28 +214,28 @@ static inline void set_24xx_gpio_triggering(struct gpio_bank *bank, int gpio, u32 gpio_bit = 1 << gpio; if (cpu_is_omap44xx()) { - MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQ_TYPE_LEVEL_LOW); - MOD_REG_BIT(OMAP4_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQ_TYPE_LEVEL_HIGH); - MOD_REG_BIT(OMAP4_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - MOD_REG_BIT(OMAP4_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); + _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + _gpio_rmw(base, OMAP4_GPIO_LEVELDETECT1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + _gpio_rmw(base, OMAP4_GPIO_RISINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + _gpio_rmw(base, OMAP4_GPIO_FALLINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); } else { - MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, - trigger & IRQ_TYPE_LEVEL_LOW); - MOD_REG_BIT(OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, - trigger & IRQ_TYPE_LEVEL_HIGH); - MOD_REG_BIT(OMAP24XX_GPIO_RISINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_RISING); - MOD_REG_BIT(OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, - trigger & IRQ_TYPE_EDGE_FALLING); + _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT0, gpio_bit, + trigger & IRQ_TYPE_LEVEL_LOW); + _gpio_rmw(base, OMAP24XX_GPIO_LEVELDETECT1, gpio_bit, + trigger & IRQ_TYPE_LEVEL_HIGH); + _gpio_rmw(base, OMAP24XX_GPIO_RISINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_RISING); + _gpio_rmw(base, OMAP24XX_GPIO_FALLINGDETECT, gpio_bit, + trigger & IRQ_TYPE_EDGE_FALLING); } if (likely(!(bank->non_wakeup_gpios & gpio_bit))) { if (cpu_is_omap44xx()) { - MOD_REG_BIT(OMAP4_GPIO_IRQWAKEN0, gpio_bit, - trigger != 0); + _gpio_rmw(base, OMAP4_GPIO_IRQWAKEN0, gpio_bit, + trigger != 0); } else { /* * GPIO wakeup request can only be generated on edge @@ -1086,6 +1090,11 @@ omap_mpuio_alloc_gc(struct gpio_bank *bank, unsigned int irq_start, gc = irq_alloc_generic_chip("MPUIO", 1, irq_start, bank->base, handle_simple_irq); + if (!gc) { + dev_err(bank->dev, "Memory alloc failed for gc\n"); + return; + } + ct = gc->chip_types; /* NOTE: No ack required, reading IRQ status clears it. */ diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 0550dcb8581..d3f3e8f5456 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -546,7 +546,7 @@ static void pca953x_irq_teardown(struct pca953x_chip *chip) * Translate OpenFirmware node properties into platform_data * WARNING: This is DEPRECATED and will be removed eventually! */ -void +static void pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) { struct device_node *node; @@ -574,7 +574,7 @@ pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) *invert = *val; } #else -void +static void pca953x_get_alt_pdata(struct i2c_client *client, int *gpio_base, int *invert) { *gpio_base = -1; @@ -596,9 +596,6 @@ static int __devinit device_pca953x_init(struct pca953x_chip *chip, int invert) /* set platform specific polarity inversion */ ret = pca953x_write_reg(chip, PCA953X_INVERT, invert); - if (ret) - goto out; - return 0; out: return ret; } @@ -640,7 +637,7 @@ static int __devinit pca953x_probe(struct i2c_client *client, struct pca953x_platform_data *pdata; struct pca953x_chip *chip; int irq_base=0, invert=0; - int ret = 0; + int ret; chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); if (chip == NULL) @@ -673,10 +670,10 @@ static int __devinit pca953x_probe(struct i2c_client *client, pca953x_setup_gpio(chip, id->driver_data & PCA_GPIO_MASK); if (chip->chip_type == PCA953X_TYPE) - device_pca953x_init(chip, invert); - else if (chip->chip_type == PCA957X_TYPE) - device_pca957x_init(chip, invert); + ret = device_pca953x_init(chip, invert); else + ret = device_pca957x_init(chip, invert); + if (ret) goto out_failed; ret = pca953x_irq_setup(chip, id, irq_base); diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c index 093c90bd3c1..4102f63230f 100644 --- a/drivers/gpio/gpio-pl061.c +++ b/drivers/gpio/gpio-pl061.c @@ -238,10 +238,6 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id) int ret, irq, i; static DECLARE_BITMAP(init_irq, NR_IRQS); - pdata = dev->dev.platform_data; - if (pdata == NULL) - return -ENODEV; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 785127cb281..1368826ef28 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -9,7 +9,6 @@ menuconfig DRM depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU select I2C select I2C_ALGOBIT - select SLOW_WORK help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select @@ -96,6 +95,7 @@ config DRM_I915 select FB_CFB_IMAGEBLIT # i915 depends on ACPI_VIDEO when ACPI is enabled # but for select to work, need to select ACPI_VIDEO's dependencies, ick + select BACKLIGHT_LCD_SUPPORT if ACPI select BACKLIGHT_CLASS_DEVICE if ACPI select VIDEO_OUTPUT_CONTROL if ACPI select INPUT if ACPI diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 711d9653abd..8323fc38984 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -163,6 +163,7 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] = { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B", 0 }, { DRM_MODE_CONNECTOR_TV, "TV", 0 }, { DRM_MODE_CONNECTOR_eDP, "eDP", 0 }, + { DRM_MODE_CONNECTOR_VIRTUAL, "Virtual", 0}, }; static struct drm_prop_enum_list drm_encoder_enum_list[] = @@ -171,6 +172,7 @@ static struct drm_prop_enum_list drm_encoder_enum_list[] = { DRM_MODE_ENCODER_TMDS, "TMDS" }, { DRM_MODE_ENCODER_LVDS, "LVDS" }, { DRM_MODE_ENCODER_TVDAC, "TV" }, + { DRM_MODE_ENCODER_VIRTUAL, "Virtual" }, }; char *drm_get_encoder_name(struct drm_encoder *encoder) @@ -464,8 +466,10 @@ void drm_connector_init(struct drm_device *dev, list_add_tail(&connector->head, &dev->mode_config.connector_list); dev->mode_config.num_connector++; - drm_connector_attach_property(connector, - dev->mode_config.edid_property, 0); + if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL) + drm_connector_attach_property(connector, + dev->mode_config.edid_property, + 0); drm_connector_attach_property(connector, dev->mode_config.dpms_property, 0); @@ -1869,6 +1873,10 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev, } if (num_clips && clips_ptr) { + if (num_clips < 0 || num_clips > DRM_MODE_FB_DIRTY_MAX_CLIPS) { + ret = -EINVAL; + goto out_err1; + } clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); if (!clips) { ret = -ENOMEM; @@ -2114,8 +2122,10 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags, property->num_values = num_values; INIT_LIST_HEAD(&property->enum_blob_list); - if (name) + if (name) { strncpy(property->name, name, DRM_PROP_NAME_LEN); + property->name[DRM_PROP_NAME_LEN-1] = '\0'; + } list_add_tail(&property->head, &dev->mode_config.property_list); return property; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 2957636161e..d2619d72cec 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -456,6 +456,30 @@ done: EXPORT_SYMBOL(drm_crtc_helper_set_mode); +static int +drm_crtc_helper_disable(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + struct drm_encoder *encoder; + + /* Decouple all encoders and their attached connectors from this crtc */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + if (encoder->crtc != crtc) + continue; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->encoder != encoder) + continue; + + connector->encoder = NULL; + } + } + + drm_helper_disable_unused_functions(dev); + return 0; +} + /** * drm_crtc_helper_set_config - set a new config from userspace * @crtc: CRTC to setup @@ -484,6 +508,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) struct drm_connector *save_connectors, *connector; int count = 0, ro, fail = 0; struct drm_crtc_helper_funcs *crtc_funcs; + struct drm_mode_set save_set; int ret = 0; int i; @@ -509,8 +534,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) (int)set->num_connectors, set->x, set->y); } else { DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); - set->mode = NULL; - set->num_connectors = 0; + return drm_crtc_helper_disable(set->crtc); } dev = set->crtc->dev; @@ -556,6 +580,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) save_connectors[count++] = *connector; } + save_set.crtc = set->crtc; + save_set.mode = &set->crtc->mode; + save_set.x = set->crtc->x; + save_set.y = set->crtc->y; + save_set.fb = set->crtc->fb; + /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ if (set->crtc->fb != set->fb) { @@ -721,6 +751,12 @@ fail: *connector = save_connectors[count++]; } + /* Try to restore the config */ + if (mode_changed && + !drm_crtc_helper_set_mode(save_set.crtc, save_set.mode, save_set.x, + save_set.y, save_set.fb)) + DRM_ERROR("failed to restore config after modeset failure\n"); + kfree(save_connectors); kfree(save_encoders); kfree(save_crtcs); diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index d067c12ba94..1c7a1c0d3ed 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -118,7 +118,10 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, tmp->minor = minor; tmp->dent = ent; tmp->info_ent = &files[i]; - list_add(&(tmp->list), &(minor->debugfs_nodes.list)); + + mutex_lock(&minor->debugfs_lock); + list_add(&tmp->list, &minor->debugfs_list); + mutex_unlock(&minor->debugfs_lock); } return 0; @@ -146,7 +149,8 @@ int drm_debugfs_init(struct drm_minor *minor, int minor_id, char name[64]; int ret; - INIT_LIST_HEAD(&minor->debugfs_nodes.list); + INIT_LIST_HEAD(&minor->debugfs_list); + mutex_init(&minor->debugfs_lock); sprintf(name, "%d", minor_id); minor->debugfs_root = debugfs_create_dir(name, root); if (!minor->debugfs_root) { @@ -192,8 +196,9 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count, struct drm_info_node *tmp; int i; + mutex_lock(&minor->debugfs_lock); for (i = 0; i < count; i++) { - list_for_each_safe(pos, q, &minor->debugfs_nodes.list) { + list_for_each_safe(pos, q, &minor->debugfs_list) { tmp = list_entry(pos, struct drm_info_node, list); if (tmp->info_ent == &files[i]) { debugfs_remove(tmp->dent); @@ -202,6 +207,7 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count, } } } + mutex_unlock(&minor->debugfs_lock); return 0; } EXPORT_SYMBOL(drm_debugfs_remove_files); diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index fc81af9dbf4..40c187c60f4 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -125,7 +125,7 @@ static struct drm_ioctl_desc drm_ioctls[] = { DRM_IOCTL_DEF(DRM_IOCTL_SG_ALLOC, drm_sg_alloc_ioctl, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), DRM_IOCTL_DEF(DRM_IOCTL_SG_FREE, drm_sg_free, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, 0), + DRM_IOCTL_DEF(DRM_IOCTL_WAIT_VBLANK, drm_wait_vblank, DRM_UNLOCKED), DRM_IOCTL_DEF(DRM_IOCTL_MODESET_CTL, drm_modeset_ctl, 0), diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index cb3794a00f9..44a5d0ad8b7 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -110,10 +110,7 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) /* Prevent vblank irq processing while disabling vblank irqs, * so no updates of timestamps or count can happen after we've * disabled. Needed to prevent races in case of delayed irq's. - * Disable preemption, so vblank_time_lock is held as short as - * possible, even under a kernel with PREEMPT_RT patches. */ - preempt_disable(); spin_lock_irqsave(&dev->vblank_time_lock, irqflags); dev->driver->disable_vblank(dev, crtc); @@ -164,7 +161,6 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc) clear_vblank_timestamps(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); - preempt_enable(); } static void vblank_disable_fn(unsigned long arg) @@ -407,13 +403,16 @@ int drm_irq_uninstall(struct drm_device *dev) /* * Wake up any waiters so they don't hang. */ - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for (i = 0; i < dev->num_crtcs; i++) { - DRM_WAKEUP(&dev->vbl_queue[i]); - dev->vblank_enabled[i] = 0; - dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i); + if (dev->num_crtcs) { + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for (i = 0; i < dev->num_crtcs; i++) { + DRM_WAKEUP(&dev->vbl_queue[i]); + dev->vblank_enabled[i] = 0; + dev->last_vblank[i] = + dev->driver->get_vblank_counter(dev, i); + } + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); if (!irq_enabled) return -EINVAL; @@ -886,10 +885,6 @@ int drm_vblank_get(struct drm_device *dev, int crtc) spin_lock_irqsave(&dev->vbl_lock, irqflags); /* Going from 0->1 means we have to enable interrupts again */ if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { - /* Disable preemption while holding vblank_time_lock. Do - * it explicitely to guard against PREEMPT_RT kernel. - */ - preempt_disable(); spin_lock_irqsave(&dev->vblank_time_lock, irqflags2); if (!dev->vblank_enabled[crtc]) { /* Enable vblank irqs under vblank_time_lock protection. @@ -909,7 +904,6 @@ int drm_vblank_get(struct drm_device *dev, int crtc) } } spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2); - preempt_enable(); } else { if (!dev->vblank_enabled[crtc]) { atomic_dec(&dev->vblank_refcount[crtc]); @@ -1125,6 +1119,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe, trace_drm_vblank_event_delivered(current->pid, pipe, vblwait->request.sequence); } else { + /* drm_handle_vblank_events will call drm_vblank_put */ list_add_tail(&e->base.link, &dev->vblank_event_list); vblwait->reply.sequence = vblwait->request.sequence; } @@ -1205,8 +1200,12 @@ int drm_wait_vblank(struct drm_device *dev, void *data, goto done; } - if (flags & _DRM_VBLANK_EVENT) + if (flags & _DRM_VBLANK_EVENT) { + /* must hold on to the vblank ref until the event fires + * drm_vblank_put will be called asynchronously + */ return drm_queue_vblank_event(dev, crtc, vblwait, file_priv); + } if ((flags & _DRM_VBLANK_NEXTONMISS) && (seq - vblwait->request.sequence) <= (1<<23)) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c index 6f8afea94fc..2bb07bca511 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c @@ -27,82 +27,84 @@ #include "drm.h" #include "exynos_drm_drv.h" +#include "exynos_drm_gem.h" #include "exynos_drm_buf.h" -static DEFINE_MUTEX(exynos_drm_buf_lock); - static int lowlevel_buffer_allocate(struct drm_device *dev, - struct exynos_drm_buf_entry *entry) + struct exynos_drm_gem_buf *buffer) { DRM_DEBUG_KMS("%s\n", __FILE__); - entry->vaddr = dma_alloc_writecombine(dev->dev, entry->size, - (dma_addr_t *)&entry->paddr, GFP_KERNEL); - if (!entry->paddr) { + buffer->kvaddr = dma_alloc_writecombine(dev->dev, buffer->size, + &buffer->dma_addr, GFP_KERNEL); + if (!buffer->kvaddr) { DRM_ERROR("failed to allocate buffer.\n"); return -ENOMEM; } - DRM_DEBUG_KMS("allocated : vaddr(0x%x), paddr(0x%x), size(0x%x)\n", - (unsigned int)entry->vaddr, entry->paddr, entry->size); + DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n", + (unsigned long)buffer->kvaddr, + (unsigned long)buffer->dma_addr, + buffer->size); return 0; } static void lowlevel_buffer_deallocate(struct drm_device *dev, - struct exynos_drm_buf_entry *entry) + struct exynos_drm_gem_buf *buffer) { DRM_DEBUG_KMS("%s.\n", __FILE__); - if (entry->paddr && entry->vaddr && entry->size) - dma_free_writecombine(dev->dev, entry->size, entry->vaddr, - entry->paddr); + if (buffer->dma_addr && buffer->size) + dma_free_writecombine(dev->dev, buffer->size, buffer->kvaddr, + (dma_addr_t)buffer->dma_addr); else - DRM_DEBUG_KMS("entry data is null.\n"); + DRM_DEBUG_KMS("buffer data are invalid.\n"); } -struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev, +struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, unsigned int size) { - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; DRM_DEBUG_KMS("%s.\n", __FILE__); + DRM_DEBUG_KMS("desired size = 0x%x\n", size); - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - DRM_ERROR("failed to allocate exynos_drm_buf_entry.\n"); + buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); + if (!buffer) { + DRM_ERROR("failed to allocate exynos_drm_gem_buf.\n"); return ERR_PTR(-ENOMEM); } - entry->size = size; + buffer->size = size; /* * allocate memory region with size and set the memory information - * to vaddr and paddr of a entry object. + * to vaddr and dma_addr of a buffer object. */ - if (lowlevel_buffer_allocate(dev, entry) < 0) { - kfree(entry); - entry = NULL; + if (lowlevel_buffer_allocate(dev, buffer) < 0) { + kfree(buffer); + buffer = NULL; return ERR_PTR(-ENOMEM); } - return entry; + return buffer; } void exynos_drm_buf_destroy(struct drm_device *dev, - struct exynos_drm_buf_entry *entry) + struct exynos_drm_gem_buf *buffer) { DRM_DEBUG_KMS("%s.\n", __FILE__); - if (!entry) { - DRM_DEBUG_KMS("entry is null.\n"); + if (!buffer) { + DRM_DEBUG_KMS("buffer is null.\n"); return; } - lowlevel_buffer_deallocate(dev, entry); + lowlevel_buffer_deallocate(dev, buffer); - kfree(entry); - entry = NULL; + kfree(buffer); + buffer = NULL; } MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.h b/drivers/gpu/drm/exynos/exynos_drm_buf.h index 045d59eab01..6e91f9caa5d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_buf.h +++ b/drivers/gpu/drm/exynos/exynos_drm_buf.h @@ -26,28 +26,15 @@ #ifndef _EXYNOS_DRM_BUF_H_ #define _EXYNOS_DRM_BUF_H_ -/* - * exynos drm buffer entry structure. - * - * @paddr: physical address of allocated memory. - * @vaddr: kernel virtual address of allocated memory. - * @size: size of allocated memory. - */ -struct exynos_drm_buf_entry { - dma_addr_t paddr; - void __iomem *vaddr; - unsigned int size; -}; - /* allocate physical memory. */ -struct exynos_drm_buf_entry *exynos_drm_buf_create(struct drm_device *dev, +struct exynos_drm_gem_buf *exynos_drm_buf_create(struct drm_device *dev, unsigned int size); -/* get physical memory information of a drm framebuffer. */ -struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb); +/* get memory information of a drm framebuffer. */ +struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb); /* remove allocated physical memory. */ void exynos_drm_buf_destroy(struct drm_device *dev, - struct exynos_drm_buf_entry *entry); + struct exynos_drm_gem_buf *buffer); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index 985d9e76872..d620b078425 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -37,6 +37,8 @@ struct exynos_drm_connector { struct drm_connector drm_connector; + uint32_t encoder_id; + struct exynos_drm_manager *manager; }; /* convert exynos_video_timings to drm_display_mode */ @@ -47,6 +49,7 @@ convert_to_display_mode(struct drm_display_mode *mode, DRM_DEBUG_KMS("%s\n", __FILE__); mode->clock = timing->pixclock / 1000; + mode->vrefresh = timing->refresh; mode->hdisplay = timing->xres; mode->hsync_start = mode->hdisplay + timing->left_margin; @@ -57,6 +60,12 @@ convert_to_display_mode(struct drm_display_mode *mode, mode->vsync_start = mode->vdisplay + timing->upper_margin; mode->vsync_end = mode->vsync_start + timing->vsync_len; mode->vtotal = mode->vsync_end + timing->lower_margin; + + if (timing->vmode & FB_VMODE_INTERLACED) + mode->flags |= DRM_MODE_FLAG_INTERLACE; + + if (timing->vmode & FB_VMODE_DOUBLE) + mode->flags |= DRM_MODE_FLAG_DBLSCAN; } /* convert drm_display_mode to exynos_video_timings */ @@ -69,7 +78,7 @@ convert_to_video_timing(struct fb_videomode *timing, memset(timing, 0, sizeof(*timing)); timing->pixclock = mode->clock * 1000; - timing->refresh = mode->vrefresh; + timing->refresh = drm_mode_vrefresh(mode); timing->xres = mode->hdisplay; timing->left_margin = mode->hsync_start - mode->hdisplay; @@ -92,15 +101,16 @@ convert_to_video_timing(struct fb_videomode *timing, static int exynos_drm_connector_get_modes(struct drm_connector *connector) { - struct exynos_drm_manager *manager = - exynos_drm_get_manager(connector->encoder); - struct exynos_drm_display *display = manager->display; + struct exynos_drm_connector *exynos_connector = + to_exynos_connector(connector); + struct exynos_drm_manager *manager = exynos_connector->manager; + struct exynos_drm_display_ops *display_ops = manager->display_ops; unsigned int count; DRM_DEBUG_KMS("%s\n", __FILE__); - if (!display) { - DRM_DEBUG_KMS("display is null.\n"); + if (!display_ops) { + DRM_DEBUG_KMS("display_ops is null.\n"); return 0; } @@ -112,7 +122,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) * P.S. in case of lcd panel, count is always 1 if success * because lcd panel has only one mode. */ - if (display->get_edid) { + if (display_ops->get_edid) { int ret; void *edid; @@ -122,7 +132,7 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) return 0; } - ret = display->get_edid(manager->dev, connector, + ret = display_ops->get_edid(manager->dev, connector, edid, MAX_EDID); if (ret < 0) { DRM_ERROR("failed to get edid data.\n"); @@ -140,8 +150,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode = drm_mode_create(connector->dev); struct fb_videomode *timing; - if (display->get_timing) - timing = display->get_timing(manager->dev); + if (display_ops->get_timing) + timing = display_ops->get_timing(manager->dev); else { drm_mode_destroy(connector->dev, mode); return 0; @@ -162,9 +172,10 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) static int exynos_drm_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - struct exynos_drm_manager *manager = - exynos_drm_get_manager(connector->encoder); - struct exynos_drm_display *display = manager->display; + struct exynos_drm_connector *exynos_connector = + to_exynos_connector(connector); + struct exynos_drm_manager *manager = exynos_connector->manager; + struct exynos_drm_display_ops *display_ops = manager->display_ops; struct fb_videomode timing; int ret = MODE_BAD; @@ -172,8 +183,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector, convert_to_video_timing(&timing, mode); - if (display && display->check_timing) - if (!display->check_timing(manager->dev, (void *)&timing)) + if (display_ops && display_ops->check_timing) + if (!display_ops->check_timing(manager->dev, (void *)&timing)) ret = MODE_OK; return ret; @@ -181,9 +192,25 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector, struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector) { + struct drm_device *dev = connector->dev; + struct exynos_drm_connector *exynos_connector = + to_exynos_connector(connector); + struct drm_mode_object *obj; + struct drm_encoder *encoder; + DRM_DEBUG_KMS("%s\n", __FILE__); - return connector->encoder; + obj = drm_mode_object_find(dev, exynos_connector->encoder_id, + DRM_MODE_OBJECT_ENCODER); + if (!obj) { + DRM_DEBUG_KMS("Unknown ENCODER ID %d\n", + exynos_connector->encoder_id); + return NULL; + } + + encoder = obj_to_encoder(obj); + + return encoder; } static struct drm_connector_helper_funcs exynos_connector_helper_funcs = { @@ -196,15 +223,17 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = { static enum drm_connector_status exynos_drm_connector_detect(struct drm_connector *connector, bool force) { - struct exynos_drm_manager *manager = - exynos_drm_get_manager(connector->encoder); - struct exynos_drm_display *display = manager->display; + struct exynos_drm_connector *exynos_connector = + to_exynos_connector(connector); + struct exynos_drm_manager *manager = exynos_connector->manager; + struct exynos_drm_display_ops *display_ops = + manager->display_ops; enum drm_connector_status status = connector_status_disconnected; DRM_DEBUG_KMS("%s\n", __FILE__); - if (display && display->is_connected) { - if (display->is_connected(manager->dev)) + if (display_ops && display_ops->is_connected) { + if (display_ops->is_connected(manager->dev)) status = connector_status_connected; else status = connector_status_disconnected; @@ -251,9 +280,11 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, connector = &exynos_connector->drm_connector; - switch (manager->display->type) { + switch (manager->display_ops->type) { case EXYNOS_DISPLAY_TYPE_HDMI: type = DRM_MODE_CONNECTOR_HDMIA; + connector->interlace_allowed = true; + connector->polled = DRM_CONNECTOR_POLL_HPD; break; default: type = DRM_MODE_CONNECTOR_Unknown; @@ -267,7 +298,10 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, if (err) goto err_connector; + exynos_connector->encoder_id = encoder->base.id; + exynos_connector->manager = manager; connector->encoder = encoder; + err = drm_mode_connector_attach_encoder(connector, encoder); if (err) { DRM_ERROR("failed to attach a connector to a encoder\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 9337e5e2dbb..ee43cc22085 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -29,36 +29,17 @@ #include "drmP.h" #include "drm_crtc_helper.h" +#include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_encoder.h" +#include "exynos_drm_gem.h" #include "exynos_drm_buf.h" #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\ drm_crtc) /* - * Exynos specific crtc postion structure. - * - * @fb_x: offset x on a framebuffer to be displyed - * - the unit is screen coordinates. - * @fb_y: offset y on a framebuffer to be displayed - * - the unit is screen coordinates. - * @crtc_x: offset x on hardware screen. - * @crtc_y: offset y on hardware screen. - * @crtc_w: width of hardware screen. - * @crtc_h: height of hardware screen. - */ -struct exynos_drm_crtc_pos { - unsigned int fb_x; - unsigned int fb_y; - unsigned int crtc_x; - unsigned int crtc_y; - unsigned int crtc_w; - unsigned int crtc_h; -}; - -/* * Exynos specific crtc structure. * * @drm_crtc: crtc object. @@ -85,30 +66,31 @@ static void exynos_drm_crtc_apply(struct drm_crtc *crtc) exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_crtc_mode_set); - exynos_drm_fn_encoder(crtc, NULL, exynos_drm_encoder_crtc_commit); + exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, + exynos_drm_encoder_crtc_commit); } -static int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, - struct drm_framebuffer *fb, - struct drm_display_mode *mode, - struct exynos_drm_crtc_pos *pos) +int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, + struct drm_framebuffer *fb, + struct drm_display_mode *mode, + struct exynos_drm_crtc_pos *pos) { - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; unsigned int actual_w; unsigned int actual_h; - entry = exynos_drm_fb_get_buf(fb); - if (!entry) { - DRM_LOG_KMS("entry is null.\n"); + buffer = exynos_drm_fb_get_buf(fb); + if (!buffer) { + DRM_LOG_KMS("buffer is null.\n"); return -EFAULT; } - overlay->paddr = entry->paddr; - overlay->vaddr = entry->vaddr; + overlay->dma_addr = buffer->dma_addr; + overlay->vaddr = buffer->kvaddr; - DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n", + DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", (unsigned long)overlay->vaddr, - (unsigned long)overlay->paddr); + (unsigned long)overlay->dma_addr); actual_w = min((mode->hdisplay - pos->crtc_x), pos->crtc_w); actual_h = min((mode->vdisplay - pos->crtc_y), pos->crtc_h); @@ -171,9 +153,26 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc) static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { - DRM_DEBUG_KMS("%s\n", __FILE__); + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - /* TODO */ + DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); + + switch (mode) { + case DRM_MODE_DPMS_ON: + exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, + exynos_drm_encoder_crtc_commit); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + /* TODO */ + exynos_drm_fn_encoder(crtc, NULL, + exynos_drm_encoder_crtc_disable); + break; + default: + DRM_DEBUG_KMS("unspecified mode %d\n", mode); + break; + } } static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) @@ -185,9 +184,12 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + DRM_DEBUG_KMS("%s\n", __FILE__); - /* drm framework doesn't check NULL. */ + exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe, + exynos_drm_encoder_crtc_commit); } static bool diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index c584042d6d2..25f72a62cb8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -35,4 +35,29 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); +/* + * Exynos specific crtc postion structure. + * + * @fb_x: offset x on a framebuffer to be displyed + * - the unit is screen coordinates. + * @fb_y: offset y on a framebuffer to be displayed + * - the unit is screen coordinates. + * @crtc_x: offset x on hardware screen. + * @crtc_y: offset y on hardware screen. + * @crtc_w: width of hardware screen. + * @crtc_h: height of hardware screen. + */ +struct exynos_drm_crtc_pos { + unsigned int fb_x; + unsigned int fb_y; + unsigned int crtc_x; + unsigned int crtc_y; + unsigned int crtc_w; + unsigned int crtc_h; +}; + +int exynos_drm_overlay_update(struct exynos_drm_overlay *overlay, + struct drm_framebuffer *fb, + struct drm_display_mode *mode, + struct exynos_drm_crtc_pos *pos); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 83810cbe3c1..53e2216de61 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -27,6 +27,7 @@ #include "drmP.h" #include "drm.h" +#include "drm_crtc_helper.h" #include <drm/exynos_drm.h> @@ -61,6 +62,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) drm_mode_config_init(dev); + /* init kms poll for handling hpd */ + drm_kms_helper_poll_init(dev); + exynos_drm_mode_config_init(dev); /* @@ -116,6 +120,7 @@ static int exynos_drm_unload(struct drm_device *dev) exynos_drm_fbdev_fini(dev); exynos_drm_device_unregister(dev); drm_vblank_cleanup(dev); + drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); kfree(dev->dev_private); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index c03683f2ae7..5e02e6ecc2e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -29,6 +29,7 @@ #ifndef _EXYNOS_DRM_DRV_H_ #define _EXYNOS_DRM_DRV_H_ +#include <linux/module.h> #include "drm.h" #define MAX_CRTC 2 @@ -79,8 +80,8 @@ struct exynos_drm_overlay_ops { * @scan_flag: interlace or progressive way. * (it could be DRM_MODE_FLAG_*) * @bpp: pixel size.(in bit) - * @paddr: bus(accessed by dma) physical memory address to this overlay - * and this is physically continuous. + * @dma_addr: bus(accessed by dma) address to the memory region allocated + * for a overlay. * @vaddr: virtual memory addresss to this overlay. * @default_win: a window to be enabled. * @color_key: color key on or off. @@ -108,7 +109,7 @@ struct exynos_drm_overlay { unsigned int scan_flag; unsigned int bpp; unsigned int pitch; - dma_addr_t paddr; + dma_addr_t dma_addr; void __iomem *vaddr; bool default_win; @@ -130,7 +131,7 @@ struct exynos_drm_overlay { * @check_timing: check if timing is valid or not. * @power_on: display device on or off. */ -struct exynos_drm_display { +struct exynos_drm_display_ops { enum exynos_drm_output_type type; bool (*is_connected)(struct device *dev); int (*get_edid)(struct device *dev, struct drm_connector *connector, @@ -146,12 +147,14 @@ struct exynos_drm_display { * @mode_set: convert drm_display_mode to hw specific display mode and * would be called by encoder->mode_set(). * @commit: set current hw specific display mode to hw. + * @disable: disable hardware specific display mode. * @enable_vblank: specific driver callback for enabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt. */ struct exynos_drm_manager_ops { void (*mode_set)(struct device *subdrv_dev, void *mode); void (*commit)(struct device *subdrv_dev); + void (*disable)(struct device *subdrv_dev); int (*enable_vblank)(struct device *subdrv_dev); void (*disable_vblank)(struct device *subdrv_dev); }; @@ -178,7 +181,7 @@ struct exynos_drm_manager { int pipe; struct exynos_drm_manager_ops *ops; struct exynos_drm_overlay_ops *overlay_ops; - struct exynos_drm_display *display; + struct exynos_drm_display_ops *display_ops; }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 7cf6fa86a67..153061415ba 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -53,15 +53,36 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct drm_connector *connector; struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); + struct exynos_drm_manager_ops *manager_ops = manager->ops; DRM_DEBUG_KMS("%s, encoder dpms: %d\n", __FILE__, mode); + switch (mode) { + case DRM_MODE_DPMS_ON: + if (manager_ops && manager_ops->commit) + manager_ops->commit(manager->dev); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + /* TODO */ + if (manager_ops && manager_ops->disable) + manager_ops->disable(manager->dev); + break; + default: + DRM_ERROR("unspecified mode %d\n", mode); + break; + } + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (connector->encoder == encoder) { - struct exynos_drm_display *display = manager->display; + struct exynos_drm_display_ops *display_ops = + manager->display_ops; - if (display && display->power_on) - display->power_on(manager->dev, mode); + DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", + connector->base.id, mode); + if (display_ops && display_ops->power_on) + display_ops->power_on(manager->dev, mode); } } } @@ -116,15 +137,11 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder) { struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); struct exynos_drm_manager_ops *manager_ops = manager->ops; - struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; DRM_DEBUG_KMS("%s\n", __FILE__); if (manager_ops && manager_ops->commit) manager_ops->commit(manager->dev); - - if (overlay_ops && overlay_ops->commit) - overlay_ops->commit(manager->dev); } static struct drm_crtc * @@ -208,10 +225,23 @@ void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, { struct drm_device *dev = crtc->dev; struct drm_encoder *encoder; + struct exynos_drm_private *private = dev->dev_private; + struct exynos_drm_manager *manager; list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - if (encoder->crtc != crtc) - continue; + /* + * if crtc is detached from encoder, check pipe, + * otherwise check crtc attached to encoder + */ + if (!encoder->crtc) { + manager = to_exynos_encoder(encoder)->manager; + if (manager->pipe < 0 || + private->crtc[manager->pipe] != crtc) + continue; + } else { + if (encoder->crtc != crtc) + continue; + } fn(encoder, data); } @@ -250,8 +280,18 @@ void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data) struct exynos_drm_manager *manager = to_exynos_encoder(encoder)->manager; struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; + int crtc = *(int *)data; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + /* + * when crtc is detached from encoder, this pipe is used + * to select manager operation + */ + manager->pipe = crtc; - overlay_ops->commit(manager->dev); + if (overlay_ops && overlay_ops->commit) + overlay_ops->commit(manager->dev); } void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data) @@ -261,7 +301,28 @@ void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data) struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; struct exynos_drm_overlay *overlay = data; - overlay_ops->mode_set(manager->dev, overlay); + if (overlay_ops && overlay_ops->mode_set) + overlay_ops->mode_set(manager->dev, overlay); +} + +void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data) +{ + struct exynos_drm_manager *manager = + to_exynos_encoder(encoder)->manager; + struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; + + DRM_DEBUG_KMS("\n"); + + if (overlay_ops && overlay_ops->disable) + overlay_ops->disable(manager->dev); + + /* + * crtc is already detached from encoder and last + * function for detaching is properly done, so + * clear pipe from manager to prevent repeated call + */ + if (!encoder->crtc) + manager->pipe = -1; } MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h index 5ecd645d06a..a22acfbf0e4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h @@ -41,5 +41,6 @@ void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data); void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data); void exynos_drm_encoder_crtc_commit(struct drm_encoder *encoder, void *data); void exynos_drm_encoder_crtc_mode_set(struct drm_encoder *encoder, void *data); +void exynos_drm_encoder_crtc_disable(struct drm_encoder *encoder, void *data); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 48d29cfd524..5bf4a1ac7f8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -29,7 +29,9 @@ #include "drmP.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" +#include "drm_fb_helper.h" +#include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_buf.h" #include "exynos_drm_gem.h" @@ -41,14 +43,14 @@ * * @fb: drm framebuffer obejct. * @exynos_gem_obj: exynos specific gem object containing a gem object. - * @entry: pointer to exynos drm buffer entry object. - * - containing only the information to physically continuous memory - * region allocated at default framebuffer creation. + * @buffer: pointer to exynos_drm_gem_buffer object. + * - contain the memory information to memory region allocated + * at default framebuffer creation. */ struct exynos_drm_fb { struct drm_framebuffer fb; struct exynos_drm_gem_obj *exynos_gem_obj; - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; }; static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) @@ -63,8 +65,8 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) * default framebuffer has no gem object so * a buffer of the default framebuffer should be released at here. */ - if (!exynos_fb->exynos_gem_obj && exynos_fb->entry) - exynos_drm_buf_destroy(fb->dev, exynos_fb->entry); + if (!exynos_fb->exynos_gem_obj && exynos_fb->buffer) + exynos_drm_buf_destroy(fb->dev, exynos_fb->buffer); kfree(exynos_fb); exynos_fb = NULL; @@ -143,29 +145,29 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, */ if (!mode_cmd->handle) { if (!file_priv) { - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; /* * in case that file_priv is NULL, it allocates * only buffer and this buffer would be used * for default framebuffer. */ - entry = exynos_drm_buf_create(dev, size); - if (IS_ERR(entry)) { - ret = PTR_ERR(entry); + buffer = exynos_drm_buf_create(dev, size); + if (IS_ERR(buffer)) { + ret = PTR_ERR(buffer); goto err_buffer; } - exynos_fb->entry = entry; + exynos_fb->buffer = buffer; - DRM_LOG_KMS("default fb: paddr = 0x%lx, size = 0x%x\n", - (unsigned long)entry->paddr, size); + DRM_LOG_KMS("default: dma_addr = 0x%lx, size = 0x%x\n", + (unsigned long)buffer->dma_addr, size); goto out; } else { - exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, - size, - &mode_cmd->handle); + exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, + &mode_cmd->handle, + size); if (IS_ERR(exynos_gem_obj)) { ret = PTR_ERR(exynos_gem_obj); goto err_buffer; @@ -189,10 +191,10 @@ exynos_drm_fb_init(struct drm_file *file_priv, struct drm_device *dev, * so that default framebuffer has no its own gem object, * only its own buffer object. */ - exynos_fb->entry = exynos_gem_obj->entry; + exynos_fb->buffer = exynos_gem_obj->buffer; - DRM_LOG_KMS("paddr = 0x%lx, size = 0x%x, gem object = 0x%x\n", - (unsigned long)exynos_fb->entry->paddr, size, + DRM_LOG_KMS("dma_addr = 0x%lx, size = 0x%x, gem object = 0x%x\n", + (unsigned long)exynos_fb->buffer->dma_addr, size, (unsigned int)&exynos_gem_obj->base); out: @@ -220,26 +222,36 @@ struct drm_framebuffer *exynos_drm_fb_create(struct drm_device *dev, return exynos_drm_fb_init(file_priv, dev, mode_cmd); } -struct exynos_drm_buf_entry *exynos_drm_fb_get_buf(struct drm_framebuffer *fb) +struct exynos_drm_gem_buf *exynos_drm_fb_get_buf(struct drm_framebuffer *fb) { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; DRM_DEBUG_KMS("%s\n", __FILE__); - entry = exynos_fb->entry; - if (!entry) + buffer = exynos_fb->buffer; + if (!buffer) return NULL; - DRM_DEBUG_KMS("vaddr = 0x%lx, paddr = 0x%lx\n", - (unsigned long)entry->vaddr, - (unsigned long)entry->paddr); + DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n", + (unsigned long)buffer->kvaddr, + (unsigned long)buffer->dma_addr); - return entry; + return buffer; +} + +static void exynos_drm_output_poll_changed(struct drm_device *dev) +{ + struct exynos_drm_private *private = dev->dev_private; + struct drm_fb_helper *fb_helper = private->fb_helper; + + if (fb_helper) + drm_fb_helper_hotplug_event(fb_helper); } static struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_drm_fb_create, + .output_poll_changed = exynos_drm_output_poll_changed, }; void exynos_drm_mode_config_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 1f4b3d1a771..836f4100818 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -33,6 +33,7 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" +#include "exynos_drm_gem.h" #include "exynos_drm_buf.h" #define MAX_CONNECTOR 4 @@ -85,15 +86,13 @@ static struct fb_ops exynos_drm_fb_ops = { }; static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, - struct drm_framebuffer *fb, - unsigned int fb_width, - unsigned int fb_height) + struct drm_framebuffer *fb) { struct fb_info *fbi = helper->fbdev; struct drm_device *dev = helper->dev; struct exynos_drm_fbdev *exynos_fb = to_exynos_fbdev(helper); - struct exynos_drm_buf_entry *entry; - unsigned int size = fb_width * fb_height * (fb->bits_per_pixel >> 3); + struct exynos_drm_gem_buf *buffer; + unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); unsigned long offset; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -101,20 +100,20 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, exynos_fb->fb = fb; drm_fb_helper_fill_fix(fbi, fb->pitch, fb->depth); - drm_fb_helper_fill_var(fbi, helper, fb_width, fb_height); + drm_fb_helper_fill_var(fbi, helper, fb->width, fb->height); - entry = exynos_drm_fb_get_buf(fb); - if (!entry) { - DRM_LOG_KMS("entry is null.\n"); + buffer = exynos_drm_fb_get_buf(fb); + if (!buffer) { + DRM_LOG_KMS("buffer is null.\n"); return -EFAULT; } offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset += fbi->var.yoffset * fb->pitch; - dev->mode_config.fb_base = entry->paddr; - fbi->screen_base = entry->vaddr + offset; - fbi->fix.smem_start = entry->paddr + offset; + dev->mode_config.fb_base = (resource_size_t)buffer->dma_addr; + fbi->screen_base = buffer->kvaddr + offset; + fbi->fix.smem_start = (unsigned long)(buffer->dma_addr + offset); fbi->screen_size = size; fbi->fix.smem_len = size; @@ -171,8 +170,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, goto out; } - ret = exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width, - sizes->fb_height); + ret = exynos_drm_fbdev_update(helper, helper->fb); if (ret < 0) fb_dealloc_cmap(&fbi->cmap); @@ -235,8 +233,7 @@ static int exynos_drm_fbdev_recreate(struct drm_fb_helper *helper, } helper->fb = exynos_fbdev->fb; - return exynos_drm_fbdev_update(helper, helper->fb, sizes->fb_width, - sizes->fb_height); + return exynos_drm_fbdev_update(helper, helper->fb); } static int exynos_drm_fbdev_probe(struct drm_fb_helper *helper, @@ -405,6 +402,18 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev) fb_helper = private->fb_helper; if (fb_helper) { + struct list_head temp_list; + + INIT_LIST_HEAD(&temp_list); + + /* + * fb_helper is reintialized but kernel fb is reused + * so kernel_fb_list need to be backuped and restored + */ + if (!list_empty(&fb_helper->kernel_fb_list)) + list_replace_init(&fb_helper->kernel_fb_list, + &temp_list); + drm_fb_helper_fini(fb_helper); ret = drm_fb_helper_init(dev, fb_helper, @@ -414,6 +423,9 @@ int exynos_drm_fbdev_reinit(struct drm_device *dev) return ret; } + if (!list_empty(&temp_list)) + list_replace(&temp_list, &fb_helper->kernel_fb_list); + ret = drm_fb_helper_single_add_all_connectors(fb_helper); if (ret < 0) { DRM_ERROR("failed to add fb helper to connectors\n"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 4659c88cdd9..db3b3d9e731 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -64,7 +64,7 @@ struct fimd_win_data { unsigned int fb_width; unsigned int fb_height; unsigned int bpp; - dma_addr_t paddr; + dma_addr_t dma_addr; void __iomem *vaddr; unsigned int buf_offsize; unsigned int line_size; /* bytes */ @@ -124,7 +124,7 @@ static int fimd_display_power_on(struct device *dev, int mode) return 0; } -static struct exynos_drm_display fimd_display = { +static struct exynos_drm_display_ops fimd_display_ops = { .type = EXYNOS_DISPLAY_TYPE_LCD, .is_connected = fimd_display_is_connected, .get_timing = fimd_get_timing, @@ -177,6 +177,40 @@ static void fimd_commit(struct device *dev) writel(val, ctx->regs + VIDCON0); } +static void fimd_disable(struct device *dev) +{ + struct fimd_context *ctx = get_fimd_context(dev); + struct exynos_drm_subdrv *subdrv = &ctx->subdrv; + struct drm_device *drm_dev = subdrv->drm_dev; + struct exynos_drm_manager *manager = &subdrv->manager; + u32 val; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + /* fimd dma off */ + val = readl(ctx->regs + VIDCON0); + val &= ~(VIDCON0_ENVID | VIDCON0_ENVID_F); + writel(val, ctx->regs + VIDCON0); + + /* + * if vblank is enabled status with dma off then + * it disables vsync interrupt. + */ + if (drm_dev->vblank_enabled[manager->pipe] && + atomic_read(&drm_dev->vblank_refcount[manager->pipe])) { + drm_vblank_put(drm_dev, manager->pipe); + + /* + * if vblank_disable_allowed is 0 then disable + * vsync interrupt right now else the vsync interrupt + * would be disabled by drm timer once a current process + * gives up ownershop of vblank event. + */ + if (!drm_dev->vblank_disable_allowed) + drm_vblank_off(drm_dev, manager->pipe); + } +} + static int fimd_enable_vblank(struct device *dev) { struct fimd_context *ctx = get_fimd_context(dev); @@ -220,6 +254,7 @@ static void fimd_disable_vblank(struct device *dev) static struct exynos_drm_manager_ops fimd_manager_ops = { .commit = fimd_commit, + .disable = fimd_disable, .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, }; @@ -251,7 +286,7 @@ static void fimd_win_mode_set(struct device *dev, win_data->ovl_height = overlay->crtc_height; win_data->fb_width = overlay->fb_width; win_data->fb_height = overlay->fb_height; - win_data->paddr = overlay->paddr + offset; + win_data->dma_addr = overlay->dma_addr + offset; win_data->vaddr = overlay->vaddr + offset; win_data->bpp = overlay->bpp; win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) * @@ -263,7 +298,7 @@ static void fimd_win_mode_set(struct device *dev, DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", win_data->ovl_width, win_data->ovl_height); DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n", - (unsigned long)win_data->paddr, + (unsigned long)win_data->dma_addr, (unsigned long)win_data->vaddr); DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n", overlay->fb_width, overlay->crtc_width); @@ -376,16 +411,16 @@ static void fimd_win_commit(struct device *dev) writel(val, ctx->regs + SHADOWCON); /* buffer start address */ - val = win_data->paddr; + val = (unsigned long)win_data->dma_addr; writel(val, ctx->regs + VIDWx_BUF_START(win, 0)); /* buffer end address */ size = win_data->fb_width * win_data->ovl_height * (win_data->bpp >> 3); - val = win_data->paddr + size; + val = (unsigned long)(win_data->dma_addr + size); writel(val, ctx->regs + VIDWx_BUF_END(win, 0)); DRM_DEBUG_KMS("start addr = 0x%lx, end addr = 0x%lx, size = 0x%lx\n", - (unsigned long)win_data->paddr, val, size); + (unsigned long)win_data->dma_addr, val, size); DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n", win_data->ovl_width, win_data->ovl_height); @@ -447,7 +482,6 @@ static void fimd_win_commit(struct device *dev) static void fimd_win_disable(struct device *dev) { struct fimd_context *ctx = get_fimd_context(dev); - struct fimd_win_data *win_data; int win = ctx->default_win; u32 val; @@ -456,8 +490,6 @@ static void fimd_win_disable(struct device *dev) if (win < 0 || win > WINDOWS_NR) return; - win_data = &ctx->win_data[win]; - /* protect windows */ val = readl(ctx->regs + SHADOWCON); val |= SHADOWCON_WINx_PROTECT(win); @@ -528,6 +560,16 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) /* VSYNC interrupt */ writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); + /* + * in case that vblank_disable_allowed is 1, it could induce + * the problem that manager->pipe could be -1 because with + * disable callback, vsync interrupt isn't disabled and at this moment, + * vsync interrupt could occur. the vsync interrupt would be disabled + * by timer handler later. + */ + if (manager->pipe == -1) + return IRQ_HANDLED; + drm_handle_vblank(drm_dev, manager->pipe); fimd_finish_pageflip(drm_dev, manager->pipe); @@ -548,13 +590,6 @@ static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) */ drm_dev->irq_enabled = 1; - /* - * with vblank_disable_allowed = 1, vblank interrupt will be disabled - * by drm timer once a current process gives up ownership of - * vblank event.(drm_vblank_put function was called) - */ - drm_dev->vblank_disable_allowed = 1; - return 0; } @@ -731,7 +766,7 @@ static int __devinit fimd_probe(struct platform_device *pdev) subdrv->manager.pipe = -1; subdrv->manager.ops = &fimd_manager_ops; subdrv->manager.overlay_ops = &fimd_overlay_ops; - subdrv->manager.display = &fimd_display; + subdrv->manager.display_ops = &fimd_display_ops; subdrv->manager.dev = dev; platform_set_drvdata(pdev, ctx); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index a8e7a88906e..aba0fe47f7e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -62,40 +62,28 @@ static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj) return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT; } -struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv, - struct drm_device *dev, unsigned int size, - unsigned int *handle) +static struct exynos_drm_gem_obj + *exynos_drm_gem_init(struct drm_device *drm_dev, + struct drm_file *file_priv, unsigned int *handle, + unsigned int size) { struct exynos_drm_gem_obj *exynos_gem_obj; - struct exynos_drm_buf_entry *entry; struct drm_gem_object *obj; int ret; - DRM_DEBUG_KMS("%s\n", __FILE__); - - size = roundup(size, PAGE_SIZE); - exynos_gem_obj = kzalloc(sizeof(*exynos_gem_obj), GFP_KERNEL); if (!exynos_gem_obj) { DRM_ERROR("failed to allocate exynos gem object.\n"); return ERR_PTR(-ENOMEM); } - /* allocate the new buffer object and memory region. */ - entry = exynos_drm_buf_create(dev, size); - if (!entry) { - kfree(exynos_gem_obj); - return ERR_PTR(-ENOMEM); - } - - exynos_gem_obj->entry = entry; - obj = &exynos_gem_obj->base; - ret = drm_gem_object_init(dev, obj, size); + ret = drm_gem_object_init(drm_dev, obj, size); if (ret < 0) { - DRM_ERROR("failed to initailize gem object.\n"); - goto err_obj_init; + DRM_ERROR("failed to initialize gem object.\n"); + ret = -EINVAL; + goto err_object_init; } DRM_DEBUG_KMS("created file object = 0x%x\n", (unsigned int)obj->filp); @@ -127,24 +115,50 @@ err_handle_create: err_create_mmap_offset: drm_gem_object_release(obj); -err_obj_init: - exynos_drm_buf_destroy(dev, exynos_gem_obj->entry); - +err_object_init: kfree(exynos_gem_obj); return ERR_PTR(ret); } +struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, + struct drm_file *file_priv, + unsigned int *handle, unsigned long size) +{ + + struct exynos_drm_gem_obj *exynos_gem_obj = NULL; + struct exynos_drm_gem_buf *buffer; + + size = roundup(size, PAGE_SIZE); + + DRM_DEBUG_KMS("%s: size = 0x%lx\n", __FILE__, size); + + buffer = exynos_drm_buf_create(dev, size); + if (IS_ERR(buffer)) { + return ERR_CAST(buffer); + } + + exynos_gem_obj = exynos_drm_gem_init(dev, file_priv, handle, size); + if (IS_ERR(exynos_gem_obj)) { + exynos_drm_buf_destroy(dev, buffer); + return exynos_gem_obj; + } + + exynos_gem_obj->buffer = buffer; + + return exynos_gem_obj; +} + int exynos_drm_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) + struct drm_file *file_priv) { struct drm_exynos_gem_create *args = data; - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem_obj *exynos_gem_obj = NULL; - DRM_DEBUG_KMS("%s : size = 0x%x\n", __FILE__, args->size); + DRM_DEBUG_KMS("%s\n", __FILE__); - exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size, - &args->handle); + exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, + &args->handle, args->size); if (IS_ERR(exynos_gem_obj)) return PTR_ERR(exynos_gem_obj); @@ -175,7 +189,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, { struct drm_gem_object *obj = filp->private_data; struct exynos_drm_gem_obj *exynos_gem_obj = to_exynos_gem_obj(obj); - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; unsigned long pfn, vm_size; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -187,20 +201,20 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp, vm_size = vma->vm_end - vma->vm_start; /* - * a entry contains information to physically continuous memory + * a buffer contains information to physically continuous memory * allocated by user request or at framebuffer creation. */ - entry = exynos_gem_obj->entry; + buffer = exynos_gem_obj->buffer; /* check if user-requested size is valid. */ - if (vm_size > entry->size) + if (vm_size > buffer->size) return -EINVAL; /* * get page frame number to physical memory to be mapped * to user space. */ - pfn = exynos_gem_obj->entry->paddr >> PAGE_SHIFT; + pfn = ((unsigned long)exynos_gem_obj->buffer->dma_addr) >> PAGE_SHIFT; DRM_DEBUG_KMS("pfn = 0x%lx\n", pfn); @@ -281,7 +295,7 @@ void exynos_drm_gem_free_object(struct drm_gem_object *gem_obj) exynos_gem_obj = to_exynos_gem_obj(gem_obj); - exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->entry); + exynos_drm_buf_destroy(gem_obj->dev, exynos_gem_obj->buffer); kfree(exynos_gem_obj); } @@ -302,8 +316,8 @@ int exynos_drm_gem_dumb_create(struct drm_file *file_priv, args->pitch = args->width * args->bpp >> 3; args->size = args->pitch * args->height; - exynos_gem_obj = exynos_drm_gem_create(file_priv, dev, args->size, - &args->handle); + exynos_gem_obj = exynos_drm_gem_create(dev, file_priv, &args->handle, + args->size); if (IS_ERR(exynos_gem_obj)) return PTR_ERR(exynos_gem_obj); @@ -360,7 +374,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) mutex_lock(&dev->struct_mutex); - pfn = (exynos_gem_obj->entry->paddr >> PAGE_SHIFT) + page_offset; + pfn = (((unsigned long)exynos_gem_obj->buffer->dma_addr) >> + PAGE_SHIFT) + page_offset; ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn); diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h index e5fc0148277..ef8797334e6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.h +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h @@ -30,13 +30,29 @@ struct exynos_drm_gem_obj, base) /* + * exynos drm gem buffer structure. + * + * @kvaddr: kernel virtual address to allocated memory region. + * @dma_addr: bus address(accessed by dma) to allocated memory region. + * - this address could be physical address without IOMMU and + * device address with IOMMU. + * @size: size of allocated memory region. + */ +struct exynos_drm_gem_buf { + void __iomem *kvaddr; + dma_addr_t dma_addr; + unsigned long size; +}; + +/* * exynos drm buffer structure. * * @base: a gem object. * - a new handle to this gem object would be created * by drm_gem_handle_create(). - * @entry: pointer to exynos drm buffer entry object. - * - containing the information to physically + * @buffer: a pointer to exynos_drm_gem_buffer object. + * - contain the information to memory region allocated + * by user request or at framebuffer creation. * continuous memory region allocated by user request * or at framebuffer creation. * @@ -45,13 +61,13 @@ */ struct exynos_drm_gem_obj { struct drm_gem_object base; - struct exynos_drm_buf_entry *entry; + struct exynos_drm_gem_buf *buffer; }; /* create a new buffer and get a new gem handle. */ -struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_file *file_priv, - struct drm_device *dev, unsigned int size, - unsigned int *handle); +struct exynos_drm_gem_obj *exynos_drm_gem_create(struct drm_device *dev, + struct drm_file *file_priv, + unsigned int *handle, unsigned long size); /* * request gem object creation and buffer allocation as the size diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index d14b44e13f5..004b048c519 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -62,6 +62,7 @@ static int i915_capabilities(struct seq_file *m, void *data) const struct intel_device_info *info = INTEL_INFO(dev); seq_printf(m, "gen: %d\n", info->gen); + seq_printf(m, "pch: %d\n", INTEL_PCH_TYPE(dev)); #define B(x) seq_printf(m, #x ": %s\n", yesno(info->x)) B(is_mobile); B(is_i85x); @@ -636,11 +637,16 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; struct intel_ring_buffer *ring; + int ret; ring = &dev_priv->ring[(uintptr_t)node->info_ent->data]; if (ring->size == 0) return 0; + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + seq_printf(m, "Ring %s:\n", ring->name); seq_printf(m, " Head : %08x\n", I915_READ_HEAD(ring) & HEAD_ADDR); seq_printf(m, " Tail : %08x\n", I915_READ_TAIL(ring) & TAIL_ADDR); @@ -654,6 +660,8 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, " Control : %08x\n", I915_READ_CTL(ring)); seq_printf(m, " Start : %08x\n", I915_READ_START(ring)); + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -842,7 +850,16 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u16 crstanddelay = I915_READ16(CRSTANDVID); + u16 crstanddelay; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + crstanddelay = I915_READ16(CRSTANDVID); + + mutex_unlock(&dev->struct_mutex); seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f)); @@ -940,7 +957,11 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 delayfreq; - int i; + int ret, i; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); @@ -948,6 +969,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -962,13 +985,19 @@ static int i915_inttoext_table(struct seq_file *m, void *unused) struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; u32 inttoext; - int i; + int ret, i; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; for (i = 1; i <= 32; i++) { inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4); seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext); } + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -977,9 +1006,19 @@ static int i915_drpc_info(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - u32 rgvmodectl = I915_READ(MEMMODECTL); - u32 rstdbyctl = I915_READ(RSTDBYCTL); - u16 crstandvid = I915_READ16(CRSTANDVID); + u32 rgvmodectl, rstdbyctl; + u16 crstandvid; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + rgvmodectl = I915_READ(MEMMODECTL); + rstdbyctl = I915_READ(RSTDBYCTL); + crstandvid = I915_READ16(CRSTANDVID); + + mutex_unlock(&dev->struct_mutex); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? "yes" : "no"); @@ -1167,9 +1206,16 @@ static int i915_gfxec(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; + int ret; + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + mutex_unlock(&dev->struct_mutex); + return 0; } @@ -1506,7 +1552,10 @@ drm_add_fake_info_node(struct drm_minor *minor, node->minor = minor; node->dent = ent; node->info_ent = (void *) key; - list_add(&node->list, &minor->debugfs_nodes.list); + + mutex_lock(&minor->debugfs_lock); + list_add(&node->list, &minor->debugfs_list); + mutex_unlock(&minor->debugfs_lock); return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a9533c54c93..a9ae374861e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1454,6 +1454,14 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) diff1 = now - dev_priv->last_time1; + /* Prevent division-by-zero if we are asking too fast. + * Also, we don't get interesting results if we are polling + * faster than once in 10ms, so just return the saved value + * in such cases. + */ + if (diff1 <= 10) + return dev_priv->chipset_power; + count1 = I915_READ(DMIEC); count2 = I915_READ(DDREC); count3 = I915_READ(CSIEC); @@ -1484,6 +1492,8 @@ unsigned long i915_chipset_val(struct drm_i915_private *dev_priv) dev_priv->last_count1 = total_count; dev_priv->last_time1 = now; + dev_priv->chipset_power = ret; + return ret; } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index cc531bb59c2..a1103fc6597 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -58,17 +58,17 @@ module_param_named(powersave, i915_powersave, int, 0600); MODULE_PARM_DESC(powersave, "Enable powersavings, fbc, downclocking, etc. (default: true)"); -unsigned int i915_semaphores __read_mostly = 0; +int i915_semaphores __read_mostly = -1; module_param_named(semaphores, i915_semaphores, int, 0600); MODULE_PARM_DESC(semaphores, - "Use semaphores for inter-ring sync (default: false)"); + "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))"); -unsigned int i915_enable_rc6 __read_mostly = 0; +int i915_enable_rc6 __read_mostly = -1; module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0600); MODULE_PARM_DESC(i915_enable_rc6, - "Enable power-saving render C-state 6 (default: true)"); + "Enable power-saving render C-state 6 (default: -1 (use per-chip default)"); -unsigned int i915_enable_fbc __read_mostly = -1; +int i915_enable_fbc __read_mostly = -1; module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600); MODULE_PARM_DESC(i915_enable_fbc, "Enable frame buffer compression for power savings " @@ -80,7 +80,7 @@ MODULE_PARM_DESC(lvds_downclock, "Use panel (LVDS/eDP) downclocking for power savings " "(default: false)"); -unsigned int i915_panel_use_ssc __read_mostly = -1; +int i915_panel_use_ssc __read_mostly = -1; module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600); MODULE_PARM_DESC(lvds_use_ssc, "Use Spread Spectrum Clock with panels [LVDS/eDP] " @@ -107,7 +107,7 @@ static struct drm_driver driver; extern int intel_agp_enabled; #define INTEL_VGA_DEVICE(id, info) { \ - .class = PCI_CLASS_DISPLAY_VGA << 8, \ + .class = PCI_BASE_CLASS_DISPLAY << 16, \ .class_mask = 0xff0000, \ .vendor = 0x8086, \ .device = id, \ @@ -328,7 +328,7 @@ void intel_detect_pch(struct drm_device *dev) } } -static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) +void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) { int count; @@ -344,6 +344,22 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) udelay(10); } +void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) +{ + int count; + + count = 0; + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1)) + udelay(10); + + I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 1); + POSTING_READ(FORCEWAKE_MT); + + count = 0; + while (count++ < 50 && (I915_READ_NOTRACE(FORCEWAKE_MT_ACK) & 1) == 0) + udelay(10); +} + /* * Generally this is called implicitly by the register read function. However, * if some sequence requires the GT to not power down then this function should @@ -356,15 +372,21 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) /* Forcewake is atomic in case we get in here without the lock */ if (atomic_add_return(1, &dev_priv->forcewake_count) == 1) - __gen6_gt_force_wake_get(dev_priv); + dev_priv->display.force_wake_get(dev_priv); } -static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) +void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) { I915_WRITE_NOTRACE(FORCEWAKE, 0); POSTING_READ(FORCEWAKE); } +void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv) +{ + I915_WRITE_NOTRACE(FORCEWAKE_MT, (1<<16) | 0); + POSTING_READ(FORCEWAKE_MT); +} + /* * see gen6_gt_force_wake_get() */ @@ -373,7 +395,7 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv) WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); if (atomic_dec_and_test(&dev_priv->forcewake_count)) - __gen6_gt_force_wake_put(dev_priv); + dev_priv->display.force_wake_put(dev_priv); } void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) @@ -789,8 +811,8 @@ static struct vm_operations_struct i915_gem_vm_ops = { }; static struct drm_driver driver = { - /* don't use mtrr's here, the Xserver or user space app should - * deal with them for intel hardware. + /* Don't use MTRRs here; the Xserver or userspace app should + * deal with them for Intel hardware. */ .driver_features = DRIVER_USE_AGP | DRIVER_REQUIRE_AGP | /* DRIVER_USE_MTRR |*/ @@ -903,8 +925,9 @@ MODULE_LICENSE("GPL and additional rights"); /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE) && \ + ((reg) != ECOBUS)) #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg) { \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 06a37f4fd74..554bef7a3b9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -107,6 +107,7 @@ struct opregion_header; struct opregion_acpi; struct opregion_swsci; struct opregion_asle; +struct drm_i915_private; struct intel_opregion { struct opregion_header *header; @@ -126,6 +127,9 @@ struct drm_i915_master_private { struct _drm_i915_sarea *sarea_priv; }; #define I915_FENCE_REG_NONE -1 +#define I915_MAX_NUM_FENCES 16 +/* 16 fences + sign bit for FENCE_REG_NONE */ +#define I915_MAX_NUM_FENCE_BITS 5 struct drm_i915_fence_reg { struct list_head lru_list; @@ -168,7 +172,7 @@ struct drm_i915_error_state { u32 instdone1; u32 seqno; u64 bbaddr; - u64 fence[16]; + u64 fence[I915_MAX_NUM_FENCES]; struct timeval time; struct drm_i915_error_object { int page_count; @@ -182,7 +186,7 @@ struct drm_i915_error_state { u32 gtt_offset; u32 read_domains; u32 write_domain; - s32 fence_reg:5; + s32 fence_reg:I915_MAX_NUM_FENCE_BITS; s32 pinned:2; u32 tiling:2; u32 dirty:1; @@ -218,6 +222,8 @@ struct drm_i915_display_funcs { struct drm_i915_gem_object *obj); int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, int x, int y); + void (*force_wake_get)(struct drm_i915_private *dev_priv); + void (*force_wake_put)(struct drm_i915_private *dev_priv); /* clock updates for mode set */ /* cursor updates */ /* render clock increase/decrease */ @@ -375,7 +381,7 @@ typedef struct drm_i915_private { struct notifier_block lid_notifier; int crt_ddc_pin; - struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */ + struct drm_i915_fence_reg fence_regs[I915_MAX_NUM_FENCES]; /* assume 965 */ int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */ int num_fence_regs; /* 8 on pre-965, 16 otherwise */ @@ -506,7 +512,7 @@ typedef struct drm_i915_private { u8 saveAR[21]; u8 saveDACMASK; u8 saveCR[37]; - uint64_t saveFENCE[16]; + uint64_t saveFENCE[I915_MAX_NUM_FENCES]; u32 saveCURACNTR; u32 saveCURAPOS; u32 saveCURABASE; @@ -707,6 +713,7 @@ typedef struct drm_i915_private { u64 last_count1; unsigned long last_time1; + unsigned long chipset_power; u64 last_count2; struct timespec last_time2; unsigned long gfx_power; @@ -777,10 +784,8 @@ struct drm_i915_gem_object { * Fence register bits (if any) for this object. Will be set * as needed when mapped into the GTT. * Protected by dev->struct_mutex. - * - * Size: 4 bits for 16 fences + sign (for FENCE_REG_NONE) */ - signed int fence_reg:5; + signed int fence_reg:I915_MAX_NUM_FENCE_BITS; /** * Advice: are the backing pages purgeable? @@ -997,12 +1002,12 @@ extern int i915_max_ioctl; extern unsigned int i915_fbpercrtc __always_unused; extern int i915_panel_ignore_lid __read_mostly; extern unsigned int i915_powersave __read_mostly; -extern unsigned int i915_semaphores __read_mostly; +extern int i915_semaphores __read_mostly; extern unsigned int i915_lvds_downclock __read_mostly; -extern unsigned int i915_panel_use_ssc __read_mostly; +extern int i915_panel_use_ssc __read_mostly; extern int i915_vbt_sdvo_panel_type __read_mostly; -extern unsigned int i915_enable_rc6 __read_mostly; -extern unsigned int i915_enable_fbc __read_mostly; +extern int i915_enable_rc6 __read_mostly; +extern int i915_enable_fbc __read_mostly; extern bool i915_enable_hangcheck __read_mostly; extern int i915_suspend(struct drm_device *dev, pm_message_t state); @@ -1307,6 +1312,11 @@ extern void gen6_set_rps(struct drm_device *dev, u8 val); extern void intel_detect_pch(struct drm_device *dev); extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); +extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv); +extern void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv); +extern void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv); +extern void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv); + /* overlay */ #ifdef CONFIG_DEBUG_FS extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev); @@ -1351,8 +1361,9 @@ void __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv); /* We give fast paths for the really cool registers */ #define NEEDS_FORCE_WAKE(dev_priv, reg) \ (((dev_priv)->info->gen >= 6) && \ - ((reg) < 0x40000) && \ - ((reg) != FORCEWAKE)) + ((reg) < 0x40000) && \ + ((reg) != FORCEWAKE) && \ + ((reg) != ECOBUS)) #define __i915_read(x, y) \ u##x i915_read##x(struct drm_i915_private *dev_priv, u32 reg); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6651c36b6e8..8359dc77704 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1396,7 +1396,7 @@ i915_gem_mmap_gtt(struct drm_file *file, if (obj->base.size > dev_priv->mm.gtt_mappable_end) { ret = -E2BIG; - goto unlock; + goto out; } if (obj->madv != I915_MADV_WILLNEED) { @@ -1745,7 +1745,7 @@ static void i915_gem_reset_fences(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int i; - for (i = 0; i < 16; i++) { + for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; struct drm_i915_gem_object *obj = reg->obj; @@ -3512,9 +3512,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data, * so emit a request to do so. */ request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request) + if (request) { ret = i915_add_request(obj->ring, NULL, request); - else + if (ret) + kfree(request); + } else ret = -ENOMEM; } @@ -3613,7 +3615,7 @@ struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, obj->base.write_domain = I915_GEM_DOMAIN_CPU; obj->base.read_domains = I915_GEM_DOMAIN_CPU; - if (IS_GEN6(dev)) { + if (IS_GEN6(dev) || IS_GEN7(dev)) { /* On Gen6, we can have the GPU use the LLC (the CPU * cache) for about a 10% performance improvement * compared to uncached. Graphics requests other than @@ -3877,7 +3879,7 @@ i915_gem_load(struct drm_device *dev) INIT_LIST_HEAD(&dev_priv->mm.gtt_list); for (i = 0; i < I915_NUM_RINGS; i++) init_ring_lists(&dev_priv->ring[i]); - for (i = 0; i < 16; i++) + for (i = 0; i < I915_MAX_NUM_FENCES; i++) INIT_LIST_HEAD(&dev_priv->fence_regs[i].lru_list); INIT_DELAYED_WORK(&dev_priv->mm.retire_work, i915_gem_retire_work_handler); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3693e83a97f..b9da8900ae4 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -32,6 +32,7 @@ #include "i915_drv.h" #include "i915_trace.h" #include "intel_drv.h" +#include <linux/dma_remapping.h> struct change_domains { uint32_t invalidate_domains; @@ -746,6 +747,22 @@ i915_gem_execbuffer_flush(struct drm_device *dev, return 0; } +static bool +intel_enable_semaphores(struct drm_device *dev) +{ + if (INTEL_INFO(dev)->gen < 6) + return 0; + + if (i915_semaphores >= 0) + return i915_semaphores; + + /* Disable semaphores on SNB */ + if (INTEL_INFO(dev)->gen == 6) + return 0; + + return 1; +} + static int i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, struct intel_ring_buffer *to) @@ -758,7 +775,7 @@ i915_gem_execbuffer_sync_rings(struct drm_i915_gem_object *obj, return 0; /* XXX gpu semaphores are implicated in various hard hangs on SNB */ - if (INTEL_INFO(obj->base.dev)->gen < 6 || !i915_semaphores) + if (!intel_enable_semaphores(obj->base.dev)) return i915_gem_object_wait_rendering(obj); idx = intel_ring_sync_index(from, to); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9ee2729fe5c..b40004b5597 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -824,6 +824,7 @@ static void i915_gem_record_fences(struct drm_device *dev, /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 5a09416e611..a26d5b0a369 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1553,12 +1553,21 @@ */ #define PP_READY (1 << 30) #define PP_SEQUENCE_NONE (0 << 28) -#define PP_SEQUENCE_ON (1 << 28) -#define PP_SEQUENCE_OFF (2 << 28) -#define PP_SEQUENCE_MASK 0x30000000 +#define PP_SEQUENCE_POWER_UP (1 << 28) +#define PP_SEQUENCE_POWER_DOWN (2 << 28) +#define PP_SEQUENCE_MASK (3 << 28) +#define PP_SEQUENCE_SHIFT 28 #define PP_CYCLE_DELAY_ACTIVE (1 << 27) -#define PP_SEQUENCE_STATE_ON_IDLE (1 << 3) #define PP_SEQUENCE_STATE_MASK 0x0000000f +#define PP_SEQUENCE_STATE_OFF_IDLE (0x0 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_1 (0x1 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_2 (0x2 << 0) +#define PP_SEQUENCE_STATE_OFF_S0_3 (0x3 << 0) +#define PP_SEQUENCE_STATE_ON_IDLE (0x8 << 0) +#define PP_SEQUENCE_STATE_ON_S1_0 (0x9 << 0) +#define PP_SEQUENCE_STATE_ON_S1_2 (0xa << 0) +#define PP_SEQUENCE_STATE_ON_S1_3 (0xb << 0) +#define PP_SEQUENCE_STATE_RESET (0xf << 0) #define PP_CONTROL 0x61204 #define POWER_TARGET_ON (1 << 0) #define PP_ON_DELAYS 0x61208 @@ -3294,10 +3303,10 @@ /* or SDVOB */ #define HDMIB 0xe1140 #define PORT_ENABLE (1 << 31) -#define TRANSCODER_A (0) -#define TRANSCODER_B (1 << 30) -#define TRANSCODER(pipe) ((pipe) << 30) -#define TRANSCODER_MASK (1 << 30) +#define TRANSCODER(pipe) ((pipe) << 30) +#define TRANSCODER_CPT(pipe) ((pipe) << 29) +#define TRANSCODER_MASK (1 << 30) +#define TRANSCODER_MASK_CPT (3 << 29) #define COLOR_FORMAT_8bpc (0) #define COLOR_FORMAT_12bpc (3 << 26) #define SDVOB_HOTPLUG_ENABLE (1 << 23) @@ -3438,12 +3447,38 @@ #define EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B (0x38<<22) #define EDP_LINK_TRAIN_VOL_EMP_MASK_SNB (0x3f<<22) +/* IVB */ +#define EDP_LINK_TRAIN_400MV_0DB_IVB (0x24 <<22) +#define EDP_LINK_TRAIN_400MV_3_5DB_IVB (0x2a <<22) +#define EDP_LINK_TRAIN_400MV_6DB_IVB (0x2f <<22) +#define EDP_LINK_TRAIN_600MV_0DB_IVB (0x30 <<22) +#define EDP_LINK_TRAIN_600MV_3_5DB_IVB (0x36 <<22) +#define EDP_LINK_TRAIN_800MV_0DB_IVB (0x38 <<22) +#define EDP_LINK_TRAIN_800MV_3_5DB_IVB (0x33 <<22) + +/* legacy values */ +#define EDP_LINK_TRAIN_500MV_0DB_IVB (0x00 <<22) +#define EDP_LINK_TRAIN_1000MV_0DB_IVB (0x20 <<22) +#define EDP_LINK_TRAIN_500MV_3_5DB_IVB (0x02 <<22) +#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB (0x22 <<22) +#define EDP_LINK_TRAIN_1000MV_6DB_IVB (0x23 <<22) + +#define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) + #define FORCEWAKE 0xA18C #define FORCEWAKE_ACK 0x130090 +#define FORCEWAKE_MT 0xa188 /* multi-threaded */ +#define FORCEWAKE_MT_ACK 0x130040 +#define ECOBUS 0xa180 +#define FORCEWAKE_MT_ENABLE (1<<5) #define GT_FIFO_FREE_ENTRIES 0x120008 #define GT_FIFO_NUM_RESERVED_ENTRIES 20 +#define GEN6_UCGCTL2 0x9404 +# define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) +# define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) + #define GEN6_RPNSWREQ 0xA008 #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index f8f602d7665..7886e4fb60e 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -370,6 +370,7 @@ static void i915_save_modeset_reg(struct drm_device *dev) /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) dev_priv->saveFENCE[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8)); @@ -404,6 +405,7 @@ static void i915_restore_modeset_reg(struct drm_device *dev) /* Fences */ switch (INTEL_INFO(dev)->gen) { + case 7: case 6: for (i = 0; i < 16; i++) I915_WRITE64(FENCE_REG_SANDYBRIDGE_0 + (i * 8), dev_priv->saveFENCE[i]); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 981b1f1c04d..daa5743ccbd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -38,8 +38,8 @@ #include "i915_drv.h" #include "i915_trace.h" #include "drm_dp_helper.h" - #include "drm_crtc_helper.h" +#include <linux/dma_remapping.h> #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) @@ -2933,7 +2933,8 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) /* For PCH DP, enable TRANS_DP_CTL */ if (HAS_PCH_CPT(dev) && - intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) { + (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) || + intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) { u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPE_BPC_MASK) >> 5; reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); @@ -4669,6 +4670,7 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) /** * intel_choose_pipe_bpp_dither - figure out what color depth the pipe should send * @crtc: CRTC structure + * @mode: requested mode * * A pipe may be connected to one or more outputs. Based on the depth of the * attached framebuffer, choose a good color depth to use on the pipe. @@ -4680,13 +4682,15 @@ static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv) * HDMI supports only 8bpc or 12bpc, so clamp to 8bpc with dither for 10bpc * Displays may support a restricted set as well, check EDID and clamp as * appropriate. + * DP may want to dither down to 6bpc to fit larger modes * * RETURNS: * Dithering requirement (i.e. false if display bpc and pipe bpc match, * true if they don't match). */ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, - unsigned int *pipe_bpp) + unsigned int *pipe_bpp, + struct drm_display_mode *mode) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4711,7 +4715,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, lvds_bpc = 6; if (lvds_bpc < display_bpc) { - DRM_DEBUG_DRIVER("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc); + DRM_DEBUG_KMS("clamping display bpc (was %d) to LVDS (%d)\n", display_bpc, lvds_bpc); display_bpc = lvds_bpc; } continue; @@ -4722,7 +4726,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, unsigned int edp_bpc = dev_priv->edp.bpp / 3; if (edp_bpc < display_bpc) { - DRM_DEBUG_DRIVER("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); + DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", display_bpc, edp_bpc); display_bpc = edp_bpc; } continue; @@ -4737,7 +4741,7 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, /* Don't use an invalid EDID bpc value */ if (connector->display_info.bpc && connector->display_info.bpc < display_bpc) { - DRM_DEBUG_DRIVER("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); + DRM_DEBUG_KMS("clamping display bpc (was %d) to EDID reported max of %d\n", display_bpc, connector->display_info.bpc); display_bpc = connector->display_info.bpc; } } @@ -4748,15 +4752,20 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, */ if (intel_encoder->type == INTEL_OUTPUT_HDMI) { if (display_bpc > 8 && display_bpc < 12) { - DRM_DEBUG_DRIVER("forcing bpc to 12 for HDMI\n"); + DRM_DEBUG_KMS("forcing bpc to 12 for HDMI\n"); display_bpc = 12; } else { - DRM_DEBUG_DRIVER("forcing bpc to 8 for HDMI\n"); + DRM_DEBUG_KMS("forcing bpc to 8 for HDMI\n"); display_bpc = 8; } } } + if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + DRM_DEBUG_KMS("Dithering DP to 6bpc\n"); + display_bpc = 6; + } + /* * We could just drive the pipe at the highest bpc all the time and * enable dithering as needed, but that costs bandwidth. So choose @@ -4789,8 +4798,8 @@ static bool intel_choose_pipe_bpp_dither(struct drm_crtc *crtc, display_bpc = min(display_bpc, bpc); - DRM_DEBUG_DRIVER("setting pipe bpc to %d (max display bpc %d)\n", - bpc, display_bpc); + DRM_DEBUG_KMS("setting pipe bpc to %d (max display bpc %d)\n", + bpc, display_bpc); *pipe_bpp = display_bpc * 3; @@ -5018,6 +5027,16 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_DOUBLE_WIDE; } + /* default to 8bpc */ + pipeconf &= ~(PIPECONF_BPP_MASK | PIPECONF_DITHER_EN); + if (is_dp) { + if (mode->private_flags & INTEL_MODE_DP_FORCE_6BPC) { + pipeconf |= PIPECONF_BPP_6 | + PIPECONF_DITHER_EN | + PIPECONF_DITHER_TYPE_SP; + } + } + dpll |= DPLL_VCO_ENABLE; DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B'); @@ -5479,7 +5498,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, /* determine panel color depth */ temp = I915_READ(PIPECONF(pipe)); temp &= ~PIPE_BPC_MASK; - dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp); + dither = intel_choose_pipe_bpp_dither(crtc, &pipe_bpp, mode); switch (pipe_bpp) { case 18: temp |= PIPE_6BPC; @@ -5671,7 +5690,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, pipeconf &= ~PIPECONF_DITHER_TYPE_MASK; if ((is_lvds && dev_priv->lvds_dither) || dither) { pipeconf |= PIPECONF_DITHER_EN; - pipeconf |= PIPECONF_DITHER_TYPE_ST1; + pipeconf |= PIPECONF_DITHER_TYPE_SP; } if (is_dp || intel_encoder_is_pch_edp(&has_edp_encoder->base)) { intel_dp_set_m_n(crtc, mode, adjusted_mode); @@ -7188,11 +7207,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->old_fb_obj = intel_fb->obj; INIT_WORK(&work->work, intel_unpin_work_fn); + ret = drm_vblank_get(dev, intel_crtc->pipe); + if (ret) + goto free_work; + /* We borrow the event spin lock for protecting unpin_work */ spin_lock_irqsave(&dev->event_lock, flags); if (intel_crtc->unpin_work) { spin_unlock_irqrestore(&dev->event_lock, flags); kfree(work); + drm_vblank_put(dev, intel_crtc->pipe); DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); return -EBUSY; @@ -7211,10 +7235,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, crtc->fb = fb; - ret = drm_vblank_get(dev, intel_crtc->pipe); - if (ret) - goto cleanup_objs; - work->pending_flip_obj = obj; work->enable_stall_check = true; @@ -7237,7 +7257,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_pending: atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip); -cleanup_objs: drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); @@ -7246,6 +7265,8 @@ cleanup_objs: intel_crtc->unpin_work = NULL; spin_unlock_irqrestore(&dev->event_lock, flags); + drm_vblank_put(dev, intel_crtc->pipe); +free_work: kfree(work); return ret; @@ -7886,6 +7907,31 @@ void intel_init_emon(struct drm_device *dev) dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK); } +static bool intel_enable_rc6(struct drm_device *dev) +{ + /* + * Respect the kernel parameter if it is set + */ + if (i915_enable_rc6 >= 0) + return i915_enable_rc6; + + /* + * Disable RC6 on Ironlake + */ + if (INTEL_INFO(dev)->gen == 5) + return 0; + + /* + * Disable rc6 on Sandybridge + */ + if (INTEL_INFO(dev)->gen == 6) { + DRM_DEBUG_DRIVER("Sandybridge: RC6 disabled\n"); + return 0; + } + DRM_DEBUG_DRIVER("RC6 enabled\n"); + return 1; +} + void gen6_enable_rps(struct drm_i915_private *dev_priv) { u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); @@ -7922,7 +7968,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv) I915_WRITE(GEN6_RC6p_THRESHOLD, 100000); I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */ - if (i915_enable_rc6) + if (intel_enable_rc6(dev_priv->dev)) rc6_mask = GEN6_RC_CTL_RC6p_ENABLE | GEN6_RC_CTL_RC6_ENABLE; @@ -8148,6 +8194,20 @@ static void gen6_init_clock_gating(struct drm_device *dev) I915_WRITE(WM2_LP_ILK, 0); I915_WRITE(WM1_LP_ILK, 0); + /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock + * gating disable must be set. Failure to set it results in + * flickering pixels due to Z write ordering failures after + * some amount of runtime in the Mesa "fire" demo, and Unigine + * Sanctuary and Tropics, and apparently anything else with + * alpha test or pixel discard. + * + * According to the spec, bit 11 (RCCUNIT) must also be set, + * but we didn't debug actual testcases to find it out. + */ + I915_WRITE(GEN6_UCGCTL2, + GEN6_RCPBUNIT_CLOCK_GATE_DISABLE | + GEN6_RCCUNIT_CLOCK_GATE_DISABLE); + /* * According to the spec the following bits should be * set in order to enable memory self-refresh and fbc: @@ -8357,7 +8417,7 @@ void ironlake_enable_rc6(struct drm_device *dev) /* rc6 disabled by default due to repeated reports of hanging during * boot and resume. */ - if (!i915_enable_rc6) + if (!intel_enable_rc6(dev)) return; mutex_lock(&dev->struct_mutex); @@ -8476,6 +8536,28 @@ static void intel_init_display(struct drm_device *dev) /* For FIFO watermark updates */ if (HAS_PCH_SPLIT(dev)) { + dev_priv->display.force_wake_get = __gen6_gt_force_wake_get; + dev_priv->display.force_wake_put = __gen6_gt_force_wake_put; + + /* IVB configs may use multi-threaded forcewake */ + if (IS_IVYBRIDGE(dev)) { + u32 ecobus; + + mutex_lock(&dev->struct_mutex); + __gen6_gt_force_wake_mt_get(dev_priv); + ecobus = I915_READ(ECOBUS); + __gen6_gt_force_wake_mt_put(dev_priv); + mutex_unlock(&dev->struct_mutex); + + if (ecobus & FORCEWAKE_MT_ENABLE) { + DRM_DEBUG_KMS("Using MT version of forcewake\n"); + dev_priv->display.force_wake_get = + __gen6_gt_force_wake_mt_get; + dev_priv->display.force_wake_put = + __gen6_gt_force_wake_mt_put; + } + } + if (HAS_PCH_IBX(dev)) dev_priv->display.init_pch_clock_gating = ibx_init_clock_gating; else if (HAS_PCH_CPT(dev)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 09b318b0227..92b041b66e4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -59,7 +59,6 @@ struct intel_dp { struct i2c_algo_dp_aux_data algo; bool is_pch_edp; uint8_t train_set[4]; - uint8_t link_status[DP_LINK_STATUS_SIZE]; int panel_power_up_delay; int panel_power_down_delay; int panel_power_cycle_delay; @@ -68,7 +67,6 @@ struct intel_dp { struct drm_display_mode *panel_fixed_mode; /* for eDP */ struct delayed_work panel_vdd_work; bool want_panel_vdd; - unsigned long panel_off_jiffies; }; /** @@ -157,16 +155,12 @@ intel_edp_link_config(struct intel_encoder *intel_encoder, static int intel_dp_max_lane_count(struct intel_dp *intel_dp) { - int max_lane_count = 4; - - if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) { - max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f; - switch (max_lane_count) { - case 1: case 2: case 4: - break; - default: - max_lane_count = 4; - } + int max_lane_count = intel_dp->dpcd[DP_MAX_LANE_COUNT] & 0x1f; + switch (max_lane_count) { + case 1: case 2: case 4: + break; + default: + max_lane_count = 4; } return max_lane_count; } @@ -214,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw) */ static int -intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock) +intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp) { struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int bpp = 24; - if (intel_crtc) + if (check_bpp) + bpp = check_bpp; + else if (intel_crtc) bpp = intel_crtc->bpp; return (pixel_clock * bpp + 9) / 10; @@ -239,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector, struct intel_dp *intel_dp = intel_attached_dp(connector); int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); int max_lanes = intel_dp_max_lane_count(intel_dp); + int max_rate, mode_rate; if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) @@ -248,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector, return MODE_PANEL; } - if (intel_dp_link_required(intel_dp, mode->clock) - > intel_dp_max_data_rate(max_link_clock, max_lanes)) - return MODE_CLOCK_HIGH; + mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0); + max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes); + + if (mode_rate > max_rate) { + mode_rate = intel_dp_link_required(intel_dp, + mode->clock, 18); + if (mode_rate > max_rate) + return MODE_CLOCK_HIGH; + else + mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC; + } if (mode->clock < 10000) return MODE_CLOCK_LOW; @@ -368,8 +373,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * clock divider. */ if (is_cpu_edp(intel_dp)) { - if (IS_GEN6(dev)) - aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ + if (IS_GEN6(dev) || IS_GEN7(dev)) + aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */ else aux_clock_divider = 225; /* eDP input clock at 450Mhz */ } else if (HAS_PCH_SPLIT(dev)) @@ -678,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, int lane_count, clock; int max_lane_count = intel_dp_max_lane_count(intel_dp); int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; + int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 0; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { @@ -695,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); - if (intel_dp_link_required(intel_dp, mode->clock) + if (intel_dp_link_required(intel_dp, mode->clock, bpp) <= link_avail) { intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; @@ -768,12 +774,11 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, continue; intel_dp = enc_to_intel_dp(encoder); - if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) { + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT || + intel_dp->base.type == INTEL_OUTPUT_EDP) + { lane_count = intel_dp->lane_count; break; - } else if (is_edp(intel_dp)) { - lane_count = dev_priv->edp.lanes; - break; } } @@ -810,6 +815,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -822,18 +828,32 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ironlake_edp_pll_off(encoder); } - intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; - intel_dp->DP |= intel_dp->color_range; + /* + * There are four kinds of DP registers: + * + * IBX PCH + * SNB CPU + * IVB CPU + * CPT PCH + * + * IBX PCH and CPU are the same for almost everything, + * except that the CPU DP PLL is configured in this + * register + * + * CPT PCH is quite different, having many bits moved + * to the TRANS_DP_CTL register instead. That + * configuration happens (oddly) in ironlake_pch_enable + */ + + /* Preserve the BIOS-computed detected bit. This is + * supposed to be read-only. + */ + intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED; + intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; - if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) - intel_dp->DP |= DP_SYNC_HS_HIGH; - if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) - intel_dp->DP |= DP_SYNC_VS_HIGH; + /* Handle DP bits in common between all three register formats */ - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) - intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; - else - intel_dp->DP |= DP_LINK_TRAIN_OFF; + intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; switch (intel_dp->lane_count) { case 1: @@ -852,59 +872,124 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; intel_write_eld(encoder, adjusted_mode); } - memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); intel_dp->link_configuration[0] = intel_dp->link_bw; intel_dp->link_configuration[1] = intel_dp->lane_count; intel_dp->link_configuration[8] = DP_SET_ANSI_8B10B; - /* * Check for DPCD version > 1.1 and enhanced framing support */ if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && (intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP)) { intel_dp->link_configuration[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - intel_dp->DP |= DP_ENHANCED_FRAMING; } - /* CPT DP's pipe select is decided in TRANS_DP_CTL */ - if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev)) - intel_dp->DP |= DP_PIPEB_SELECT; + /* Split out the IBX/CPU vs CPT settings */ + + if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) { + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + intel_dp->DP |= DP_SYNC_HS_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + intel_dp->DP |= DP_SYNC_VS_HIGH; + intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; + + if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) + intel_dp->DP |= DP_ENHANCED_FRAMING; + + intel_dp->DP |= intel_crtc->pipe << 29; - if (is_cpu_edp(intel_dp)) { /* don't miss out required setting for eDP */ intel_dp->DP |= DP_PLL_ENABLE; if (adjusted_mode->clock < 200000) intel_dp->DP |= DP_PLL_FREQ_160MHZ; else intel_dp->DP |= DP_PLL_FREQ_270MHZ; + } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) { + intel_dp->DP |= intel_dp->color_range; + + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) + intel_dp->DP |= DP_SYNC_HS_HIGH; + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) + intel_dp->DP |= DP_SYNC_VS_HIGH; + intel_dp->DP |= DP_LINK_TRAIN_OFF; + + if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN) + intel_dp->DP |= DP_ENHANCED_FRAMING; + + if (intel_crtc->pipe == 1) + intel_dp->DP |= DP_PIPEB_SELECT; + + if (is_cpu_edp(intel_dp)) { + /* don't miss out required setting for eDP */ + intel_dp->DP |= DP_PLL_ENABLE; + if (adjusted_mode->clock < 200000) + intel_dp->DP |= DP_PLL_FREQ_160MHZ; + else + intel_dp->DP |= DP_PLL_FREQ_270MHZ; + } + } else { + intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; } } -static void ironlake_wait_panel_off(struct intel_dp *intel_dp) +#define IDLE_ON_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) +#define IDLE_ON_VALUE (PP_ON | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_ON_IDLE) + +#define IDLE_OFF_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | 0 | PP_SEQUENCE_STATE_MASK) +#define IDLE_OFF_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) + +#define IDLE_CYCLE_MASK (PP_ON | 0 | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK) +#define IDLE_CYCLE_VALUE (0 | 0 | PP_SEQUENCE_NONE | 0 | PP_SEQUENCE_STATE_OFF_IDLE) + +static void ironlake_wait_panel_status(struct intel_dp *intel_dp, + u32 mask, + u32 value) { - unsigned long off_time; - unsigned long delay; + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; - DRM_DEBUG_KMS("Wait for panel power off time\n"); + DRM_DEBUG_KMS("mask %08x value %08x status %08x control %08x\n", + mask, value, + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); - if (ironlake_edp_have_panel_power(intel_dp) || - ironlake_edp_have_panel_vdd(intel_dp)) - { - DRM_DEBUG_KMS("Panel still on, no delay needed\n"); - return; + if (_wait_for((I915_READ(PCH_PP_STATUS) & mask) == value, 5000, 10)) { + DRM_ERROR("Panel status timeout: status %08x control %08x\n", + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); } +} - off_time = intel_dp->panel_off_jiffies + msecs_to_jiffies(intel_dp->panel_power_down_delay); - if (time_after(jiffies, off_time)) { - DRM_DEBUG_KMS("Time already passed"); - return; - } - delay = jiffies_to_msecs(off_time - jiffies); - if (delay > intel_dp->panel_power_down_delay) - delay = intel_dp->panel_power_down_delay; - DRM_DEBUG_KMS("Waiting an additional %ld ms\n", delay); - msleep(delay); +static void ironlake_wait_panel_on(struct intel_dp *intel_dp) +{ + DRM_DEBUG_KMS("Wait for panel power on\n"); + ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE); +} + +static void ironlake_wait_panel_off(struct intel_dp *intel_dp) +{ + DRM_DEBUG_KMS("Wait for panel power off time\n"); + ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE); +} + +static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp) +{ + DRM_DEBUG_KMS("Wait for panel power cycle\n"); + ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE); +} + + +/* Read the current pp_control value, unlocking the register if it + * is locked + */ + +static u32 ironlake_get_pp_control(struct drm_i915_private *dev_priv) +{ + u32 control = I915_READ(PCH_PP_CONTROL); + + control &= ~PANEL_UNLOCK_MASK; + control |= PANEL_UNLOCK_REGS; + return control; } static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) @@ -921,15 +1006,16 @@ static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) "eDP VDD already requested on\n"); intel_dp->want_panel_vdd = true; + if (ironlake_edp_have_panel_vdd(intel_dp)) { DRM_DEBUG_KMS("eDP VDD already on\n"); return; } - ironlake_wait_panel_off(intel_dp); - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; + if (!ironlake_edp_have_panel_power(intel_dp)) + ironlake_wait_panel_power_cycle(intel_dp); + + pp = ironlake_get_pp_control(dev_priv); pp |= EDP_FORCE_VDD; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -952,9 +1038,7 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) u32 pp; if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; + pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_FORCE_VDD; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -962,7 +1046,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) /* Make sure sequencer is idle before allowing subsequent activity */ DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); - intel_dp->panel_off_jiffies = jiffies; + + msleep(intel_dp->panel_power_down_delay); } } @@ -972,9 +1057,9 @@ static void ironlake_panel_vdd_work(struct work_struct *__work) struct intel_dp, panel_vdd_work); struct drm_device *dev = intel_dp->base.base.dev; - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev->mode_config.mutex); ironlake_panel_vdd_off_sync(intel_dp); - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->mode_config.mutex); } static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) @@ -984,7 +1069,7 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); - + intel_dp->want_panel_vdd = false; if (sync) { @@ -1000,23 +1085,25 @@ static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) } } -/* Returns true if the panel was already on when called */ static void ironlake_edp_panel_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE; + u32 pp; if (!is_edp(intel_dp)) return; - if (ironlake_edp_have_panel_power(intel_dp)) + + DRM_DEBUG_KMS("Turn eDP power on\n"); + + if (ironlake_edp_have_panel_power(intel_dp)) { + DRM_DEBUG_KMS("eDP power already on\n"); return; + } - ironlake_wait_panel_off(intel_dp); - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; + ironlake_wait_panel_power_cycle(intel_dp); + pp = ironlake_get_pp_control(dev_priv); if (IS_GEN5(dev)) { /* ILK workaround: disable reset around power sequence */ pp &= ~PANEL_POWER_RESET; @@ -1025,13 +1112,13 @@ static void ironlake_edp_panel_on(struct intel_dp *intel_dp) } pp |= POWER_TARGET_ON; + if (!IS_GEN5(dev)) + pp |= PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); - if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask, - 5000)) - DRM_ERROR("panel on wait timed out: 0x%08x\n", - I915_READ(PCH_PP_STATUS)); + ironlake_wait_panel_on(intel_dp); if (IS_GEN5(dev)) { pp |= PANEL_POWER_RESET; /* restore panel reset bit */ @@ -1040,46 +1127,25 @@ static void ironlake_edp_panel_on(struct intel_dp *intel_dp) } } -static void ironlake_edp_panel_off(struct drm_encoder *encoder) +static void ironlake_edp_panel_off(struct intel_dp *intel_dp) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_device *dev = encoder->dev; + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK | - PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK; + u32 pp; if (!is_edp(intel_dp)) return; - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; - if (IS_GEN5(dev)) { - /* ILK workaround: disable reset around power sequence */ - pp &= ~PANEL_POWER_RESET; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - } + DRM_DEBUG_KMS("Turn eDP power off\n"); - intel_dp->panel_off_jiffies = jiffies; + WARN(intel_dp->want_panel_vdd, "Cannot turn power off while VDD is on\n"); - if (IS_GEN5(dev)) { - pp &= ~POWER_TARGET_ON; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - pp &= ~POWER_TARGET_ON; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - msleep(intel_dp->panel_power_cycle_delay); - - if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000)) - DRM_ERROR("panel off wait timed out: 0x%08x\n", - I915_READ(PCH_PP_STATUS)); + pp = ironlake_get_pp_control(dev_priv); + pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); - pp |= PANEL_POWER_RESET; /* restore panel reset bit */ - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - } + ironlake_wait_panel_off(intel_dp); } static void ironlake_edp_backlight_on(struct intel_dp *intel_dp) @@ -1099,9 +1165,7 @@ static void ironlake_edp_backlight_on(struct intel_dp *intel_dp) * allowing it to appear. */ msleep(intel_dp->backlight_on_delay); - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; + pp = ironlake_get_pp_control(dev_priv); pp |= EDP_BLC_ENABLE; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -1117,9 +1181,7 @@ static void ironlake_edp_backlight_off(struct intel_dp *intel_dp) return; DRM_DEBUG_KMS("\n"); - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~PANEL_UNLOCK_MASK; - pp |= PANEL_UNLOCK_REGS; + pp = ironlake_get_pp_control(dev_priv); pp &= ~EDP_BLC_ENABLE; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -1187,17 +1249,18 @@ static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + ironlake_edp_backlight_off(intel_dp); + ironlake_edp_panel_off(intel_dp); + /* Wake up the sink first */ ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + intel_dp_link_down(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); /* Make sure the panel is off before trying to * change the mode */ - ironlake_edp_backlight_off(intel_dp); - intel_dp_link_down(intel_dp); - ironlake_edp_panel_off(encoder); } static void intel_dp_commit(struct drm_encoder *encoder) @@ -1211,7 +1274,6 @@ static void intel_dp_commit(struct drm_encoder *encoder) intel_dp_start_link_train(intel_dp); ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, true); - intel_dp_complete_link_train(intel_dp); ironlake_edp_backlight_on(intel_dp); @@ -1230,16 +1292,20 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { + ironlake_edp_backlight_off(intel_dp); + ironlake_edp_panel_off(intel_dp); + ironlake_edp_panel_vdd_on(intel_dp); - if (is_edp(intel_dp)) - ironlake_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); - ironlake_edp_panel_off(encoder); - if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) - ironlake_edp_pll_off(encoder); ironlake_edp_panel_vdd_off(intel_dp, false); + + if (is_cpu_edp(intel_dp)) + ironlake_edp_pll_off(encoder); } else { + if (is_cpu_edp(intel_dp)) + ironlake_edp_pll_on(encoder); + ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, mode); if (!(dp_reg & DP_PORT_EN)) { @@ -1247,7 +1313,6 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); - ironlake_edp_backlight_on(intel_dp); } else ironlake_edp_panel_vdd_off(intel_dp, false); ironlake_edp_backlight_on(intel_dp); @@ -1285,11 +1350,11 @@ intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address, * link status information */ static bool -intel_dp_get_link_status(struct intel_dp *intel_dp) +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { return intel_dp_aux_native_read_retry(intel_dp, DP_LANE0_1_STATUS, - intel_dp->link_status, + link_status, DP_LINK_STATUS_SIZE); } @@ -1301,27 +1366,25 @@ intel_dp_link_status(uint8_t link_status[DP_LINK_STATUS_SIZE], } static uint8_t -intel_get_adjust_request_voltage(uint8_t link_status[DP_LINK_STATUS_SIZE], +intel_get_adjust_request_voltage(uint8_t adjust_request[2], int lane) { - int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); int s = ((lane & 1) ? DP_ADJUST_VOLTAGE_SWING_LANE1_SHIFT : DP_ADJUST_VOLTAGE_SWING_LANE0_SHIFT); - uint8_t l = intel_dp_link_status(link_status, i); + uint8_t l = adjust_request[lane>>1]; return ((l >> s) & 3) << DP_TRAIN_VOLTAGE_SWING_SHIFT; } static uint8_t -intel_get_adjust_request_pre_emphasis(uint8_t link_status[DP_LINK_STATUS_SIZE], +intel_get_adjust_request_pre_emphasis(uint8_t adjust_request[2], int lane) { - int i = DP_ADJUST_REQUEST_LANE0_1 + (lane >> 1); int s = ((lane & 1) ? DP_ADJUST_PRE_EMPHASIS_LANE1_SHIFT : DP_ADJUST_PRE_EMPHASIS_LANE0_SHIFT); - uint8_t l = intel_dp_link_status(link_status, i); + uint8_t l = adjust_request[lane>>1]; return ((l >> s) & 3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; } @@ -1343,34 +1406,63 @@ static char *link_train_names[] = { * These are source-specific values; current Intel hardware supports * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB */ -#define I830_DP_VOLTAGE_MAX DP_TRAIN_VOLTAGE_SWING_800 static uint8_t -intel_dp_pre_emphasis_max(uint8_t voltage_swing) +intel_dp_voltage_max(struct intel_dp *intel_dp) { - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { - case DP_TRAIN_VOLTAGE_SWING_400: - return DP_TRAIN_PRE_EMPHASIS_6; - case DP_TRAIN_VOLTAGE_SWING_600: - return DP_TRAIN_PRE_EMPHASIS_6; - case DP_TRAIN_VOLTAGE_SWING_800: - return DP_TRAIN_PRE_EMPHASIS_3_5; - case DP_TRAIN_VOLTAGE_SWING_1200: - default: - return DP_TRAIN_PRE_EMPHASIS_0; + struct drm_device *dev = intel_dp->base.base.dev; + + if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) + return DP_TRAIN_VOLTAGE_SWING_800; + else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + return DP_TRAIN_VOLTAGE_SWING_1200; + else + return DP_TRAIN_VOLTAGE_SWING_800; +} + +static uint8_t +intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) +{ + struct drm_device *dev = intel_dp->base.base.dev; + + if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_600: + case DP_TRAIN_VOLTAGE_SWING_800: + return DP_TRAIN_PRE_EMPHASIS_3_5; + default: + return DP_TRAIN_PRE_EMPHASIS_0; + } + } else { + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) { + case DP_TRAIN_VOLTAGE_SWING_400: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_600: + return DP_TRAIN_PRE_EMPHASIS_6; + case DP_TRAIN_VOLTAGE_SWING_800: + return DP_TRAIN_PRE_EMPHASIS_3_5; + case DP_TRAIN_VOLTAGE_SWING_1200: + default: + return DP_TRAIN_PRE_EMPHASIS_0; + } } } static void -intel_get_adjust_train(struct intel_dp *intel_dp) +intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { uint8_t v = 0; uint8_t p = 0; int lane; + uint8_t *adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS); + uint8_t voltage_max; + uint8_t preemph_max; for (lane = 0; lane < intel_dp->lane_count; lane++) { - uint8_t this_v = intel_get_adjust_request_voltage(intel_dp->link_status, lane); - uint8_t this_p = intel_get_adjust_request_pre_emphasis(intel_dp->link_status, lane); + uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, lane); + uint8_t this_p = intel_get_adjust_request_pre_emphasis(adjust_request, lane); if (this_v > v) v = this_v; @@ -1378,18 +1470,20 @@ intel_get_adjust_train(struct intel_dp *intel_dp) p = this_p; } - if (v >= I830_DP_VOLTAGE_MAX) - v = I830_DP_VOLTAGE_MAX | DP_TRAIN_MAX_SWING_REACHED; + voltage_max = intel_dp_voltage_max(intel_dp); + if (v >= voltage_max) + v = voltage_max | DP_TRAIN_MAX_SWING_REACHED; - if (p >= intel_dp_pre_emphasis_max(v)) - p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + preemph_max = intel_dp_pre_emphasis_max(intel_dp, v); + if (p >= preemph_max) + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; for (lane = 0; lane < 4; lane++) intel_dp->train_set[lane] = v | p; } static uint32_t -intel_dp_signal_levels(uint8_t train_set, int lane_count) +intel_dp_signal_levels(uint8_t train_set) { uint32_t signal_levels = 0; @@ -1454,13 +1548,43 @@ intel_gen6_edp_signal_levels(uint8_t train_set) } } +/* Gen7's DP voltage swing and pre-emphasis control */ +static uint32_t +intel_gen7_edp_signal_levels(uint8_t train_set) +{ + int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + switch (signal_levels) { + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0: + return EDP_LINK_TRAIN_400MV_0DB_IVB; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5: + return EDP_LINK_TRAIN_400MV_3_5DB_IVB; + case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6: + return EDP_LINK_TRAIN_400MV_6DB_IVB; + + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0: + return EDP_LINK_TRAIN_600MV_0DB_IVB; + case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5: + return EDP_LINK_TRAIN_600MV_3_5DB_IVB; + + case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0: + return EDP_LINK_TRAIN_800MV_0DB_IVB; + case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5: + return EDP_LINK_TRAIN_800MV_3_5DB_IVB; + + default: + DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:" + "0x%x\n", signal_levels); + return EDP_LINK_TRAIN_500MV_0DB_IVB; + } +} + static uint8_t intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane) { - int i = DP_LANE0_1_STATUS + (lane >> 1); int s = (lane & 1) * 4; - uint8_t l = intel_dp_link_status(link_status, i); + uint8_t l = link_status[lane>>1]; return (l >> s) & 0xf; } @@ -1485,18 +1609,18 @@ intel_clock_recovery_ok(uint8_t link_status[DP_LINK_STATUS_SIZE], int lane_count DP_LANE_CHANNEL_EQ_DONE|\ DP_LANE_SYMBOL_LOCKED) static bool -intel_channel_eq_ok(struct intel_dp *intel_dp) +intel_channel_eq_ok(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { uint8_t lane_align; uint8_t lane_status; int lane; - lane_align = intel_dp_link_status(intel_dp->link_status, + lane_align = intel_dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED); if ((lane_align & DP_INTERLANE_ALIGN_DONE) == 0) return false; for (lane = 0; lane < intel_dp->lane_count; lane++) { - lane_status = intel_get_lane_status(intel_dp->link_status, lane); + lane_status = intel_get_lane_status(link_status, lane); if ((lane_status & CHANNEL_EQ_BITS) != CHANNEL_EQ_BITS) return false; } @@ -1521,8 +1645,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp, ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET, - intel_dp->train_set, 4); - if (ret != 4) + intel_dp->train_set, + intel_dp->lane_count); + if (ret != intel_dp->lane_count) return false; return true; @@ -1538,7 +1663,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) int i; uint8_t voltage; bool clock_recovery = false; - int tries; + int voltage_tries, loop_tries; u32 reg; uint32_t DP = intel_dp->DP; @@ -1559,26 +1684,35 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP_LINK_CONFIGURATION_SIZE); DP |= DP_PORT_EN; - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; memset(intel_dp->train_set, 0, 4); voltage = 0xff; - tries = 0; + voltage_tries = 0; + loop_tries = 0; clock_recovery = false; for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ + uint8_t link_status[DP_LINK_STATUS_SIZE]; uint32_t signal_levels; - if (IS_GEN6(dev) && is_edp(intel_dp)) { + + + if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); + DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; + } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); + DRM_DEBUG_KMS("training pattern 1 signal levels %08x\n", signal_levels); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) reg = DP | DP_LINK_TRAIN_PAT_1_CPT; else reg = DP | DP_LINK_TRAIN_PAT_1; @@ -1590,10 +1724,13 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) /* Set training pattern 1 */ udelay(100); - if (!intel_dp_get_link_status(intel_dp)) + if (!intel_dp_get_link_status(intel_dp, link_status)) { + DRM_ERROR("failed to get link status\n"); break; + } - if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { + if (intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { + DRM_DEBUG_KMS("clock recovery OK\n"); clock_recovery = true; break; } @@ -1602,20 +1739,30 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) for (i = 0; i < intel_dp->lane_count; i++) if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) break; - if (i == intel_dp->lane_count) - break; + if (i == intel_dp->lane_count) { + ++loop_tries; + if (loop_tries == 5) { + DRM_DEBUG_KMS("too many full retries, give up\n"); + break; + } + memset(intel_dp->train_set, 0, 4); + voltage_tries = 0; + continue; + } /* Check to see if we've tried the same voltage 5 times */ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { - ++tries; - if (tries == 5) + ++voltage_tries; + if (voltage_tries == 5) { + DRM_DEBUG_KMS("too many voltage retries, give up\n"); break; + } } else - tries = 0; + voltage_tries = 0; voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); + intel_get_adjust_train(intel_dp, link_status); } intel_dp->DP = DP; @@ -1638,6 +1785,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) for (;;) { /* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */ uint32_t signal_levels; + uint8_t link_status[DP_LINK_STATUS_SIZE]; if (cr_tries > 5) { DRM_ERROR("failed to train DP, aborting\n"); @@ -1645,15 +1793,18 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; } - if (IS_GEN6(dev) && is_edp(intel_dp)) { + if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) { + signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]); + DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels; + } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) { signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels; } else { - signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count); + signal_levels = intel_dp_signal_levels(intel_dp->train_set[0]); DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) reg = DP | DP_LINK_TRAIN_PAT_2_CPT; else reg = DP | DP_LINK_TRAIN_PAT_2; @@ -1665,17 +1816,17 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) break; udelay(400); - if (!intel_dp_get_link_status(intel_dp)) + if (!intel_dp_get_link_status(intel_dp, link_status)) break; /* Make sure clock is still ok */ - if (!intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) { + if (!intel_clock_recovery_ok(link_status, intel_dp->lane_count)) { intel_dp_start_link_train(intel_dp); cr_tries++; continue; } - if (intel_channel_eq_ok(intel_dp)) { + if (intel_channel_eq_ok(intel_dp, link_status)) { channel_eq = true; break; } @@ -1690,11 +1841,11 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) } /* Compute new intel_dp->train_set as requested by target */ - intel_get_adjust_train(intel_dp); + intel_get_adjust_train(intel_dp, link_status); ++tries; } - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) reg = DP | DP_LINK_TRAIN_OFF_CPT; else reg = DP | DP_LINK_TRAIN_OFF; @@ -1724,7 +1875,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) udelay(100); } - if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) { + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) { DP &= ~DP_LINK_TRAIN_MASK_CPT; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); } else { @@ -1735,8 +1886,12 @@ intel_dp_link_down(struct intel_dp *intel_dp) msleep(17); - if (is_edp(intel_dp)) - DP |= DP_LINK_TRAIN_OFF; + if (is_edp(intel_dp)) { + if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) + DP |= DP_LINK_TRAIN_OFF_CPT; + else + DP |= DP_LINK_TRAIN_OFF; + } if (!HAS_PCH_CPT(dev) && I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) { @@ -1822,6 +1977,7 @@ static void intel_dp_check_link_status(struct intel_dp *intel_dp) { u8 sink_irq_vector; + u8 link_status[DP_LINK_STATUS_SIZE]; if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1830,7 +1986,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) return; /* Try to read receiver status if the link appears to be up */ - if (!intel_dp_get_link_status(intel_dp)) { + if (!intel_dp_get_link_status(intel_dp, link_status)) { intel_dp_link_down(intel_dp); return; } @@ -1855,7 +2011,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } - if (!intel_channel_eq_ok(intel_dp)) { + if (!intel_channel_eq_ok(intel_dp, link_status)) { DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", drm_get_encoder_name(&intel_dp->base.base)); intel_dp_start_link_train(intel_dp); @@ -2179,7 +2335,8 @@ intel_trans_dp_port_sel(struct drm_crtc *crtc) continue; intel_dp = enc_to_intel_dp(encoder); - if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) + if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT || + intel_dp->base.type == INTEL_OUTPUT_EDP) return intel_dp->output_reg; } @@ -2321,7 +2478,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >> PANEL_LIGHT_ON_DELAY_SHIFT; - + cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >> PANEL_LIGHT_OFF_DELAY_SHIFT; @@ -2354,11 +2511,10 @@ intel_dp_init(struct drm_device *dev, int output_reg) DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); - intel_dp->panel_off_jiffies = jiffies - intel_dp->panel_power_down_delay; - ironlake_edp_panel_vdd_on(intel_dp); ret = intel_dp_get_dpcd(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, false); + if (ret) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) dev_priv->no_aux_handshake = diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bd9a604b73d..a1b4343814e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -110,6 +110,7 @@ /* drm_display_mode->private_flags */ #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0) #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT) +#define INTEL_MODE_DP_FORCE_6BPC (0x10) static inline void intel_mode_set_pixel_multiplier(struct drm_display_mode *mode, diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 42f165a520d..e44191132ac 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -715,6 +715,14 @@ static const struct dmi_system_id intel_no_lvds[] = { DMI_MATCH(DMI_PRODUCT_NAME, "EB1007"), }, }, + { + .callback = intel_no_lvds_dmi_callback, + .ident = "Asus AT5NM10T-I", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."), + DMI_MATCH(DMI_BOARD_NAME, "AT5NM10T-I"), + }, + }, { } /* terminating entry */ }; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 499d4c0dbee..04d79fd1dc9 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -178,13 +178,10 @@ u32 intel_panel_get_max_backlight(struct drm_device *dev) if (HAS_PCH_SPLIT(dev)) { max >>= 16; } else { - if (IS_PINEVIEW(dev)) { + if (INTEL_INFO(dev)->gen < 4) max >>= 17; - } else { + else max >>= 16; - if (INTEL_INFO(dev)->gen < 4) - max &= ~1; - } if (is_backlight_combination_mode(dev)) max *= 0xff; @@ -203,13 +200,12 @@ u32 intel_panel_get_backlight(struct drm_device *dev) val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; } else { val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK; - if (IS_PINEVIEW(dev)) + if (INTEL_INFO(dev)->gen < 4) val >>= 1; if (is_backlight_combination_mode(dev)) { u8 lbpc; - val &= ~1; pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc); val *= lbpc; } @@ -246,11 +242,9 @@ static void intel_panel_actually_set_backlight(struct drm_device *dev, u32 level } tmp = I915_READ(BLC_PWM_CTL); - if (IS_PINEVIEW(dev)) { - tmp &= ~(BACKLIGHT_DUTY_CYCLE_MASK - 1); + if (INTEL_INFO(dev)->gen < 4) level <<= 1; - } else - tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; + tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK; I915_WRITE(BLC_PWM_CTL, tmp | level); } @@ -326,7 +320,8 @@ static int intel_panel_update_status(struct backlight_device *bd) static int intel_panel_get_brightness(struct backlight_device *bd) { struct drm_device *dev = bl_get_data(bd); - return intel_panel_get_backlight(dev); + struct drm_i915_private *dev_priv = dev->dev_private; + return dev_priv->backlight_level; } static const struct backlight_ops intel_panel_bl_ops = { diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 3003fb25aef..f7b9268df26 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -50,6 +50,7 @@ #define IS_TMDS(c) (c->output_flag & SDVO_TMDS_MASK) #define IS_LVDS(c) (c->output_flag & SDVO_LVDS_MASK) #define IS_TV_OR_LVDS(c) (c->output_flag & (SDVO_TV_MASK | SDVO_LVDS_MASK)) +#define IS_DIGITAL(c) (c->output_flag & (SDVO_TMDS_MASK | SDVO_LVDS_MASK)) static const char *tv_format_names[] = { @@ -1086,8 +1087,12 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder, } sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; } - if (intel_crtc->pipe == 1) - sdvox |= SDVO_PIPE_B_SELECT; + + if (INTEL_PCH_TYPE(dev) >= PCH_CPT) + sdvox |= TRANSCODER_CPT(intel_crtc->pipe); + else + sdvox |= TRANSCODER(intel_crtc->pipe); + if (intel_sdvo->has_hdmi_audio) sdvox |= SDVO_AUDIO_ENABLE; @@ -1314,6 +1319,18 @@ intel_sdvo_tmds_sink_detect(struct drm_connector *connector) return status; } +static bool +intel_sdvo_connector_matches_edid(struct intel_sdvo_connector *sdvo, + struct edid *edid) +{ + bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); + bool connector_is_digital = !!IS_DIGITAL(sdvo); + + DRM_DEBUG_KMS("connector_is_digital? %d, monitor_is_digital? %d\n", + connector_is_digital, monitor_is_digital); + return connector_is_digital == monitor_is_digital; +} + static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector, bool force) { @@ -1358,10 +1375,12 @@ intel_sdvo_detect(struct drm_connector *connector, bool force) if (edid == NULL) edid = intel_sdvo_get_analog_edid(connector); if (edid != NULL) { - if (edid->input & DRM_EDID_INPUT_DIGITAL) - ret = connector_status_disconnected; - else + if (intel_sdvo_connector_matches_edid(intel_sdvo_connector, + edid)) ret = connector_status_connected; + else + ret = connector_status_disconnected; + connector->display_info.raw_edid = NULL; kfree(edid); } else @@ -1402,11 +1421,8 @@ static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) edid = intel_sdvo_get_analog_edid(connector); if (edid != NULL) { - struct intel_sdvo_connector *intel_sdvo_connector = to_intel_sdvo_connector(connector); - bool monitor_is_digital = !!(edid->input & DRM_EDID_INPUT_DIGITAL); - bool connector_is_digital = !!IS_TMDS(intel_sdvo_connector); - - if (connector_is_digital == monitor_is_digital) { + if (intel_sdvo_connector_matches_edid(to_intel_sdvo_connector(connector), + edid)) { drm_mode_connector_update_edid_property(connector, edid); drm_add_edid_modes(connector, edid); } diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 032a8209813..5fc201b49d3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -640,10 +640,9 @@ static int nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk) { struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t reg0 = nv_rd32(dev, reg + 0); - uint32_t reg1 = nv_rd32(dev, reg + 4); struct nouveau_pll_vals pll; struct pll_lims pll_limits; + u32 ctrl, mask, coef; int ret; ret = get_pll_limits(dev, reg, &pll_limits); @@ -654,15 +653,20 @@ nv50_pll_set(struct drm_device *dev, uint32_t reg, uint32_t clk) if (!clk) return -ERANGE; - reg0 = (reg0 & 0xfff8ffff) | (pll.log2P << 16); - reg1 = (reg1 & 0xffff0000) | (pll.N1 << 8) | pll.M1; - - if (dev_priv->vbios.execute) { - still_alive(); - nv_wr32(dev, reg + 4, reg1); - nv_wr32(dev, reg + 0, reg0); + coef = pll.N1 << 8 | pll.M1; + ctrl = pll.log2P << 16; + mask = 0x00070000; + if (reg == 0x004008) { + mask |= 0x01f80000; + ctrl |= (pll_limits.log2p_bias << 19); + ctrl |= (pll.log2P << 22); } + if (!dev_priv->vbios.execute) + return 0; + + nv_mask(dev, reg + 0, mask, ctrl); + nv_wr32(dev, reg + 4, coef); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 7226f419e17..7cc37e69086 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -148,7 +148,7 @@ set_placement_range(struct nouveau_bo *nvbo, uint32_t type) if (dev_priv->card_type == NV_10 && nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && - nvbo->bo.mem.num_pages < vram_pages / 2) { + nvbo->bo.mem.num_pages < vram_pages / 4) { /* * Make sure that the color and depth buffers are handled * by independent memory controller units. Up to a 9x diff --git a/drivers/gpu/drm/nouveau/nouveau_channel.c b/drivers/gpu/drm/nouveau/nouveau_channel.c index a319d5646ea..bb6ec9ef867 100644 --- a/drivers/gpu/drm/nouveau/nouveau_channel.c +++ b/drivers/gpu/drm/nouveau/nouveau_channel.c @@ -158,6 +158,7 @@ nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, INIT_LIST_HEAD(&chan->nvsw.vbl_wait); INIT_LIST_HEAD(&chan->nvsw.flip); INIT_LIST_HEAD(&chan->fence.pending); + spin_lock_init(&chan->fence.lock); /* setup channel's memory and vm */ ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index e0d275e1c96..cea6696b190 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -710,7 +710,7 @@ nouveau_connector_mode_valid(struct drm_connector *connector, case OUTPUT_DP: max_clock = nv_encoder->dp.link_nr; max_clock *= nv_encoder->dp.link_bw; - clock = clock * nouveau_connector_bpp(connector) / 8; + clock = clock * nouveau_connector_bpp(connector) / 10; break; default: BUG_ON(1); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index ddbabefb427..b12fd2c8081 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -369,3 +369,48 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, spin_unlock_irqrestore(&dev->event_lock, flags); return 0; } + +int +nouveau_display_dumb_create(struct drm_file *file_priv, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct nouveau_bo *bo; + int ret; + + args->pitch = roundup(args->width * (args->bpp / 8), 256); + args->size = args->pitch * args->height; + args->size = roundup(args->size, PAGE_SIZE); + + ret = nouveau_gem_new(dev, args->size, 0, TTM_PL_FLAG_VRAM, 0, 0, &bo); + if (ret) + return ret; + + ret = drm_gem_handle_create(file_priv, bo->gem, &args->handle); + drm_gem_object_unreference_unlocked(bo->gem); + return ret; +} + +int +nouveau_display_dumb_destroy(struct drm_file *file_priv, struct drm_device *dev, + uint32_t handle) +{ + return drm_gem_handle_delete(file_priv, handle); +} + +int +nouveau_display_dumb_map_offset(struct drm_file *file_priv, + struct drm_device *dev, + uint32_t handle, uint64_t *poffset) +{ + struct drm_gem_object *gem; + + gem = drm_gem_object_lookup(dev, file_priv, handle); + if (gem) { + struct nouveau_bo *bo = gem->driver_private; + *poffset = bo->bo.addr_space_offset; + drm_gem_object_unreference_unlocked(gem); + return 0; + } + + return -ENOENT; +} diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index 9f7bb129526..9791d13c9e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -433,6 +433,10 @@ static struct drm_driver driver = { .gem_open_object = nouveau_gem_object_open, .gem_close_object = nouveau_gem_object_close, + .dumb_create = nouveau_display_dumb_create, + .dumb_map_offset = nouveau_display_dumb_map_offset, + .dumb_destroy = nouveau_display_dumb_destroy, + .name = DRIVER_NAME, .desc = DRIVER_DESC, #ifdef GIT_REVISION diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 29837da1098..4c0be3a4ed8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1418,6 +1418,12 @@ int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event); int nouveau_finish_page_flip(struct nouveau_channel *, struct nouveau_page_flip_state *); +int nouveau_display_dumb_create(struct drm_file *, struct drm_device *, + struct drm_mode_create_dumb *args); +int nouveau_display_dumb_map_offset(struct drm_file *, struct drm_device *, + uint32_t handle, uint64_t *offset); +int nouveau_display_dumb_destroy(struct drm_file *, struct drm_device *, + uint32_t handle); /* nv10_gpio.c */ int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 14a8627efe4..3a4cc32b9e4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -487,6 +487,7 @@ int nouveau_fbcon_init(struct drm_device *dev) { struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_fbdev *nfbdev; + int preferred_bpp; int ret; nfbdev = kzalloc(sizeof(struct nouveau_fbdev), GFP_KERNEL); @@ -505,7 +506,15 @@ int nouveau_fbcon_init(struct drm_device *dev) } drm_fb_helper_single_add_all_connectors(&nfbdev->helper); - drm_fb_helper_initial_config(&nfbdev->helper, 32); + + if (dev_priv->vram_size <= 32 * 1024 * 1024) + preferred_bpp = 8; + else if (dev_priv->vram_size <= 64 * 1024 * 1024) + preferred_bpp = 16; + else + preferred_bpp = 32; + + drm_fb_helper_initial_config(&nfbdev->helper, preferred_bpp); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 81116cfea27..2f6daae68b9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -539,8 +539,6 @@ nouveau_fence_channel_init(struct nouveau_channel *chan) return ret; } - INIT_LIST_HEAD(&chan->fence.pending); - spin_lock_init(&chan->fence.lock); atomic_set(&chan->fence.last_sequence_irq, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_i2c.c b/drivers/gpu/drm/nouveau/nouveau_i2c.c index c6143df48b9..d39b2202b19 100644 --- a/drivers/gpu/drm/nouveau/nouveau_i2c.c +++ b/drivers/gpu/drm/nouveau/nouveau_i2c.c @@ -333,7 +333,7 @@ nouveau_i2c_identify(struct drm_device *dev, const char *what, NV_DEBUG(dev, "Probing %ss on I2C bus: %d\n", what, index); - for (i = 0; info[i].addr; i++) { + for (i = 0; i2c && info[i].addr; i++) { if (nouveau_probe_i2c_addr(i2c, info[i].addr) && (!match || match(i2c, &info[i]))) { NV_INFO(dev, "Detected %s: %s\n", what, info[i].type); diff --git a/drivers/gpu/drm/nouveau/nouveau_object.c b/drivers/gpu/drm/nouveau/nouveau_object.c index 02222c540ae..960c0ae0c0c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_object.c +++ b/drivers/gpu/drm/nouveau/nouveau_object.c @@ -680,7 +680,7 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan) return ret; } - ret = drm_mm_init(&chan->ramin_heap, base, size); + ret = drm_mm_init(&chan->ramin_heap, base, size - base); if (ret) { NV_ERROR(dev, "Error creating PRAMIN heap: %d\n", ret); nouveau_gpuobj_ref(NULL, &chan->ramin); diff --git a/drivers/gpu/drm/nouveau/nouveau_perf.c b/drivers/gpu/drm/nouveau/nouveau_perf.c index 9f178aa9416..33d03fbf00d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_perf.c +++ b/drivers/gpu/drm/nouveau/nouveau_perf.c @@ -239,7 +239,7 @@ nouveau_perf_init(struct drm_device *dev) if(version == 0x15) { memtimings->timing = kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); - if(!memtimings) { + if (!memtimings->timing) { NV_WARN(dev,"Could not allocate memtiming table\n"); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c index b75258a9fe4..c8a463b76c8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c +++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c @@ -67,7 +67,10 @@ nouveau_sgdma_clear(struct ttm_backend *be) pci_unmap_page(dev->pdev, nvbe->pages[nvbe->nr_pages], PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); } + nvbe->unmap_pages = false; } + + nvbe->pages = NULL; } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 82478e0998e..d8831ab42bb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -579,6 +579,14 @@ nouveau_card_init(struct drm_device *dev) if (ret) goto out_display_early; + /* workaround an odd issue on nvc1 by disabling the device's + * nosnoop capability. hopefully won't cause issues until a + * better fix is found - assuming there is one... + */ + if (dev_priv->chipset == 0xc1) { + nv_mask(dev, 0x00088080, 0x00000800, 0x00000000); + } + nouveau_pm_init(dev); ret = engine->vram.init(dev); @@ -1102,12 +1110,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags) dev_priv->noaccel = !!nouveau_noaccel; if (nouveau_noaccel == -1) { switch (dev_priv->chipset) { - case 0xc1: /* known broken */ - case 0xc8: /* never tested */ +#if 0 + case 0xXX: /* known broken */ NV_INFO(dev, "acceleration disabled by default, pass " "noaccel=0 to force enable\n"); dev_priv->noaccel = true; break; +#endif default: dev_priv->noaccel = false; break; diff --git a/drivers/gpu/drm/nouveau/nv40_pm.c b/drivers/gpu/drm/nouveau/nv40_pm.c index bbc0b9c7e1f..e676b0d5347 100644 --- a/drivers/gpu/drm/nouveau/nv40_pm.c +++ b/drivers/gpu/drm/nouveau/nv40_pm.c @@ -57,12 +57,14 @@ read_pll_2(struct drm_device *dev, u32 reg) int P = (ctrl & 0x00070000) >> 16; u32 ref = 27000, clk = 0; - if (ctrl & 0x80000000) + if ((ctrl & 0x80000000) && M1) { clk = ref * N1 / M1; - - if (!(ctrl & 0x00000100)) { - if (ctrl & 0x40000000) - clk = clk * N2 / M2; + if ((ctrl & 0x40000100) == 0x40000000) { + if (M2) + clk = clk * N2 / M2; + else + clk = 0; + } } return clk >> P; @@ -177,6 +179,11 @@ nv40_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) } /* memory clock */ + if (!perflvl->memory) { + info->mpll_ctrl = 0x00000000; + goto out; + } + ret = nv40_calc_pll(dev, 0x004020, &pll, perflvl->memory, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) @@ -264,6 +271,9 @@ nv40_pm_clocks_set(struct drm_device *dev, void *pre_state) mdelay(5); nv_mask(dev, 0x00c040, 0x00000333, info->ctrl); + if (!info->mpll_ctrl) + goto resume; + /* wait for vblank start on active crtcs, disable memory access */ for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index d23ca00e7d6..06de250fe61 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -616,7 +616,7 @@ nv50_display_unk10_handler(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nv50_display *disp = nv50_display(dev); u32 unk30 = nv_rd32(dev, 0x610030), mc; - int i, crtc, or, type = OUTPUT_ANY; + int i, crtc, or = 0, type = OUTPUT_ANY; NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); disp->irq.dcb = NULL; @@ -708,7 +708,7 @@ nv50_display_unk20_handler(struct drm_device *dev) struct nv50_display *disp = nv50_display(dev); u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0; struct dcb_entry *dcb; - int i, crtc, or, type = OUTPUT_ANY; + int i, crtc, or = 0, type = OUTPUT_ANY; NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); dcb = disp->irq.dcb; diff --git a/drivers/gpu/drm/nouveau/nv50_graph.c b/drivers/gpu/drm/nouveau/nv50_graph.c index 8c979b31ff6..ac601f7c4e1 100644 --- a/drivers/gpu/drm/nouveau/nv50_graph.c +++ b/drivers/gpu/drm/nouveau/nv50_graph.c @@ -131,8 +131,8 @@ nv50_graph_init(struct drm_device *dev, int engine) NV_DEBUG(dev, "\n"); /* master reset */ - nv_mask(dev, 0x000200, 0x00200100, 0x00000000); - nv_mask(dev, 0x000200, 0x00200100, 0x00200100); + nv_mask(dev, 0x000200, 0x00201000, 0x00000000); + nv_mask(dev, 0x000200, 0x00201000, 0x00201000); nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */ /* reset/enable traps and interrupts */ diff --git a/drivers/gpu/drm/nouveau/nv50_grctx.c b/drivers/gpu/drm/nouveau/nv50_grctx.c index d05c2c3b244..4b46d696856 100644 --- a/drivers/gpu/drm/nouveau/nv50_grctx.c +++ b/drivers/gpu/drm/nouveau/nv50_grctx.c @@ -601,7 +601,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx) gr_def(ctx, offset + 0x1c, 0x00880000); break; case 0x86: - gr_def(ctx, offset + 0x1c, 0x008c0000); + gr_def(ctx, offset + 0x1c, 0x018c0000); break; case 0x92: case 0x96: diff --git a/drivers/gpu/drm/nouveau/nv50_vram.c b/drivers/gpu/drm/nouveau/nv50_vram.c index 9da23838e63..2e45e57fd86 100644 --- a/drivers/gpu/drm/nouveau/nv50_vram.c +++ b/drivers/gpu/drm/nouveau/nv50_vram.c @@ -160,7 +160,7 @@ nv50_vram_rblock(struct drm_device *dev) colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; - banks = ((r4 & 0x01000000) ? 8 : 4); + banks = 1 << (((r4 & 0x03000000) >> 24) + 2); rowsize = parts * banks * (1 << colbits) * 8; predicted = rowsize << rowbitsa; diff --git a/drivers/gpu/drm/nouveau/nvc0_graph.c b/drivers/gpu/drm/nouveau/nvc0_graph.c index bbdbc51830c..ecfafd70cf0 100644 --- a/drivers/gpu/drm/nouveau/nvc0_graph.c +++ b/drivers/gpu/drm/nouveau/nvc0_graph.c @@ -157,8 +157,8 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR); struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; int i = 0, gpc, tp, ret; - u32 magic; ret = nouveau_gpuobj_new(dev, chan, 0x2000, 256, NVOBJ_FLAG_VM, &grch->unk408004); @@ -207,14 +207,37 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan) nv_wo32(grch->mmio, i++ * 4, 0x0041880c); nv_wo32(grch->mmio, i++ * 4, 0x80000018); - magic = 0x02180000; - nv_wo32(grch->mmio, i++ * 4, 0x00405830); - nv_wo32(grch->mmio, i++ * 4, magic); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x0324) { - u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800); - nv_wo32(grch->mmio, i++ * 4, reg); - nv_wo32(grch->mmio, i++ * 4, magic); + if (dev_priv->chipset != 0xc1) { + u32 magic = 0x02180000; + nv_wo32(grch->mmio, i++ * 4, 0x00405830); + nv_wo32(grch->mmio, i++ * 4, magic); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { + u32 reg = TP_UNIT(gpc, tp, 0x520); + nv_wo32(grch->mmio, i++ * 4, reg); + nv_wo32(grch->mmio, i++ * 4, magic); + magic += 0x0324; + } + } + } else { + u32 magic = 0x02180000; + nv_wo32(grch->mmio, i++ * 4, 0x00405830); + nv_wo32(grch->mmio, i++ * 4, magic | 0x0000218); + nv_wo32(grch->mmio, i++ * 4, 0x004064c4); + nv_wo32(grch->mmio, i++ * 4, 0x0086ffff); + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { + u32 reg = TP_UNIT(gpc, tp, 0x520); + nv_wo32(grch->mmio, i++ * 4, reg); + nv_wo32(grch->mmio, i++ * 4, (1 << 28) | magic); + magic += 0x0324; + } + for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { + u32 reg = TP_UNIT(gpc, tp, 0x544); + nv_wo32(grch->mmio, i++ * 4, reg); + nv_wo32(grch->mmio, i++ * 4, magic); + magic += 0x0324; + } } } @@ -358,6 +381,8 @@ nvc0_graph_init_gpc_0(struct drm_device *dev) u8 tpnr[GPC_MAX]; int i, gpc, tpc; + nv_wr32(dev, TP_UNIT(0, 0, 0x5c), 1); /* affects TFB offset queries */ + /* * TP ROP UNKVAL(magic_not_rop_nr) * 450: 4/0/0/0 2 3 diff --git a/drivers/gpu/drm/nouveau/nvc0_grctx.c b/drivers/gpu/drm/nouveau/nvc0_grctx.c index dd0e6a736b3..96b0b93d94c 100644 --- a/drivers/gpu/drm/nouveau/nvc0_grctx.c +++ b/drivers/gpu/drm/nouveau/nvc0_grctx.c @@ -1812,6 +1812,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan) /* calculate first set of magics */ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + gpc = -1; for (tp = 0; tp < priv->tp_total; tp++) { do { gpc = (gpc + 1) % priv->gpc_nr; @@ -1861,30 +1862,26 @@ nvc0_grctx_generate(struct nouveau_channel *chan) if (1) { u32 tp_mask = 0, tp_set = 0; - u8 tpnr[GPC_MAX]; + u8 tpnr[GPC_MAX], a, b; memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); for (gpc = 0; gpc < priv->gpc_nr; gpc++) tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8); - gpc = -1; - for (i = 0, gpc = -1; i < 32; i++) { - int ltp = i * (priv->tp_total - 1) / 32; - - do { - gpc = (gpc + 1) % priv->gpc_nr; - } while (!tpnr[gpc]); - tp = priv->tp_nr[gpc] - tpnr[gpc]--; + for (i = 0, gpc = -1, b = -1; i < 32; i++) { + a = (i * (priv->tp_total - 1)) / 32; + if (a != b) { + b = a; + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpnr[gpc]); + tp = priv->tp_nr[gpc] - tpnr[gpc]--; - tp_set |= 1 << ((gpc * 8) + tp); + tp_set |= 1 << ((gpc * 8) + tp); + } - do { - nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); - tp_set ^= tp_mask; - nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set); - tp_set ^= tp_mask; - } while (ltp == (++i * (priv->tp_total - 1) / 32)); - i--; + nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); + nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set ^ tp_mask); } } diff --git a/drivers/gpu/drm/nouveau/nvc0_vram.c b/drivers/gpu/drm/nouveau/nvc0_vram.c index edbfe9360ae..ce984d573a5 100644 --- a/drivers/gpu/drm/nouveau/nvc0_vram.c +++ b/drivers/gpu/drm/nouveau/nvc0_vram.c @@ -43,7 +43,7 @@ static const u8 types[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, + 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0 @@ -110,22 +110,26 @@ nvc0_vram_init(struct drm_device *dev) u32 bsize = nv_rd32(dev, 0x10f20c); u32 offset, length; bool uniform = true; - int ret, i; + int ret, part; NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize); /* read amount of vram attached to each memory controller */ - for (i = 0; i < parts; i++) { - u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000)); + part = 0; + while (parts) { + u32 psize = nv_rd32(dev, 0x11020c + (part++ * 0x1000)); + if (psize == 0) + continue; + parts--; + if (psize != bsize) { if (psize < bsize) bsize = psize; uniform = false; } - NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize); - + NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", part, psize); dev_priv->vram_size += (u64)psize << 20; } diff --git a/drivers/gpu/drm/nouveau/nvd0_display.c b/drivers/gpu/drm/nouveau/nvd0_display.c index 23d63b4b3d7..cb006a718e7 100644 --- a/drivers/gpu/drm/nouveau/nvd0_display.c +++ b/drivers/gpu/drm/nouveau/nvd0_display.c @@ -780,7 +780,7 @@ nvd0_sor_dpms(struct drm_encoder *encoder, int mode) continue; if (nv_partner != nv_encoder && - nv_partner->dcb->or == nv_encoder->or) { + nv_partner->dcb->or == nv_encoder->dcb->or) { if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) return; break; diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile index 9f363e0c4b6..cf8b4bc3e73 100644 --- a/drivers/gpu/drm/radeon/Makefile +++ b/drivers/gpu/drm/radeon/Makefile @@ -70,7 +70,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \ r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ - radeon_trace_points.o ni.o cayman_blit_shaders.o + radeon_trace_points.o ni.o cayman_blit_shaders.o atombios_encoders.o radeon-$(CONFIG_COMPAT) += radeon_ioc32.o radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a515b2a09d8..2b97262e3ab 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -558,7 +558,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, bpc = connector->display_info.bpc; encoder_mode = atombios_get_encoder_mode(encoder); if ((radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder)) { + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE)) { if (connector) { struct radeon_connector *radeon_connector = to_radeon_connector(connector); struct radeon_connector_atom_dig *dig_connector = @@ -638,44 +638,29 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, if (ss_enabled && ss->percentage) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE; - if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT) || - radeon_encoder_is_dp_bridge(encoder)) { + if (ENCODER_MODE_IS_DP(encoder_mode)) { + args.v3.sInput.ucDispPllConfig |= + DISPPLL_CONFIG_COHERENT_MODE; + /* 16200 or 27000 */ + args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); + } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (encoder_mode == ATOM_ENCODER_MODE_DP) { + if (encoder_mode == ATOM_ENCODER_MODE_HDMI) + /* deep color support */ + args.v3.sInput.usPixelClock = + cpu_to_le16((mode->clock * bpc / 8) / 10); + if (dig->coherent_mode) args.v3.sInput.ucDispPllConfig |= DISPPLL_CONFIG_COHERENT_MODE; - /* 16200 or 27000 */ - args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); - } else { - if (encoder_mode == ATOM_ENCODER_MODE_HDMI) { - /* deep color support */ - args.v3.sInput.usPixelClock = - cpu_to_le16((mode->clock * bpc / 8) / 10); - } - if (dig->coherent_mode) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_COHERENT_MODE; - if (mode->clock > 165000) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_DUAL_LINK; - } - } else if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (encoder_mode == ATOM_ENCODER_MODE_DP) { + if (mode->clock > 165000) args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_COHERENT_MODE; - /* 16200 or 27000 */ - args.v3.sInput.usPixelClock = cpu_to_le16(dp_clock / 10); - } else if (encoder_mode != ATOM_ENCODER_MODE_LVDS) { - if (mode->clock > 165000) - args.v3.sInput.ucDispPllConfig |= - DISPPLL_CONFIG_DUAL_LINK; - } + DISPPLL_CONFIG_DUAL_LINK; } - if (radeon_encoder_is_dp_bridge(encoder)) { - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); - args.v3.sInput.ucExtTransmitterID = ext_radeon_encoder->encoder_id; - } else + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != + ENCODER_OBJECT_ID_NONE) + args.v3.sInput.ucExtTransmitterID = + radeon_encoder_get_dp_bridge_encoder_id(encoder); + else args.v3.sInput.ucExtTransmitterID = 0; atom_execute_table(rdev->mode_info.atom_context, @@ -945,6 +930,7 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode bpc = connector->display_info.bpc; switch (encoder_mode) { + case ATOM_ENCODER_MODE_DP_MST: case ATOM_ENCODER_MODE_DP: /* DP/eDP */ dp_clock = dig_connector->dp_clock / 10; @@ -1121,9 +1107,40 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, return -EINVAL; } - if (tiling_flags & RADEON_TILING_MACRO) + if (tiling_flags & RADEON_TILING_MACRO) { + if (rdev->family >= CHIP_CAYMAN) + tmp = rdev->config.cayman.tile_config; + else + tmp = rdev->config.evergreen.tile_config; + + switch ((tmp & 0xf0) >> 4) { + case 0: /* 4 banks */ + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); + break; + case 1: /* 8 banks */ + default: + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); + break; + case 2: /* 16 banks */ + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); + break; + } + + switch ((tmp & 0xf000) >> 12) { + case 0: /* 1KB rows */ + default: + fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB); + break; + case 1: /* 2KB rows */ + fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB); + break; + case 2: /* 4KB rows */ + fb_format |= EVERGREEN_GRPH_TILE_SPLIT(EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB); + break; + } + fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); - else if (tiling_flags & RADEON_TILING_MICRO) + } else if (tiling_flags & RADEON_TILING_MICRO) fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); switch (radeon_crtc->crtc_id) { @@ -1450,7 +1467,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) * PPLL/DCPLL programming and only program the DP DTO for the * crtc virtual pixel clock. */ - if (atombios_get_encoder_mode(test_encoder) == ATOM_ENCODER_MODE_DP) { + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(test_encoder))) { if (ASIC_IS_DCE5(rdev) || rdev->clock.dp_extclk) return ATOM_PPLL_INVALID; } @@ -1536,12 +1553,6 @@ static bool atombios_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; - - /* adjust pm to upcoming mode change */ - radeon_pm_compute_clocks(rdev); - if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; return true; diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 79e8ebc0530..6fb335a4fdd 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -283,7 +283,7 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, } } - DRM_ERROR("aux i2c too many retries, giving up\n"); + DRM_DEBUG_KMS("aux i2c too many retries, giving up\n"); return -EREMOTEIO; } @@ -482,7 +482,8 @@ static int radeon_dp_get_dp_link_clock(struct drm_connector *connector, int bpp = convert_bpc_to_bpp(connector->display_info.bpc); int lane_num, max_pix_clock; - if (radeon_connector_encoder_is_dp_bridge(connector)) + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_NUTMEG) return 270000; lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock); @@ -553,17 +554,32 @@ static void radeon_dp_set_panel_mode(struct drm_encoder *encoder, { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; + struct radeon_connector *radeon_connector = to_radeon_connector(connector); int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; if (!ASIC_IS_DCE4(rdev)) return; - if (radeon_connector_encoder_is_dp_bridge(connector)) + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_NUTMEG) panel_mode = DP_PANEL_MODE_INTERNAL_DP1_MODE; + else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_TRAVIS) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + u8 tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + if (tmp & 1) + panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; + } atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP_PANEL_MODE, panel_mode); + + if ((connector->connector_type == DRM_MODE_CONNECTOR_eDP) && + (panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { + radeon_write_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_SET, 1); + } } void radeon_dp_set_link_config(struct drm_connector *connector, diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c new file mode 100644 index 00000000000..39c04c1b847 --- /dev/null +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -0,0 +1,2369 @@ +/* + * Copyright 2007-11 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + * Authors: Dave Airlie + * Alex Deucher + */ +#include "drmP.h" +#include "drm_crtc_helper.h" +#include "radeon_drm.h" +#include "radeon.h" +#include "atom.h" + +extern int atom_debug; + +/* evil but including atombios.h is much worse */ +bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, + struct drm_display_mode *mode); + + +static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + return true; + default: + return false; + } +} + +static struct drm_connector * +radeon_get_connector_for_encoder_init(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + radeon_connector = to_radeon_connector(connector); + if (radeon_encoder->devices & radeon_connector->devices) + return connector; + } + return NULL; +} + +static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + + /* set the active encoder to connector routing */ + radeon_encoder_set_active_device(encoder); + drm_mode_set_crtcinfo(adjusted_mode, 0); + + /* hw bug */ + if ((mode->flags & DRM_MODE_FLAG_INTERLACE) + && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) + adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; + + /* get the native mode for LVDS */ + if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) + radeon_panel_mode_fixup(encoder, adjusted_mode); + + /* get the native mode for TV */ + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { + struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; + if (tv_dac) { + if (tv_dac->tv_std == TV_STD_NTSC || + tv_dac->tv_std == TV_STD_NTSC_J || + tv_dac->tv_std == TV_STD_PAL_M) + radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); + else + radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); + } + } + + if (ASIC_IS_DCE3(rdev) && + ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE))) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + radeon_dp_set_link_config(connector, mode); + } + + return true; +} + +static void +atombios_dac_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DAC_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); + break; + } + + args.ucAction = action; + + if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_PS2; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.ucDacStandard = ATOM_DAC1_CV; + else { + switch (dac_info->tv_std) { + case TV_STD_PAL: + case TV_STD_PAL_M: + case TV_STD_SCART_PAL: + case TV_STD_SECAM: + case TV_STD_PAL_CN: + args.ucDacStandard = ATOM_DAC1_PAL; + break; + case TV_STD_NTSC: + case TV_STD_NTSC_J: + case TV_STD_PAL_60: + default: + args.ucDacStandard = ATOM_DAC1_NTSC; + break; + } + } + args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +static void +atombios_tv_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + TV_ENCODER_CONTROL_PS_ALLOCATION args; + int index = 0; + struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; + + memset(&args, 0, sizeof(args)); + + index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); + + args.sTVEncoder.ucAction = action; + + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.sTVEncoder.ucTvStandard = ATOM_TV_CV; + else { + switch (dac_info->tv_std) { + case TV_STD_NTSC: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + case TV_STD_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; + break; + case TV_STD_PAL_M: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; + break; + case TV_STD_PAL_60: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; + break; + case TV_STD_NTSC_J: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; + break; + case TV_STD_SCART_PAL: + args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ + break; + case TV_STD_SECAM: + args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; + break; + case TV_STD_PAL_CN: + args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; + break; + default: + args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; + break; + } + } + + args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dvo_encoder_control { + ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; + DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; + DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; +}; + +void +atombios_dvo_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + union dvo_encoder_control args; + int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + /* R4xx, R5xx */ + args.ext_tmds.sXTmdsEncoder.ucEnable = action; + + if (radeon_encoder->pixel_clock > 165000) + args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; + + args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; + break; + case 2: + /* RS600/690/740 */ + args.dvo.sDVOEncoder.ucAction = action; + args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + /* DFP1, CRT1, TV1 depending on the type of port */ + args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; + + if (radeon_encoder->pixel_clock > 165000) + args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; + break; + case 3: + /* R6xx */ + args.dvo_v3.ucAction = action; + args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.dvo_v3.ucDVOConfig = 0; /* XXX */ + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +union lvds_encoder_control { + LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; + LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; +}; + +void +atombios_digital_setup(struct drm_encoder *encoder, int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + union lvds_encoder_control args; + int index = 0; + int hdmi_detected = 0; + uint8_t frev, crev; + + if (!dig) + return; + + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) + hdmi_detected = 1; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); + break; + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + case 2: + switch (crev) { + case 1: + args.v1.ucMisc = 0; + args.v1.ucAction = action; + if (hdmi_detected) + args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; + } else { + if (dig->linkb) + args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; + /*if (pScrn->rgbBits == 8) */ + args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; + } + break; + case 2: + case 3: + args.v2.ucMisc = 0; + args.v2.ucAction = action; + if (crev == 3) { + if (dig->coherent_mode) + args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; + } + if (hdmi_detected) + args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v2.ucTruncate = 0; + args.v2.ucSpatial = 0; + args.v2.ucTemporal = 0; + args.v2.ucFRC = 0; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { + args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; + } + if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { + args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; + if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; + if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) + args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; + } + } else { + if (dig->linkb) + args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; + if (radeon_encoder->pixel_clock > 165000) + args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +int +atombios_get_encoder_mode(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct drm_connector *connector; + struct radeon_connector *radeon_connector; + struct radeon_connector_atom_dig *dig_connector; + + /* dp bridges are always DP */ + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) + return ATOM_ENCODER_MODE_DP; + + /* DVO is always DVO */ + if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) + return ATOM_ENCODER_MODE_DVO; + + connector = radeon_get_connector_for_encoder(encoder); + /* if we don't have an active device yet, just use one of + * the connectors tied to the encoder. + */ + if (!connector) + connector = radeon_get_connector_for_encoder_init(encoder); + radeon_connector = to_radeon_connector(connector); + + switch (connector->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else if (radeon_connector->use_digital) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_HDMIA: + default: + if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_LVDS: + return ATOM_ENCODER_MODE_LVDS; + break; + case DRM_MODE_CONNECTOR_DisplayPort: + dig_connector = radeon_connector->con_priv; + if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || + (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) + return ATOM_ENCODER_MODE_DP; + else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { + /* fix me */ + if (ASIC_IS_DCE4(rdev)) + return ATOM_ENCODER_MODE_DVI; + else + return ATOM_ENCODER_MODE_HDMI; + } else + return ATOM_ENCODER_MODE_DVI; + break; + case DRM_MODE_CONNECTOR_eDP: + return ATOM_ENCODER_MODE_DP; + case DRM_MODE_CONNECTOR_DVIA: + case DRM_MODE_CONNECTOR_VGA: + return ATOM_ENCODER_MODE_CRT; + break; + case DRM_MODE_CONNECTOR_Composite: + case DRM_MODE_CONNECTOR_SVIDEO: + case DRM_MODE_CONNECTOR_9PinDIN: + /* fix me */ + return ATOM_ENCODER_MODE_TV; + /*return ATOM_ENCODER_MODE_CV;*/ + break; + } +} + +/* + * DIG Encoder/Transmitter Setup + * + * DCE 3.0/3.1 + * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. + * Supports up to 3 digital outputs + * - 2 DIG encoder blocks. + * DIG1 can drive UNIPHY link A or link B + * DIG2 can drive UNIPHY link B or LVTMA + * + * DCE 3.2 + * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). + * Supports up to 5 digital outputs + * - 2 DIG encoder blocks. + * DIG1/2 can drive UNIPHY0/1/2 link A or link B + * + * DCE 4.0/5.0 + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). + * Supports up to 6 digital outputs + * - 6 DIG encoder blocks. + * - DIG to PHY mapping is hardcoded + * DIG1 drives UNIPHY0 link A, A+B + * DIG2 drives UNIPHY0 link B + * DIG3 drives UNIPHY1 link A, A+B + * DIG4 drives UNIPHY1 link B + * DIG5 drives UNIPHY2 link A, A+B + * DIG6 drives UNIPHY2 link B + * + * DCE 4.1 + * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). + * Supports up to 6 digital outputs + * - 2 DIG encoder blocks. + * DIG1/2 can drive UNIPHY0/1/2 link A or link B + * + * Routing + * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) + * Examples: + * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI + * crtc1 -> dig1 -> UNIPHY0 link B -> DP + * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS + * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI + */ + +union dig_encoder_control { + DIG_ENCODER_CONTROL_PS_ALLOCATION v1; + DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; + DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; + DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; +}; + +void +atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + union dig_encoder_control args; + int index = 0; + uint8_t frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int hpd_id = RADEON_HPD_NONE; + int bpc = 8; + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + hpd_id = radeon_connector->hpd.hpd; + bpc = connector->display_info.bpc; + } + + /* no dig encoder assigned */ + if (dig->dig_encoder == -1) + return; + + memset(&args, 0, sizeof(args)); + + if (ASIC_IS_DCE4(rdev)) + index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); + else { + if (dig->dig_encoder) + index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); + else + index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + args.v1.ucAction = action; + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v3.ucPanelMode = panel_mode; + else + args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v1.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v1.ucLaneNum = 8; + else + args.v1.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; + break; + } + if (dig->linkb) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; + else + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; + break; + case 2: + case 3: + args.v3.ucAction = action; + args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v3.ucPanelMode = panel_mode; + else + args.v3.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v3.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v3.ucLaneNum = 8; + else + args.v3.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode) && (dp_clock == 270000)) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; + args.v3.acConfig.ucDigSel = dig->dig_encoder; + switch (bpc) { + case 0: + args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + break; + case 4: + args.v4.ucAction = action; + args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) + args.v4.ucPanelMode = panel_mode; + else + args.v4.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) + args.v4.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v4.ucLaneNum = 8; + else + args.v4.ucLaneNum = 4; + + if (ENCODER_MODE_IS_DP(args.v1.ucEncoderMode)) { + if (dp_clock == 270000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; + } + args.v4.acConfig.ucDigSel = dig->dig_encoder; + switch (bpc) { + case 0: + args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + if (hpd_id == RADEON_HPD_NONE) + args.v4.ucHPD_ID = 0; + else + args.v4.ucHPD_ID = hpd_id + 1; + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + +} + +union dig_transmitter_control { + DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; + DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; +}; + +void +atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + struct drm_connector *connector; + union dig_transmitter_control args; + int index = 0; + uint8_t frev, crev; + bool is_dp = false; + int pll_id = 0; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + int igp_lane_info = 0; + int dig_encoder = dig->dig_encoder; + + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + connector = radeon_get_connector_for_encoder_init(encoder); + /* just needed to avoid bailing in the encoder check. the encoder + * isn't used for init + */ + dig_encoder = 0; + } else + connector = radeon_get_connector_for_encoder(encoder); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + igp_lane_info = dig_connector->igp_lane_info; + } + + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + pll_id = radeon_crtc->pll_id; + } + + /* no dig encoder assigned */ + if (dig_encoder == -1) + return; + + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder))) + is_dp = true; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); + break; + } + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + args.v1.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v1.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v1.asMode.ucLaneSel = lane_num; + args.v1.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v1.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; + + if (dig_encoder) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; + + if ((rdev->flags & RADEON_IS_IGP) && + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { + if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { + if (igp_lane_info & 0x1) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; + else if (igp_lane_info & 0x2) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; + else if (igp_lane_info & 0x4) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; + else if (igp_lane_info & 0x8) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; + } else { + if (igp_lane_info & 0x3) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; + else if (igp_lane_info & 0xc) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; + } + } + + if (dig->linkb) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; + else + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; + + if (is_dp) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; + if (radeon_encoder->pixel_clock > 165000) + args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; + } + break; + case 2: + args.v2.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v2.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v2.asMode.ucLaneSel = lane_num; + args.v2.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v2.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v2.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + args.v2.acConfig.ucEncoderSel = dig_encoder; + if (dig->linkb) + args.v2.acConfig.ucLinkSel = 1; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v2.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v2.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v2.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) { + args.v2.acConfig.fCoherentMode = 1; + args.v2.acConfig.fDPConnector = 1; + } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v2.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v2.acConfig.fDualLinkConnector = 1; + } + break; + case 3: + args.v3.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v3.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v3.asMode.ucLaneSel = lane_num; + args.v3.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v3.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v3.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + if (is_dp) + args.v3.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v3.ucLaneNum = 8; + else + args.v3.ucLaneNum = 4; + + if (dig->linkb) + args.v3.acConfig.ucLinkSel = 1; + if (dig_encoder & 1) + args.v3.acConfig.ucEncoderSel = 1; + + /* Select the PLL for the PHY + * DP PHY should be clocked from external src if there is + * one. + */ + /* On DCE4, if there is an external clock, it generates the DP ref clock */ + if (is_dp && rdev->clock.dp_extclk) + args.v3.acConfig.ucRefClkSource = 2; /* external src */ + else + args.v3.acConfig.ucRefClkSource = pll_id; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v3.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v3.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v3.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) + args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v3.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v3.acConfig.fDualLinkConnector = 1; + } + break; + case 4: + args.v4.ucAction = action; + if (action == ATOM_TRANSMITTER_ACTION_INIT) { + args.v4.usInitInfo = cpu_to_le16(connector_object_id); + } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { + args.v4.asMode.ucLaneSel = lane_num; + args.v4.asMode.ucLaneSet = lane_set; + } else { + if (is_dp) + args.v4.usPixelClock = + cpu_to_le16(dp_clock / 10); + else if (radeon_encoder->pixel_clock > 165000) + args.v4.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); + else + args.v4.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + } + + if (is_dp) + args.v4.ucLaneNum = dp_lane_count; + else if (radeon_encoder->pixel_clock > 165000) + args.v4.ucLaneNum = 8; + else + args.v4.ucLaneNum = 4; + + if (dig->linkb) + args.v4.acConfig.ucLinkSel = 1; + if (dig_encoder & 1) + args.v4.acConfig.ucEncoderSel = 1; + + /* Select the PLL for the PHY + * DP PHY should be clocked from external src if there is + * one. + */ + /* On DCE5 DCPLL usually generates the DP ref clock */ + if (is_dp) { + if (rdev->clock.dp_extclk) + args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; + else + args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; + } else + args.v4.acConfig.ucRefClkSource = pll_id; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + args.v4.acConfig.ucTransmitterSel = 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + args.v4.acConfig.ucTransmitterSel = 1; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + args.v4.acConfig.ucTransmitterSel = 2; + break; + } + + if (is_dp) + args.v4.acConfig.fCoherentMode = 1; /* DP requires coherent */ + else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { + if (dig->coherent_mode) + args.v4.acConfig.fCoherentMode = 1; + if (radeon_encoder->pixel_clock > 165000) + args.v4.acConfig.fDualLinkConnector = 1; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + break; + default: + DRM_ERROR("Unknown table version %d, %d\n", frev, crev); + break; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +bool +atombios_set_edp_panel_power(struct drm_connector *connector, int action) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_device *dev = radeon_connector->base.dev; + struct radeon_device *rdev = dev->dev_private; + union dig_transmitter_control args; + int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); + uint8_t frev, crev; + + if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) + goto done; + + if (!ASIC_IS_DCE4(rdev)) + goto done; + + if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && + (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) + goto done; + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + goto done; + + memset(&args, 0, sizeof(args)); + + args.v1.ucAction = action; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + /* wait for the panel to power up */ + if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { + int i; + + for (i = 0; i < 300; i++) { + if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) + return true; + mdelay(1); + } + return false; + } +done: + return true; +} + +union external_encoder_control { + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; + EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; +}; + +static void +atombios_external_encoder_setup(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int action) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); + union external_encoder_control args; + struct drm_connector *connector; + int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); + u8 frev, crev; + int dp_clock = 0; + int dp_lane_count = 0; + int connector_object_id = 0; + u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + int bpc = 8; + + if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) + connector = radeon_get_connector_for_encoder_init(encoder); + else + connector = radeon_get_connector_for_encoder(encoder); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector = + radeon_connector->con_priv; + + dp_clock = dig_connector->dp_clock; + dp_lane_count = dig_connector->dp_lane_count; + connector_object_id = + (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + bpc = connector->display_info.bpc; + } + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + /* no params on frev 1 */ + break; + case 2: + switch (crev) { + case 1: + case 2: + args.v1.sDigEncoder.ucAction = action; + args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v1.sDigEncoder.ucEncoderMode)) { + if (dp_clock == 270000) + args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; + args.v1.sDigEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v1.sDigEncoder.ucLaneNum = 8; + else + args.v1.sDigEncoder.ucLaneNum = 4; + break; + case 3: + args.v3.sExtEncoder.ucAction = action; + if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) + args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); + else + args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); + args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); + + if (ENCODER_MODE_IS_DP(args.v3.sExtEncoder.ucEncoderMode)) { + if (dp_clock == 270000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; + else if (dp_clock == 540000) + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; + args.v3.sExtEncoder.ucLaneNum = dp_lane_count; + } else if (radeon_encoder->pixel_clock > 165000) + args.v3.sExtEncoder.ucLaneNum = 8; + else + args.v3.sExtEncoder.ucLaneNum = 4; + switch (ext_enum) { + case GRAPH_OBJECT_ENUM_ID1: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; + break; + case GRAPH_OBJECT_ENUM_ID2: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; + break; + case GRAPH_OBJECT_ENUM_ID3: + args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; + break; + } + switch (bpc) { + case 0: + args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE; + break; + case 6: + args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR; + break; + case 8: + default: + args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; + break; + case 10: + args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR; + break; + case 12: + args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR; + break; + case 16: + args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR; + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); +} + +static void +atombios_yuv_setup(struct drm_encoder *encoder, bool enable) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + ENABLE_YUV_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); + uint32_t temp, reg; + + memset(&args, 0, sizeof(args)); + + if (rdev->family >= CHIP_R600) + reg = R600_BIOS_3_SCRATCH; + else + reg = RADEON_BIOS_3_SCRATCH; + + /* XXX: fix up scratch reg handling */ + temp = RREG32(reg); + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + WREG32(reg, (ATOM_S3_TV1_ACTIVE | + (radeon_crtc->crtc_id << 18))); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); + else + WREG32(reg, 0); + + if (enable) + args.ucEnable = ATOM_ENABLE; + args.ucCRTC = radeon_crtc->crtc_id; + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + WREG32(reg, temp); +} + +static void +radeon_atom_encoder_dpms_avivo(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; + int index = 0; + + memset(&args, 0, sizeof(args)); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); + else + index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); + break; + default: + return; + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + args.ucAction = ATOM_ENABLE; + /* workaround for DVOOutputControl on some RS690 systems */ + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { + u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); + WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + WREG32(RADEON_BIOS_3_SCRATCH, reg); + } else + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLON; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + args.ucAction = ATOM_DISABLE; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + args.ucAction = ATOM_LCD_BLOFF; + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + } + break; + } +} + +static void +radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + struct radeon_connector *radeon_connector = NULL; + struct radeon_connector_atom_dig *radeon_dig_connector = NULL; + + if (connector) { + radeon_connector = to_radeon_connector(connector); + radeon_dig_connector = radeon_connector->con_priv; + } + + switch (mode) { + case DRM_MODE_DPMS_ON: + /* some early dce3.2 boards have a bug in their transmitter control table */ + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + else + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + radeon_dig_connector->edp_on = true; + } + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + radeon_dp_link_train(encoder, connector); + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { + if (ASIC_IS_DCE4(rdev)) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_OFF); + radeon_dig_connector->edp_on = false; + } + } + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); + break; + } +} + +static void +radeon_atom_encoder_dpms_ext(struct drm_encoder *encoder, + struct drm_encoder *ext_encoder, + int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + + switch (mode) { + case DRM_MODE_DPMS_ON: + default: + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (ASIC_IS_DCE41(rdev)) { + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); + } else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); + break; + } +} + +static void +radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", + radeon_encoder->encoder_id, mode, radeon_encoder->devices, + radeon_encoder->active_device); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + radeon_atom_encoder_dpms_dig(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + if (ASIC_IS_DCE5(rdev)) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dvo_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dvo_setup(encoder, ATOM_DISABLE); + break; + } + } else if (ASIC_IS_DCE3(rdev)) + radeon_atom_encoder_dpms_dig(encoder, mode); + else + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (ASIC_IS_DCE5(rdev)) { + switch (mode) { + case DRM_MODE_DPMS_ON: + atombios_dac_setup(encoder, ATOM_ENABLE); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + atombios_dac_setup(encoder, ATOM_DISABLE); + break; + } + } else + radeon_atom_encoder_dpms_avivo(encoder, mode); + break; + default: + return; + } + + if (ext_encoder) + radeon_atom_encoder_dpms_ext(encoder, ext_encoder, mode); + + radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); + +} + +union crtc_source_param { + SELECT_CRTC_SOURCE_PS_ALLOCATION v1; + SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; +}; + +static void +atombios_set_encoder_crtc_source(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + union crtc_source_param args; + int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); + uint8_t frev, crev; + struct radeon_encoder_atom_dig *dig; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return; + + switch (frev) { + case 1: + switch (crev) { + case 1: + default: + if (ASIC_IS_AVIVO(rdev)) + args.v1.ucCRTC = radeon_crtc->crtc_id; + else { + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { + args.v1.ucCRTC = radeon_crtc->crtc_id; + } else { + args.v1.ucCRTC = radeon_crtc->crtc_id << 2; + } + } + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) + args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; + else + args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; + break; + } + break; + case 2: + args.v2.ucCRTC = radeon_crtc->crtc_id; + if (radeon_encoder_get_dp_bridge_encoder_id(encoder) != ENCODER_OBJECT_ID_NONE) { + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) + args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; + else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) + args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; + else + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + } else + args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + dig = radeon_encoder->enc_priv; + switch (dig->dig_encoder) { + case 0: + args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; + break; + case 1: + args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; + break; + case 2: + args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; + break; + case 3: + args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; + break; + case 4: + args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; + break; + case 5: + args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; + break; + } + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; + break; + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) + args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; + else + args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; + break; + } + break; + } + break; + default: + DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); + return; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + /* update scratch regs with new routing */ + radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); +} + +static void +atombios_apply_encoder_quirks(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + + /* Funky macbooks */ + if ((dev->pdev->device == 0x71C5) && + (dev->pdev->subsystem_vendor == 0x106b) && + (dev->pdev->subsystem_device == 0x0080)) { + if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { + uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); + + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; + lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; + + WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); + } + } + + /* set scaler clears this on some chips */ + if (ASIC_IS_AVIVO(rdev) && + (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { + if (ASIC_IS_DCE4(rdev)) { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, + EVERGREEN_INTERLEAVE_EN); + else + WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } else { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, + AVIVO_D1MODE_INTERLEAVE_EN); + else + WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); + } + } +} + +static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *test_encoder; + struct radeon_encoder_atom_dig *dig; + uint32_t dig_enc_in_use = 0; + + /* DCE4/5 */ + if (ASIC_IS_DCE4(rdev)) { + dig = radeon_encoder->enc_priv; + if (ASIC_IS_DCE41(rdev)) { + /* ontario follows DCE4 */ + if (rdev->family == CHIP_PALM) { + if (dig->linkb) + return 1; + else + return 0; + } else + /* llano follows DCE3.2 */ + return radeon_crtc->crtc_id; + } else { + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + if (dig->linkb) + return 1; + else + return 0; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + if (dig->linkb) + return 3; + else + return 2; + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (dig->linkb) + return 5; + else + return 4; + break; + } + } + } + + /* on DCE32 and encoder can driver any block so just crtc id */ + if (ASIC_IS_DCE32(rdev)) { + return radeon_crtc->crtc_id; + } + + /* on DCE3 - LVTMA can only be driven by DIGB */ + list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_test_encoder; + + if (encoder == test_encoder) + continue; + + if (!radeon_encoder_is_digital(test_encoder)) + continue; + + radeon_test_encoder = to_radeon_encoder(test_encoder); + dig = radeon_test_encoder->enc_priv; + + if (dig->dig_encoder >= 0) + dig_enc_in_use |= (1 << dig->dig_encoder); + } + + if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { + if (dig_enc_in_use & 0x2) + DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); + return 1; + } + if (!(dig_enc_in_use & 1)) + return 0; + return 1; +} + +/* This only needs to be called once at startup */ +void +radeon_atom_encoder_init(struct radeon_device *rdev) +{ + struct drm_device *dev = rdev->ddev; + struct drm_encoder *encoder; + + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); + break; + default: + break; + } + + if (ext_encoder && ASIC_IS_DCE41(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); + } +} + +static void +radeon_atom_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + radeon_encoder->pixel_clock = adjusted_mode->clock; + + if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { + if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) + atombios_yuv_setup(encoder, true); + else + atombios_yuv_setup(encoder, false); + } + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + if (ASIC_IS_DCE4(rdev)) { + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + /* setup and enable the encoder */ + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); + + /* enable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + } else { + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + + /* setup and enable the encoder and transmitter */ + atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_dvo_setup(encoder, ATOM_ENABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_ENABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { + if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_ENABLE); + else + atombios_tv_setup(encoder, ATOM_DISABLE); + } + break; + } + + if (ext_encoder) { + if (ASIC_IS_DCE41(rdev)) + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); + else + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); + } + + atombios_apply_encoder_quirks(encoder, adjusted_mode); + + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { + r600_hdmi_enable(encoder); + r600_hdmi_setmode(encoder, adjusted_mode); + } +} + +static bool +atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | + ATOM_DEVICE_CV_SUPPORT | + ATOM_DEVICE_CRT_SUPPORT)) { + DAC_LOAD_DETECTION_PS_ALLOCATION args; + int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); + uint8_t frev, crev; + + memset(&args, 0, sizeof(args)); + + if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) + return false; + + args.sDacload.ucMisc = 0; + + if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || + (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) + args.sDacload.ucDacType = ATOM_DAC_A; + else + args.sDacload.ucDacType = ATOM_DAC_B; + + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); + else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); + if (crev >= 3) + args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; + } + + atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); + + return true; + } else + return false; +} + +static enum drm_connector_status +radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + uint32_t bios_0_scratch; + + if (!atombios_dac_load_detect(encoder, connector)) { + DRM_DEBUG_KMS("detect returned false \n"); + return connector_status_unknown; + } + + if (rdev->family >= CHIP_R600) + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + else + bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); + + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +static enum drm_connector_status +radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + u32 bios_0_scratch; + + if (!ASIC_IS_DCE4(rdev)) + return connector_status_unknown; + + if (!ext_encoder) + return connector_status_unknown; + + if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) + return connector_status_unknown; + + /* load detect on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); + + bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); + + DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); + if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT1_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { + if (bios_0_scratch & ATOM_S0_CRT2_MASK) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) + return connector_status_connected; + } + if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { + if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) + return connector_status_connected; /* CTV */ + else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) + return connector_status_connected; /* STV */ + } + return connector_status_disconnected; +} + +void +radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) +{ + struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); + + if (ext_encoder) + /* ddc_setup on the dp bridge */ + atombios_external_encoder_setup(encoder, ext_encoder, + EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); + +} + +static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); + + if ((radeon_encoder->active_device & + (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || + (radeon_encoder_get_dp_bridge_encoder_id(encoder) != + ENCODER_OBJECT_ID_NONE)) { + struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; + if (dig) + dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); + } + + radeon_atom_output_lock(encoder, true); + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + if (connector) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + /* select the clock/data port if it uses a router */ + if (radeon_connector->router.cd_valid) + radeon_router_select_cd_port(radeon_connector); + + /* turn eDP panel on for mode set */ + if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) + atombios_set_edp_panel_power(connector, + ATOM_TRANSMITTER_ACTION_POWER_ON); + } + + /* this is needed for the pll/ss setup to work correctly in some cases */ + atombios_set_encoder_crtc_source(encoder); +} + +static void radeon_atom_encoder_commit(struct drm_encoder *encoder) +{ + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); + radeon_atom_output_lock(encoder, false); +} + +static void radeon_atom_encoder_disable(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + struct radeon_encoder_atom_dig *dig; + + /* check for pre-DCE3 cards with shared encoders; + * can't really use the links individually, so don't disable + * the encoder if it's in use by another connector + */ + if (!ASIC_IS_DCE3(rdev)) { + struct drm_encoder *other_encoder; + struct radeon_encoder *other_radeon_encoder; + + list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { + other_radeon_encoder = to_radeon_encoder(other_encoder); + if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && + drm_helper_encoder_in_use(other_encoder)) + goto disable_done; + } + } + + radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + if (ASIC_IS_DCE4(rdev)) + /* disable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + else { + /* disable the encoder and transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); + } + break; + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + atombios_dvo_setup(encoder, ATOM_DISABLE); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + atombios_dac_setup(encoder, ATOM_DISABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) + atombios_tv_setup(encoder, ATOM_DISABLE); + break; + } + +disable_done: + if (radeon_encoder_is_digital(encoder)) { + if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) + r600_hdmi_disable(encoder); + dig = radeon_encoder->enc_priv; + dig->dig_encoder = -1; + } + radeon_encoder->active_device = 0; +} + +/* these are handled by the primary encoders */ +static void radeon_atom_ext_prepare(struct drm_encoder *encoder) +{ + +} + +static void radeon_atom_ext_commit(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + +} + +static void radeon_atom_ext_disable(struct drm_encoder *encoder) +{ + +} + +static void +radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) +{ + +} + +static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { + .dpms = radeon_atom_ext_dpms, + .mode_fixup = radeon_atom_ext_mode_fixup, + .prepare = radeon_atom_ext_prepare, + .mode_set = radeon_atom_ext_mode_set, + .commit = radeon_atom_ext_commit, + .disable = radeon_atom_ext_disable, + /* no detect for TMDS/LVDS yet */ +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .disable = radeon_atom_encoder_disable, + .detect = radeon_atom_dig_detect, +}; + +static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { + .dpms = radeon_atom_encoder_dpms, + .mode_fixup = radeon_atom_mode_fixup, + .prepare = radeon_atom_encoder_prepare, + .mode_set = radeon_atom_encoder_mode_set, + .commit = radeon_atom_encoder_commit, + .detect = radeon_atom_dac_detect, +}; + +void radeon_enc_destroy(struct drm_encoder *encoder) +{ + struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); + kfree(radeon_encoder->enc_priv); + drm_encoder_cleanup(encoder); + kfree(radeon_encoder); +} + +static const struct drm_encoder_funcs radeon_atom_enc_funcs = { + .destroy = radeon_enc_destroy, +}; + +struct radeon_encoder_atom_dac * +radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) +{ + struct drm_device *dev = radeon_encoder->base.dev; + struct radeon_device *rdev = dev->dev_private; + struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); + + if (!dac) + return NULL; + + dac->tv_std = radeon_atombios_get_tv_info(rdev); + return dac; +} + +struct radeon_encoder_atom_dig * +radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) +{ + int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; + struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); + + if (!dig) + return NULL; + + /* coherent mode by default */ + dig->coherent_mode = true; + dig->dig_encoder = -1; + + if (encoder_enum == 2) + dig->linkb = true; + else + dig->linkb = false; + + return dig; +} + +void +radeon_add_atom_encoder(struct drm_device *dev, + uint32_t encoder_enum, + uint32_t supported_device, + u16 caps) +{ + struct radeon_device *rdev = dev->dev_private; + struct drm_encoder *encoder; + struct radeon_encoder *radeon_encoder; + + /* see if we already added it */ + list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + radeon_encoder = to_radeon_encoder(encoder); + if (radeon_encoder->encoder_enum == encoder_enum) { + radeon_encoder->devices |= supported_device; + return; + } + + } + + /* add a new one */ + radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); + if (!radeon_encoder) + return; + + encoder = &radeon_encoder->base; + switch (rdev->num_crtc) { + case 1: + encoder->possible_crtcs = 0x1; + break; + case 2: + default: + encoder->possible_crtcs = 0x3; + break; + case 4: + encoder->possible_crtcs = 0xf; + break; + case 6: + encoder->possible_crtcs = 0x3f; + break; + } + + radeon_encoder->enc_priv = NULL; + + radeon_encoder->encoder_enum = encoder_enum; + radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; + radeon_encoder->devices = supported_device; + radeon_encoder->rmx_type = RMX_OFF; + radeon_encoder->underscan_type = UNDERSCAN_OFF; + radeon_encoder->is_ext_encoder = false; + radeon_encoder->caps = caps; + + switch (radeon_encoder->encoder_id) { + case ENCODER_OBJECT_ID_INTERNAL_LVDS: + case ENCODER_OBJECT_ID_INTERNAL_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: + case ENCODER_OBJECT_ID_INTERNAL_LVTM1: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC1: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DAC2: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); + radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); + drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); + break; + case ENCODER_OBJECT_ID_INTERNAL_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: + case ENCODER_OBJECT_ID_INTERNAL_DDI: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: + case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: + case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { + radeon_encoder->rmx_type = RMX_FULL; + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); + } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } else { + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); + } + drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); + break; + case ENCODER_OBJECT_ID_SI170B: + case ENCODER_OBJECT_ID_CH7303: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: + case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: + case ENCODER_OBJECT_ID_TITFP513: + case ENCODER_OBJECT_ID_VT1623: + case ENCODER_OBJECT_ID_HDMI_SI1930: + case ENCODER_OBJECT_ID_TRAVIS: + case ENCODER_OBJECT_ID_NUTMEG: + /* these are handled by the primary encoders */ + radeon_encoder->is_ext_encoder = true; + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); + else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); + else + drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); + break; + } +} diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index ed406e8404a..92c9628c572 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -82,6 +82,7 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= EVERGREEN_GRPH_UPDATE_LOCK; @@ -99,7 +100,11 @@ u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -157,6 +162,57 @@ int sumo_get_temp(struct radeon_device *rdev) return actual_temp * 1000; } +void sumo_pm_init_profile(struct radeon_device *rdev) +{ + int idx; + + /* default */ + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_ps_idx = rdev->pm.default_power_state_index; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 0; + + /* low,mid sh/mh */ + if (rdev->flags & RADEON_IS_MOBILITY) + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + else + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; + + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; + + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 0; + + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 0; + + /* high sh/mh */ + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = + rdev->pm.power_state[idx].num_clock_modes - 1; + + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = + rdev->pm.power_state[idx].num_clock_modes - 1; +} + void evergreen_pm_misc(struct radeon_device *rdev) { int req_ps_idx = rdev->pm.requested_power_state_index; @@ -353,6 +409,7 @@ void evergreen_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) evergreen_irq_set(rdev); @@ -893,7 +950,7 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -945,7 +1002,6 @@ int evergreen_pcie_gart_enable(struct radeon_device *rdev) void evergreen_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); @@ -965,14 +1021,7 @@ void evergreen_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void evergreen_pcie_gart_fini(struct radeon_device *rdev) @@ -1226,7 +1275,7 @@ void evergreen_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12); } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); if (rdev->flags & RADEON_IS_IGP) { tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF; tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24; @@ -3031,6 +3080,10 @@ static int evergreen_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + evergreen_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { evergreen_agp_enable(rdev); @@ -3223,6 +3276,18 @@ int evergreen_init(struct radeon_device *rdev) rdev->accel_working = false; } } + + /* Don't start up if the MC ucode is missing on BTC parts. + * The default clocks and voltages before the MC ucode + * is loaded are not suffient for advanced operations. + */ + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->mc_fw && !(rdev->flags & RADEON_IS_IGP)) { + DRM_ERROR("radeon: MC ucode required for NI+.\n"); + return -EINVAL; + } + } + return 0; } @@ -3235,6 +3300,7 @@ void evergreen_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); evergreen_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_blit_kms.c b/drivers/gpu/drm/radeon/evergreen_blit_kms.c index dcf11bbc06d..914e5af8416 100644 --- a/drivers/gpu/drm/radeon/evergreen_blit_kms.c +++ b/drivers/gpu/drm/radeon/evergreen_blit_kms.c @@ -94,6 +94,15 @@ cp_set_surface_sync(struct radeon_device *rdev, else cp_coher_size = ((size + 255) >> 8); + if (rdev->family >= CHIP_CAYMAN) { + /* CP_COHER_CNTL2 has to be set manually when submitting a surface_sync + * to the RB directly. For IBs, the CP programs this as part of the + * surface_sync packet. + */ + radeon_ring_write(rdev, PACKET3(PACKET3_SET_CONFIG_REG, 1)); + radeon_ring_write(rdev, (0x85e8 - PACKET3_SET_CONFIG_REG_START) >> 2); + radeon_ring_write(rdev, 0); /* CP_COHER_CNTL2 */ + } radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); radeon_ring_write(rdev, sync_type); radeon_ring_write(rdev, cp_coher_size); @@ -174,7 +183,7 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) static void set_tex_resource(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr) + u64 gpu_addr, u32 size) { u32 sq_tex_resource_word0, sq_tex_resource_word1; u32 sq_tex_resource_word4, sq_tex_resource_word7; @@ -196,6 +205,9 @@ set_tex_resource(struct radeon_device *rdev, sq_tex_resource_word7 = format | S__SQ_CONSTANT_TYPE(SQ_TEX_VTX_VALID_TEXTURE); + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, size, gpu_addr); + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 8)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, sq_tex_resource_word0); @@ -613,11 +625,13 @@ int evergreen_blit_init(struct radeon_device *rdev) rdev->r600_blit.primitives.set_default_state = set_default_state; rdev->r600_blit.ring_size_common = 55; /* shaders + def state */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for VB IB */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for VB IB */ rdev->r600_blit.ring_size_common += 5; /* done copy */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for done copy */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for done copy */ rdev->r600_blit.ring_size_per_loop = 74; + if (rdev->family >= CHIP_CAYMAN) + rdev->r600_blit.ring_size_per_loop += 9; /* additional DWs for surface sync */ rdev->r600_blit.max_dim = 16384; diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index 7fdfa8ea757..cd4590aae15 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -38,6 +38,7 @@ struct evergreen_cs_track { u32 group_size; u32 nbanks; u32 npipes; + u32 row_size; /* value we track */ u32 nsamples; u32 cb_color_base_last[12]; @@ -77,6 +78,44 @@ struct evergreen_cs_track { struct radeon_bo *db_s_write_bo; }; +static u32 evergreen_cs_get_aray_mode(u32 tiling_flags) +{ + if (tiling_flags & RADEON_TILING_MACRO) + return ARRAY_2D_TILED_THIN1; + else if (tiling_flags & RADEON_TILING_MICRO) + return ARRAY_1D_TILED_THIN1; + else + return ARRAY_LINEAR_GENERAL; +} + +static u32 evergreen_cs_get_num_banks(u32 nbanks) +{ + switch (nbanks) { + case 2: + return ADDR_SURF_2_BANK; + case 4: + return ADDR_SURF_4_BANK; + case 8: + default: + return ADDR_SURF_8_BANK; + case 16: + return ADDR_SURF_16_BANK; + } +} + +static u32 evergreen_cs_get_tile_split(u32 row_size) +{ + switch (row_size) { + case 1: + default: + return ADDR_SURF_TILE_SPLIT_1KB; + case 2: + return ADDR_SURF_TILE_SPLIT_2KB; + case 4: + return ADDR_SURF_TILE_SPLIT_4KB; + } +} + static void evergreen_cs_track_init(struct evergreen_cs_track *track) { int i; @@ -480,21 +519,22 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) } break; case DB_Z_INFO: - r = evergreen_cs_packet_next_reloc(p, &reloc); - if (r) { - dev_warn(p->dev, "bad SET_CONTEXT_REG " - "0x%04X\n", reg); - return -EINVAL; - } track->db_z_info = radeon_get_ib_value(p, idx); - ib[idx] &= ~Z_ARRAY_MODE(0xf); - track->db_z_info &= ~Z_ARRAY_MODE(0xf); - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { - ib[idx] |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - track->db_z_info |= Z_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - } else { - ib[idx] |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); - track->db_z_info |= Z_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx] &= ~Z_ARRAY_MODE(0xf); + track->db_z_info &= ~Z_ARRAY_MODE(0xf); + ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); + track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); + ib[idx] |= DB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size)); + } } break; case DB_STENCIL_INFO: @@ -607,40 +647,34 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case CB_COLOR5_INFO: case CB_COLOR6_INFO: case CB_COLOR7_INFO: - r = evergreen_cs_packet_next_reloc(p, &reloc); - if (r) { - dev_warn(p->dev, "bad SET_CONTEXT_REG " - "0x%04X\n", reg); - return -EINVAL; - } tmp = (reg - CB_COLOR0_INFO) / 0x3c; track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { - ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { - ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); - track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); } break; case CB_COLOR8_INFO: case CB_COLOR9_INFO: case CB_COLOR10_INFO: case CB_COLOR11_INFO: - r = evergreen_cs_packet_next_reloc(p, &reloc); - if (r) { - dev_warn(p->dev, "bad SET_CONTEXT_REG " - "0x%04X\n", reg); - return -EINVAL; - } tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8; track->cb_color_info[tmp] = radeon_get_ib_value(p, idx); - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { - ib[idx] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) { - ib[idx] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); - track->cb_color_info[tmp] |= CB_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); + track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); } break; case CB_COLOR0_PITCH: @@ -695,6 +729,16 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case CB_COLOR9_ATTRIB: case CB_COLOR10_ATTRIB: case CB_COLOR11_ATTRIB: + r = evergreen_cs_packet_next_reloc(p, &reloc); + if (r) { + dev_warn(p->dev, "bad SET_CONTEXT_REG " + "0x%04X\n", reg); + return -EINVAL; + } + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); + ib[idx] |= CB_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size)); + } break; case CB_COLOR0_DIM: case CB_COLOR1_DIM: @@ -1311,10 +1355,16 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p, return -EINVAL; } ib[idx+1+(i*8)+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) - ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_2D_TILED_THIN1); - else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) - ib[idx+1+(i*8)+1] |= TEX_ARRAY_MODE(ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + ib[idx+1+(i*8)+1] |= + TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags)); + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) { + ib[idx+1+(i*8)+6] |= + TEX_TILE_SPLIT(evergreen_cs_get_tile_split(track->row_size)); + ib[idx+1+(i*8)+7] |= + TEX_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks)); + } + } texture = reloc->robj; /* tex mip base */ r = evergreen_cs_packet_next_reloc(p, &reloc); @@ -1414,6 +1464,7 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) { struct radeon_cs_packet pkt; struct evergreen_cs_track *track; + u32 tmp; int r; if (p->track == NULL) { @@ -1422,9 +1473,63 @@ int evergreen_cs_parse(struct radeon_cs_parser *p) if (track == NULL) return -ENOMEM; evergreen_cs_track_init(track); - track->npipes = p->rdev->config.evergreen.tiling_npipes; - track->nbanks = p->rdev->config.evergreen.tiling_nbanks; - track->group_size = p->rdev->config.evergreen.tiling_group_size; + if (p->rdev->family >= CHIP_CAYMAN) + tmp = p->rdev->config.cayman.tile_config; + else + tmp = p->rdev->config.evergreen.tile_config; + + switch (tmp & 0xf) { + case 0: + track->npipes = 1; + break; + case 1: + default: + track->npipes = 2; + break; + case 2: + track->npipes = 4; + break; + case 3: + track->npipes = 8; + break; + } + + switch ((tmp & 0xf0) >> 4) { + case 0: + track->nbanks = 4; + break; + case 1: + default: + track->nbanks = 8; + break; + case 2: + track->nbanks = 16; + break; + } + + switch ((tmp & 0xf00) >> 8) { + case 0: + track->group_size = 256; + break; + case 1: + default: + track->group_size = 512; + break; + } + + switch ((tmp & 0xf000) >> 12) { + case 0: + track->row_size = 1; + break; + case 1: + default: + track->row_size = 2; + break; + case 2: + track->row_size = 4; + break; + } + p->track = track; } do { diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index c781c92c345..7d7f2155e34 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -42,6 +42,17 @@ # define EVERGREEN_GRPH_DEPTH_8BPP 0 # define EVERGREEN_GRPH_DEPTH_16BPP 1 # define EVERGREEN_GRPH_DEPTH_32BPP 2 +# define EVERGREEN_GRPH_NUM_BANKS(x) (((x) & 0x3) << 2) +# define EVERGREEN_ADDR_SURF_2_BANK 0 +# define EVERGREEN_ADDR_SURF_4_BANK 1 +# define EVERGREEN_ADDR_SURF_8_BANK 2 +# define EVERGREEN_ADDR_SURF_16_BANK 3 +# define EVERGREEN_GRPH_Z(x) (((x) & 0x3) << 4) +# define EVERGREEN_GRPH_BANK_WIDTH(x) (((x) & 0x3) << 6) +# define EVERGREEN_ADDR_SURF_BANK_WIDTH_1 0 +# define EVERGREEN_ADDR_SURF_BANK_WIDTH_2 1 +# define EVERGREEN_ADDR_SURF_BANK_WIDTH_4 2 +# define EVERGREEN_ADDR_SURF_BANK_WIDTH_8 3 # define EVERGREEN_GRPH_FORMAT(x) (((x) & 0x7) << 8) /* 8 BPP */ # define EVERGREEN_GRPH_FORMAT_INDEXED 0 @@ -61,6 +72,24 @@ # define EVERGREEN_GRPH_FORMAT_8B_BGRA1010102 5 # define EVERGREEN_GRPH_FORMAT_RGB111110 6 # define EVERGREEN_GRPH_FORMAT_BGR101111 7 +# define EVERGREEN_GRPH_BANK_HEIGHT(x) (((x) & 0x3) << 11) +# define EVERGREEN_ADDR_SURF_BANK_HEIGHT_1 0 +# define EVERGREEN_ADDR_SURF_BANK_HEIGHT_2 1 +# define EVERGREEN_ADDR_SURF_BANK_HEIGHT_4 2 +# define EVERGREEN_ADDR_SURF_BANK_HEIGHT_8 3 +# define EVERGREEN_GRPH_TILE_SPLIT(x) (((x) & 0x7) << 13) +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_64B 0 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_128B 1 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_256B 2 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_512B 3 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_1KB 4 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_2KB 5 +# define EVERGREEN_ADDR_SURF_TILE_SPLIT_4KB 6 +# define EVERGREEN_GRPH_MACRO_TILE_ASPECT(x) (((x) & 0x3) << 18) +# define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_1 0 +# define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_2 1 +# define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_4 2 +# define EVERGREEN_ADDR_SURF_MACRO_TILE_ASPECT_8 3 # define EVERGREEN_GRPH_ARRAY_MODE(x) (((x) & 0x7) << 20) # define EVERGREEN_GRPH_ARRAY_LINEAR_GENERAL 0 # define EVERGREEN_GRPH_ARRAY_LINEAR_ALIGNED 1 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index b937c49054d..e00039e59a7 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -899,6 +899,10 @@ #define DB_HTILE_DATA_BASE 0x28014 #define DB_Z_INFO 0x28040 # define Z_ARRAY_MODE(x) ((x) << 4) +# define DB_TILE_SPLIT(x) (((x) & 0x7) << 8) +# define DB_NUM_BANKS(x) (((x) & 0x3) << 12) +# define DB_BANK_WIDTH(x) (((x) & 0x3) << 16) +# define DB_BANK_HEIGHT(x) (((x) & 0x3) << 20) #define DB_STENCIL_INFO 0x28044 #define DB_Z_READ_BASE 0x28048 #define DB_STENCIL_READ_BASE 0x2804c @@ -951,6 +955,29 @@ # define CB_SF_EXPORT_FULL 0 # define CB_SF_EXPORT_NORM 1 #define CB_COLOR0_ATTRIB 0x28c74 +# define CB_TILE_SPLIT(x) (((x) & 0x7) << 5) +# define ADDR_SURF_TILE_SPLIT_64B 0 +# define ADDR_SURF_TILE_SPLIT_128B 1 +# define ADDR_SURF_TILE_SPLIT_256B 2 +# define ADDR_SURF_TILE_SPLIT_512B 3 +# define ADDR_SURF_TILE_SPLIT_1KB 4 +# define ADDR_SURF_TILE_SPLIT_2KB 5 +# define ADDR_SURF_TILE_SPLIT_4KB 6 +# define CB_NUM_BANKS(x) (((x) & 0x3) << 10) +# define ADDR_SURF_2_BANK 0 +# define ADDR_SURF_4_BANK 1 +# define ADDR_SURF_8_BANK 2 +# define ADDR_SURF_16_BANK 3 +# define CB_BANK_WIDTH(x) (((x) & 0x3) << 13) +# define ADDR_SURF_BANK_WIDTH_1 0 +# define ADDR_SURF_BANK_WIDTH_2 1 +# define ADDR_SURF_BANK_WIDTH_4 2 +# define ADDR_SURF_BANK_WIDTH_8 3 +# define CB_BANK_HEIGHT(x) (((x) & 0x3) << 16) +# define ADDR_SURF_BANK_HEIGHT_1 0 +# define ADDR_SURF_BANK_HEIGHT_2 1 +# define ADDR_SURF_BANK_HEIGHT_4 2 +# define ADDR_SURF_BANK_HEIGHT_8 3 #define CB_COLOR0_DIM 0x28c78 /* only CB0-7 blocks have these regs */ #define CB_COLOR0_CMASK 0x28c7c @@ -1137,7 +1164,11 @@ # define SQ_SEL_1 5 #define SQ_TEX_RESOURCE_WORD5_0 0x30014 #define SQ_TEX_RESOURCE_WORD6_0 0x30018 +# define TEX_TILE_SPLIT(x) (((x) & 0x7) << 29) #define SQ_TEX_RESOURCE_WORD7_0 0x3001c +# define TEX_BANK_WIDTH(x) (((x) & 0x3) << 8) +# define TEX_BANK_HEIGHT(x) (((x) & 0x3) << 10) +# define TEX_NUM_BANKS(x) (((x) & 0x3) << 16) #define SQ_VTX_CONSTANT_WORD0_0 0x30000 #define SQ_VTX_CONSTANT_WORD1_0 0x30004 diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index fdb93f88457..0e579985746 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -262,8 +262,11 @@ int ni_mc_load_microcode(struct radeon_device *rdev) WREG32(MC_SEQ_SUP_CNTL, 0x00000001); /* wait for training to complete */ - while (!(RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD)) - udelay(10); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(MC_IO_PAD_CNTL_D0) & MEM_FALL_OUT_CMD) + break; + udelay(1); + } if (running) WREG32(MC_SHARED_BLACKOUT_CNTL, blackout); @@ -933,7 +936,7 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -978,8 +981,6 @@ int cayman_pcie_gart_enable(struct radeon_device *rdev) void cayman_pcie_gart_disable(struct radeon_device *rdev) { - int r; - /* Disable all tables */ WREG32(VM_CONTEXT0_CNTL, 0); WREG32(VM_CONTEXT1_CNTL, 0); @@ -995,14 +996,7 @@ void cayman_pcie_gart_disable(struct radeon_device *rdev) WREG32(VM_L2_CNTL2, 0); WREG32(VM_L2_CNTL3, L2_CACHE_BIGK_ASSOCIATIVITY | L2_CACHE_BIGK_FRAGMENT_SIZE(6)); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void cayman_pcie_gart_fini(struct radeon_device *rdev) @@ -1362,6 +1356,10 @@ static int cayman_startup(struct radeon_device *rdev) return r; } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + evergreen_mc_program(rdev); r = cayman_pcie_gart_enable(rdev); if (r) @@ -1557,6 +1555,7 @@ void cayman_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); cayman_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_bo_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index cbf49f4f408..bfc08f6320f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -187,13 +187,18 @@ u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; + int i; /* Lock the graphics update lock */ /* update the scanout addresses */ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); /* Wait for update_pending to go high. */ - while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -537,6 +542,7 @@ void r100_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r100_irq_set(rdev); @@ -577,7 +583,7 @@ int r100_pci_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "R100 PCI GART already initialized\n"); return 0; } @@ -636,10 +642,12 @@ void r100_pci_gart_disable(struct radeon_device *rdev) int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { + u32 *gtt = rdev->gart.ptr; + if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; } - rdev->gart.table.ram.ptr[i] = cpu_to_le32(lower_32_bits(addr)); + gtt[i] = cpu_to_le32(lower_32_bits(addr)); return 0; } diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index 33f2b68c680..c93bc64707e 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -74,7 +74,7 @@ void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev) int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -93,7 +93,7 @@ int rv370_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RV370 PCIE GART already initialized\n"); return 0; } @@ -116,7 +116,7 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) uint32_t tmp; int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -154,7 +154,6 @@ int rv370_pcie_gart_enable(struct radeon_device *rdev) void rv370_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; WREG32_PCIE(RADEON_PCIE_TX_GART_START_LO, 0); WREG32_PCIE(RADEON_PCIE_TX_GART_END_LO, 0); @@ -163,14 +162,7 @@ void rv370_pcie_gart_disable(struct radeon_device *rdev) tmp = RREG32_PCIE(RADEON_PCIE_TX_GART_CNTL); tmp |= RADEON_PCIE_TX_GART_UNMAPPED_ACCESS_DISCARD; WREG32_PCIE(RADEON_PCIE_TX_GART_CNTL, tmp & ~RADEON_PCIE_TX_GART_EN); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv370_pcie_gart_fini(struct radeon_device *rdev) @@ -709,16 +701,21 @@ static int r300_packet0_check(struct radeon_cs_parser *p, return r; } - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) - tile_flags |= R300_TXO_MACRO_TILE; - if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) - tile_flags |= R300_TXO_MICRO_TILE; - else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) - tile_flags |= R300_TXO_MICRO_TILE_SQUARE; - - tmp = idx_value + ((u32)reloc->lobj.gpu_offset); - tmp |= tile_flags; - ib[idx] = tmp; + if (p->keep_tiling_flags) { + ib[idx] = (idx_value & 31) | /* keep the 1st 5 bits */ + ((idx_value & ~31) + (u32)reloc->lobj.gpu_offset); + } else { + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + tile_flags |= R300_TXO_MACRO_TILE; + if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + tile_flags |= R300_TXO_MICRO_TILE; + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) + tile_flags |= R300_TXO_MICRO_TILE_SQUARE; + + tmp = idx_value + ((u32)reloc->lobj.gpu_offset); + tmp |= tile_flags; + ib[idx] = tmp; + } track->textures[i].robj = reloc->robj; track->tex_dirty = true; break; @@ -768,24 +765,26 @@ static int r300_packet0_check(struct radeon_cs_parser *p, /* RB3D_COLORPITCH1 */ /* RB3D_COLORPITCH2 */ /* RB3D_COLORPITCH3 */ - r = r100_cs_packet_next_reloc(p, &reloc); - if (r) { - DRM_ERROR("No reloc for ib[%d]=0x%04X\n", - idx, reg); - r100_cs_dump_packet(p, pkt); - return r; - } + if (!p->keep_tiling_flags) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) - tile_flags |= R300_COLOR_TILE_ENABLE; - if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) - tile_flags |= R300_COLOR_MICROTILE_ENABLE; - else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) - tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE; + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + tile_flags |= R300_COLOR_TILE_ENABLE; + if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + tile_flags |= R300_COLOR_MICROTILE_ENABLE; + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) + tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE; - tmp = idx_value & ~(0x7 << 16); - tmp |= tile_flags; - ib[idx] = tmp; + tmp = idx_value & ~(0x7 << 16); + tmp |= tile_flags; + ib[idx] = tmp; + } i = (reg - 0x4E38) >> 2; track->cb[i].pitch = idx_value & 0x3FFE; switch (((idx_value >> 21) & 0xF)) { @@ -851,25 +850,26 @@ static int r300_packet0_check(struct radeon_cs_parser *p, break; case 0x4F24: /* ZB_DEPTHPITCH */ - r = r100_cs_packet_next_reloc(p, &reloc); - if (r) { - DRM_ERROR("No reloc for ib[%d]=0x%04X\n", - idx, reg); - r100_cs_dump_packet(p, pkt); - return r; - } - - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) - tile_flags |= R300_DEPTHMACROTILE_ENABLE; - if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) - tile_flags |= R300_DEPTHMICROTILE_TILED; - else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) - tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE; + if (!p->keep_tiling_flags) { + r = r100_cs_packet_next_reloc(p, &reloc); + if (r) { + DRM_ERROR("No reloc for ib[%d]=0x%04X\n", + idx, reg); + r100_cs_dump_packet(p, pkt); + return r; + } - tmp = idx_value & ~(0x7 << 16); - tmp |= tile_flags; - ib[idx] = tmp; + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + tile_flags |= R300_DEPTHMACROTILE_ENABLE; + if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + tile_flags |= R300_DEPTHMICROTILE_TILED; + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE) + tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE; + tmp = idx_value & ~(0x7 << 16); + tmp |= tile_flags; + ib[idx] = tmp; + } track->zb.pitch = idx_value & 0x3FFC; track->zb_dirty = true; break; diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 4e777c1e4b7..9cdda0b3b08 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -288,24 +288,6 @@ void r600_pm_get_dynpm_state(struct radeon_device *rdev) pcie_lanes); } -static int r600_pm_get_type_index(struct radeon_device *rdev, - enum radeon_pm_state_type ps_type, - int instance) -{ - int i; - int found_instance = -1; - - for (i = 0; i < rdev->pm.num_power_states; i++) { - if (rdev->pm.power_state[i].type == ps_type) { - found_instance++; - if (found_instance == instance) - return i; - } - } - /* return default if no match */ - return rdev->pm.default_power_state_index; -} - void rs780_pm_init_profile(struct radeon_device *rdev) { if (rdev->pm.num_power_states == 2) { @@ -421,6 +403,8 @@ void rs780_pm_init_profile(struct radeon_device *rdev) void r600_pm_init_profile(struct radeon_device *rdev) { + int idx; + if (rdev->family == CHIP_R600) { /* XXX */ /* default */ @@ -502,81 +486,43 @@ void r600_pm_init_profile(struct radeon_device *rdev) rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_DEFAULT_IDX].dpms_on_cm_idx = 2; /* low sh */ - if (rdev->flags & RADEON_IS_MOBILITY) { - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; - } else { - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; - } + if (rdev->flags & RADEON_IS_MOBILITY) + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); + else + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_SH_IDX].dpms_on_cm_idx = 0; /* mid sh */ - if (rdev->flags & RADEON_IS_MOBILITY) { - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 0); - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; - } else { - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; - } + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_SH_IDX].dpms_on_cm_idx = 1; /* high sh */ - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); - rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 0); + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_ps_idx = idx; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_SH_IDX].dpms_on_cm_idx = 2; /* low mh */ - if (rdev->flags & RADEON_IS_MOBILITY) { - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; - } else { - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; - } + if (rdev->flags & RADEON_IS_MOBILITY) + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); + else + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_LOW_MH_IDX].dpms_on_cm_idx = 0; /* mid mh */ - if (rdev->flags & RADEON_IS_MOBILITY) { - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_BATTERY, 1); - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; - } else { - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; - rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; - } + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_off_cm_idx = 0; + rdev->pm.profiles[PM_PROFILE_MID_MH_IDX].dpms_on_cm_idx = 1; /* high mh */ - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); - rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = - r600_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + idx = radeon_pm_get_type_index(rdev, POWER_STATE_TYPE_PERFORMANCE, 1); + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_ps_idx = idx; + rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_ps_idx = idx; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_off_cm_idx = 0; rdev->pm.profiles[PM_PROFILE_HIGH_MH_IDX].dpms_on_cm_idx = 2; } @@ -763,13 +709,14 @@ void r600_hpd_init(struct radeon_device *rdev) struct drm_device *dev = rdev->ddev; struct drm_connector *connector; - if (ASIC_IS_DCE3(rdev)) { - u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); - if (ASIC_IS_DCE32(rdev)) - tmp |= DC_HPDx_EN; + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + + if (ASIC_IS_DCE3(rdev)) { + u32 tmp = DC_HPDx_CONNECTION_TIMER(0x9c4) | DC_HPDx_RX_INT_TIMER(0xfa); + if (ASIC_IS_DCE32(rdev)) + tmp |= DC_HPDx_EN; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HPD1_CONTROL, tmp); @@ -799,10 +746,7 @@ void r600_hpd_init(struct radeon_device *rdev) default: break; } - } - } else { - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); + } else { switch (radeon_connector->hpd.hpd) { case RADEON_HPD_1: WREG32(DC_HOT_PLUG_DETECT1_CONTROL, DC_HOT_PLUG_DETECTx_EN); @@ -820,6 +764,7 @@ void r600_hpd_init(struct radeon_device *rdev) break; } } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) r600_irq_set(rdev); @@ -897,7 +842,7 @@ void r600_pcie_gart_tlb_flush(struct radeon_device *rdev) /* flush hdp cache so updates hit vram */ if ((rdev->family >= CHIP_RV770) && (rdev->family <= CHIP_RV740) && !(rdev->flags & RADEON_IS_AGP)) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; u32 tmp; /* r7xx hw bug. write to HDP_DEBUG1 followed by fb read @@ -932,7 +877,7 @@ int r600_pcie_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "R600 PCIE GART already initialized\n"); return 0; } @@ -949,7 +894,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -1004,7 +949,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev) void r600_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -1031,14 +976,7 @@ void r600_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp); WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void r600_pcie_gart_fini(struct radeon_device *rdev) @@ -1138,7 +1076,7 @@ static void r600_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12); WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12); } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -1277,6 +1215,53 @@ int r600_mc_init(struct radeon_device *rdev) return 0; } +int r600_vram_scratch_init(struct radeon_device *rdev) +{ + int r; + + if (rdev->vram_scratch.robj == NULL) { + r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, + PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, + &rdev->vram_scratch.robj); + if (r) { + return r; + } + } + + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (unlikely(r != 0)) + return r; + r = radeon_bo_pin(rdev->vram_scratch.robj, + RADEON_GEM_DOMAIN_VRAM, &rdev->vram_scratch.gpu_addr); + if (r) { + radeon_bo_unreserve(rdev->vram_scratch.robj); + return r; + } + r = radeon_bo_kmap(rdev->vram_scratch.robj, + (void **)&rdev->vram_scratch.ptr); + if (r) + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + + return r; +} + +void r600_vram_scratch_fini(struct radeon_device *rdev) +{ + int r; + + if (rdev->vram_scratch.robj == NULL) { + return; + } + r = radeon_bo_reserve(rdev->vram_scratch.robj, false); + if (likely(r == 0)) { + radeon_bo_kunmap(rdev->vram_scratch.robj); + radeon_bo_unpin(rdev->vram_scratch.robj); + radeon_bo_unreserve(rdev->vram_scratch.robj); + } + radeon_bo_unref(&rdev->vram_scratch.robj); +} + /* We doesn't check that the GPU really needs a reset we simply do the * reset, it's up to the caller to determine if the GPU needs one. We * might add an helper function to check that. @@ -2332,6 +2317,14 @@ void r600_fence_ring_emit(struct radeon_device *rdev, if (rdev->wb.use_event) { u64 addr = rdev->wb.gpu_addr + R600_WB_EVENT_OFFSET + (u64)(rdev->fence_drv.scratch_reg - rdev->scratch.reg_base); + /* flush read cache over gart */ + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); + radeon_ring_write(rdev, PACKET3_TC_ACTION_ENA | + PACKET3_VC_ACTION_ENA | + PACKET3_SH_ACTION_ENA); + radeon_ring_write(rdev, 0xFFFFFFFF); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 10); /* poll interval */ /* EVENT_WRITE_EOP - flush caches, send int */ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE_EOP, 4)); radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT_TS) | EVENT_INDEX(5)); @@ -2340,6 +2333,14 @@ void r600_fence_ring_emit(struct radeon_device *rdev, radeon_ring_write(rdev, fence->seq); radeon_ring_write(rdev, 0); } else { + /* flush read cache over gart */ + radeon_ring_write(rdev, PACKET3(PACKET3_SURFACE_SYNC, 3)); + radeon_ring_write(rdev, PACKET3_TC_ACTION_ENA | + PACKET3_VC_ACTION_ENA | + PACKET3_SH_ACTION_ENA); + radeon_ring_write(rdev, 0xFFFFFFFF); + radeon_ring_write(rdev, 0); + radeon_ring_write(rdev, 10); /* poll interval */ radeon_ring_write(rdev, PACKET3(PACKET3_EVENT_WRITE, 0)); radeon_ring_write(rdev, EVENT_TYPE(CACHE_FLUSH_AND_INV_EVENT) | EVENT_INDEX(0)); /* wait for 3D idle clean */ @@ -2421,6 +2422,10 @@ int r600_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + r600_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { r600_agp_enable(rdev); @@ -2641,6 +2646,7 @@ void r600_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); r600_pcie_gart_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_agp_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600_blit_kms.c b/drivers/gpu/drm/radeon/r600_blit_kms.c index c4cf1308d4a..e09d2818f94 100644 --- a/drivers/gpu/drm/radeon/r600_blit_kms.c +++ b/drivers/gpu/drm/radeon/r600_blit_kms.c @@ -201,7 +201,7 @@ set_vtx_resource(struct radeon_device *rdev, u64 gpu_addr) static void set_tex_resource(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr) + u64 gpu_addr, u32 size) { uint32_t sq_tex_resource_word0, sq_tex_resource_word1, sq_tex_resource_word4; @@ -222,6 +222,9 @@ set_tex_resource(struct radeon_device *rdev, S_038010_DST_SEL_Z(SQ_SEL_Z) | S_038010_DST_SEL_W(SQ_SEL_W); + cp_set_surface_sync(rdev, + PACKET3_TC_ACTION_ENA, size, gpu_addr); + radeon_ring_write(rdev, PACKET3(PACKET3_SET_RESOURCE, 7)); radeon_ring_write(rdev, 0); radeon_ring_write(rdev, sq_tex_resource_word0); @@ -500,9 +503,9 @@ int r600_blit_init(struct radeon_device *rdev) rdev->r600_blit.primitives.set_default_state = set_default_state; rdev->r600_blit.ring_size_common = 40; /* shaders + def state */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for VB IB */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for VB IB */ rdev->r600_blit.ring_size_common += 5; /* done copy */ - rdev->r600_blit.ring_size_common += 10; /* fence emit for done copy */ + rdev->r600_blit.ring_size_common += 16; /* fence emit for done copy */ rdev->r600_blit.ring_size_per_loop = 76; /* set_render_target emits 2 extra dwords on rv6xx */ @@ -760,10 +763,7 @@ void r600_kms_blit_copy(struct radeon_device *rdev, vb[11] = i2f(h); rdev->r600_blit.primitives.set_tex_resource(rdev, FMT_8_8_8_8, - w, h, w, src_gpu_addr); - rdev->r600_blit.primitives.cp_set_surface_sync(rdev, - PACKET3_TC_ACTION_ENA, - size_in_bytes, src_gpu_addr); + w, h, w, src_gpu_addr, size_in_bytes); rdev->r600_blit.primitives.set_render_target(rdev, COLOR_8_8_8_8, w, h, dst_gpu_addr); rdev->r600_blit.primitives.set_scissors(rdev, 0, 0, w, h); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index 0a2e023c155..cb1acffd243 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -941,7 +941,8 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) track->db_depth_control = radeon_get_ib_value(p, idx); break; case R_028010_DB_DEPTH_INFO: - if (r600_cs_packet_next_is_pkt3_nop(p)) { + if (!p->keep_tiling_flags && + r600_cs_packet_next_is_pkt3_nop(p)) { r = r600_cs_packet_next_reloc(p, &reloc); if (r) { dev_warn(p->dev, "bad SET_CONTEXT_REG " @@ -992,7 +993,8 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx) case R_0280B4_CB_COLOR5_INFO: case R_0280B8_CB_COLOR6_INFO: case R_0280BC_CB_COLOR7_INFO: - if (r600_cs_packet_next_is_pkt3_nop(p)) { + if (!p->keep_tiling_flags && + r600_cs_packet_next_is_pkt3_nop(p)) { r = r600_cs_packet_next_reloc(p, &reloc); if (r) { dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg); @@ -1291,10 +1293,12 @@ static int r600_check_texture_resource(struct radeon_cs_parser *p, u32 idx, mip_offset <<= 8; word0 = radeon_get_ib_value(p, idx + 0); - if (tiling_flags & RADEON_TILING_MACRO) - word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); - else if (tiling_flags & RADEON_TILING_MICRO) - word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + if (tiling_flags & RADEON_TILING_MACRO) + word0 |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); + else if (tiling_flags & RADEON_TILING_MICRO) + word0 |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); + } word1 = radeon_get_ib_value(p, idx + 1); w0 = G_038000_TEX_WIDTH(word0) + 1; h0 = G_038004_TEX_HEIGHT(word1) + 1; @@ -1621,10 +1625,12 @@ static int r600_packet3_check(struct radeon_cs_parser *p, return -EINVAL; } base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff); - if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) - ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); - else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) - ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); + if (!p->keep_tiling_flags) { + if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) + ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1); + else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) + ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1); + } texture = reloc->robj; /* tex mip base */ r = r600_cs_packet_next_reloc(p, &reloc); diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index e3170c794c1..8227e76b5c7 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -93,6 +93,7 @@ extern int radeon_audio; extern int radeon_disp_priority; extern int radeon_hw_i2c; extern int radeon_pcie_gen2; +extern int radeon_msi; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -306,30 +307,17 @@ int radeon_mode_dumb_destroy(struct drm_file *file_priv, */ struct radeon_mc; -struct radeon_gart_table_ram { - volatile uint32_t *ptr; -}; - -struct radeon_gart_table_vram { - struct radeon_bo *robj; - volatile uint32_t *ptr; -}; - -union radeon_gart_table { - struct radeon_gart_table_ram ram; - struct radeon_gart_table_vram vram; -}; - #define RADEON_GPU_PAGE_SIZE 4096 #define RADEON_GPU_PAGE_MASK (RADEON_GPU_PAGE_SIZE - 1) #define RADEON_GPU_PAGE_SHIFT 12 struct radeon_gart { dma_addr_t table_addr; + struct radeon_bo *robj; + void *ptr; unsigned num_gpu_pages; unsigned num_cpu_pages; unsigned table_size; - union radeon_gart_table table; struct page **pages; dma_addr_t *pages_addr; bool *ttm_alloced; @@ -340,6 +328,8 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev); void radeon_gart_table_ram_free(struct radeon_device *rdev); int radeon_gart_table_vram_alloc(struct radeon_device *rdev); void radeon_gart_table_vram_free(struct radeon_device *rdev); +int radeon_gart_table_vram_pin(struct radeon_device *rdev); +void radeon_gart_table_vram_unpin(struct radeon_device *rdev); int radeon_gart_init(struct radeon_device *rdev); void radeon_gart_fini(struct radeon_device *rdev); void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, @@ -347,6 +337,7 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, int pages, struct page **pagelist, dma_addr_t *dma_addr); +void radeon_gart_restore(struct radeon_device *rdev); /* @@ -437,25 +428,26 @@ union radeon_irq_stat_regs { struct evergreen_irq_stat_regs evergreen; }; +#define RADEON_MAX_HPD_PINS 6 +#define RADEON_MAX_CRTCS 6 +#define RADEON_MAX_HDMI_BLOCKS 2 + struct radeon_irq { bool installed; bool sw_int; - /* FIXME: use a define max crtc rather than hardcode it */ - bool crtc_vblank_int[6]; - bool pflip[6]; + bool crtc_vblank_int[RADEON_MAX_CRTCS]; + bool pflip[RADEON_MAX_CRTCS]; wait_queue_head_t vblank_queue; - /* FIXME: use defines for max hpd/dacs */ - bool hpd[6]; + bool hpd[RADEON_MAX_HPD_PINS]; bool gui_idle; bool gui_idle_acked; wait_queue_head_t idle_queue; - /* FIXME: use defines for max HDMI blocks */ - bool hdmi[2]; + bool hdmi[RADEON_MAX_HDMI_BLOCKS]; spinlock_t sw_lock; int sw_refcount; union radeon_irq_stat_regs stat_regs; - spinlock_t pflip_lock[6]; - int pflip_refcount[6]; + spinlock_t pflip_lock[RADEON_MAX_CRTCS]; + int pflip_refcount[RADEON_MAX_CRTCS]; }; int radeon_irq_kms_init(struct radeon_device *rdev); @@ -533,7 +525,7 @@ struct r600_blit_cp_primitives { void (*set_vtx_resource)(struct radeon_device *rdev, u64 gpu_addr); void (*set_tex_resource)(struct radeon_device *rdev, int format, int w, int h, int pitch, - u64 gpu_addr); + u64 gpu_addr, u32 size); void (*set_scissors)(struct radeon_device *rdev, int x1, int y1, int x2, int y2); void (*draw_auto)(struct radeon_device *rdev); @@ -619,7 +611,8 @@ struct radeon_cs_parser { struct radeon_ib *ib; void *track; unsigned family; - int parser_error; + int parser_error; + bool keep_tiling_flags; }; extern int radeon_cs_update_pages(struct radeon_cs_parser *p, int pg_idx); @@ -792,8 +785,7 @@ struct radeon_pm_clock_info { struct radeon_power_state { enum radeon_pm_state_type type; - /* XXX: use a define for num clock modes */ - struct radeon_pm_clock_info clock_info[8]; + struct radeon_pm_clock_info *clock_info; /* number of valid clock modes in this power state */ int num_clock_modes; struct radeon_pm_clock_info *default_clock_mode; @@ -863,6 +855,9 @@ struct radeon_pm { struct device *int_hwmon_dev; }; +int radeon_pm_get_type_index(struct radeon_device *rdev, + enum radeon_pm_state_type ps_type, + int instance); /* * Benchmarking @@ -1143,12 +1138,55 @@ int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, int radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, struct drm_file *filp); -/* VRAM scratch page for HDP bug */ -struct r700_vram_scratch { +/* VRAM scratch page for HDP bug, default vram page */ +struct r600_vram_scratch { struct radeon_bo *robj; volatile uint32_t *ptr; + u64 gpu_addr; }; + +/* + * Mutex which allows recursive locking from the same process. + */ +struct radeon_mutex { + struct mutex mutex; + struct task_struct *owner; + int level; +}; + +static inline void radeon_mutex_init(struct radeon_mutex *mutex) +{ + mutex_init(&mutex->mutex); + mutex->owner = NULL; + mutex->level = 0; +} + +static inline void radeon_mutex_lock(struct radeon_mutex *mutex) +{ + if (mutex_trylock(&mutex->mutex)) { + /* The mutex was unlocked before, so it's ours now */ + mutex->owner = current; + } else if (mutex->owner != current) { + /* Another process locked the mutex, take it */ + mutex_lock(&mutex->mutex); + mutex->owner = current; + } + /* Otherwise the mutex was already locked by this process */ + + mutex->level++; +} + +static inline void radeon_mutex_unlock(struct radeon_mutex *mutex) +{ + if (--mutex->level > 0) + return; + + mutex->owner = NULL; + mutex_unlock(&mutex->mutex); +} + + /* * Core structure, functions and helpers. */ @@ -1204,7 +1242,7 @@ struct radeon_device { struct radeon_gem gem; struct radeon_pm pm; uint32_t bios_scratch[RADEON_BIOS_NUM_SCRATCH]; - struct mutex cs_mutex; + struct radeon_mutex cs_mutex; struct radeon_wb wb; struct radeon_dummy_page dummy_page; bool gpu_lockup; @@ -1218,7 +1256,7 @@ struct radeon_device { const struct firmware *rlc_fw; /* r6/700 RLC firmware */ const struct firmware *mc_fw; /* NI MC firmware */ struct r600_blit r600_blit; - struct r700_vram_scratch vram_scratch; + struct r600_vram_scratch vram_scratch; int msi_enabled; /* msi enabled */ struct r600_ih ih; /* r6/700 interrupt ring */ struct work_struct hotplug_work; @@ -1442,8 +1480,6 @@ void radeon_ring_write(struct radeon_device *rdev, uint32_t v); /* AGP */ extern int radeon_gpu_reset(struct radeon_device *rdev); extern void radeon_agp_disable(struct radeon_device *rdev); -extern int radeon_gart_table_vram_pin(struct radeon_device *rdev); -extern void radeon_gart_restore(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); extern void radeon_modeset_fini(struct radeon_device *rdev); extern bool radeon_card_posted(struct radeon_device *rdev); @@ -1467,6 +1503,12 @@ extern int radeon_suspend_kms(struct drm_device *dev, pm_message_t state); extern void radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size); /* + * R600 vram scratch functions + */ +int r600_vram_scratch_init(struct radeon_device *rdev); +void r600_vram_scratch_fini(struct radeon_device *rdev); + +/* * r600 functions used by radeon_encoder.c */ extern void r600_hdmi_enable(struct drm_encoder *encoder); diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 3f6636bb2d7..3516a6081dc 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -35,7 +35,8 @@ static int radeon_atif_call(acpi_handle handle) /* Fail only if calling the method fails and ATIF is supported */ if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - printk(KERN_DEBUG "failed to evaluate ATIF got %s\n", acpi_format_exception(status)); + DRM_DEBUG_DRIVER("failed to evaluate ATIF got %s\n", + acpi_format_exception(status)); kfree(buffer.pointer); return 1; } @@ -50,13 +51,13 @@ int radeon_acpi_init(struct radeon_device *rdev) acpi_handle handle; int ret; - /* No need to proceed if we're sure that ATIF is not supported */ - if (!ASIC_IS_AVIVO(rdev) || !rdev->bios) - return 0; - /* Get the device handle */ handle = DEVICE_ACPI_HANDLE(&rdev->pdev->dev); + /* No need to proceed if we're sure that ATIF is not supported */ + if (!ASIC_IS_AVIVO(rdev) || !rdev->bios || !handle) + return 0; + /* Call the ATIF method */ ret = radeon_atif_call(handle); if (ret) diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index e2944566ffe..a2e1eae114e 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -834,7 +834,7 @@ static struct radeon_asic sumo_asic = { .pm_misc = &evergreen_pm_misc, .pm_prepare = &evergreen_pm_prepare, .pm_finish = &evergreen_pm_finish, - .pm_init_profile = &rs780_pm_init_profile, + .pm_init_profile = &sumo_pm_init_profile, .pm_get_dynpm_state = &r600_pm_get_dynpm_state, .pre_page_flip = &evergreen_pre_page_flip, .page_flip = &evergreen_page_flip, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index 85f14f0337e..59914842a72 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -413,6 +413,7 @@ extern int evergreen_cs_parse(struct radeon_cs_parser *p); extern void evergreen_pm_misc(struct radeon_device *rdev); extern void evergreen_pm_prepare(struct radeon_device *rdev); extern void evergreen_pm_finish(struct radeon_device *rdev); +extern void sumo_pm_init_profile(struct radeon_device *rdev); extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc); extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 08d0b94332e..5082d17d14d 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -62,6 +62,87 @@ union atom_supported_devices { struct _ATOM_SUPPORTED_DEVICES_INFO_2d1 info_2d1; }; +static void radeon_lookup_i2c_gpio_quirks(struct radeon_device *rdev, + ATOM_GPIO_I2C_ASSIGMENT *gpio, + u8 index) +{ + /* r4xx mask is technically not used by the hw, so patch in the legacy mask bits */ + if ((rdev->family == CHIP_R420) || + (rdev->family == CHIP_R423) || + (rdev->family == CHIP_RV410)) { + if ((le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0018) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x0019) || + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x001a)) { + gpio->ucClkMaskShift = 0x19; + gpio->ucDataMaskShift = 0x18; + } + } + + /* some evergreen boards have bad data for this entry */ + if (ASIC_IS_DCE4(rdev)) { + if ((index == 7) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && + (gpio->sucI2cId.ucAccess == 0)) { + gpio->sucI2cId.ucAccess = 0x97; + gpio->ucDataMaskShift = 8; + gpio->ucDataEnShift = 8; + gpio->ucDataY_Shift = 8; + gpio->ucDataA_Shift = 8; + } + } + + /* some DCE3 boards have bad data for this entry */ + if (ASIC_IS_DCE3(rdev)) { + if ((index == 4) && + (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && + (gpio->sucI2cId.ucAccess == 0x94)) + gpio->sucI2cId.ucAccess = 0x14; + } +} + +static struct radeon_i2c_bus_rec radeon_get_bus_rec_for_i2c_gpio(ATOM_GPIO_I2C_ASSIGMENT *gpio) +{ + struct radeon_i2c_bus_rec i2c; + + memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); + + i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; + i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; + i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; + i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; + i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; + i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; + i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; + i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; + i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); + i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); + i2c.en_clk_mask = (1 << gpio->ucClkEnShift); + i2c.en_data_mask = (1 << gpio->ucDataEnShift); + i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); + i2c.y_data_mask = (1 << gpio->ucDataY_Shift); + i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); + i2c.a_data_mask = (1 << gpio->ucDataA_Shift); + + if (gpio->sucI2cId.sbfAccess.bfHW_Capable) + i2c.hw_capable = true; + else + i2c.hw_capable = false; + + if (gpio->sucI2cId.ucAccess == 0xa0) + i2c.mm_i2c = true; + else + i2c.mm_i2c = false; + + i2c.i2c_id = gpio->sucI2cId.ucAccess; + + if (i2c.mask_clk_reg) + i2c.valid = true; + else + i2c.valid = false; + + return i2c; +} + static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rdev, uint8_t id) { @@ -85,59 +166,10 @@ static struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_device *rd for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; - /* some evergreen boards have bad data for this entry */ - if (ASIC_IS_DCE4(rdev)) { - if ((i == 7) && - (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && - (gpio->sucI2cId.ucAccess == 0)) { - gpio->sucI2cId.ucAccess = 0x97; - gpio->ucDataMaskShift = 8; - gpio->ucDataEnShift = 8; - gpio->ucDataY_Shift = 8; - gpio->ucDataA_Shift = 8; - } - } - - /* some DCE3 boards have bad data for this entry */ - if (ASIC_IS_DCE3(rdev)) { - if ((i == 4) && - (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && - (gpio->sucI2cId.ucAccess == 0x94)) - gpio->sucI2cId.ucAccess = 0x14; - } + radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); if (gpio->sucI2cId.ucAccess == id) { - i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; - i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; - i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; - i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; - i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; - i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; - i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; - i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; - i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); - i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); - i2c.en_clk_mask = (1 << gpio->ucClkEnShift); - i2c.en_data_mask = (1 << gpio->ucDataEnShift); - i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); - i2c.y_data_mask = (1 << gpio->ucDataY_Shift); - i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); - i2c.a_data_mask = (1 << gpio->ucDataA_Shift); - - if (gpio->sucI2cId.sbfAccess.bfHW_Capable) - i2c.hw_capable = true; - else - i2c.hw_capable = false; - - if (gpio->sucI2cId.ucAccess == 0xa0) - i2c.mm_i2c = true; - else - i2c.mm_i2c = false; - - i2c.i2c_id = gpio->sucI2cId.ucAccess; - - if (i2c.mask_clk_reg) - i2c.valid = true; + i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); break; } } @@ -157,8 +189,6 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) int i, num_indices; char stmp[32]; - memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec)); - if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) { i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset); @@ -167,60 +197,12 @@ void radeon_atombios_i2c_init(struct radeon_device *rdev) for (i = 0; i < num_indices; i++) { gpio = &i2c_info->asGPIO_Info[i]; - i2c.valid = false; - - /* some evergreen boards have bad data for this entry */ - if (ASIC_IS_DCE4(rdev)) { - if ((i == 7) && - (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1936) && - (gpio->sucI2cId.ucAccess == 0)) { - gpio->sucI2cId.ucAccess = 0x97; - gpio->ucDataMaskShift = 8; - gpio->ucDataEnShift = 8; - gpio->ucDataY_Shift = 8; - gpio->ucDataA_Shift = 8; - } - } - - /* some DCE3 boards have bad data for this entry */ - if (ASIC_IS_DCE3(rdev)) { - if ((i == 4) && - (le16_to_cpu(gpio->usClkMaskRegisterIndex) == 0x1fda) && - (gpio->sucI2cId.ucAccess == 0x94)) - gpio->sucI2cId.ucAccess = 0x14; - } - - i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4; - i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4; - i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4; - i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4; - i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4; - i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4; - i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4; - i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4; - i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift); - i2c.mask_data_mask = (1 << gpio->ucDataMaskShift); - i2c.en_clk_mask = (1 << gpio->ucClkEnShift); - i2c.en_data_mask = (1 << gpio->ucDataEnShift); - i2c.y_clk_mask = (1 << gpio->ucClkY_Shift); - i2c.y_data_mask = (1 << gpio->ucDataY_Shift); - i2c.a_clk_mask = (1 << gpio->ucClkA_Shift); - i2c.a_data_mask = (1 << gpio->ucDataA_Shift); - - if (gpio->sucI2cId.sbfAccess.bfHW_Capable) - i2c.hw_capable = true; - else - i2c.hw_capable = false; - if (gpio->sucI2cId.ucAccess == 0xa0) - i2c.mm_i2c = true; - else - i2c.mm_i2c = false; + radeon_lookup_i2c_gpio_quirks(rdev, gpio, i); - i2c.i2c_id = gpio->sucI2cId.ucAccess; + i2c = radeon_get_bus_rec_for_i2c_gpio(gpio); - if (i2c.mask_clk_reg) { - i2c.valid = true; + if (i2c.valid) { sprintf(stmp, "0x%x", i2c.i2c_id); rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp); } @@ -1996,10 +1978,14 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) return state_index; /* last mode is usually default, array is low to high */ for (i = 0; i < num_modes; i++) { + rdev->pm.power_state[state_index].clock_info = + kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + if (!rdev->pm.power_state[state_index].clock_info) + return state_index; + rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; switch (frev) { case 1: - rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].mclk = le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); rdev->pm.power_state[state_index].clock_info[0].sclk = @@ -2035,7 +2021,6 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) state_index++; break; case 2: - rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].mclk = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); rdev->pm.power_state[state_index].clock_info[0].sclk = @@ -2072,7 +2057,6 @@ static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) state_index++; break; case 3: - rdev->pm.power_state[state_index].num_clock_modes = 1; rdev->pm.power_state[state_index].clock_info[0].mclk = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); rdev->pm.power_state[state_index].clock_info[0].sclk = @@ -2257,7 +2241,7 @@ static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rde rdev->pm.default_power_state_index = state_index; rdev->pm.power_state[state_index].default_clock_mode = &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; - if (ASIC_IS_DCE5(rdev)) { + if (ASIC_IS_DCE5(rdev) && !(rdev->flags & RADEON_IS_IGP)) { /* NI chips post without MC ucode, so default clocks are strobe mode only */ rdev->pm.default_sclk = rdev->pm.power_state[state_index].clock_info[0].sclk; rdev->pm.default_mclk = rdev->pm.power_state[state_index].clock_info[0].mclk; @@ -2377,17 +2361,31 @@ static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + (power_state->v1.ucNonClockStateIndex * power_info->pplib.ucNonClockSize)); - for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { - clock_info = (union pplib_clock_info *) - (mode_info->atom_context->bios + data_offset + - le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + - (power_state->v1.ucClockStateIndices[j] * - power_info->pplib.ucClockInfoSize)); - valid = radeon_atombios_parse_pplib_clock_info(rdev, - state_index, mode_index, - clock_info); - if (valid) - mode_index++; + rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * + ((power_info->pplib.ucStateEntrySize - 1) ? + (power_info->pplib.ucStateEntrySize - 1) : 1), + GFP_KERNEL); + if (!rdev->pm.power_state[i].clock_info) + return state_index; + if (power_info->pplib.ucStateEntrySize - 1) { + for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { + clock_info = (union pplib_clock_info *) + (mode_info->atom_context->bios + data_offset + + le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + + (power_state->v1.ucClockStateIndices[j] * + power_info->pplib.ucClockInfoSize)); + valid = radeon_atombios_parse_pplib_clock_info(rdev, + state_index, mode_index, + clock_info); + if (valid) + mode_index++; + } + } else { + rdev->pm.power_state[state_index].clock_info[0].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = + rdev->clock.default_sclk; + mode_index++; } rdev->pm.power_state[state_index].num_clock_modes = mode_index; if (mode_index) { @@ -2456,18 +2454,32 @@ static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) &non_clock_info_array->nonClockInfo[non_clock_array_index]; - for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { - clock_array_index = power_state->v2.clockInfoIndex[j]; - /* XXX this might be an inagua bug... */ - if (clock_array_index >= clock_info_array->ucNumEntries) - continue; - clock_info = (union pplib_clock_info *) - &clock_info_array->clockInfo[clock_array_index]; - valid = radeon_atombios_parse_pplib_clock_info(rdev, - state_index, mode_index, - clock_info); - if (valid) - mode_index++; + rdev->pm.power_state[i].clock_info = kzalloc(sizeof(struct radeon_pm_clock_info) * + (power_state->v2.ucNumDPMLevels ? + power_state->v2.ucNumDPMLevels : 1), + GFP_KERNEL); + if (!rdev->pm.power_state[i].clock_info) + return state_index; + if (power_state->v2.ucNumDPMLevels) { + for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { + clock_array_index = power_state->v2.clockInfoIndex[j]; + /* XXX this might be an inagua bug... */ + if (clock_array_index >= clock_info_array->ucNumEntries) + continue; + clock_info = (union pplib_clock_info *) + &clock_info_array->clockInfo[clock_array_index]; + valid = radeon_atombios_parse_pplib_clock_info(rdev, + state_index, mode_index, + clock_info); + if (valid) + mode_index++; + } + } else { + rdev->pm.power_state[state_index].clock_info[0].mclk = + rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = + rdev->clock.default_sclk; + mode_index++; } rdev->pm.power_state[state_index].num_clock_modes = mode_index; if (mode_index) { @@ -2524,19 +2536,23 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) } else { rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state), GFP_KERNEL); if (rdev->pm.power_state) { - /* add the default mode */ - rdev->pm.power_state[state_index].type = - POWER_STATE_TYPE_DEFAULT; - rdev->pm.power_state[state_index].num_clock_modes = 1; - rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; - rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; - rdev->pm.power_state[state_index].default_clock_mode = - &rdev->pm.power_state[state_index].clock_info[0]; - rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; - rdev->pm.power_state[state_index].pcie_lanes = 16; - rdev->pm.default_power_state_index = state_index; - rdev->pm.power_state[state_index].flags = 0; - state_index++; + rdev->pm.power_state[0].clock_info = + kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + if (rdev->pm.power_state[0].clock_info) { + /* add the default mode */ + rdev->pm.power_state[state_index].type = + POWER_STATE_TYPE_DEFAULT; + rdev->pm.power_state[state_index].num_clock_modes = 1; + rdev->pm.power_state[state_index].clock_info[0].mclk = rdev->clock.default_mclk; + rdev->pm.power_state[state_index].clock_info[0].sclk = rdev->clock.default_sclk; + rdev->pm.power_state[state_index].default_clock_mode = + &rdev->pm.power_state[state_index].clock_info[0]; + rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; + rdev->pm.power_state[state_index].pcie_lanes = 16; + rdev->pm.default_power_state_index = state_index; + rdev->pm.power_state[state_index].flags = 0; + state_index++; + } } } @@ -2544,7 +2560,11 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev) rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + if (rdev->pm.default_power_state_index >= 0) + rdev->pm.current_vddc = + rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + else + rdev->pm.current_vddc = 0; } void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable) diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c index 5cafc90de7f..17e1a9b2d8f 100644 --- a/drivers/gpu/drm/radeon/radeon_benchmark.c +++ b/drivers/gpu/drm/radeon/radeon_benchmark.c @@ -98,7 +98,7 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size, struct radeon_bo *sobj = NULL; uint64_t saddr, daddr; int r, n; - unsigned int time; + int time; n = RADEON_BENCHMARK_ITERATIONS; r = radeon_bo_create(rdev, size, PAGE_SIZE, true, sdomain, &sobj); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 8bf83c4b414..81fc100be7e 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -2563,14 +2563,17 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev) /* allocate 2 power states */ rdev->pm.power_state = kzalloc(sizeof(struct radeon_power_state) * 2, GFP_KERNEL); - if (!rdev->pm.power_state) { - rdev->pm.default_power_state_index = state_index; - rdev->pm.num_power_states = 0; - - rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; - rdev->pm.current_clock_mode_index = 0; - return; - } + if (rdev->pm.power_state) { + /* allocate 1 clock mode per state */ + rdev->pm.power_state[0].clock_info = + kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + rdev->pm.power_state[1].clock_info = + kzalloc(sizeof(struct radeon_pm_clock_info) * 1, GFP_KERNEL); + if (!rdev->pm.power_state[0].clock_info || + !rdev->pm.power_state[1].clock_info) + goto pm_failed; + } else + goto pm_failed; /* check for a thermal chip */ offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE); @@ -2735,6 +2738,14 @@ default_mode: rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; rdev->pm.current_clock_mode_index = 0; + return; + +pm_failed: + rdev->pm.default_power_state_index = state_index; + rdev->pm.num_power_states = 0; + + rdev->pm.current_power_state_index = rdev->pm.default_power_state_index; + rdev->pm.current_clock_mode_index = 0; } void radeon_external_tmds_setup(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index dec6cbe6a0a..e7cb3ab0924 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -44,8 +44,6 @@ extern void radeon_legacy_backlight_init(struct radeon_encoder *radeon_encoder, struct drm_connector *drm_connector); -bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector); - void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -432,55 +430,6 @@ int radeon_connector_set_property(struct drm_connector *connector, struct drm_pr return 0; } -/* - * Some integrated ATI Radeon chipset implementations (e. g. - * Asus M2A-VM HDMI) may indicate the availability of a DDC, - * even when there's no monitor connected. For these connectors - * following DDC probe extension will be applied: check also for the - * availability of EDID with at least a correct EDID header. Only then, - * DDC is assumed to be available. This prevents drm_get_edid() and - * drm_edid_block_valid() from periodically dumping data and kernel - * errors into the logs and onto the terminal. - */ -static bool radeon_connector_needs_extended_probe(struct radeon_device *dev, - uint32_t supported_device, - int connector_type) -{ - /* Asus M2A-VM HDMI board sends data to i2c bus even, - * if HDMI add-on card is not plugged in or HDMI is disabled in - * BIOS. Valid DDC can only be assumed, if also a valid EDID header - * can be retrieved via i2c bus during DDC probe */ - if ((dev->pdev->device == 0x791e) && - (dev->pdev->subsystem_vendor == 0x1043) && - (dev->pdev->subsystem_device == 0x826d)) { - if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - /* ECS A740GM-M with ATI RADEON 2100 sends data to i2c bus - * for a DVI connector that is not implemented */ - if ((dev->pdev->device == 0x796e) && - (dev->pdev->subsystem_vendor == 0x1019) && - (dev->pdev->subsystem_device == 0x2615)) { - if ((connector_type == DRM_MODE_CONNECTOR_DVID) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - /* TOSHIBA Satellite L300D with ATI Mobility Radeon x1100 - * (RS690M) sends data to i2c bus for a HDMI connector that - * is not implemented */ - if ((dev->pdev->device == 0x791f) && - (dev->pdev->subsystem_vendor == 0x1179) && - (dev->pdev->subsystem_device == 0xff68)) { - if ((connector_type == DRM_MODE_CONNECTOR_HDMIA) && - (supported_device == ATOM_DEVICE_DFP2_SUPPORT)) - return true; - } - - /* Default: no EDID header probe required for DDC probing */ - return false; -} - static void radeon_fixup_lvds_native_mode(struct drm_encoder *encoder, struct drm_connector *connector) { @@ -721,8 +670,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) ret = connector_status_disconnected; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -764,7 +712,7 @@ radeon_vga_detect(struct drm_connector *connector, bool force) if (radeon_connector->dac_load_detect && encoder) { encoder_funcs = encoder->helper_private; ret = encoder_funcs->detect(encoder, connector); - if (ret == connector_status_connected) + if (ret != connector_status_disconnected) radeon_connector->detected_by_load = true; } } @@ -904,8 +852,7 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) bool dret = false; if (radeon_connector->ddc_bus) - dret = radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe); + dret = radeon_ddc_probe(radeon_connector); if (dret) { radeon_connector->detected_by_load = false; if (radeon_connector->edid) { @@ -1005,8 +952,9 @@ radeon_dvi_detect(struct drm_connector *connector, bool force) ret = encoder_funcs->detect(encoder, connector); if (ret == connector_status_connected) { radeon_connector->use_digital = false; - radeon_connector->detected_by_load = true; } + if (ret != connector_status_disconnected) + radeon_connector->detected_by_load = true; } break; } @@ -1203,7 +1151,8 @@ static int radeon_dp_get_modes(struct drm_connector *connector) } } else { /* need to setup ddc on the bridge */ - if (radeon_connector_encoder_is_dp_bridge(connector)) { + if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) { if (encoder) radeon_atom_ext_encoder_setup_ddc(encoder); } @@ -1213,13 +1162,12 @@ static int radeon_dp_get_modes(struct drm_connector *connector) return ret; } -bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector) +u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector) { struct drm_mode_object *obj; struct drm_encoder *encoder; struct radeon_encoder *radeon_encoder; int i; - bool found = false; for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) { if (connector->encoder_ids[i] == 0) @@ -1235,14 +1183,13 @@ bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector) switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_TRAVIS: case ENCODER_OBJECT_ID_NUTMEG: - found = true; - break; + return radeon_encoder->encoder_id; default: break; } } - return found; + return ENCODER_OBJECT_ID_NONE; } bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector) @@ -1319,7 +1266,8 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (!radeon_dig_connector->edp_on) atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); - } else if (radeon_connector_encoder_is_dp_bridge(connector)) { + } else if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) != + ENCODER_OBJECT_ID_NONE) { /* DP bridges are always DP */ radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; /* get the DPCD from the bridge */ @@ -1328,8 +1276,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (encoder) { /* setup ddc on the bridge */ radeon_atom_ext_encoder_setup_ddc(encoder); - if (radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe)) /* try DDC */ + if (radeon_ddc_probe(radeon_connector)) /* try DDC */ ret = connector_status_connected; else if (radeon_connector->dac_load_detect) { /* try load detection */ struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private; @@ -1347,8 +1294,7 @@ radeon_dp_detect(struct drm_connector *connector, bool force) if (radeon_dp_getdpcd(radeon_connector)) ret = connector_status_connected; } else { - if (radeon_ddc_probe(radeon_connector, - radeon_connector->requires_extended_probe)) + if (radeon_ddc_probe(radeon_connector)) ret = connector_status_connected; } } @@ -1493,9 +1439,7 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_connector->shared_ddc = shared_ddc; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); + radeon_connector->router = *router; if (router->ddc_valid || router->cd_valid) { radeon_connector->router_bus = radeon_i2c_lookup(rdev, &router->i2c_info); @@ -1842,9 +1786,7 @@ radeon_add_legacy_connector(struct drm_device *dev, radeon_connector->devices = supported_device; radeon_connector->connector_object_id = connector_object_id; radeon_connector->hpd = *hpd; - radeon_connector->requires_extended_probe = - radeon_connector_needs_extended_probe(rdev, supported_device, - connector_type); + switch (connector_type) { case DRM_MODE_CONNECTOR_VGA: drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type); diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index fae00c0d75a..29afd71e084 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c @@ -93,7 +93,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) { struct drm_radeon_cs *cs = data; uint64_t *chunk_array_ptr; - unsigned size, i; + unsigned size, i, flags = 0; if (!cs->num_chunks) { return 0; @@ -140,6 +140,10 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) if (p->chunks[i].length_dw == 0) return -EINVAL; } + if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS && + !p->chunks[i].length_dw) { + return -EINVAL; + } p->chunks[i].length_dw = user_chunk.length_dw; p->chunks[i].user_ptr = (void __user *)(unsigned long)user_chunk.chunk_data; @@ -155,6 +159,9 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) p->chunks[i].user_ptr, size)) { return -EFAULT; } + if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) { + flags = p->chunks[i].kdata[0]; + } } else { p->chunks[i].kpage[0] = kmalloc(PAGE_SIZE, GFP_KERNEL); p->chunks[i].kpage[1] = kmalloc(PAGE_SIZE, GFP_KERNEL); @@ -174,6 +181,8 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data) p->chunks[p->chunk_ib_idx].length_dw); return -EINVAL; } + + p->keep_tiling_flags = (flags & RADEON_CS_KEEP_TILING_FLAGS) != 0; return 0; } @@ -222,7 +231,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) struct radeon_cs_chunk *ib_chunk; int r; - mutex_lock(&rdev->cs_mutex); + radeon_mutex_lock(&rdev->cs_mutex); /* initialize parser */ memset(&parser, 0, sizeof(struct radeon_cs_parser)); parser.filp = filp; @@ -233,14 +242,14 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r) { DRM_ERROR("Failed to initialize parser !\n"); radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_ib_get(rdev, &parser.ib); if (r) { DRM_ERROR("Failed to get ib !\n"); radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_cs_parser_relocs(&parser); @@ -248,7 +257,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r != -ERESTARTSYS) DRM_ERROR("Failed to parse relocation %d!\n", r); radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } /* Copy the packet into the IB, the parser will read from the @@ -260,14 +269,14 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) if (r || parser.parser_error) { DRM_ERROR("Invalid command stream !\n"); radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_cs_finish_pages(&parser); if (r) { DRM_ERROR("Invalid command stream !\n"); radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } r = radeon_ib_schedule(rdev, parser.ib); @@ -275,7 +284,7 @@ int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) DRM_ERROR("Failed to schedule IB !\n"); } radeon_cs_parser_fini(&parser, r); - mutex_unlock(&rdev->cs_mutex); + radeon_mutex_unlock(&rdev->cs_mutex); return r; } diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index c33bc914d93..c4d00a17141 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -716,7 +716,7 @@ int radeon_device_init(struct radeon_device *rdev, /* mutex initialization are all done here so we * can recall function without having locking issues */ - mutex_init(&rdev->cs_mutex); + radeon_mutex_init(&rdev->cs_mutex); mutex_init(&rdev->ib_pool.mutex); mutex_init(&rdev->cp.mutex); mutex_init(&rdev->dc_hw_i2c_mutex); @@ -955,6 +955,9 @@ int radeon_gpu_reset(struct radeon_device *rdev) int r; int resched; + /* Prevent CS ioctl from interfering */ + radeon_mutex_lock(&rdev->cs_mutex); + radeon_save_bios_scratch_regs(rdev); /* block TTM */ resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); @@ -967,10 +970,15 @@ int radeon_gpu_reset(struct radeon_device *rdev) radeon_restore_bios_scratch_regs(rdev); drm_helper_resume_force_mode(rdev->ddev); ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); - return 0; } - /* bad news, how to tell it to userspace ? */ - dev_info(rdev->dev, "GPU reset failed\n"); + + radeon_mutex_unlock(&rdev->cs_mutex); + + if (r) { + /* bad news, how to tell it to userspace ? */ + dev_info(rdev->dev, "GPU reset failed\n"); + } + return r; } diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 6adb3e58aff..a22d6e6a49a 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -33,8 +33,6 @@ #include "drm_crtc_helper.h" #include "drm_edid.h" -static int radeon_ddc_dump(struct drm_connector *connector); - static void avivo_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -669,7 +667,6 @@ static void radeon_print_display_setup(struct drm_device *dev) static bool radeon_setup_enc_conn(struct drm_device *dev) { struct radeon_device *rdev = dev->dev_private; - struct drm_connector *drm_connector; bool ret = false; if (rdev->bios) { @@ -689,8 +686,6 @@ static bool radeon_setup_enc_conn(struct drm_device *dev) if (ret) { radeon_setup_encoder_clones(dev); radeon_print_display_setup(dev); - list_for_each_entry(drm_connector, &dev->mode_config.connector_list, head) - radeon_ddc_dump(drm_connector); } return ret; @@ -708,7 +703,8 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if ((radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_DisplayPort) || (radeon_connector->base.connector_type == DRM_MODE_CONNECTOR_eDP) || - radeon_connector_encoder_is_dp_bridge(&radeon_connector->base)) { + (radeon_connector_encoder_get_dp_bridge_encoder_id(&radeon_connector->base) != + ENCODER_OBJECT_ID_NONE)) { struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; if ((dig->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT || @@ -743,34 +739,6 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) return 0; } -static int radeon_ddc_dump(struct drm_connector *connector) -{ - struct edid *edid; - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - int ret = 0; - - /* on hw with routers, select right port */ - if (radeon_connector->router.ddc_valid) - radeon_router_select_ddc_port(radeon_connector); - - if (!radeon_connector->ddc_bus) - return -1; - edid = drm_get_edid(connector, &radeon_connector->ddc_bus->adapter); - /* Log EDID retrieval status here. In particular with regard to - * connectors with requires_extended_probe flag set, that will prevent - * function radeon_dvi_detect() to fetch EDID on this connector, - * as long as there is no valid EDID header found */ - if (edid) { - DRM_INFO("Radeon display connector %s: Found valid EDID", - drm_get_connector_name(connector)); - kfree(edid); - } else { - DRM_INFO("Radeon display connector %s: No monitor connected or invalid EDID", - drm_get_connector_name(connector)); - } - return ret; -} - /* avivo */ static void avivo_get_fb_div(struct radeon_pll *pll, u32 target_clock, diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 969933833cc..71499fc3daf 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -53,9 +53,10 @@ * 2.9.0 - r600 tiling (s3tc,rgtc) working, SET_PREDICATION packet 3 on r600 + eg, backend query * 2.10.0 - fusion 2D tiling * 2.11.0 - backend map, initial compute support for the CS checker + * 2.12.0 - RADEON_CS_KEEP_TILING_FLAGS */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 11 +#define KMS_DRIVER_MINOR 12 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); @@ -119,6 +120,7 @@ int radeon_audio = 0; int radeon_disp_priority = 0; int radeon_hw_i2c = 0; int radeon_pcie_gen2 = 0; +int radeon_msi = -1; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -165,6 +167,9 @@ module_param_named(hw_i2c, radeon_hw_i2c, int, 0444); MODULE_PARM_DESC(pcie_gen2, "PCIE Gen2 mode (1 = enable)"); module_param_named(pcie_gen2, radeon_pcie_gen2, int, 0444); +MODULE_PARM_DESC(msi, "MSI support (1 = enable, 0 = disable, -1 = auto)"); +module_param_named(msi, radeon_msi, int, 0444); + static int radeon_suspend(struct drm_device *dev, pm_message_t state) { drm_radeon_private_t *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c index eb3f6dc6df8..4b27efa4405 100644 --- a/drivers/gpu/drm/radeon/radeon_encoders.c +++ b/drivers/gpu/drm/radeon/radeon_encoders.c @@ -29,12 +29,6 @@ #include "radeon.h" #include "atom.h" -extern int atom_debug; - -/* evil but including atombios.h is much worse */ -bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index, - struct drm_display_mode *mode); - static uint32_t radeon_encoder_clones(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; @@ -156,27 +150,6 @@ radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, uint8 return ret; } -static inline bool radeon_encoder_is_digital(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - return true; - default: - return false; - } -} - void radeon_link_encoder_connector(struct drm_device *dev) { @@ -229,23 +202,7 @@ radeon_get_connector_for_encoder(struct drm_encoder *encoder) return NULL; } -static struct drm_connector * -radeon_get_connector_for_encoder_init(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - radeon_connector = to_radeon_connector(connector); - if (radeon_encoder->devices & radeon_connector->devices) - return connector; - } - return NULL; -} - -struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder) +struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); @@ -266,9 +223,9 @@ struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder return NULL; } -bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder) +u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder) { - struct drm_encoder *other_encoder = radeon_atom_get_external_encoder(encoder); + struct drm_encoder *other_encoder = radeon_get_external_encoder(encoder); if (other_encoder) { struct radeon_encoder *radeon_encoder = to_radeon_encoder(other_encoder); @@ -276,13 +233,12 @@ bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder) switch (radeon_encoder->encoder_id) { case ENCODER_OBJECT_ID_TRAVIS: case ENCODER_OBJECT_ID_NUTMEG: - return true; + return radeon_encoder->encoder_id; default: - return false; + return ENCODER_OBJECT_ID_NONE; } } - - return false; + return ENCODER_OBJECT_ID_NONE; } void radeon_panel_mode_fixup(struct drm_encoder *encoder, @@ -332,2105 +288,3 @@ void radeon_panel_mode_fixup(struct drm_encoder *encoder, } -static bool radeon_atom_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - - /* set the active encoder to connector routing */ - radeon_encoder_set_active_device(encoder); - drm_mode_set_crtcinfo(adjusted_mode, 0); - - /* hw bug */ - if ((mode->flags & DRM_MODE_FLAG_INTERLACE) - && (mode->crtc_vsync_start < (mode->crtc_vdisplay + 2))) - adjusted_mode->crtc_vsync_start = adjusted_mode->crtc_vdisplay + 2; - - /* get the native mode for LVDS */ - if (radeon_encoder->active_device & (ATOM_DEVICE_LCD_SUPPORT)) - radeon_panel_mode_fixup(encoder, adjusted_mode); - - /* get the native mode for TV */ - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) { - struct radeon_encoder_atom_dac *tv_dac = radeon_encoder->enc_priv; - if (tv_dac) { - if (tv_dac->tv_std == TV_STD_NTSC || - tv_dac->tv_std == TV_STD_NTSC_J || - tv_dac->tv_std == TV_STD_PAL_M) - radeon_atom_get_tv_timings(rdev, 0, adjusted_mode); - else - radeon_atom_get_tv_timings(rdev, 1, adjusted_mode); - } - } - - if (ASIC_IS_DCE3(rdev) && - ((radeon_encoder->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder))) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - radeon_dp_set_link_config(connector, mode); - } - - return true; -} - -static void -atombios_dac_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - DAC_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; - struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - index = GetIndexIntoMasterTable(COMMAND, DAC1EncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - index = GetIndexIntoMasterTable(COMMAND, DAC2EncoderControl); - break; - } - - args.ucAction = action; - - if (radeon_encoder->active_device & (ATOM_DEVICE_CRT_SUPPORT)) - args.ucDacStandard = ATOM_DAC1_PS2; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.ucDacStandard = ATOM_DAC1_CV; - else { - switch (dac_info->tv_std) { - case TV_STD_PAL: - case TV_STD_PAL_M: - case TV_STD_SCART_PAL: - case TV_STD_SECAM: - case TV_STD_PAL_CN: - args.ucDacStandard = ATOM_DAC1_PAL; - break; - case TV_STD_NTSC: - case TV_STD_NTSC_J: - case TV_STD_PAL_60: - default: - args.ucDacStandard = ATOM_DAC1_NTSC; - break; - } - } - args.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -static void -atombios_tv_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - TV_ENCODER_CONTROL_PS_ALLOCATION args; - int index = 0; - struct radeon_encoder_atom_dac *dac_info = radeon_encoder->enc_priv; - - memset(&args, 0, sizeof(args)); - - index = GetIndexIntoMasterTable(COMMAND, TVEncoderControl); - - args.sTVEncoder.ucAction = action; - - if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.sTVEncoder.ucTvStandard = ATOM_TV_CV; - else { - switch (dac_info->tv_std) { - case TV_STD_NTSC: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; - break; - case TV_STD_PAL: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; - break; - case TV_STD_PAL_M: - args.sTVEncoder.ucTvStandard = ATOM_TV_PALM; - break; - case TV_STD_PAL_60: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL60; - break; - case TV_STD_NTSC_J: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSCJ; - break; - case TV_STD_SCART_PAL: - args.sTVEncoder.ucTvStandard = ATOM_TV_PAL; /* ??? */ - break; - case TV_STD_SECAM: - args.sTVEncoder.ucTvStandard = ATOM_TV_SECAM; - break; - case TV_STD_PAL_CN: - args.sTVEncoder.ucTvStandard = ATOM_TV_PALCN; - break; - default: - args.sTVEncoder.ucTvStandard = ATOM_TV_NTSC; - break; - } - } - - args.sTVEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -union dvo_encoder_control { - ENABLE_EXTERNAL_TMDS_ENCODER_PS_ALLOCATION ext_tmds; - DVO_ENCODER_CONTROL_PS_ALLOCATION dvo; - DVO_ENCODER_CONTROL_PS_ALLOCATION_V3 dvo_v3; -}; - -void -atombios_dvo_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - union dvo_encoder_control args; - int index = GetIndexIntoMasterTable(COMMAND, DVOEncoderControl); - - memset(&args, 0, sizeof(args)); - - if (ASIC_IS_DCE3(rdev)) { - /* DCE3+ */ - args.dvo_v3.ucAction = action; - args.dvo_v3.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.dvo_v3.ucDVOConfig = 0; /* XXX */ - } else if (ASIC_IS_DCE2(rdev)) { - /* DCE2 (pre-DCE3 R6xx, RS600/690/740 */ - args.dvo.sDVOEncoder.ucAction = action; - args.dvo.sDVOEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - /* DFP1, CRT1, TV1 depending on the type of port */ - args.dvo.sDVOEncoder.ucDeviceType = ATOM_DEVICE_DFP1_INDEX; - - if (radeon_encoder->pixel_clock > 165000) - args.dvo.sDVOEncoder.usDevAttr.sDigAttrib.ucAttribute |= PANEL_ENCODER_MISC_DUAL; - } else { - /* R4xx, R5xx */ - args.ext_tmds.sXTmdsEncoder.ucEnable = action; - - if (radeon_encoder->pixel_clock > 165000) - args.ext_tmds.sXTmdsEncoder.ucMisc |= PANEL_ENCODER_MISC_DUAL; - - /*if (pScrn->rgbBits == 8)*/ - args.ext_tmds.sXTmdsEncoder.ucMisc |= ATOM_PANEL_MISC_888RGB; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -union lvds_encoder_control { - LVDS_ENCODER_CONTROL_PS_ALLOCATION v1; - LVDS_ENCODER_CONTROL_PS_ALLOCATION_V2 v2; -}; - -void -atombios_digital_setup(struct drm_encoder *encoder, int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - union lvds_encoder_control args; - int index = 0; - int hdmi_detected = 0; - uint8_t frev, crev; - - if (!dig) - return; - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) - hdmi_detected = 1; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - index = GetIndexIntoMasterTable(COMMAND, TMDS1EncoderControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, LVDSEncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, TMDS2EncoderControl); - break; - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - case 2: - switch (crev) { - case 1: - args.v1.ucMisc = 0; - args.v1.ucAction = action; - if (hdmi_detected) - args.v1.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) - args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; - } else { - if (dig->linkb) - args.v1.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; - if (radeon_encoder->pixel_clock > 165000) - args.v1.ucMisc |= PANEL_ENCODER_MISC_DUAL; - /*if (pScrn->rgbBits == 8) */ - args.v1.ucMisc |= ATOM_PANEL_MISC_888RGB; - } - break; - case 2: - case 3: - args.v2.ucMisc = 0; - args.v2.ucAction = action; - if (crev == 3) { - if (dig->coherent_mode) - args.v2.ucMisc |= PANEL_ENCODER_MISC_COHERENT; - } - if (hdmi_detected) - args.v2.ucMisc |= PANEL_ENCODER_MISC_HDMI_TYPE; - args.v2.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v2.ucTruncate = 0; - args.v2.ucSpatial = 0; - args.v2.ucTemporal = 0; - args.v2.ucFRC = 0; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - if (dig->lcd_misc & ATOM_PANEL_MISC_DUAL) - args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; - if (dig->lcd_misc & ATOM_PANEL_MISC_SPATIAL) { - args.v2.ucSpatial = PANEL_ENCODER_SPATIAL_DITHER_EN; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v2.ucSpatial |= PANEL_ENCODER_SPATIAL_DITHER_DEPTH; - } - if (dig->lcd_misc & ATOM_PANEL_MISC_TEMPORAL) { - args.v2.ucTemporal = PANEL_ENCODER_TEMPORAL_DITHER_EN; - if (dig->lcd_misc & ATOM_PANEL_MISC_888RGB) - args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_DITHER_DEPTH; - if (((dig->lcd_misc >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT) & 0x3) == 2) - args.v2.ucTemporal |= PANEL_ENCODER_TEMPORAL_LEVEL_4; - } - } else { - if (dig->linkb) - args.v2.ucMisc |= PANEL_ENCODER_MISC_TMDS_LINKB; - if (radeon_encoder->pixel_clock > 165000) - args.v2.ucMisc |= PANEL_ENCODER_MISC_DUAL; - } - break; - default: - DRM_ERROR("Unknown table version %d, %d\n", frev, crev); - break; - } - break; - default: - DRM_ERROR("Unknown table version %d, %d\n", frev, crev); - break; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -int -atombios_get_encoder_mode(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct drm_connector *connector; - struct radeon_connector *radeon_connector; - struct radeon_connector_atom_dig *dig_connector; - - /* dp bridges are always DP */ - if (radeon_encoder_is_dp_bridge(encoder)) - return ATOM_ENCODER_MODE_DP; - - /* DVO is always DVO */ - if (radeon_encoder->encoder_id == ATOM_ENCODER_MODE_DVO) - return ATOM_ENCODER_MODE_DVO; - - connector = radeon_get_connector_for_encoder(encoder); - /* if we don't have an active device yet, just use one of - * the connectors tied to the encoder. - */ - if (!connector) - connector = radeon_get_connector_for_encoder_init(encoder); - radeon_connector = to_radeon_connector(connector); - - switch (connector->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_HDMIB: /* HDMI-B is basically DL-DVI; analog works fine */ - if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else if (radeon_connector->use_digital) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_CRT; - break; - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_HDMIA: - default: - if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else - return ATOM_ENCODER_MODE_DVI; - break; - case DRM_MODE_CONNECTOR_LVDS: - return ATOM_ENCODER_MODE_LVDS; - break; - case DRM_MODE_CONNECTOR_DisplayPort: - dig_connector = radeon_connector->con_priv; - if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) || - (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) - return ATOM_ENCODER_MODE_DP; - else if (drm_detect_monitor_audio(radeon_connector->edid) && radeon_audio) { - /* fix me */ - if (ASIC_IS_DCE4(rdev)) - return ATOM_ENCODER_MODE_DVI; - else - return ATOM_ENCODER_MODE_HDMI; - } else - return ATOM_ENCODER_MODE_DVI; - break; - case DRM_MODE_CONNECTOR_eDP: - return ATOM_ENCODER_MODE_DP; - case DRM_MODE_CONNECTOR_DVIA: - case DRM_MODE_CONNECTOR_VGA: - return ATOM_ENCODER_MODE_CRT; - break; - case DRM_MODE_CONNECTOR_Composite: - case DRM_MODE_CONNECTOR_SVIDEO: - case DRM_MODE_CONNECTOR_9PinDIN: - /* fix me */ - return ATOM_ENCODER_MODE_TV; - /*return ATOM_ENCODER_MODE_CV;*/ - break; - } -} - -/* - * DIG Encoder/Transmitter Setup - * - * DCE 3.0/3.1 - * - 2 DIG transmitter blocks. UNIPHY (links A and B) and LVTMA. - * Supports up to 3 digital outputs - * - 2 DIG encoder blocks. - * DIG1 can drive UNIPHY link A or link B - * DIG2 can drive UNIPHY link B or LVTMA - * - * DCE 3.2 - * - 3 DIG transmitter blocks. UNIPHY0/1/2 (links A and B). - * Supports up to 5 digital outputs - * - 2 DIG encoder blocks. - * DIG1/2 can drive UNIPHY0/1/2 link A or link B - * - * DCE 4.0/5.0 - * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). - * Supports up to 6 digital outputs - * - 6 DIG encoder blocks. - * - DIG to PHY mapping is hardcoded - * DIG1 drives UNIPHY0 link A, A+B - * DIG2 drives UNIPHY0 link B - * DIG3 drives UNIPHY1 link A, A+B - * DIG4 drives UNIPHY1 link B - * DIG5 drives UNIPHY2 link A, A+B - * DIG6 drives UNIPHY2 link B - * - * DCE 4.1 - * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). - * Supports up to 6 digital outputs - * - 2 DIG encoder blocks. - * DIG1/2 can drive UNIPHY0/1/2 link A or link B - * - * Routing - * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) - * Examples: - * crtc0 -> dig2 -> LVTMA links A+B -> TMDS/HDMI - * crtc1 -> dig1 -> UNIPHY0 link B -> DP - * crtc0 -> dig1 -> UNIPHY2 link A -> LVDS - * crtc1 -> dig2 -> UNIPHY1 link B+A -> TMDS/HDMI - */ - -union dig_encoder_control { - DIG_ENCODER_CONTROL_PS_ALLOCATION v1; - DIG_ENCODER_CONTROL_PARAMETERS_V2 v2; - DIG_ENCODER_CONTROL_PARAMETERS_V3 v3; - DIG_ENCODER_CONTROL_PARAMETERS_V4 v4; -}; - -void -atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - union dig_encoder_control args; - int index = 0; - uint8_t frev, crev; - int dp_clock = 0; - int dp_lane_count = 0; - int hpd_id = RADEON_HPD_NONE; - int bpc = 8; - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - hpd_id = radeon_connector->hpd.hpd; - bpc = connector->display_info.bpc; - } - - /* no dig encoder assigned */ - if (dig->dig_encoder == -1) - return; - - memset(&args, 0, sizeof(args)); - - if (ASIC_IS_DCE4(rdev)) - index = GetIndexIntoMasterTable(COMMAND, DIGxEncoderControl); - else { - if (dig->dig_encoder) - index = GetIndexIntoMasterTable(COMMAND, DIG2EncoderControl); - else - index = GetIndexIntoMasterTable(COMMAND, DIG1EncoderControl); - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - args.v1.ucAction = action; - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - if (action == ATOM_ENCODER_CMD_SETUP_PANEL_MODE) - args.v3.ucPanelMode = panel_mode; - else - args.v1.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || - (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) - args.v1.ucLaneNum = dp_lane_count; - else if (radeon_encoder->pixel_clock > 165000) - args.v1.ucLaneNum = 8; - else - args.v1.ucLaneNum = 4; - - if (ASIC_IS_DCE5(rdev)) { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) || - (args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP_MST)) { - if (dp_clock == 270000) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ; - else if (dp_clock == 540000) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ; - } - args.v4.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v4.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v4.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v4.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v4.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v4.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v4.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - if (hpd_id == RADEON_HPD_NONE) - args.v4.ucHPD_ID = 0; - else - args.v4.ucHPD_ID = hpd_id + 1; - } else if (ASIC_IS_DCE4(rdev)) { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; - args.v3.acConfig.ucDigSel = dig->dig_encoder; - switch (bpc) { - case 0: - args.v3.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - } else { - if ((args.v1.ucEncoderMode == ATOM_ENCODER_MODE_DP) && (dp_clock == 270000)) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER2; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v1.ucConfig = ATOM_ENCODER_CONFIG_V2_TRANSMITTER3; - break; - } - if (dig->linkb) - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKB; - else - args.v1.ucConfig |= ATOM_ENCODER_CONFIG_LINKA; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - -} - -union dig_transmitter_control { - DIG_TRANSMITTER_CONTROL_PS_ALLOCATION v1; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 v2; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 v3; - DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 v4; -}; - -void -atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - struct drm_connector *connector; - union dig_transmitter_control args; - int index = 0; - uint8_t frev, crev; - bool is_dp = false; - int pll_id = 0; - int dp_clock = 0; - int dp_lane_count = 0; - int connector_object_id = 0; - int igp_lane_info = 0; - int dig_encoder = dig->dig_encoder; - - if (action == ATOM_TRANSMITTER_ACTION_INIT) { - connector = radeon_get_connector_for_encoder_init(encoder); - /* just needed to avoid bailing in the encoder check. the encoder - * isn't used for init - */ - dig_encoder = 0; - } else - connector = radeon_get_connector_for_encoder(encoder); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - connector_object_id = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - igp_lane_info = dig_connector->igp_lane_info; - } - - /* no dig encoder assigned */ - if (dig_encoder == -1) - return; - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) - is_dp = true; - - memset(&args, 0, sizeof(args)); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - index = GetIndexIntoMasterTable(COMMAND, LVTMATransmitterControl); - break; - } - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - args.v1.ucAction = action; - if (action == ATOM_TRANSMITTER_ACTION_INIT) { - args.v1.usInitInfo = cpu_to_le16(connector_object_id); - } else if (action == ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH) { - args.v1.asMode.ucLaneSel = lane_num; - args.v1.asMode.ucLaneSet = lane_set; - } else { - if (is_dp) - args.v1.usPixelClock = - cpu_to_le16(dp_clock / 10); - else if (radeon_encoder->pixel_clock > 165000) - args.v1.usPixelClock = cpu_to_le16((radeon_encoder->pixel_clock / 2) / 10); - else - args.v1.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - } - if (ASIC_IS_DCE4(rdev)) { - if (is_dp) - args.v3.ucLaneNum = dp_lane_count; - else if (radeon_encoder->pixel_clock > 165000) - args.v3.ucLaneNum = 8; - else - args.v3.ucLaneNum = 4; - - if (dig->linkb) - args.v3.acConfig.ucLinkSel = 1; - if (dig_encoder & 1) - args.v3.acConfig.ucEncoderSel = 1; - - /* Select the PLL for the PHY - * DP PHY should be clocked from external src if there is - * one. - */ - if (encoder->crtc) { - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - pll_id = radeon_crtc->pll_id; - } - - if (ASIC_IS_DCE5(rdev)) { - /* On DCE5 DCPLL usually generates the DP ref clock */ - if (is_dp) { - if (rdev->clock.dp_extclk) - args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_EXTCLK; - else - args.v4.acConfig.ucRefClkSource = ENCODER_REFCLK_SRC_DCPLL; - } else - args.v4.acConfig.ucRefClkSource = pll_id; - } else { - /* On DCE4, if there is an external clock, it generates the DP ref clock */ - if (is_dp && rdev->clock.dp_extclk) - args.v3.acConfig.ucRefClkSource = 2; /* external src */ - else - args.v3.acConfig.ucRefClkSource = pll_id; - } - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v3.acConfig.ucTransmitterSel = 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - args.v3.acConfig.ucTransmitterSel = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v3.acConfig.ucTransmitterSel = 2; - break; - } - - if (is_dp) - args.v3.acConfig.fCoherentMode = 1; /* DP requires coherent */ - else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v3.acConfig.fCoherentMode = 1; - if (radeon_encoder->pixel_clock > 165000) - args.v3.acConfig.fDualLinkConnector = 1; - } - } else if (ASIC_IS_DCE32(rdev)) { - args.v2.acConfig.ucEncoderSel = dig_encoder; - if (dig->linkb) - args.v2.acConfig.ucLinkSel = 1; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - args.v2.acConfig.ucTransmitterSel = 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - args.v2.acConfig.ucTransmitterSel = 1; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - args.v2.acConfig.ucTransmitterSel = 2; - break; - } - - if (is_dp) { - args.v2.acConfig.fCoherentMode = 1; - args.v2.acConfig.fDPConnector = 1; - } else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v2.acConfig.fCoherentMode = 1; - if (radeon_encoder->pixel_clock > 165000) - args.v2.acConfig.fDualLinkConnector = 1; - } - } else { - args.v1.ucConfig = ATOM_TRANSMITTER_CONFIG_CLKSRC_PPLL; - - if (dig_encoder) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG2_ENCODER; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_DIG1_ENCODER; - - if ((rdev->flags & RADEON_IS_IGP) && - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_UNIPHY)) { - if (is_dp || (radeon_encoder->pixel_clock <= 165000)) { - if (igp_lane_info & 0x1) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_3; - else if (igp_lane_info & 0x2) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_4_7; - else if (igp_lane_info & 0x4) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_11; - else if (igp_lane_info & 0x8) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_12_15; - } else { - if (igp_lane_info & 0x3) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_0_7; - else if (igp_lane_info & 0xc) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LANE_8_15; - } - } - - if (dig->linkb) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKB; - else - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_LINKA; - - if (is_dp) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; - else if (radeon_encoder->devices & (ATOM_DEVICE_DFP_SUPPORT)) { - if (dig->coherent_mode) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_COHERENT; - if (radeon_encoder->pixel_clock > 165000) - args.v1.ucConfig |= ATOM_TRANSMITTER_CONFIG_8LANE_LINK; - } - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -bool -atombios_set_edp_panel_power(struct drm_connector *connector, int action) -{ - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_device *dev = radeon_connector->base.dev; - struct radeon_device *rdev = dev->dev_private; - union dig_transmitter_control args; - int index = GetIndexIntoMasterTable(COMMAND, UNIPHYTransmitterControl); - uint8_t frev, crev; - - if (connector->connector_type != DRM_MODE_CONNECTOR_eDP) - goto done; - - if (!ASIC_IS_DCE4(rdev)) - goto done; - - if ((action != ATOM_TRANSMITTER_ACTION_POWER_ON) && - (action != ATOM_TRANSMITTER_ACTION_POWER_OFF)) - goto done; - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - goto done; - - memset(&args, 0, sizeof(args)); - - args.v1.ucAction = action; - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - /* wait for the panel to power up */ - if (action == ATOM_TRANSMITTER_ACTION_POWER_ON) { - int i; - - for (i = 0; i < 300; i++) { - if (radeon_hpd_sense(rdev, radeon_connector->hpd.hpd)) - return true; - mdelay(1); - } - return false; - } -done: - return true; -} - -union external_encoder_control { - EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; - EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; -}; - -static void -atombios_external_encoder_setup(struct drm_encoder *encoder, - struct drm_encoder *ext_encoder, - int action) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); - union external_encoder_control args; - struct drm_connector *connector; - int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); - u8 frev, crev; - int dp_clock = 0; - int dp_lane_count = 0; - int connector_object_id = 0; - u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - int bpc = 8; - - if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) - connector = radeon_get_connector_for_encoder_init(encoder); - else - connector = radeon_get_connector_for_encoder(encoder); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *dig_connector = - radeon_connector->con_priv; - - dp_clock = dig_connector->dp_clock; - dp_lane_count = dig_connector->dp_lane_count; - connector_object_id = - (radeon_connector->connector_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - bpc = connector->display_info.bpc; - } - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - /* no params on frev 1 */ - break; - case 2: - switch (crev) { - case 1: - case 2: - args.v1.sDigEncoder.ucAction = action; - args.v1.sDigEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v1.sDigEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if (args.v1.sDigEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_clock == 270000) - args.v1.sDigEncoder.ucConfig |= ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ; - args.v1.sDigEncoder.ucLaneNum = dp_lane_count; - } else if (radeon_encoder->pixel_clock > 165000) - args.v1.sDigEncoder.ucLaneNum = 8; - else - args.v1.sDigEncoder.ucLaneNum = 4; - break; - case 3: - args.v3.sExtEncoder.ucAction = action; - if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) - args.v3.sExtEncoder.usConnectorId = cpu_to_le16(connector_object_id); - else - args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); - args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); - - if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { - if (dp_clock == 270000) - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; - else if (dp_clock == 540000) - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; - args.v3.sExtEncoder.ucLaneNum = dp_lane_count; - } else if (radeon_encoder->pixel_clock > 165000) - args.v3.sExtEncoder.ucLaneNum = 8; - else - args.v3.sExtEncoder.ucLaneNum = 4; - switch (ext_enum) { - case GRAPH_OBJECT_ENUM_ID1: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; - break; - case GRAPH_OBJECT_ENUM_ID2: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; - break; - case GRAPH_OBJECT_ENUM_ID3: - args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; - break; - } - switch (bpc) { - case 0: - args.v3.sExtEncoder.ucBitPerColor = PANEL_BPC_UNDEFINE; - break; - case 6: - args.v3.sExtEncoder.ucBitPerColor = PANEL_6BIT_PER_COLOR; - break; - case 8: - default: - args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; - break; - case 10: - args.v3.sExtEncoder.ucBitPerColor = PANEL_10BIT_PER_COLOR; - break; - case 12: - args.v3.sExtEncoder.ucBitPerColor = PANEL_12BIT_PER_COLOR; - break; - case 16: - args.v3.sExtEncoder.ucBitPerColor = PANEL_16BIT_PER_COLOR; - break; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); -} - -static void -atombios_yuv_setup(struct drm_encoder *encoder, bool enable) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - ENABLE_YUV_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, EnableYUV); - uint32_t temp, reg; - - memset(&args, 0, sizeof(args)); - - if (rdev->family >= CHIP_R600) - reg = R600_BIOS_3_SCRATCH; - else - reg = RADEON_BIOS_3_SCRATCH; - - /* XXX: fix up scratch reg handling */ - temp = RREG32(reg); - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - WREG32(reg, (ATOM_S3_TV1_ACTIVE | - (radeon_crtc->crtc_id << 18))); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - WREG32(reg, (ATOM_S3_CV_ACTIVE | (radeon_crtc->crtc_id << 24))); - else - WREG32(reg, 0); - - if (enable) - args.ucEnable = ATOM_ENABLE; - args.ucCRTC = radeon_crtc->crtc_id; - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - WREG32(reg, temp); -} - -static void -radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION args; - int index = 0; - bool is_dig = false; - bool is_dce5_dac = false; - bool is_dce5_dvo = false; - - memset(&args, 0, sizeof(args)); - - DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", - radeon_encoder->encoder_id, mode, radeon_encoder->devices, - radeon_encoder->active_device); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - index = GetIndexIntoMasterTable(COMMAND, TMDSAOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - is_dig = true; - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - if (ASIC_IS_DCE5(rdev)) - is_dce5_dvo = true; - else if (ASIC_IS_DCE3(rdev)) - is_dig = true; - else - index = GetIndexIntoMasterTable(COMMAND, DVOOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, LCD1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, LVTMAOutputControl); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (ASIC_IS_DCE5(rdev)) - is_dce5_dac = true; - else { - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, DAC1OutputControl); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, TV1OutputControl); - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - index = GetIndexIntoMasterTable(COMMAND, CV1OutputControl); - else - index = GetIndexIntoMasterTable(COMMAND, DAC2OutputControl); - break; - } - - if (is_dig) { - switch (mode) { - case DRM_MODE_DPMS_ON: - /* some early dce3.2 boards have a bug in their transmitter control table */ - if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - else - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE_OUTPUT, 0, 0); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (connector && - (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = - radeon_connector->con_priv; - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_ON); - radeon_dig_connector->edp_on = true; - } - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); - radeon_dp_link_train(encoder, connector); - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); - } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE_OUTPUT, 0, 0); - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_DP) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); - if (connector && - (connector->connector_type == DRM_MODE_CONNECTOR_eDP)) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct radeon_connector_atom_dig *radeon_dig_connector = - radeon_connector->con_priv; - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_OFF); - radeon_dig_connector->edp_on = false; - } - } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); - break; - } - } else if (is_dce5_dac) { - switch (mode) { - case DRM_MODE_DPMS_ON: - atombios_dac_setup(encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dac_setup(encoder, ATOM_DISABLE); - break; - } - } else if (is_dce5_dvo) { - switch (mode) { - case DRM_MODE_DPMS_ON: - atombios_dvo_setup(encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - atombios_dvo_setup(encoder, ATOM_DISABLE); - break; - } - } else { - switch (mode) { - case DRM_MODE_DPMS_ON: - args.ucAction = ATOM_ENABLE; - /* workaround for DVOOutputControl on some RS690 systems */ - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DDI) { - u32 reg = RREG32(RADEON_BIOS_3_SCRATCH); - WREG32(RADEON_BIOS_3_SCRATCH, reg & ~ATOM_S3_DFP2I_ACTIVE); - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - WREG32(RADEON_BIOS_3_SCRATCH, reg); - } else - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLON; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - args.ucAction = ATOM_DISABLE; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - args.ucAction = ATOM_LCD_BLOFF; - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - } - break; - } - } - - if (ext_encoder) { - switch (mode) { - case DRM_MODE_DPMS_ON: - default: - if (ASIC_IS_DCE41(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); - break; - } - } - - radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); - -} - -union crtc_source_param { - SELECT_CRTC_SOURCE_PS_ALLOCATION v1; - SELECT_CRTC_SOURCE_PARAMETERS_V2 v2; -}; - -static void -atombios_set_encoder_crtc_source(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - union crtc_source_param args; - int index = GetIndexIntoMasterTable(COMMAND, SelectCRTC_Source); - uint8_t frev, crev; - struct radeon_encoder_atom_dig *dig; - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return; - - switch (frev) { - case 1: - switch (crev) { - case 1: - default: - if (ASIC_IS_AVIVO(rdev)) - args.v1.ucCRTC = radeon_crtc->crtc_id; - else { - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) { - args.v1.ucCRTC = radeon_crtc->crtc_id; - } else { - args.v1.ucCRTC = radeon_crtc->crtc_id << 2; - } - } - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - args.v1.ucDevice = ATOM_DEVICE_DFP1_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) - args.v1.ucDevice = ATOM_DEVICE_LCD1_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_DFP3_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - args.v1.ucDevice = ATOM_DEVICE_DFP2_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_CRT1_INDEX; - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_TV1_INDEX; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v1.ucDevice = ATOM_DEVICE_CV_INDEX; - else - args.v1.ucDevice = ATOM_DEVICE_CRT2_INDEX; - break; - } - break; - case 2: - args.v2.ucCRTC = radeon_crtc->crtc_id; - if (radeon_encoder_is_dp_bridge(encoder)) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) - args.v2.ucEncodeMode = ATOM_ENCODER_MODE_LVDS; - else if (connector->connector_type == DRM_MODE_CONNECTOR_VGA) - args.v2.ucEncodeMode = ATOM_ENCODER_MODE_CRT; - else - args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); - } else - args.v2.ucEncodeMode = atombios_get_encoder_mode(encoder); - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - dig = radeon_encoder->enc_priv; - switch (dig->dig_encoder) { - case 0: - args.v2.ucEncoderID = ASIC_INT_DIG1_ENCODER_ID; - break; - case 1: - args.v2.ucEncoderID = ASIC_INT_DIG2_ENCODER_ID; - break; - case 2: - args.v2.ucEncoderID = ASIC_INT_DIG3_ENCODER_ID; - break; - case 3: - args.v2.ucEncoderID = ASIC_INT_DIG4_ENCODER_ID; - break; - case 4: - args.v2.ucEncoderID = ASIC_INT_DIG5_ENCODER_ID; - break; - case 5: - args.v2.ucEncoderID = ASIC_INT_DIG6_ENCODER_ID; - break; - } - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - args.v2.ucEncoderID = ASIC_INT_DVO_ENCODER_ID; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DAC1_ENCODER_ID; - break; - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT)) - args.v2.ucEncoderID = ASIC_INT_TV_ENCODER_ID; - else - args.v2.ucEncoderID = ASIC_INT_DAC2_ENCODER_ID; - break; - } - break; - } - break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - /* update scratch regs with new routing */ - radeon_atombios_encoder_crtc_scratch_regs(encoder, radeon_crtc->crtc_id); -} - -static void -atombios_apply_encoder_quirks(struct drm_encoder *encoder, - struct drm_display_mode *mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - - /* Funky macbooks */ - if ((dev->pdev->device == 0x71C5) && - (dev->pdev->subsystem_vendor == 0x106b) && - (dev->pdev->subsystem_device == 0x0080)) { - if (radeon_encoder->devices & ATOM_DEVICE_LCD1_SUPPORT) { - uint32_t lvtma_bit_depth_control = RREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL); - - lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_TRUNCATE_EN; - lvtma_bit_depth_control &= ~AVIVO_LVTMA_BIT_DEPTH_CONTROL_SPATIAL_DITHER_EN; - - WREG32(AVIVO_LVTMA_BIT_DEPTH_CONTROL, lvtma_bit_depth_control); - } - } - - /* set scaler clears this on some chips */ - if (ASIC_IS_AVIVO(rdev) && - (!(radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT)))) { - if (ASIC_IS_DCE4(rdev)) { - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, - EVERGREEN_INTERLEAVE_EN); - else - WREG32(EVERGREEN_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - } else { - if (mode->flags & DRM_MODE_FLAG_INTERLACE) - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, - AVIVO_D1MODE_INTERLEAVE_EN); - else - WREG32(AVIVO_D1MODE_DATA_FORMAT + radeon_crtc->crtc_offset, 0); - } - } -} - -static int radeon_atom_pick_dig_encoder(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *test_encoder; - struct radeon_encoder_atom_dig *dig; - uint32_t dig_enc_in_use = 0; - - /* DCE4/5 */ - if (ASIC_IS_DCE4(rdev)) { - dig = radeon_encoder->enc_priv; - if (ASIC_IS_DCE41(rdev)) { - /* ontario follows DCE4 */ - if (rdev->family == CHIP_PALM) { - if (dig->linkb) - return 1; - else - return 0; - } else - /* llano follows DCE3.2 */ - return radeon_crtc->crtc_id; - } else { - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - if (dig->linkb) - return 1; - else - return 0; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - if (dig->linkb) - return 3; - else - return 2; - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (dig->linkb) - return 5; - else - return 4; - break; - } - } - } - - /* on DCE32 and encoder can driver any block so just crtc id */ - if (ASIC_IS_DCE32(rdev)) { - return radeon_crtc->crtc_id; - } - - /* on DCE3 - LVTMA can only be driven by DIGB */ - list_for_each_entry(test_encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_test_encoder; - - if (encoder == test_encoder) - continue; - - if (!radeon_encoder_is_digital(test_encoder)) - continue; - - radeon_test_encoder = to_radeon_encoder(test_encoder); - dig = radeon_test_encoder->enc_priv; - - if (dig->dig_encoder >= 0) - dig_enc_in_use |= (1 << dig->dig_encoder); - } - - if (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA) { - if (dig_enc_in_use & 0x2) - DRM_ERROR("LVDS required digital encoder 2 but it was in use - stealing\n"); - return 1; - } - if (!(dig_enc_in_use & 1)) - return 0; - return 1; -} - -/* This only needs to be called once at startup */ -void -radeon_atom_encoder_init(struct radeon_device *rdev) -{ - struct drm_device *dev = rdev->ddev; - struct drm_encoder *encoder; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_INIT, 0, 0); - break; - default: - break; - } - - if (ext_encoder && ASIC_IS_DCE41(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); - } -} - -static void -radeon_atom_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - radeon_encoder->pixel_clock = adjusted_mode->clock; - - if (ASIC_IS_AVIVO(rdev) && !ASIC_IS_DCE4(rdev)) { - if (radeon_encoder->active_device & (ATOM_DEVICE_CV_SUPPORT | ATOM_DEVICE_TV_SUPPORT)) - atombios_yuv_setup(encoder, true); - else - atombios_yuv_setup(encoder, false); - } - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_ENABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) { - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - /* setup and enable the encoder */ - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - - /* enable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - - /* setup and enable the encoder and transmitter */ - atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_dvo_setup(encoder, ATOM_ENABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - atombios_dac_setup(encoder, ATOM_ENABLE); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) { - if (radeon_encoder->active_device & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) - atombios_tv_setup(encoder, ATOM_ENABLE); - else - atombios_tv_setup(encoder, ATOM_DISABLE); - } - break; - } - - if (ext_encoder) { - if (ASIC_IS_DCE41(rdev)) - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); - else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - } - - atombios_apply_encoder_quirks(encoder, adjusted_mode); - - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) { - r600_hdmi_enable(encoder); - r600_hdmi_setmode(encoder, adjusted_mode); - } -} - -static bool -atombios_dac_load_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | - ATOM_DEVICE_CV_SUPPORT | - ATOM_DEVICE_CRT_SUPPORT)) { - DAC_LOAD_DETECTION_PS_ALLOCATION args; - int index = GetIndexIntoMasterTable(COMMAND, DAC_LoadDetection); - uint8_t frev, crev; - - memset(&args, 0, sizeof(args)); - - if (!atom_parse_cmd_header(rdev->mode_info.atom_context, index, &frev, &crev)) - return false; - - args.sDacload.ucMisc = 0; - - if ((radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_DAC1) || - (radeon_encoder->encoder_id == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1)) - args.sDacload.ucDacType = ATOM_DAC_A; - else - args.sDacload.ucDacType = ATOM_DAC_B; - - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT); - else if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_CV_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } else if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - args.sDacload.usDeviceID = cpu_to_le16(ATOM_DEVICE_TV1_SUPPORT); - if (crev >= 3) - args.sDacload.ucMisc = DAC_LOAD_MISC_YPrPb; - } - - atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args); - - return true; - } else - return false; -} - -static enum drm_connector_status -radeon_atom_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - uint32_t bios_0_scratch; - - if (!atombios_dac_load_detect(encoder, connector)) { - DRM_DEBUG_KMS("detect returned false \n"); - return connector_status_unknown; - } - - if (rdev->family >= CHIP_R600) - bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); - else - bios_0_scratch = RREG32(RADEON_BIOS_0_SCRATCH); - - DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT1_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT2_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) - return connector_status_connected; /* CTV */ - else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) - return connector_status_connected; /* STV */ - } - return connector_status_disconnected; -} - -static enum drm_connector_status -radeon_atom_dig_detect(struct drm_encoder *encoder, struct drm_connector *connector) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - u32 bios_0_scratch; - - if (!ASIC_IS_DCE4(rdev)) - return connector_status_unknown; - - if (!ext_encoder) - return connector_status_unknown; - - if ((radeon_connector->devices & ATOM_DEVICE_CRT_SUPPORT) == 0) - return connector_status_unknown; - - /* load detect on the dp bridge */ - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION); - - bios_0_scratch = RREG32(R600_BIOS_0_SCRATCH); - - DRM_DEBUG_KMS("Bios 0 scratch %x %08x\n", bios_0_scratch, radeon_encoder->devices); - if (radeon_connector->devices & ATOM_DEVICE_CRT1_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT1_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CRT2_SUPPORT) { - if (bios_0_scratch & ATOM_S0_CRT2_MASK) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_CV_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_CV_MASK|ATOM_S0_CV_MASK_A)) - return connector_status_connected; - } - if (radeon_connector->devices & ATOM_DEVICE_TV1_SUPPORT) { - if (bios_0_scratch & (ATOM_S0_TV1_COMPOSITE | ATOM_S0_TV1_COMPOSITE_A)) - return connector_status_connected; /* CTV */ - else if (bios_0_scratch & (ATOM_S0_TV1_SVIDEO | ATOM_S0_TV1_SVIDEO_A)) - return connector_status_connected; /* STV */ - } - return connector_status_disconnected; -} - -void -radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder) -{ - struct drm_encoder *ext_encoder = radeon_atom_get_external_encoder(encoder); - - if (ext_encoder) - /* ddc_setup on the dp bridge */ - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); - -} - -static void radeon_atom_encoder_prepare(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - - if ((radeon_encoder->active_device & - (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) || - radeon_encoder_is_dp_bridge(encoder)) { - struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; - if (dig) - dig->dig_encoder = radeon_atom_pick_dig_encoder(encoder); - } - - radeon_atom_output_lock(encoder, true); - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); - - /* select the clock/data port if it uses a router */ - if (radeon_connector->router.cd_valid) - radeon_router_select_cd_port(radeon_connector); - - /* turn eDP panel on for mode set */ - if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) - atombios_set_edp_panel_power(connector, - ATOM_TRANSMITTER_ACTION_POWER_ON); - } - - /* this is needed for the pll/ss setup to work correctly in some cases */ - atombios_set_encoder_crtc_source(encoder); -} - -static void radeon_atom_encoder_commit(struct drm_encoder *encoder) -{ - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_ON); - radeon_atom_output_lock(encoder, false); -} - -static void radeon_atom_encoder_disable(struct drm_encoder *encoder) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct radeon_encoder_atom_dig *dig; - - /* check for pre-DCE3 cards with shared encoders; - * can't really use the links individually, so don't disable - * the encoder if it's in use by another connector - */ - if (!ASIC_IS_DCE3(rdev)) { - struct drm_encoder *other_encoder; - struct radeon_encoder *other_radeon_encoder; - - list_for_each_entry(other_encoder, &dev->mode_config.encoder_list, head) { - other_radeon_encoder = to_radeon_encoder(other_encoder); - if ((radeon_encoder->encoder_id == other_radeon_encoder->encoder_id) && - drm_helper_encoder_in_use(other_encoder)) - goto disable_done; - } - } - - radeon_atom_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - atombios_digital_setup(encoder, PANEL_ENCODER_ACTION_DISABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - if (ASIC_IS_DCE4(rdev)) - /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - else { - /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); - atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); - } - break; - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - atombios_dvo_setup(encoder, ATOM_DISABLE); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - atombios_dac_setup(encoder, ATOM_DISABLE); - if (radeon_encoder->devices & (ATOM_DEVICE_TV_SUPPORT | ATOM_DEVICE_CV_SUPPORT)) - atombios_tv_setup(encoder, ATOM_DISABLE); - break; - } - -disable_done: - if (radeon_encoder_is_digital(encoder)) { - if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) - r600_hdmi_disable(encoder); - dig = radeon_encoder->enc_priv; - dig->dig_encoder = -1; - } - radeon_encoder->active_device = 0; -} - -/* these are handled by the primary encoders */ -static void radeon_atom_ext_prepare(struct drm_encoder *encoder) -{ - -} - -static void radeon_atom_ext_commit(struct drm_encoder *encoder) -{ - -} - -static void -radeon_atom_ext_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - -} - -static void radeon_atom_ext_disable(struct drm_encoder *encoder) -{ - -} - -static void -radeon_atom_ext_dpms(struct drm_encoder *encoder, int mode) -{ - -} - -static bool radeon_atom_ext_mode_fixup(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - -static const struct drm_encoder_helper_funcs radeon_atom_ext_helper_funcs = { - .dpms = radeon_atom_ext_dpms, - .mode_fixup = radeon_atom_ext_mode_fixup, - .prepare = radeon_atom_ext_prepare, - .mode_set = radeon_atom_ext_mode_set, - .commit = radeon_atom_ext_commit, - .disable = radeon_atom_ext_disable, - /* no detect for TMDS/LVDS yet */ -}; - -static const struct drm_encoder_helper_funcs radeon_atom_dig_helper_funcs = { - .dpms = radeon_atom_encoder_dpms, - .mode_fixup = radeon_atom_mode_fixup, - .prepare = radeon_atom_encoder_prepare, - .mode_set = radeon_atom_encoder_mode_set, - .commit = radeon_atom_encoder_commit, - .disable = radeon_atom_encoder_disable, - .detect = radeon_atom_dig_detect, -}; - -static const struct drm_encoder_helper_funcs radeon_atom_dac_helper_funcs = { - .dpms = radeon_atom_encoder_dpms, - .mode_fixup = radeon_atom_mode_fixup, - .prepare = radeon_atom_encoder_prepare, - .mode_set = radeon_atom_encoder_mode_set, - .commit = radeon_atom_encoder_commit, - .detect = radeon_atom_dac_detect, -}; - -void radeon_enc_destroy(struct drm_encoder *encoder) -{ - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - kfree(radeon_encoder->enc_priv); - drm_encoder_cleanup(encoder); - kfree(radeon_encoder); -} - -static const struct drm_encoder_funcs radeon_atom_enc_funcs = { - .destroy = radeon_enc_destroy, -}; - -struct radeon_encoder_atom_dac * -radeon_atombios_set_dac_info(struct radeon_encoder *radeon_encoder) -{ - struct drm_device *dev = radeon_encoder->base.dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder_atom_dac *dac = kzalloc(sizeof(struct radeon_encoder_atom_dac), GFP_KERNEL); - - if (!dac) - return NULL; - - dac->tv_std = radeon_atombios_get_tv_info(rdev); - return dac; -} - -struct radeon_encoder_atom_dig * -radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder) -{ - int encoder_enum = (radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - struct radeon_encoder_atom_dig *dig = kzalloc(sizeof(struct radeon_encoder_atom_dig), GFP_KERNEL); - - if (!dig) - return NULL; - - /* coherent mode by default */ - dig->coherent_mode = true; - dig->dig_encoder = -1; - - if (encoder_enum == 2) - dig->linkb = true; - else - dig->linkb = false; - - return dig; -} - -void -radeon_add_atom_encoder(struct drm_device *dev, - uint32_t encoder_enum, - uint32_t supported_device, - u16 caps) -{ - struct radeon_device *rdev = dev->dev_private; - struct drm_encoder *encoder; - struct radeon_encoder *radeon_encoder; - - /* see if we already added it */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - radeon_encoder = to_radeon_encoder(encoder); - if (radeon_encoder->encoder_enum == encoder_enum) { - radeon_encoder->devices |= supported_device; - return; - } - - } - - /* add a new one */ - radeon_encoder = kzalloc(sizeof(struct radeon_encoder), GFP_KERNEL); - if (!radeon_encoder) - return; - - encoder = &radeon_encoder->base; - switch (rdev->num_crtc) { - case 1: - encoder->possible_crtcs = 0x1; - break; - case 2: - default: - encoder->possible_crtcs = 0x3; - break; - case 4: - encoder->possible_crtcs = 0xf; - break; - case 6: - encoder->possible_crtcs = 0x3f; - break; - } - - radeon_encoder->enc_priv = NULL; - - radeon_encoder->encoder_enum = encoder_enum; - radeon_encoder->encoder_id = (encoder_enum & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT; - radeon_encoder->devices = supported_device; - radeon_encoder->rmx_type = RMX_OFF; - radeon_encoder->underscan_type = UNDERSCAN_OFF; - radeon_encoder->is_ext_encoder = false; - radeon_encoder->caps = caps; - - switch (radeon_encoder->encoder_id) { - case ENCODER_OBJECT_ID_INTERNAL_LVDS: - case ENCODER_OBJECT_ID_INTERNAL_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1: - case ENCODER_OBJECT_ID_INTERNAL_LVTM1: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - radeon_encoder->rmx_type = RMX_FULL; - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); - } else { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } - drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC1: - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); - drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DAC2: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2: - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TVDAC); - radeon_encoder->enc_priv = radeon_atombios_set_dac_info(radeon_encoder); - drm_encoder_helper_add(encoder, &radeon_atom_dac_helper_funcs); - break; - case ENCODER_OBJECT_ID_INTERNAL_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: - case ENCODER_OBJECT_ID_INTERNAL_DDI: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY: - case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1: - case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2: - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) { - radeon_encoder->rmx_type = RMX_FULL; - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - radeon_encoder->enc_priv = radeon_atombios_get_lvds_info(radeon_encoder); - } else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } else { - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder); - } - drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs); - break; - case ENCODER_OBJECT_ID_SI170B: - case ENCODER_OBJECT_ID_CH7303: - case ENCODER_OBJECT_ID_EXTERNAL_SDVOA: - case ENCODER_OBJECT_ID_EXTERNAL_SDVOB: - case ENCODER_OBJECT_ID_TITFP513: - case ENCODER_OBJECT_ID_VT1623: - case ENCODER_OBJECT_ID_HDMI_SI1930: - case ENCODER_OBJECT_ID_TRAVIS: - case ENCODER_OBJECT_ID_NUTMEG: - /* these are handled by the primary encoders */ - radeon_encoder->is_ext_encoder = true; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_LVDS); - else if (radeon_encoder->devices & (ATOM_DEVICE_CRT_SUPPORT)) - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_DAC); - else - drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS); - drm_encoder_helper_add(encoder, &radeon_atom_ext_helper_funcs); - break; - } -} diff --git a/drivers/gpu/drm/radeon/radeon_gart.c b/drivers/gpu/drm/radeon/radeon_gart.c index fdc3a9a54bf..ba7ab79e12c 100644 --- a/drivers/gpu/drm/radeon/radeon_gart.c +++ b/drivers/gpu/drm/radeon/radeon_gart.c @@ -49,27 +49,27 @@ int radeon_gart_table_ram_alloc(struct radeon_device *rdev) rdev->gart.table_size >> PAGE_SHIFT); } #endif - rdev->gart.table.ram.ptr = ptr; - memset((void *)rdev->gart.table.ram.ptr, 0, rdev->gart.table_size); + rdev->gart.ptr = ptr; + memset((void *)rdev->gart.ptr, 0, rdev->gart.table_size); return 0; } void radeon_gart_table_ram_free(struct radeon_device *rdev) { - if (rdev->gart.table.ram.ptr == NULL) { + if (rdev->gart.ptr == NULL) { return; } #ifdef CONFIG_X86 if (rdev->family == CHIP_RS400 || rdev->family == CHIP_RS480 || rdev->family == CHIP_RS690 || rdev->family == CHIP_RS740) { - set_memory_wb((unsigned long)rdev->gart.table.ram.ptr, + set_memory_wb((unsigned long)rdev->gart.ptr, rdev->gart.table_size >> PAGE_SHIFT); } #endif pci_free_consistent(rdev->pdev, rdev->gart.table_size, - (void *)rdev->gart.table.ram.ptr, + (void *)rdev->gart.ptr, rdev->gart.table_addr); - rdev->gart.table.ram.ptr = NULL; + rdev->gart.ptr = NULL; rdev->gart.table_addr = 0; } @@ -77,10 +77,10 @@ int radeon_gart_table_vram_alloc(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { r = radeon_bo_create(rdev, rdev->gart.table_size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - &rdev->gart.table.vram.robj); + &rdev->gart.robj); if (r) { return r; } @@ -93,38 +93,46 @@ int radeon_gart_table_vram_pin(struct radeon_device *rdev) uint64_t gpu_addr; int r; - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (unlikely(r != 0)) return r; - r = radeon_bo_pin(rdev->gart.table.vram.robj, + r = radeon_bo_pin(rdev->gart.robj, RADEON_GEM_DOMAIN_VRAM, &gpu_addr); if (r) { - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unreserve(rdev->gart.robj); return r; } - r = radeon_bo_kmap(rdev->gart.table.vram.robj, - (void **)&rdev->gart.table.vram.ptr); + r = radeon_bo_kmap(rdev->gart.robj, &rdev->gart.ptr); if (r) - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); rdev->gart.table_addr = gpu_addr; return r; } -void radeon_gart_table_vram_free(struct radeon_device *rdev) +void radeon_gart_table_vram_unpin(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { return; } - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); + r = radeon_bo_reserve(rdev->gart.robj, false); if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); + radeon_bo_kunmap(rdev->gart.robj); + radeon_bo_unpin(rdev->gart.robj); + radeon_bo_unreserve(rdev->gart.robj); + rdev->gart.ptr = NULL; } - radeon_bo_unref(&rdev->gart.table.vram.robj); +} + +void radeon_gart_table_vram_free(struct radeon_device *rdev) +{ + if (rdev->gart.robj == NULL) { + return; + } + radeon_gart_table_vram_unpin(rdev); + radeon_bo_unref(&rdev->gart.robj); } @@ -151,12 +159,14 @@ void radeon_gart_unbind(struct radeon_device *rdev, unsigned offset, if (rdev->gart.pages[p]) { if (!rdev->gart.ttm_alloced[p]) pci_unmap_page(rdev->pdev, rdev->gart.pages_addr[p], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); rdev->gart.pages[p] = NULL; rdev->gart.pages_addr[p] = rdev->dummy_page.addr; page_base = rdev->gart.pages_addr[p]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); + if (rdev->gart.ptr) { + radeon_gart_set_page(rdev, t, page_base); + } page_base += RADEON_GPU_PAGE_SIZE; } } @@ -199,10 +209,12 @@ int radeon_gart_bind(struct radeon_device *rdev, unsigned offset, } } rdev->gart.pages[p] = pagelist[i]; - page_base = rdev->gart.pages_addr[p]; - for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { - radeon_gart_set_page(rdev, t, page_base); - page_base += RADEON_GPU_PAGE_SIZE; + if (rdev->gart.ptr) { + page_base = rdev->gart.pages_addr[p]; + for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { + radeon_gart_set_page(rdev, t, page_base); + page_base += RADEON_GPU_PAGE_SIZE; + } } } mb(); @@ -215,6 +227,9 @@ void radeon_gart_restore(struct radeon_device *rdev) int i, j, t; u64 page_base; + if (!rdev->gart.ptr) { + return; + } for (i = 0, t = 0; i < rdev->gart.num_cpu_pages; i++) { page_base = rdev->gart.pages_addr[i]; for (j = 0; j < (PAGE_SIZE / RADEON_GPU_PAGE_SIZE); j++, t++) { diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index e6d110ce233..7bb1b079f48 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -34,7 +34,7 @@ * radeon_ddc_probe * */ -bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_extended_probe) +bool radeon_ddc_probe(struct radeon_connector *radeon_connector) { u8 out = 0x0; u8 buf[8]; @@ -49,15 +49,11 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_e { .addr = 0x50, .flags = I2C_M_RD, - .len = 1, + .len = 8, .buf = buf, } }; - /* Read 8 bytes from i2c for extended probe of EDID header */ - if (requires_extended_probe) - msgs[1].len = 8; - /* on hw with routers, select right port */ if (radeon_connector->router.ddc_valid) radeon_router_select_ddc_port(radeon_connector); @@ -66,17 +62,15 @@ bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool requires_e if (ret != 2) /* Couldn't find an accessible DDC on this connector */ return false; - if (requires_extended_probe) { - /* Probe also for valid EDID header - * EDID header starts with: - * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. - * Only the first 6 bytes must be valid as - * drm_edid_block_valid() can fix the last 2 bytes */ - if (drm_edid_header_is_valid(buf) < 6) { - /* Couldn't find an accessible EDID on this - * connector */ - return false; - } + /* Probe also for valid EDID header + * EDID header starts with: + * 0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00. + * Only the first 6 bytes must be valid as + * drm_edid_block_valid() can fix the last 2 bytes */ + if (drm_edid_header_is_valid(buf) < 6) { + /* Couldn't find an accessible EDID on this + * connector */ + return false; } return true; } diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 9ec830c77af..8f86aeb2669 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c @@ -67,10 +67,10 @@ void radeon_driver_irq_preinstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) { + for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; + for (i = 0; i < RADEON_MAX_CRTCS; i++) { + rdev->irq.crtc_vblank_int[i] = false; rdev->irq.pflip[i] = false; } radeon_irq_set(rdev); @@ -99,15 +99,55 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev) /* Disable *all* interrupts */ rdev->irq.sw_int = false; rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; - for (i = 0; i < 6; i++) { + for (i = 0; i < RADEON_MAX_HPD_PINS; i++) rdev->irq.hpd[i] = false; + for (i = 0; i < RADEON_MAX_CRTCS; i++) { + rdev->irq.crtc_vblank_int[i] = false; rdev->irq.pflip[i] = false; } radeon_irq_set(rdev); } +static bool radeon_msi_ok(struct radeon_device *rdev) +{ + /* RV370/RV380 was first asic with MSI support */ + if (rdev->family < CHIP_RV380) + return false; + + /* MSIs don't work on AGP */ + if (rdev->flags & RADEON_IS_AGP) + return false; + + /* force MSI on */ + if (radeon_msi == 1) + return true; + else if (radeon_msi == 0) + return false; + + /* Quirks */ + /* HP RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x103c) && + (rdev->pdev->subsystem_device == 0x30c2)) + return true; + + /* Dell RS690 only seems to work with MSIs. */ + if ((rdev->pdev->device == 0x791f) && + (rdev->pdev->subsystem_vendor == 0x1028) && + (rdev->pdev->subsystem_device == 0x01fd)) + return true; + + if (rdev->flags & RADEON_IS_IGP) { + /* APUs work fine with MSIs */ + if (rdev->family >= CHIP_PALM) + return true; + /* lots of IGPs have problems with MSIs */ + return false; + } + + return true; +} + int radeon_irq_kms_init(struct radeon_device *rdev) { int i; @@ -124,12 +164,8 @@ int radeon_irq_kms_init(struct radeon_device *rdev) } /* enable msi */ rdev->msi_enabled = 0; - /* MSIs don't seem to work reliably on all IGP - * chips. Disable MSI on them for now. - */ - if ((rdev->family >= CHIP_RV380) && - ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && - (!(rdev->flags & RADEON_IS_AGP))) { + + if (radeon_msi_ok(rdev)) { int ret = pci_enable_msi(rdev->pdev); if (!ret) { rdev->msi_enabled = 1; diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 41a5d48e657..daadf211104 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -991,12 +991,6 @@ static bool radeon_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = crtc->dev; - struct radeon_device *rdev = dev->dev_private; - - /* adjust pm to upcoming mode change */ - radeon_pm_compute_clocks(rdev); - if (!radeon_crtc_scaling_mode_fixup(crtc, mode, adjusted_mode)) return false; return true; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index ed0178f0323..2c2e75ef8a3 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -438,9 +438,6 @@ struct radeon_connector { struct radeon_i2c_chan *ddc_bus; /* some systems have an hdmi and vga port with a shared ddc line */ bool shared_ddc; - /* for some Radeon chip families we apply an additional EDID header - check as part of the DDC probe */ - bool requires_extended_probe; bool use_digital; /* we need to mind the EDID between detect and get modes due to analog/digital/tvencoder */ @@ -459,6 +456,8 @@ struct radeon_framebuffer { struct drm_gem_object *obj; }; +#define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \ + ((em) == ATOM_ENCODER_MODE_DP_MST)) extern enum radeon_tv_std radeon_combios_get_tv_info(struct radeon_device *rdev); @@ -468,8 +467,8 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev); extern struct drm_connector * radeon_get_connector_for_encoder(struct drm_encoder *encoder); -extern bool radeon_encoder_is_dp_bridge(struct drm_encoder *encoder); -extern bool radeon_connector_encoder_is_dp_bridge(struct drm_connector *connector); +extern u16 radeon_encoder_get_dp_bridge_encoder_id(struct drm_encoder *encoder); +extern u16 radeon_connector_encoder_get_dp_bridge_encoder_id(struct drm_connector *connector); extern bool radeon_connector_encoder_is_hbr2(struct drm_connector *connector); extern bool radeon_connector_is_dp12_capable(struct drm_connector *connector); @@ -489,7 +488,7 @@ extern void atombios_dig_transmitter_setup(struct drm_encoder *encoder, int action, uint8_t lane_num, uint8_t lane_set); extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); -extern struct drm_encoder *radeon_atom_get_external_encoder(struct drm_encoder *encoder); +extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, u8 write_byte, u8 *read_byte); @@ -519,8 +518,7 @@ extern void radeon_i2c_put_byte(struct radeon_i2c_chan *i2c, u8 val); extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connector); extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector); -extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, - bool requires_extended_probe); +extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector); extern int radeon_ddc_get_modes(struct radeon_connector *radeon_connector); extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector); diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 6fabe89fa6a..78a665bd951 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -53,6 +53,24 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev); #define ACPI_AC_CLASS "ac_adapter" +int radeon_pm_get_type_index(struct radeon_device *rdev, + enum radeon_pm_state_type ps_type, + int instance) +{ + int i; + int found_instance = -1; + + for (i = 0; i < rdev->pm.num_power_states; i++) { + if (rdev->pm.power_state[i].type == ps_type) { + found_instance++; + if (found_instance == instance) + return i; + } + } + /* return default if no match */ + return rdev->pm.default_power_state_index; +} + #ifdef CONFIG_ACPI static int radeon_acpi_event(struct notifier_block *nb, unsigned long val, diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 89a6e1ecea8..06b90c87f8f 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -77,7 +77,7 @@ int rs400_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.ram.ptr) { + if (rdev->gart.ptr) { WARN(1, "RS400 GART already initialized\n"); return 0; } @@ -212,6 +212,7 @@ void rs400_gart_fini(struct radeon_device *rdev) int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { uint32_t entry; + u32 *gtt = rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; @@ -221,7 +222,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) ((upper_32_bits(addr) & 0xff) << 4) | RS400_PTE_WRITEABLE | RS400_PTE_READABLE; entry = cpu_to_le32(entry); - rdev->gart.table.ram.ptr[i] = entry; + gtt[i] = entry; return 0; } diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 9320dd6404f..b1053d64042 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -62,6 +62,7 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -74,7 +75,11 @@ u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -287,6 +292,7 @@ void rs600_hpd_init(struct radeon_device *rdev) default: break; } + radeon_hpd_set_polarity(rdev, radeon_connector->hpd.hpd); } if (rdev->irq.installed) rs600_irq_set(rdev); @@ -413,7 +419,7 @@ int rs600_gart_init(struct radeon_device *rdev) { int r; - if (rdev->gart.table.vram.robj) { + if (rdev->gart.robj) { WARN(1, "RS600 GART already initialized\n"); return 0; } @@ -431,7 +437,7 @@ static int rs600_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -494,20 +500,12 @@ static int rs600_gart_enable(struct radeon_device *rdev) void rs600_gart_disable(struct radeon_device *rdev) { u32 tmp; - int r; /* FIXME: disable out of gart access */ WREG32_MC(R_000100_MC_PT0_CNTL, 0); tmp = RREG32_MC(R_000009_MC_CNTL1); WREG32_MC(R_000009_MC_CNTL1, tmp & C_000009_ENABLE_PAGE_TABLES); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (r == 0) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rs600_gart_fini(struct radeon_device *rdev) @@ -525,7 +523,7 @@ void rs600_gart_fini(struct radeon_device *rdev) int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr) { - void __iomem *ptr = (void *)rdev->gart.table.vram.ptr; + void __iomem *ptr = (void *)rdev->gart.ptr; if (i < 0 || i > rdev->gart.num_gpu_pages) { return -EINVAL; diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 87cc1feee3a..23ae1c60ab3 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -47,6 +47,7 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) { struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); + int i; /* Lock the graphics update lock */ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; @@ -66,7 +67,11 @@ u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) (u32)crtc_base); /* Wait for update_pending to go high. */ - while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING) + break; + udelay(1); + } DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); /* Unlock the lock, so double-buffering can take place inside vblank */ @@ -124,7 +129,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) u32 tmp; int r, i; - if (rdev->gart.table.vram.robj == NULL) { + if (rdev->gart.robj == NULL) { dev_err(rdev->dev, "No VRAM object for PCIE GART.\n"); return -EINVAL; } @@ -171,7 +176,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev) void rv770_pcie_gart_disable(struct radeon_device *rdev) { u32 tmp; - int i, r; + int i; /* Disable all tables */ for (i = 0; i < 7; i++) @@ -191,14 +196,7 @@ void rv770_pcie_gart_disable(struct radeon_device *rdev) WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp); WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp); - if (rdev->gart.table.vram.robj) { - r = radeon_bo_reserve(rdev->gart.table.vram.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->gart.table.vram.robj); - radeon_bo_unpin(rdev->gart.table.vram.robj); - radeon_bo_unreserve(rdev->gart.table.vram.robj); - } - } + radeon_gart_table_vram_unpin(rdev); } void rv770_pcie_gart_fini(struct radeon_device *rdev) @@ -282,7 +280,7 @@ static void rv770_mc_program(struct radeon_device *rdev) WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12); } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); + WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, rdev->vram_scratch.gpu_addr >> 12); tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); WREG32(MC_VM_FB_LOCATION, tmp); @@ -959,54 +957,6 @@ static void rv770_gpu_init(struct radeon_device *rdev) } -static int rv770_vram_scratch_init(struct radeon_device *rdev) -{ - int r; - u64 gpu_addr; - - if (rdev->vram_scratch.robj == NULL) { - r = radeon_bo_create(rdev, RADEON_GPU_PAGE_SIZE, - PAGE_SIZE, true, RADEON_GEM_DOMAIN_VRAM, - &rdev->vram_scratch.robj); - if (r) { - return r; - } - } - - r = radeon_bo_reserve(rdev->vram_scratch.robj, false); - if (unlikely(r != 0)) - return r; - r = radeon_bo_pin(rdev->vram_scratch.robj, - RADEON_GEM_DOMAIN_VRAM, &gpu_addr); - if (r) { - radeon_bo_unreserve(rdev->vram_scratch.robj); - return r; - } - r = radeon_bo_kmap(rdev->vram_scratch.robj, - (void **)&rdev->vram_scratch.ptr); - if (r) - radeon_bo_unpin(rdev->vram_scratch.robj); - radeon_bo_unreserve(rdev->vram_scratch.robj); - - return r; -} - -static void rv770_vram_scratch_fini(struct radeon_device *rdev) -{ - int r; - - if (rdev->vram_scratch.robj == NULL) { - return; - } - r = radeon_bo_reserve(rdev->vram_scratch.robj, false); - if (likely(r == 0)) { - radeon_bo_kunmap(rdev->vram_scratch.robj); - radeon_bo_unpin(rdev->vram_scratch.robj); - radeon_bo_unreserve(rdev->vram_scratch.robj); - } - radeon_bo_unref(&rdev->vram_scratch.robj); -} - void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) { u64 size_bf, size_af; @@ -1106,6 +1056,10 @@ static int rv770_startup(struct radeon_device *rdev) } } + r = r600_vram_scratch_init(rdev); + if (r) + return r; + rv770_mc_program(rdev); if (rdev->flags & RADEON_IS_AGP) { rv770_agp_enable(rdev); @@ -1114,9 +1068,7 @@ static int rv770_startup(struct radeon_device *rdev) if (r) return r; } - r = rv770_vram_scratch_init(rdev); - if (r) - return r; + rv770_gpu_init(rdev); r = r600_blit_init(rdev); if (r) { @@ -1316,7 +1268,7 @@ void rv770_fini(struct radeon_device *rdev) radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); rv770_pcie_gart_fini(rdev); - rv770_vram_scratch_fini(rdev); + r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); radeon_agp_fini(rdev); diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 617b64678fc..0bb0f5f713e 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -574,10 +574,16 @@ retry: return ret; spin_lock(&glob->lru_lock); + + if (unlikely(list_empty(&bo->ddestroy))) { + spin_unlock(&glob->lru_lock); + return 0; + } + ret = ttm_bo_reserve_locked(bo, interruptible, no_wait_reserve, false, 0); - if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) { + if (unlikely(ret != 0)) { spin_unlock(&glob->lru_lock); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1805b8c2a94..dff8fc76715 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -104,6 +104,9 @@ #define DRM_IOCTL_VMW_PRESENT_READBACK \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_PRESENT_READBACK, \ struct drm_vmw_present_readback_arg) +#define DRM_IOCTL_VMW_UPDATE_LAYOUT \ + DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT, \ + struct drm_vmw_update_layout_arg) /** * The core DRM version of this macro doesn't account for @@ -166,6 +169,9 @@ static struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_PRESENT_READBACK, vmw_present_readback_ioctl, DRM_MASTER | DRM_AUTH | DRM_UNLOCKED), + VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT, + vmw_kms_update_layout_ioctl, + DRM_MASTER | DRM_UNLOCKED), }; static struct pci_device_id vmw_pci_id_list[] = { diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 30589d0aecd..dc279706ca7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,9 +40,9 @@ #include "ttm/ttm_module.h" #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20111008" +#define VMWGFX_DRIVER_DATE "20111025" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 2 +#define VMWGFX_DRIVER_MINOR 3 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -390,6 +390,11 @@ extern int vmw_context_check(struct vmw_private *dev_priv, struct ttm_object_file *tfile, int id, struct vmw_resource **p_res); +extern int vmw_user_lookup_handle(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t handle, + struct vmw_surface **out_surf, + struct vmw_dma_buffer **out_buf); extern void vmw_surface_res_free(struct vmw_resource *res); extern int vmw_surface_init(struct vmw_private *dev_priv, struct vmw_surface *srf, @@ -633,6 +638,8 @@ int vmw_kms_readback(struct vmw_private *dev_priv, struct drm_vmw_fence_rep __user *user_fence_rep, struct drm_vmw_rect *clips, uint32_t num_clips); +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv); /** * Overlay control - vmwgfx_overlay.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c index 03bbc2a6f9a..a0c2f12b1e1 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c @@ -33,6 +33,7 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; uint32_t fifo_min, hwversion; + const struct vmw_fifo_state *fifo = &dev_priv->fifo; if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO)) return false; @@ -41,7 +42,12 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv) if (fifo_min <= SVGA_FIFO_3D_HWVERSION * sizeof(unsigned int)) return false; - hwversion = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + hwversion = ioread32(fifo_mem + + ((fifo->capabilities & + SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? + SVGA_FIFO_3D_HWVERSION_REVISED : + SVGA_FIFO_3D_HWVERSION)); + if (hwversion == 0) return false; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 3f6343502d1..66917c6c381 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -58,8 +58,14 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, case DRM_VMW_PARAM_FIFO_HW_VERSION: { __le32 __iomem *fifo_mem = dev_priv->mmio_virt; - - param->value = ioread32(fifo_mem + SVGA_FIFO_3D_HWVERSION); + const struct vmw_fifo_state *fifo = &dev_priv->fifo; + + param->value = + ioread32(fifo_mem + + ((fifo->capabilities & + SVGA_FIFO_CAP_3D_HWVERSION_REVISED) ? + SVGA_FIFO_3D_HWVERSION_REVISED : + SVGA_FIFO_3D_HWVERSION)); break; } default: @@ -140,7 +146,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, goto out_clips; } - clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); + clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (clips == NULL) { DRM_ERROR("Failed to allocate clip rect list.\n"); ret = -ENOMEM; @@ -166,13 +172,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, ret = -EINVAL; goto out_no_fb; } - vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj)); - if (!vfb->dmabuf) { - DRM_ERROR("Framebuffer not dmabuf backed.\n"); - ret = -EINVAL; - goto out_no_fb; - } ret = ttm_read_lock(&vmaster->lock, true); if (unlikely(ret != 0)) @@ -232,7 +232,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_clips; } - clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL); + clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL); if (clips == NULL) { DRM_ERROR("Failed to allocate clip rect list.\n"); ret = -ENOMEM; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8b14dfd513a..f94b33ae221 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -31,6 +31,44 @@ /* Might need a hrtimer here? */ #define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1) + +struct vmw_clip_rect { + int x1, x2, y1, y2; +}; + +/** + * Clip @num_rects number of @rects against @clip storing the + * results in @out_rects and the number of passed rects in @out_num. + */ +void vmw_clip_cliprects(struct drm_clip_rect *rects, + int num_rects, + struct vmw_clip_rect clip, + SVGASignedRect *out_rects, + int *out_num) +{ + int i, k; + + for (i = 0, k = 0; i < num_rects; i++) { + int x1 = max_t(int, clip.x1, rects[i].x1); + int y1 = max_t(int, clip.y1, rects[i].y1); + int x2 = min_t(int, clip.x2, rects[i].x2); + int y2 = min_t(int, clip.y2, rects[i].y2); + + if (x1 >= x2) + continue; + if (y1 >= y2) + continue; + + out_rects[k].left = x1; + out_rects[k].top = y1; + out_rects[k].right = x2; + out_rects[k].bottom = y2; + k++; + } + + *out_num = k; +} + void vmw_display_unit_cleanup(struct vmw_display_unit *du) { if (du->cursor_surface) @@ -82,6 +120,43 @@ int vmw_cursor_update_image(struct vmw_private *dev_priv, return 0; } +int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY) +{ + struct ttm_bo_kmap_obj map; + unsigned long kmap_offset; + unsigned long kmap_num; + void *virtual; + bool dummy; + int ret; + + kmap_offset = 0; + kmap_num = (width*height*4 + PAGE_SIZE - 1) >> PAGE_SHIFT; + + ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); + if (unlikely(ret != 0)) { + DRM_ERROR("reserve failed\n"); + return -EINVAL; + } + + ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); + if (unlikely(ret != 0)) + goto err_unreserve; + + virtual = ttm_kmap_obj_virtual(&map, &dummy); + ret = vmw_cursor_update_image(dev_priv, virtual, width, height, + hotspotX, hotspotY); + + ttm_bo_kunmap(&map); +err_unreserve: + ttm_bo_unreserve(&dmabuf->base); + + return ret; +} + + void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y) { @@ -105,24 +180,26 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, struct vmw_dma_buffer *dmabuf = NULL; int ret; + /* A lot of the code assumes this */ + if (handle && (width != 64 || height != 64)) + return -EINVAL; + if (handle) { - ret = vmw_user_surface_lookup_handle(dev_priv, tfile, - handle, &surface); - if (!ret) { - if (!surface->snooper.image) { - DRM_ERROR("surface not suitable for cursor\n"); - return -EINVAL; - } - } else { - ret = vmw_user_dmabuf_lookup(tfile, - handle, &dmabuf); - if (ret) { - DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); - return -EINVAL; - } + ret = vmw_user_lookup_handle(dev_priv, tfile, + handle, &surface, &dmabuf); + if (ret) { + DRM_ERROR("failed to find surface or dmabuf: %i\n", ret); + return -EINVAL; } } + /* need to do this before taking down old image */ + if (surface && !surface->snooper.image) { + DRM_ERROR("surface not suitable for cursor\n"); + vmw_surface_unreference(&surface); + return -EINVAL; + } + /* takedown old cursor */ if (du->cursor_surface) { du->cursor_surface->snooper.crtc = NULL; @@ -141,42 +218,19 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, vmw_cursor_update_image(dev_priv, surface->snooper.image, 64, 64, du->hotspot_x, du->hotspot_y); } else if (dmabuf) { - struct ttm_bo_kmap_obj map; - unsigned long kmap_offset; - unsigned long kmap_num; - void *virtual; - bool dummy; - /* vmw_user_surface_lookup takes one reference */ du->cursor_dmabuf = dmabuf; - kmap_offset = 0; - kmap_num = (64*64*4) >> PAGE_SHIFT; - - ret = ttm_bo_reserve(&dmabuf->base, true, false, false, 0); - if (unlikely(ret != 0)) { - DRM_ERROR("reserve failed\n"); - return -EINVAL; - } - - ret = ttm_bo_kmap(&dmabuf->base, kmap_offset, kmap_num, &map); - if (unlikely(ret != 0)) - goto err_unreserve; - - virtual = ttm_kmap_obj_virtual(&map, &dummy); - vmw_cursor_update_image(dev_priv, virtual, 64, 64, - du->hotspot_x, du->hotspot_y); - - ttm_bo_kunmap(&map); -err_unreserve: - ttm_bo_unreserve(&dmabuf->base); - + ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height, + du->hotspot_x, du->hotspot_y); } else { vmw_cursor_update_position(dev_priv, false, 0, 0); return 0; } - vmw_cursor_update_position(dev_priv, true, du->cursor_x, du->cursor_y); + vmw_cursor_update_position(dev_priv, true, + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } @@ -191,7 +245,8 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) du->cursor_y = y + crtc->y; vmw_cursor_update_position(dev_priv, shown, - du->cursor_x, du->cursor_y); + du->cursor_x + du->hotspot_x, + du->cursor_y + du->hotspot_y); return 0; } @@ -212,7 +267,7 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, SVGA3dCmdHeader header; SVGA3dCmdSurfaceDMA dma; } *cmd; - int ret; + int i, ret; cmd = container_of(header, struct vmw_dma_cmd, header); @@ -234,16 +289,19 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, box_count = (cmd->header.size - sizeof(SVGA3dCmdSurfaceDMA)) / sizeof(SVGA3dCopyBox); - if (cmd->dma.guest.pitch != (64 * 4) || - cmd->dma.guest.ptr.offset % PAGE_SIZE || + if (cmd->dma.guest.ptr.offset % PAGE_SIZE || box->x != 0 || box->y != 0 || box->z != 0 || box->srcx != 0 || box->srcy != 0 || box->srcz != 0 || - box->w != 64 || box->h != 64 || box->d != 1 || - box_count != 1) { + box->d != 1 || box_count != 1) { /* TODO handle none page aligned offsets */ - /* TODO handle partial uploads and pitch != 256 */ - /* TODO handle more then one copy (size != 64) */ - DRM_ERROR("lazy programmer, can't handle weird stuff\n"); + /* TODO handle more dst & src != 0 */ + /* TODO handle more then one copy */ + DRM_ERROR("Cant snoop dma request for cursor!\n"); + DRM_ERROR("(%u, %u, %u) (%u, %u, %u) (%ux%ux%u) %u %u\n", + box->srcx, box->srcy, box->srcz, + box->x, box->y, box->z, + box->w, box->h, box->d, box_count, + cmd->dma.guest.ptr.offset); return; } @@ -262,7 +320,16 @@ void vmw_kms_cursor_snoop(struct vmw_surface *srf, virtual = ttm_kmap_obj_virtual(&map, &dummy); - memcpy(srf->snooper.image, virtual, 64*64*4); + if (box->w == 64 && cmd->dma.guest.pitch == 64*4) { + memcpy(srf->snooper.image, virtual, 64*64*4); + } else { + /* Image is unsigned pointer. */ + for (i = 0; i < box->h; i++) + memcpy(srf->snooper.image + i * 64, + virtual + i * cmd->dma.guest.pitch, + box->w * 4); + } + srf->snooper.age++; /* we can't call this function from this function since execbuf has @@ -357,8 +424,9 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, struct drm_clip_rect *clips, unsigned num_clips, int inc) { - struct drm_clip_rect *clips_ptr; struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *clips_ptr; + struct drm_clip_rect *tmp; struct drm_crtc *crtc; size_t fifo_size; int i, num_units; @@ -371,7 +439,6 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, } *cmd; SVGASignedRect *blits; - num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { @@ -382,20 +449,32 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, BUG_ON(!clips || !num_clips); + tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); + if (unlikely(tmp == NULL)) { + DRM_ERROR("Temporary cliprect memory alloc failed.\n"); + return -ENOMEM; + } + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; cmd = kzalloc(fifo_size, GFP_KERNEL); if (unlikely(cmd == NULL)) { DRM_ERROR("Temporary fifo memory alloc failed.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_free_tmp; } + /* setup blits pointer */ + blits = (SVGASignedRect *)&cmd[1]; + + /* initial clip region */ left = clips->x1; right = clips->x2; top = clips->y1; bottom = clips->y2; - clips_ptr = clips; - for (i = 1; i < num_clips; i++, clips_ptr += inc) { + /* skip the first clip rect */ + for (i = 1, clips_ptr = clips + inc; + i < num_clips; i++, clips_ptr += inc) { left = min_t(int, left, (int)clips_ptr->x1); right = max_t(int, right, (int)clips_ptr->x2); top = min_t(int, top, (int)clips_ptr->y1); @@ -413,45 +492,60 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, cmd->body.srcRect.bottom = bottom; clips_ptr = clips; - blits = (SVGASignedRect *)&cmd[1]; for (i = 0; i < num_clips; i++, clips_ptr += inc) { - blits[i].left = clips_ptr->x1 - left; - blits[i].right = clips_ptr->x2 - left; - blits[i].top = clips_ptr->y1 - top; - blits[i].bottom = clips_ptr->y2 - top; + tmp[i].x1 = clips_ptr->x1 - left; + tmp[i].x2 = clips_ptr->x2 - left; + tmp[i].y1 = clips_ptr->y1 - top; + tmp[i].y2 = clips_ptr->y2 - top; } /* do per unit writing, reuse fifo for each */ for (i = 0; i < num_units; i++) { struct vmw_display_unit *unit = units[i]; - int clip_x1 = left - unit->crtc.x; - int clip_y1 = top - unit->crtc.y; - int clip_x2 = right - unit->crtc.x; - int clip_y2 = bottom - unit->crtc.y; + struct vmw_clip_rect clip; + int num; + + clip.x1 = left - unit->crtc.x; + clip.y1 = top - unit->crtc.y; + clip.x2 = right - unit->crtc.x; + clip.y2 = bottom - unit->crtc.y; /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) + if (clip.x1 >= unit->crtc.mode.hdisplay || + clip.y1 >= unit->crtc.mode.vdisplay || + clip.x2 <= 0 || clip.y2 <= 0) continue; + /* + * In order for the clip rects to be correctly scaled + * the src and dest rects needs to be the same size. + */ + cmd->body.destRect.left = clip.x1; + cmd->body.destRect.right = clip.x2; + cmd->body.destRect.top = clip.y1; + cmd->body.destRect.bottom = clip.y2; + + /* create a clip rect of the crtc in dest coords */ + clip.x2 = unit->crtc.mode.hdisplay - clip.x1; + clip.y2 = unit->crtc.mode.vdisplay - clip.y1; + clip.x1 = 0 - clip.x1; + clip.y1 = 0 - clip.y1; + /* need to reset sid as it is changed by execbuf */ cmd->body.srcImage.sid = cpu_to_le32(framebuffer->user_handle); - cmd->body.destScreenId = unit->unit; - /* - * The blit command is a lot more resilient then the - * readback command when it comes to clip rects. So its - * okay to go out of bounds. - */ + /* clip and write blits to cmd stream */ + vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - cmd->body.destRect.left = clip_x1; - cmd->body.destRect.right = clip_x2; - cmd->body.destRect.top = clip_y1; - cmd->body.destRect.bottom = clip_y2; + /* if no cliprects hit skip this */ + if (num == 0) + continue; + /* recalculate package length */ + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, 0, NULL); @@ -459,7 +553,10 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, break; } + kfree(cmd); +out_free_tmp: + kfree(tmp); return ret; } @@ -535,6 +632,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv, * Sanity checks. */ + /* Surface must be marked as a scanout. */ + if (unlikely(!surface->scanout)) + return -EINVAL; + if (unlikely(surface->mip_levels[0] != 1 || surface->num_sizes != 1 || surface->sizes[0].width < mode_cmd->width || @@ -761,6 +862,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, int clip_y1 = clips_ptr->y1 - unit->crtc.y; int clip_x2 = clips_ptr->x2 - unit->crtc.x; int clip_y2 = clips_ptr->y2 - unit->crtc.y; + int move_x, move_y; /* skip any crtcs that misses the clip region */ if (clip_x1 >= unit->crtc.mode.hdisplay || @@ -768,12 +870,21 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, clip_x2 <= 0 || clip_y2 <= 0) continue; + /* clip size to crtc size */ + clip_x2 = min_t(int, clip_x2, unit->crtc.mode.hdisplay); + clip_y2 = min_t(int, clip_y2, unit->crtc.mode.vdisplay); + + /* translate both src and dest to bring clip into screen */ + move_x = min_t(int, clip_x1, 0); + move_y = min_t(int, clip_y1, 0); + + /* actual translate done here */ blits[hit_num].header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; blits[hit_num].body.destScreenId = unit->unit; - blits[hit_num].body.srcOrigin.x = clips_ptr->x1; - blits[hit_num].body.srcOrigin.y = clips_ptr->y1; - blits[hit_num].body.destRect.left = clip_x1; - blits[hit_num].body.destRect.top = clip_y1; + blits[hit_num].body.srcOrigin.x = clips_ptr->x1 - move_x; + blits[hit_num].body.srcOrigin.y = clips_ptr->y1 - move_y; + blits[hit_num].body.destRect.left = clip_x1 - move_x; + blits[hit_num].body.destRect.top = clip_y1 - move_y; blits[hit_num].body.destRect.right = clip_x2; blits[hit_num].body.destRect.bottom = clip_y2; hit_num++; @@ -982,7 +1093,6 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct vmw_surface *surface = NULL; struct vmw_dma_buffer *bo = NULL; struct ttm_base_object *user_obj; - u64 required_size; int ret; /** @@ -991,10 +1101,11 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, * requested framebuffer. */ - required_size = mode_cmd->pitch * mode_cmd->height; - if (unlikely(required_size > (u64) dev_priv->vram_size)) { + if (!vmw_kms_validate_mode_vram(dev_priv, + mode_cmd->pitch, + mode_cmd->height)) { DRM_ERROR("VRAM size is too small for requested mode.\n"); - return NULL; + return ERR_PTR(-ENOMEM); } /* @@ -1012,46 +1123,29 @@ static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, return ERR_PTR(-ENOENT); } - /** - * End conditioned code. - */ - - ret = vmw_user_surface_lookup_handle(dev_priv, tfile, - mode_cmd->handle, &surface); + /* returns either a dmabuf or surface */ + ret = vmw_user_lookup_handle(dev_priv, tfile, + mode_cmd->handle, + &surface, &bo); if (ret) - goto try_dmabuf; - - if (!surface->scanout) - goto err_not_scanout; - - ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, surface, - &vfb, mode_cmd); - - /* vmw_user_surface_lookup takes one ref so does new_fb */ - vmw_surface_unreference(&surface); - - if (ret) { - DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); - ttm_base_object_unref(&user_obj); - return ERR_PTR(ret); - } else - vfb->user_obj = user_obj; - return &vfb->base; - -try_dmabuf: - DRM_INFO("%s: trying buffer\n", __func__); - - ret = vmw_user_dmabuf_lookup(tfile, mode_cmd->handle, &bo); - if (ret) { - DRM_ERROR("failed to find buffer: %i\n", ret); - return ERR_PTR(-ENOENT); - } - - ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, - mode_cmd); - - /* vmw_user_dmabuf_lookup takes one ref so does new_fb */ - vmw_dmabuf_unreference(&bo); + goto err_out; + + /* Create the new framebuffer depending one what we got back */ + if (bo) + ret = vmw_kms_new_framebuffer_dmabuf(dev_priv, bo, &vfb, + mode_cmd); + else if (surface) + ret = vmw_kms_new_framebuffer_surface(dev_priv, file_priv, + surface, &vfb, mode_cmd); + else + BUG(); + +err_out: + /* vmw_user_lookup_handle takes one ref so does new_fb */ + if (bo) + vmw_dmabuf_unreference(&bo); + if (surface) + vmw_surface_unreference(&surface); if (ret) { DRM_ERROR("failed to create vmw_framebuffer: %i\n", ret); @@ -1061,14 +1155,6 @@ try_dmabuf: vfb->user_obj = user_obj; return &vfb->base; - -err_not_scanout: - DRM_ERROR("surface not marked as scanout\n"); - /* vmw_user_surface_lookup takes one ref */ - vmw_surface_unreference(&surface); - ttm_base_object_unref(&user_obj); - - return ERR_PTR(-EINVAL); } static struct drm_mode_config_funcs vmw_kms_funcs = { @@ -1085,10 +1171,12 @@ int vmw_kms_present(struct vmw_private *dev_priv, uint32_t num_clips) { struct vmw_display_unit *units[VMWGFX_NUM_DISPLAY_UNITS]; + struct drm_clip_rect *tmp; struct drm_crtc *crtc; size_t fifo_size; int i, k, num_units; int ret = 0; /* silence warning */ + int left, right, top, bottom; struct { SVGA3dCmdHeader header; @@ -1106,60 +1194,95 @@ int vmw_kms_present(struct vmw_private *dev_priv, BUG_ON(surface == NULL); BUG_ON(!clips || !num_clips); + tmp = kzalloc(sizeof(*tmp) * num_clips, GFP_KERNEL); + if (unlikely(tmp == NULL)) { + DRM_ERROR("Temporary cliprect memory alloc failed.\n"); + return -ENOMEM; + } + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num_clips; cmd = kmalloc(fifo_size, GFP_KERNEL); if (unlikely(cmd == NULL)) { DRM_ERROR("Failed to allocate temporary fifo memory.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_free_tmp; + } + + left = clips->x; + right = clips->x + clips->w; + top = clips->y; + bottom = clips->y + clips->h; + + for (i = 1; i < num_clips; i++) { + left = min_t(int, left, (int)clips[i].x); + right = max_t(int, right, (int)clips[i].x + clips[i].w); + top = min_t(int, top, (int)clips[i].y); + bottom = max_t(int, bottom, (int)clips[i].y + clips[i].h); } /* only need to do this once */ memset(cmd, 0, fifo_size); cmd->header.id = cpu_to_le32(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN); - cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); - - cmd->body.srcRect.left = 0; - cmd->body.srcRect.right = surface->sizes[0].width; - cmd->body.srcRect.top = 0; - cmd->body.srcRect.bottom = surface->sizes[0].height; blits = (SVGASignedRect *)&cmd[1]; + + cmd->body.srcRect.left = left; + cmd->body.srcRect.right = right; + cmd->body.srcRect.top = top; + cmd->body.srcRect.bottom = bottom; + for (i = 0; i < num_clips; i++) { - blits[i].left = clips[i].x; - blits[i].right = clips[i].x + clips[i].w; - blits[i].top = clips[i].y; - blits[i].bottom = clips[i].y + clips[i].h; + tmp[i].x1 = clips[i].x - left; + tmp[i].x2 = clips[i].x + clips[i].w - left; + tmp[i].y1 = clips[i].y - top; + tmp[i].y2 = clips[i].y + clips[i].h - top; } for (k = 0; k < num_units; k++) { struct vmw_display_unit *unit = units[k]; - int clip_x1 = destX - unit->crtc.x; - int clip_y1 = destY - unit->crtc.y; - int clip_x2 = clip_x1 + surface->sizes[0].width; - int clip_y2 = clip_y1 + surface->sizes[0].height; + struct vmw_clip_rect clip; + int num; + + clip.x1 = left + destX - unit->crtc.x; + clip.y1 = top + destY - unit->crtc.y; + clip.x2 = right + destX - unit->crtc.x; + clip.y2 = bottom + destY - unit->crtc.y; /* skip any crtcs that misses the clip region */ - if (clip_x1 >= unit->crtc.mode.hdisplay || - clip_y1 >= unit->crtc.mode.vdisplay || - clip_x2 <= 0 || clip_y2 <= 0) + if (clip.x1 >= unit->crtc.mode.hdisplay || + clip.y1 >= unit->crtc.mode.vdisplay || + clip.x2 <= 0 || clip.y2 <= 0) continue; + /* + * In order for the clip rects to be correctly scaled + * the src and dest rects needs to be the same size. + */ + cmd->body.destRect.left = clip.x1; + cmd->body.destRect.right = clip.x2; + cmd->body.destRect.top = clip.y1; + cmd->body.destRect.bottom = clip.y2; + + /* create a clip rect of the crtc in dest coords */ + clip.x2 = unit->crtc.mode.hdisplay - clip.x1; + clip.y2 = unit->crtc.mode.vdisplay - clip.y1; + clip.x1 = 0 - clip.x1; + clip.y1 = 0 - clip.y1; + /* need to reset sid as it is changed by execbuf */ cmd->body.srcImage.sid = sid; - cmd->body.destScreenId = unit->unit; - /* - * The blit command is a lot more resilient then the - * readback command when it comes to clip rects. So its - * okay to go out of bounds. - */ + /* clip and write blits to cmd stream */ + vmw_clip_cliprects(tmp, num_clips, clip, blits, &num); - cmd->body.destRect.left = clip_x1; - cmd->body.destRect.right = clip_x2; - cmd->body.destRect.top = clip_y1; - cmd->body.destRect.bottom = clip_y2; + /* if no cliprects hit skip this */ + if (num == 0) + continue; + /* recalculate package length */ + fifo_size = sizeof(*cmd) + sizeof(SVGASignedRect) * num; + cmd->header.size = cpu_to_le32(fifo_size - sizeof(cmd->header)); ret = vmw_execbuf_process(file_priv, dev_priv, NULL, cmd, fifo_size, 0, NULL); @@ -1168,6 +1291,8 @@ int vmw_kms_present(struct vmw_private *dev_priv, } kfree(cmd); +out_free_tmp: + kfree(tmp); return ret; } @@ -1307,7 +1432,10 @@ int vmw_kms_close(struct vmw_private *dev_priv) * drm_encoder_cleanup which takes the lock we deadlock. */ drm_mode_config_cleanup(dev_priv->dev); - vmw_kms_close_legacy_display_system(dev_priv); + if (dev_priv->sou_priv) + vmw_kms_close_screen_object_display(dev_priv); + else + vmw_kms_close_legacy_display_system(dev_priv); return 0; } @@ -1517,6 +1645,8 @@ int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, du->pref_width = rects[du->unit].w; du->pref_height = rects[du->unit].h; du->pref_active = true; + du->gui_x = rects[du->unit].x; + du->gui_y = rects[du->unit].y; } else { du->pref_width = 800; du->pref_height = 600; @@ -1572,12 +1702,14 @@ vmw_du_connector_detect(struct drm_connector *connector, bool force) uint32_t num_displays; struct drm_device *dev = connector->dev; struct vmw_private *dev_priv = vmw_priv(dev); + struct vmw_display_unit *du = vmw_connector_to_du(connector); mutex_lock(&dev_priv->hw_mutex); num_displays = vmw_read(dev_priv, SVGA_REG_NUM_DISPLAYS); mutex_unlock(&dev_priv->hw_mutex); - return ((vmw_connector_to_du(connector)->unit < num_displays) ? + return ((vmw_connector_to_du(connector)->unit < num_displays && + du->pref_active) ? connector_status_connected : connector_status_disconnected); } @@ -1658,6 +1790,28 @@ static struct drm_display_mode vmw_kms_connector_builtin[] = { { DRM_MODE("", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }, }; +/** + * vmw_guess_mode_timing - Provide fake timings for a + * 60Hz vrefresh mode. + * + * @mode - Pointer to a struct drm_display_mode with hdisplay and vdisplay + * members filled in. + */ +static void vmw_guess_mode_timing(struct drm_display_mode *mode) +{ + mode->hsync_start = mode->hdisplay + 50; + mode->hsync_end = mode->hsync_start + 50; + mode->htotal = mode->hsync_end + 50; + + mode->vsync_start = mode->vdisplay + 50; + mode->vsync_end = mode->vsync_start + 50; + mode->vtotal = mode->vsync_end + 50; + + mode->clock = (u32)mode->htotal * (u32)mode->vtotal / 100 * 6; + mode->vrefresh = drm_mode_vrefresh(mode); +} + + int vmw_du_connector_fill_modes(struct drm_connector *connector, uint32_t max_width, uint32_t max_height) { @@ -1680,18 +1834,23 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, return 0; mode->hdisplay = du->pref_width; mode->vdisplay = du->pref_height; - mode->vrefresh = drm_mode_vrefresh(mode); + vmw_guess_mode_timing(mode); + if (vmw_kms_validate_mode_vram(dev_priv, mode->hdisplay * 2, mode->vdisplay)) { drm_mode_probed_add(connector, mode); + } else { + drm_mode_destroy(dev, mode); + mode = NULL; + } - if (du->pref_mode) { - list_del_init(&du->pref_mode->head); - drm_mode_destroy(dev, du->pref_mode); - } - - du->pref_mode = mode; + if (du->pref_mode) { + list_del_init(&du->pref_mode->head); + drm_mode_destroy(dev, du->pref_mode); } + + /* mode might be null here, this is intended */ + du->pref_mode = mode; } for (i = 0; vmw_kms_connector_builtin[i].type != 0; i++) { @@ -1712,6 +1871,10 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, drm_mode_probed_add(connector, mode); } + /* Move the prefered mode first, help apps pick the right mode. */ + if (du->pref_mode) + list_move(&du->pref_mode->head, &connector->probed_modes); + drm_mode_connector_list_update(connector); return 1; @@ -1723,3 +1886,64 @@ int vmw_du_connector_set_property(struct drm_connector *connector, { return 0; } + + +int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, + struct drm_file *file_priv) +{ + struct vmw_private *dev_priv = vmw_priv(dev); + struct drm_vmw_update_layout_arg *arg = + (struct drm_vmw_update_layout_arg *)data; + struct vmw_master *vmaster = vmw_master(file_priv->master); + void __user *user_rects; + struct drm_vmw_rect *rects; + unsigned rects_size; + int ret; + int i; + struct drm_mode_config *mode_config = &dev->mode_config; + + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + return ret; + + if (!arg->num_outputs) { + struct drm_vmw_rect def_rect = {0, 0, 800, 600}; + vmw_du_update_layout(dev_priv, 1, &def_rect); + goto out_unlock; + } + + rects_size = arg->num_outputs * sizeof(struct drm_vmw_rect); + rects = kcalloc(arg->num_outputs, sizeof(struct drm_vmw_rect), + GFP_KERNEL); + if (unlikely(!rects)) { + ret = -ENOMEM; + goto out_unlock; + } + + user_rects = (void __user *)(unsigned long)arg->rects; + ret = copy_from_user(rects, user_rects, rects_size); + if (unlikely(ret != 0)) { + DRM_ERROR("Failed to get rects.\n"); + ret = -EFAULT; + goto out_free; + } + + for (i = 0; i < arg->num_outputs; ++i) { + if (rects[i].x < 0 || + rects[i].y < 0 || + rects[i].x + rects[i].w > mode_config->max_width || + rects[i].y + rects[i].h > mode_config->max_height) { + DRM_ERROR("Invalid GUI layout.\n"); + ret = -EINVAL; + goto out_free; + } + } + + vmw_du_update_layout(dev_priv, arg->num_outputs, rects); + +out_free: + kfree(rects); +out_unlock: + ttm_read_unlock(&vmaster->lock); + return ret; +} diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index db0b901f8c3..e1cb8556355 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -62,9 +62,14 @@ struct vmw_framebuffer { int vmw_cursor_update_image(struct vmw_private *dev_priv, u32 *image, u32 width, u32 height, u32 hotspotX, u32 hotspotY); +int vmw_cursor_update_dmabuf(struct vmw_private *dev_priv, + struct vmw_dma_buffer *dmabuf, + u32 width, u32 height, + u32 hotspotX, u32 hotspotY); void vmw_cursor_update_position(struct vmw_private *dev_priv, bool show, int x, int y); + /** * Base class display unit. * @@ -96,6 +101,13 @@ struct vmw_display_unit { unsigned pref_height; bool pref_active; struct drm_display_mode *pref_mode; + + /* + * Gui positioning + */ + int gui_x; + int gui_y; + bool is_implicit; }; #define vmw_crtc_to_du(x) \ @@ -126,8 +138,7 @@ int vmw_du_connector_fill_modes(struct drm_connector *connector, int vmw_du_connector_set_property(struct drm_connector *connector, struct drm_property *property, uint64_t val); -int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num, - struct drm_vmw_rect *rects); + /* * Legacy display unit functions - vmwgfx_ldu.c diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index 92f56bc594e..8f8dbd43c33 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -74,9 +74,10 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) { struct vmw_legacy_display *lds = dev_priv->ldu_priv; struct vmw_legacy_display_unit *entry; + struct vmw_display_unit *du = NULL; struct drm_framebuffer *fb = NULL; struct drm_crtc *crtc = NULL; - int i = 0; + int i = 0, ret; /* If there is no display topology the host just assumes * that the guest will set the same layout as the host. @@ -129,6 +130,25 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) lds->last_num_active = lds->num_active; + + /* Find the first du with a cursor. */ + list_for_each_entry(entry, &lds->active, active) { + du = &entry->base; + + if (!du->cursor_dmabuf) + continue; + + ret = vmw_cursor_update_dmabuf(dev_priv, + du->cursor_dmabuf, + 64, 64, + du->hotspot_x, + du->hotspot_y); + if (ret == 0) + break; + + DRM_ERROR("Could not update cursor image\n"); + } + return 0; } @@ -337,13 +357,14 @@ static int vmw_ldu_init(struct vmw_private *dev_priv, unsigned unit) ldu->base.pref_width = 800; ldu->base.pref_height = 600; ldu->base.pref_mode = NULL; + ldu->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + DRM_MODE_CONNECTOR_VIRTUAL); connector->status = vmw_du_connector_detect(connector, true); drm_encoder_init(dev, encoder, &vmw_legacy_encoder_funcs, - DRM_MODE_ENCODER_LVDS); + DRM_MODE_ENCODER_VIRTUAL); drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 86c5e4cceb3..1c7f09e2681 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -1190,6 +1190,29 @@ void vmw_resource_unreserve(struct list_head *list) write_unlock(lock); } +/** + * Helper function that looks either a surface or dmabuf. + * + * The pointer this pointed at by out_surf and out_buf needs to be null. + */ +int vmw_user_lookup_handle(struct vmw_private *dev_priv, + struct ttm_object_file *tfile, + uint32_t handle, + struct vmw_surface **out_surf, + struct vmw_dma_buffer **out_buf) +{ + int ret; + + BUG_ON(*out_surf || *out_buf); + + ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, out_surf); + if (!ret) + return 0; + + ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf); + return ret; +} + int vmw_user_surface_lookup_handle(struct vmw_private *dev_priv, struct ttm_object_file *tfile, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 477b2a9eb3c..4defdcf1c72 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -36,12 +36,9 @@ container_of(x, struct vmw_screen_object_unit, base.connector) struct vmw_screen_object_display { - struct list_head active; + unsigned num_implicit; - unsigned num_active; - unsigned last_num_active; - - struct vmw_framebuffer *fb; + struct vmw_framebuffer *implicit_fb; }; /** @@ -54,13 +51,11 @@ struct vmw_screen_object_unit { struct vmw_dma_buffer *buffer; /**< Backing store buffer */ bool defined; - - struct list_head active; + bool active_implicit; }; static void vmw_sou_destroy(struct vmw_screen_object_unit *sou) { - list_del_init(&sou->active); vmw_display_unit_cleanup(&sou->base); kfree(sou); } @@ -75,58 +70,31 @@ static void vmw_sou_crtc_destroy(struct drm_crtc *crtc) vmw_sou_destroy(vmw_crtc_to_sou(crtc)); } -static int vmw_sou_del_active(struct vmw_private *vmw_priv, +static void vmw_sou_del_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - if (list_empty(&sou->active)) - return 0; - /* Must init otherwise list_empty(&sou->active) will not work. */ - list_del_init(&sou->active); - if (--(ld->num_active) == 0) { - BUG_ON(!ld->fb); - if (ld->fb->unpin) - ld->fb->unpin(ld->fb); - ld->fb = NULL; + if (sou->active_implicit) { + if (--(ld->num_implicit) == 0) + ld->implicit_fb = NULL; + sou->active_implicit = false; } - - return 0; } -static int vmw_sou_add_active(struct vmw_private *vmw_priv, +static void vmw_sou_add_active(struct vmw_private *vmw_priv, struct vmw_screen_object_unit *sou, struct vmw_framebuffer *vfb) { struct vmw_screen_object_display *ld = vmw_priv->sou_priv; - struct vmw_screen_object_unit *entry; - struct list_head *at; - - BUG_ON(!ld->num_active && ld->fb); - if (vfb != ld->fb) { - if (ld->fb && ld->fb->unpin) - ld->fb->unpin(ld->fb); - if (vfb->pin) - vfb->pin(vfb); - ld->fb = vfb; - } - - if (!list_empty(&sou->active)) - return 0; - at = &ld->active; - list_for_each_entry(entry, &ld->active, active) { - if (entry->base.unit > sou->base.unit) - break; + BUG_ON(!ld->num_implicit && ld->implicit_fb); - at = &entry->active; + if (!sou->active_implicit && sou->base.is_implicit) { + ld->implicit_fb = vfb; + sou->active_implicit = true; + ld->num_implicit++; } - - list_add(&sou->active, at); - - ld->num_active++; - - return 0; } /** @@ -164,8 +132,13 @@ static int vmw_sou_fifo_create(struct vmw_private *dev_priv, (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); cmd->obj.size.width = mode->hdisplay; cmd->obj.size.height = mode->vdisplay; - cmd->obj.root.x = x; - cmd->obj.root.y = y; + if (sou->base.is_implicit) { + cmd->obj.root.x = x; + cmd->obj.root.y = y; + } else { + cmd->obj.root.x = sou->base.gui_x; + cmd->obj.root.y = sou->base.gui_y; + } /* Ok to assume that buffer is pinned in vram */ vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); @@ -312,10 +285,11 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) } /* sou only supports one fb active at the time */ - if (dev_priv->sou_priv->fb && vfb && - !(dev_priv->sou_priv->num_active == 1 && - !list_empty(&sou->active)) && - dev_priv->sou_priv->fb != vfb) { + if (sou->base.is_implicit && + dev_priv->sou_priv->implicit_fb && vfb && + !(dev_priv->sou_priv->num_implicit == 1 && + sou->active_implicit) && + dev_priv->sou_priv->implicit_fb != vfb) { DRM_ERROR("Multiple framebuffers not supported\n"); return -EINVAL; } @@ -471,19 +445,20 @@ static int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) encoder = &sou->base.encoder; connector = &sou->base.connector; - INIT_LIST_HEAD(&sou->active); + sou->active_implicit = false; sou->base.pref_active = (unit == 0); sou->base.pref_width = 800; sou->base.pref_height = 600; sou->base.pref_mode = NULL; + sou->base.is_implicit = true; drm_connector_init(dev, connector, &vmw_legacy_connector_funcs, - DRM_MODE_CONNECTOR_LVDS); + DRM_MODE_CONNECTOR_VIRTUAL); connector->status = vmw_du_connector_detect(connector, true); drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, - DRM_MODE_ENCODER_LVDS); + DRM_MODE_ENCODER_VIRTUAL); drm_mode_connector_attach_encoder(connector, encoder); encoder->possible_crtcs = (1 << unit); encoder->possible_clones = 0; @@ -520,10 +495,8 @@ int vmw_kms_init_screen_object_display(struct vmw_private *dev_priv) if (unlikely(!dev_priv->sou_priv)) goto err_no_mem; - INIT_LIST_HEAD(&dev_priv->sou_priv->active); - dev_priv->sou_priv->num_active = 0; - dev_priv->sou_priv->last_num_active = 0; - dev_priv->sou_priv->fb = NULL; + dev_priv->sou_priv->num_implicit = 0; + dev_priv->sou_priv->implicit_fb = NULL; ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); if (unlikely(ret != 0)) @@ -558,9 +531,6 @@ int vmw_kms_close_screen_object_display(struct vmw_private *dev_priv) drm_vblank_cleanup(dev); - if (!list_empty(&dev_priv->sou_priv->active)) - DRM_ERROR("Still have active outputs when unloading driver"); - kfree(dev_priv->sou_priv); return 0; diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index c72f1c0b5e6..111d956d8e7 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -465,31 +465,29 @@ static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev) while (new_bus) { new_bridge = new_bus->self; - if (new_bridge) { - /* go through list of devices already registered */ - list_for_each_entry(same_bridge_vgadev, &vga_list, list) { - bus = same_bridge_vgadev->pdev->bus; - bridge = bus->self; - - /* see if the share a bridge with this device */ - if (new_bridge == bridge) { - /* if their direct parent bridge is the same - as any bridge of this device then it can't be used - for that device */ - same_bridge_vgadev->bridge_has_one_vga = false; - } + /* go through list of devices already registered */ + list_for_each_entry(same_bridge_vgadev, &vga_list, list) { + bus = same_bridge_vgadev->pdev->bus; + bridge = bus->self; + + /* see if the share a bridge with this device */ + if (new_bridge == bridge) { + /* if their direct parent bridge is the same + as any bridge of this device then it can't be used + for that device */ + same_bridge_vgadev->bridge_has_one_vga = false; + } - /* now iterate the previous devices bridge hierarchy */ - /* if the new devices parent bridge is in the other devices - hierarchy then we can't use it to control this device */ - while (bus) { - bridge = bus->self; - if (bridge) { - if (bridge == vgadev->pdev->bus->self) - vgadev->bridge_has_one_vga = false; - } - bus = bus->parent; + /* now iterate the previous devices bridge hierarchy */ + /* if the new devices parent bridge is in the other devices + hierarchy then we can't use it to control this device */ + while (bus) { + bridge = bus->self; + if (bridge) { + if (bridge == vgadev->pdev->bus->self) + vgadev->bridge_has_one_vga = false; } + bus = bus->parent; } } new_bus = new_bus->parent; @@ -993,14 +991,20 @@ static ssize_t vga_arb_write(struct file *file, const char __user * buf, uc = &priv->cards[i]; } - if (!uc) - return -EINVAL; + if (!uc) { + ret_val = -EINVAL; + goto done; + } - if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) - return -EINVAL; + if (io_state & VGA_RSRC_LEGACY_IO && uc->io_cnt == 0) { + ret_val = -EINVAL; + goto done; + } - if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) - return -EINVAL; + if (io_state & VGA_RSRC_LEGACY_MEM && uc->mem_cnt == 0) { + ret_val = -EINVAL; + goto done; + } vga_put(pdev, io_state); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 848a56c0279..af353842f75 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1771,8 +1771,8 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) }, { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 06ce996b8b6..4a441a6f996 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -266,7 +266,7 @@ #define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 #define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001 +#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 #define USB_VENDOR_ID_GLAB 0x06c2 #define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 9ec854ae118..91be41f6080 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -315,7 +315,7 @@ config SENSORS_DS1621 config SENSORS_EXYNOS4_TMU tristate "Temperature sensor on Samsung EXYNOS4" - depends on EXYNOS4_DEV_TMU + depends on ARCH_EXYNOS4 help If you say yes here you get support for TMU (Thermal Managment Unit) on SAMSUNG EXYNOS4 series of SoC. diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c index 318e38e8537..5d760f3d21c 100644 --- a/drivers/hwmon/ad7314.c +++ b/drivers/hwmon/ad7314.c @@ -160,7 +160,6 @@ MODULE_DEVICE_TABLE(spi, ad7314_id); static struct spi_driver ad7314_driver = { .driver = { .name = "ad7314", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = ad7314_probe, diff --git a/drivers/hwmon/ads7871.c b/drivers/hwmon/ads7871.c index 52319340e18..04450f8bf5d 100644 --- a/drivers/hwmon/ads7871.c +++ b/drivers/hwmon/ads7871.c @@ -227,7 +227,6 @@ static int __devexit ads7871_remove(struct spi_device *spi) static struct spi_driver ads7871_driver = { .driver = { .name = DEVICE_NAME, - .bus = &spi_bus_type, .owner = THIS_MODULE, }, diff --git a/drivers/hwmon/exynos4_tmu.c b/drivers/hwmon/exynos4_tmu.c index faa0884f61f..f2359a0093b 100644 --- a/drivers/hwmon/exynos4_tmu.c +++ b/drivers/hwmon/exynos4_tmu.c @@ -506,17 +506,7 @@ static struct platform_driver exynos4_tmu_driver = { .resume = exynos4_tmu_resume, }; -static int __init exynos4_tmu_driver_init(void) -{ - return platform_driver_register(&exynos4_tmu_driver); -} -module_init(exynos4_tmu_driver_init); - -static void __exit exynos4_tmu_driver_exit(void) -{ - platform_driver_unregister(&exynos4_tmu_driver); -} -module_exit(exynos4_tmu_driver_exit); +module_platform_driver(exynos4_tmu_driver); MODULE_DESCRIPTION("EXYNOS4 TMU Driver"); MODULE_AUTHOR("Donggeun Kim <dg77.kim@samsung.com>"); diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 89aa9fb743a..9ba38f318ff 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -539,18 +539,7 @@ static struct platform_driver gpio_fan_driver = { }, }; -static int __init gpio_fan_init(void) -{ - return platform_driver_register(&gpio_fan_driver); -} - -static void __exit gpio_fan_exit(void) -{ - platform_driver_unregister(&gpio_fan_driver); -} - -module_init(gpio_fan_init); -module_exit(gpio_fan_exit); +module_platform_driver(gpio_fan_driver); MODULE_AUTHOR("Simon Guinot <sguinot@lacie.com>"); MODULE_DESCRIPTION("GPIO FAN driver"); diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index fea292d4340..5253d23361d 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -59,7 +59,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, { struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); struct completion *completion = &hwmon->read_completion; - unsigned long t; + long t; unsigned long val; int ret; @@ -203,7 +203,7 @@ static int __devexit jz4740_hwmon_remove(struct platform_device *pdev) return 0; } -struct platform_driver jz4740_hwmon_driver = { +static struct platform_driver jz4740_hwmon_driver = { .probe = jz4740_hwmon_probe, .remove = __devexit_p(jz4740_hwmon_remove), .driver = { @@ -212,17 +212,7 @@ struct platform_driver jz4740_hwmon_driver = { }, }; -static int __init jz4740_hwmon_init(void) -{ - return platform_driver_register(&jz4740_hwmon_driver); -} -module_init(jz4740_hwmon_init); - -static void __exit jz4740_hwmon_exit(void) -{ - platform_driver_unregister(&jz4740_hwmon_driver); -} -module_exit(jz4740_hwmon_exit); +module_platform_driver(jz4740_hwmon_driver); MODULE_DESCRIPTION("JZ4740 SoC HWMON driver"); MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index eab11615dce..9b382ec2c3b 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -432,19 +432,7 @@ static struct platform_driver ntc_thermistor_driver = { .id_table = ntc_thermistor_id, }; -static int __init ntc_thermistor_init(void) -{ - return platform_driver_register(&ntc_thermistor_driver); -} - -module_init(ntc_thermistor_init); - -static void __exit ntc_thermistor_cleanup(void) -{ - platform_driver_unregister(&ntc_thermistor_driver); -} - -module_exit(ntc_thermistor_cleanup); +module_platform_driver(ntc_thermistor_driver); MODULE_DESCRIPTION("NTC Thermistor Driver"); MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>"); diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index b39f52e2752..f6c26d19f52 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -393,18 +393,7 @@ static struct platform_driver s3c_hwmon_driver = { .remove = __devexit_p(s3c_hwmon_remove), }; -static int __init s3c_hwmon_init(void) -{ - return platform_driver_register(&s3c_hwmon_driver); -} - -static void __exit s3c_hwmon_exit(void) -{ - platform_driver_unregister(&s3c_hwmon_driver); -} - -module_init(s3c_hwmon_init); -module_exit(s3c_hwmon_exit); +module_platform_driver(s3c_hwmon_driver); MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); MODULE_DESCRIPTION("S3C ADC HWMon driver"); diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index e3b5c6039c2..79b6dabe316 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -590,19 +590,8 @@ static struct platform_driver sch5627_driver = { .remove = sch5627_remove, }; -static int __init sch5627_init(void) -{ - return platform_driver_register(&sch5627_driver); -} - -static void __exit sch5627_exit(void) -{ - platform_driver_unregister(&sch5627_driver); -} +module_platform_driver(sch5627_driver); MODULE_DESCRIPTION("SMSC SCH5627 Hardware Monitoring Driver"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_LICENSE("GPL"); - -module_init(sch5627_init); -module_exit(sch5627_exit); diff --git a/drivers/hwmon/sch5636.c b/drivers/hwmon/sch5636.c index 244407aa79f..9d5236fb09b 100644 --- a/drivers/hwmon/sch5636.c +++ b/drivers/hwmon/sch5636.c @@ -521,19 +521,8 @@ static struct platform_driver sch5636_driver = { .remove = sch5636_remove, }; -static int __init sch5636_init(void) -{ - return platform_driver_register(&sch5636_driver); -} - -static void __exit sch5636_exit(void) -{ - platform_driver_unregister(&sch5636_driver); -} +module_platform_driver(sch5636_driver); MODULE_DESCRIPTION("SMSC SCH5636 Hardware Monitoring Driver"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_LICENSE("GPL"); - -module_init(sch5636_init); -module_exit(sch5636_exit); diff --git a/drivers/hwmon/twl4030-madc-hwmon.c b/drivers/hwmon/twl4030-madc-hwmon.c index 57240740b16..0018c7dd009 100644 --- a/drivers/hwmon/twl4030-madc-hwmon.c +++ b/drivers/hwmon/twl4030-madc-hwmon.c @@ -136,19 +136,7 @@ static struct platform_driver twl4030_madc_hwmon_driver = { }, }; -static int __init twl4030_madc_hwmon_init(void) -{ - return platform_driver_register(&twl4030_madc_hwmon_driver); -} - -module_init(twl4030_madc_hwmon_init); - -static void __exit twl4030_madc_hwmon_exit(void) -{ - platform_driver_unregister(&twl4030_madc_hwmon_driver); -} - -module_exit(twl4030_madc_hwmon_exit); +module_platform_driver(twl4030_madc_hwmon_driver); MODULE_DESCRIPTION("TWL4030 ADC Hwmon driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/ultra45_env.c b/drivers/hwmon/ultra45_env.c index 3cd07bf42dc..b9a87e89bab 100644 --- a/drivers/hwmon/ultra45_env.c +++ b/drivers/hwmon/ultra45_env.c @@ -309,15 +309,4 @@ static struct platform_driver env_driver = { .remove = __devexit_p(env_remove), }; -static int __init env_init(void) -{ - return platform_driver_register(&env_driver); -} - -static void __exit env_exit(void) -{ - platform_driver_unregister(&env_driver); -} - -module_init(env_init); -module_exit(env_exit); +module_platform_driver(env_driver); diff --git a/drivers/hwmon/wm831x-hwmon.c b/drivers/hwmon/wm831x-hwmon.c index 97b1f834a47..9b598ed2602 100644 --- a/drivers/hwmon/wm831x-hwmon.c +++ b/drivers/hwmon/wm831x-hwmon.c @@ -209,17 +209,7 @@ static struct platform_driver wm831x_hwmon_driver = { }, }; -static int __init wm831x_hwmon_init(void) -{ - return platform_driver_register(&wm831x_hwmon_driver); -} -module_init(wm831x_hwmon_init); - -static void __exit wm831x_hwmon_exit(void) -{ - platform_driver_unregister(&wm831x_hwmon_driver); -} -module_exit(wm831x_hwmon_exit); +module_platform_driver(wm831x_hwmon_driver); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("WM831x Hardware Monitoring"); diff --git a/drivers/hwmon/wm8350-hwmon.c b/drivers/hwmon/wm8350-hwmon.c index 13290595ca8..3ff67edbdc4 100644 --- a/drivers/hwmon/wm8350-hwmon.c +++ b/drivers/hwmon/wm8350-hwmon.c @@ -133,17 +133,7 @@ static struct platform_driver wm8350_hwmon_driver = { }, }; -static int __init wm8350_hwmon_init(void) -{ - return platform_driver_register(&wm8350_hwmon_driver); -} -module_init(wm8350_hwmon_init); - -static void __exit wm8350_hwmon_exit(void) -{ - platform_driver_unregister(&wm8350_hwmon_driver); -} -module_exit(wm8350_hwmon_exit); +module_platform_driver(wm8350_hwmon_driver); MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); MODULE_DESCRIPTION("WM8350 Hardware Monitoring"); diff --git a/drivers/hwspinlock/u8500_hsem.c b/drivers/hwspinlock/u8500_hsem.c index 143461a95ae..86980fe0411 100644 --- a/drivers/hwspinlock/u8500_hsem.c +++ b/drivers/hwspinlock/u8500_hsem.c @@ -21,6 +21,7 @@ * General Public License for more details. */ +#include <linux/module.h> #include <linux/delay.h> #include <linux/io.h> #include <linux/pm_runtime.h> @@ -108,10 +109,8 @@ static int __devinit u8500_hsem_probe(struct platform_device *pdev) return -ENODEV; io_base = ioremap(res->start, resource_size(res)); - if (!io_base) { - ret = -ENOMEM; - goto free_state; - } + if (!io_base) + return -ENOMEM; /* make sure protocol 1 is selected */ val = readl(io_base + HSEM_CTRL_REG); diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index 85584a547c2..525c7345fa0 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -488,7 +488,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) if (flags & I2C_M_TEN) { /* a ten bit address */ - addr = 0xf0 | ((msg->addr >> 7) & 0x03); + addr = 0xf0 | ((msg->addr >> 7) & 0x06); bit_dbg(2, &i2c_adap->dev, "addr0: %d\n", addr); /* try extended address code...*/ ret = try_address(i2c_adap, addr, retries); @@ -498,7 +498,7 @@ static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) return -ENXIO; } /* the remaining 8 bit address */ - ret = i2c_outb(i2c_adap, msg->addr & 0x7f); + ret = i2c_outb(i2c_adap, msg->addr & 0xff); if ((ret != 1) && !nak_ok) { /* the chip did not ack / xmission error occurred */ dev_err(&i2c_adap->dev, "died at 2nd address code\n"); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 8cebef49aea..18936ac9d51 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -893,6 +893,13 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, /* Set the number of I2C channel instance */ adap_info->ch_num = id->driver_data; + ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, + KBUILD_MODNAME, adap_info); + if (ret) { + pch_pci_err(pdev, "request_irq FAILED\n"); + goto err_request_irq; + } + for (i = 0; i < adap_info->ch_num; i++) { pch_adap = &adap_info->pch_data[i].pch_adapter; adap_info->pch_i2c_suspended = false; @@ -910,28 +917,23 @@ static int __devinit pch_i2c_probe(struct pci_dev *pdev, pch_adap->dev.parent = &pdev->dev; + pch_i2c_init(&adap_info->pch_data[i]); ret = i2c_add_adapter(pch_adap); if (ret) { pch_pci_err(pdev, "i2c_add_adapter[ch:%d] FAILED\n", i); - goto err_i2c_add_adapter; + goto err_add_adapter; } - - pch_i2c_init(&adap_info->pch_data[i]); - } - ret = request_irq(pdev->irq, pch_i2c_handler, IRQF_SHARED, - KBUILD_MODNAME, adap_info); - if (ret) { - pch_pci_err(pdev, "request_irq FAILED\n"); - goto err_i2c_add_adapter; } pci_set_drvdata(pdev, adap_info); pch_pci_dbg(pdev, "returns %d.\n", ret); return 0; -err_i2c_add_adapter: +err_add_adapter: for (j = 0; j < i; j++) i2c_del_adapter(&adap_info->pch_data[j].pch_adapter); + free_irq(pdev->irq, adap_info); +err_request_irq: pci_iounmap(pdev, base_addr); err_pci_iomap: pci_release_regions(pdev); diff --git a/drivers/i2c/busses/i2c-nuc900.c b/drivers/i2c/busses/i2c-nuc900.c index 835e47b39bc..03b61577888 100644 --- a/drivers/i2c/busses/i2c-nuc900.c +++ b/drivers/i2c/busses/i2c-nuc900.c @@ -593,7 +593,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev) i2c->adap.algo_data = i2c; i2c->adap.dev.parent = &pdev->dev; - mfp_set_groupg(&pdev->dev); + mfp_set_groupg(&pdev->dev, NULL); clk_get_rate(i2c->clk); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a43d0023446..fa23faa20f0 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1047,13 +1047,14 @@ omap_i2c_probe(struct platform_device *pdev) * size. This is to ensure that we can handle the status on int * call back latencies. */ - if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) { - dev->fifo_size = 0; + + dev->fifo_size = (dev->fifo_size / 2); + + if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) dev->b_hw = 0; /* Disable hardware fixes */ - } else { - dev->fifo_size = (dev->fifo_size / 2); + else dev->b_hw = 1; /* Enable hardware fixes */ - } + /* calculate wakeup latency constraint for MPU */ if (dev->set_mpu_wkup_lat != NULL) dev->latency = (1000000 * dev->fifo_size) / diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 2754cef86a0..4c171808168 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -534,6 +534,7 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, /* first, try busy waiting briefly */ do { + cpu_relax(); iicstat = readl(i2c->regs + S3C2410_IICSTAT); } while ((iicstat & S3C2410_IICSTAT_START) && --spins); @@ -786,7 +787,7 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) #else static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { - return -EINVAL; + return 0; } static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 131079a3e29..1e5606185b4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -539,8 +539,10 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.type = &i2c_client_type; client->dev.of_node = info->of_node; + /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), - client->addr); + client->addr | ((client->flags & I2C_CLIENT_TEN) + ? 0xa000 : 0)); status = device_register(&client->dev); if (status) goto out_err; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index c90ce50b619..57a45ce84b2 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -579,7 +579,7 @@ static int i2cdev_detach_adapter(struct device *dev, void *dummy) return 0; } -int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, +static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; diff --git a/drivers/ide/cy82c693.c b/drivers/ide/cy82c693.c index 67cbcfa3512..847553fd8b9 100644 --- a/drivers/ide/cy82c693.c +++ b/drivers/ide/cy82c693.c @@ -1,7 +1,7 @@ /* * Copyright (C) 1998-2000 Andreas S. Krebs (akrebs@altavista.net), Maintainer * Copyright (C) 1998-2002 Andre Hedrick <andre@linux-ide.org>, Integrator - * Copyright (C) 2007-2010 Bartlomiej Zolnierkiewicz + * Copyright (C) 2007-2011 Bartlomiej Zolnierkiewicz * * CYPRESS CY82C693 chipset IDE controller * @@ -90,7 +90,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) u8 time_16, time_8; /* select primary or secondary channel */ - if (hwif->index > 0) { /* drive is on the secondary channel */ + if (drive->dn > 1) { /* drive is on the secondary channel */ dev = pci_get_slot(dev->bus, dev->devfn+1); if (!dev) { printk(KERN_ERR "%s: tune_drive: " @@ -141,7 +141,7 @@ static void cy82c693_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) pci_write_config_byte(dev, CY82_IDE_SLAVE_IOW, time_16); pci_write_config_byte(dev, CY82_IDE_SLAVE_8BIT, time_8); } - if (hwif->index > 0) + if (drive->dn > 1) pci_dev_put(dev); } diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 4a697a238e2..8716066a2f2 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -521,8 +521,8 @@ icside_register_v6(struct icside_state *state, struct expansion_card *ec) if (ec->dma != NO_DMA && !request_dma(ec->dma, DRV_NAME)) { d.init_dma = icside_dma_init; d.port_ops = &icside_v6_port_ops; + } else d.dma_ops = NULL; - } ret = ide_host_register(host, &d, hws); if (ret) diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 04b09564bfa..8126824dacc 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -43,7 +43,6 @@ /* For SCSI -> ATAPI command conversion */ #include <scsi/scsi.h> -#include <linux/irq.h> #include <linux/io.h> #include <asm/byteorder.h> #include <linux/uaccess.h> diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 61fdf544fbd..3d42043fec5 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -35,7 +35,6 @@ #include <scsi/scsi_ioctl.h> #include <asm/byteorder.h> -#include <linux/irq.h> #include <linux/uaccess.h> #include <linux/io.h> #include <asm/unaligned.h> diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 7ecb1ade887..ce8237d3615 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -41,7 +41,6 @@ #include <scsi/scsi.h> #include <asm/byteorder.h> -#include <linux/irq.h> #include <linux/uaccess.h> #include <linux/io.h> #include <asm/unaligned.h> diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index b59d04c7205..1892e81fb00 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -331,7 +331,7 @@ static const struct ide_port_ops ich_port_ops = { .udma_mask = udma, \ } -#define DECLARE_ICH_DEV(udma) \ +#define DECLARE_ICH_DEV(mwdma, udma) \ { \ .name = DRV_NAME, \ .init_chipset = init_chipset_ich, \ @@ -340,7 +340,7 @@ static const struct ide_port_ops ich_port_ops = { .port_ops = &ich_port_ops, \ .pio_mask = ATA_PIO4, \ .swdma_mask = ATA_SWDMA2_ONLY, \ - .mwdma_mask = ATA_MWDMA12_ONLY, \ + .mwdma_mask = mwdma, \ .udma_mask = udma, \ } @@ -362,13 +362,15 @@ static const struct ide_port_info piix_pci_info[] __devinitdata = { /* 2: PIIX4 */ DECLARE_PIIX_DEV(ATA_UDMA2), /* 3: ICH0 */ - DECLARE_ICH_DEV(ATA_UDMA2), + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA2), /* 4: ICH */ - DECLARE_ICH_DEV(ATA_UDMA4), + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA4), /* 5: PIIX4 */ DECLARE_PIIX_DEV(ATA_UDMA4), - /* 6: ICH[2-7]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */ - DECLARE_ICH_DEV(ATA_UDMA5), + /* 6: ICH[2-6]/ICH[2-3]M/C-ICH/ICH5-SATA/ESB2/ICH8M */ + DECLARE_ICH_DEV(ATA_MWDMA12_ONLY, ATA_UDMA5), + /* 7: ICH7/7-R, no MWDMA1 */ + DECLARE_ICH_DEV(ATA_MWDMA2_ONLY, ATA_UDMA5), }; /** @@ -438,9 +440,9 @@ static const struct pci_device_id piix_pci_tbl[] = { #endif { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB_2), 6 }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH6_19), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH7_21), 7 }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82801DB_1), 6 }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 6 }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ESB2_18), 7 }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICH8_6), 6 }, { 0, }, }; diff --git a/drivers/ide/triflex.c b/drivers/ide/triflex.c index e53a1b78378..281c9142634 100644 --- a/drivers/ide/triflex.c +++ b/drivers/ide/triflex.c @@ -113,12 +113,26 @@ static const struct pci_device_id triflex_pci_tbl[] = { }; MODULE_DEVICE_TABLE(pci, triflex_pci_tbl); +#ifdef CONFIG_PM +static int triflex_ide_pci_suspend(struct pci_dev *dev, pm_message_t state) +{ + /* + * We must not disable or powerdown the device. + * APM bios refuses to suspend if IDE is not accessible. + */ + pci_save_state(dev); + return 0; +} +#else +#define triflex_ide_pci_suspend NULL +#endif + static struct pci_driver triflex_pci_driver = { .name = "TRIFLEX_IDE", .id_table = triflex_pci_tbl, .probe = triflex_init_one, .remove = ide_pci_remove, - .suspend = ide_pci_suspend, + .suspend = triflex_ide_pci_suspend, .resume = ide_pci_resume, }; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 18767f8ab09..20bce51c2e8 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -82,7 +82,8 @@ static unsigned int mwait_substates; static unsigned int lapic_timer_reliable_states = (1 << 1); /* Default to only C1 */ static struct cpuidle_device __percpu *intel_idle_cpuidle_devices; -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state); +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index); static struct cpuidle_state *cpuidle_state_table; @@ -110,7 +111,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-NHM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 3, .target_residency = 6, @@ -118,7 +118,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-NHM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 20, .target_residency = 80, @@ -126,7 +125,6 @@ static struct cpuidle_state nehalem_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-NHM", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 200, .target_residency = 800, @@ -138,7 +136,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-SNB", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 1, @@ -146,7 +143,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C3-SNB", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 80, .target_residency = 211, @@ -154,7 +150,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C3 */ .name = "C6-SNB", .desc = "MWAIT 0x20", - .driver_data = (void *) 0x20, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 104, .target_residency = 345, @@ -162,7 +157,6 @@ static struct cpuidle_state snb_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C7-SNB", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 109, .target_residency = 345, @@ -174,7 +168,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C1 */ .name = "C1-ATM", .desc = "MWAIT 0x00", - .driver_data = (void *) 0x00, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 1, .target_residency = 4, @@ -182,7 +175,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C2 */ .name = "C2-ATM", .desc = "MWAIT 0x10", - .driver_data = (void *) 0x10, .flags = CPUIDLE_FLAG_TIME_VALID, .exit_latency = 20, .target_residency = 80, @@ -191,7 +183,6 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C4 */ .name = "C4-ATM", .desc = "MWAIT 0x30", - .driver_data = (void *) 0x30, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 100, .target_residency = 400, @@ -200,23 +191,56 @@ static struct cpuidle_state atom_cstates[MWAIT_MAX_NUM_CSTATES] = { { /* MWAIT C6 */ .name = "C6-ATM", .desc = "MWAIT 0x52", - .driver_data = (void *) 0x52, .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED, .exit_latency = 140, .target_residency = 560, .enter = &intel_idle }, }; +static long get_driver_data(int cstate) +{ + int driver_data; + switch (cstate) { + + case 1: /* MWAIT C1 */ + driver_data = 0x00; + break; + case 2: /* MWAIT C2 */ + driver_data = 0x10; + break; + case 3: /* MWAIT C3 */ + driver_data = 0x20; + break; + case 4: /* MWAIT C4 */ + driver_data = 0x30; + break; + case 5: /* MWAIT C5 */ + driver_data = 0x40; + break; + case 6: /* MWAIT C6 */ + driver_data = 0x52; + break; + default: + driver_data = 0x00; + } + return driver_data; +} + /** * intel_idle * @dev: cpuidle_device - * @state: cpuidle state + * @drv: cpuidle driver + * @index: index of cpuidle state * + * Must be called under local_irq_disable(). */ -static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) +static int intel_idle(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) { unsigned long ecx = 1; /* break on interrupt flag */ - unsigned long eax = (unsigned long)cpuidle_get_statedata(state); + struct cpuidle_state *state = &drv->states[index]; + struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; + unsigned long eax = (unsigned long)cpuidle_get_statedata(state_usage); unsigned int cstate; ktime_t kt_before, kt_after; s64 usec_delta; @@ -224,8 +248,6 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) cstate = (((eax) >> MWAIT_SUBSTATE_SIZE) & MWAIT_CSTATE_MASK) + 1; - local_irq_disable(); - /* * leave_mm() to avoid costly and often unnecessary wakeups * for flushing the user TLB's associated with the active mm. @@ -257,7 +279,10 @@ static int intel_idle(struct cpuidle_device *dev, struct cpuidle_state *state) if (!(lapic_timer_reliable_states & (1 << (cstate)))) clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu); - return usec_delta; + /* Update cpuidle counters */ + dev->last_residency = (int)usec_delta; + + return index; } static void __setup_broadcast_timer(void *arg) @@ -322,7 +347,8 @@ static int intel_idle_probe(void) cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &mwait_substates); if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || - !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) + !(ecx & CPUID5_ECX_INTERRUPT_BREAK) || + !mwait_substates) return -ENODEV; pr_debug(PREFIX "MWAIT substates: 0x%x\n", mwait_substates); @@ -368,7 +394,7 @@ static int intel_idle_probe(void) if (boot_cpu_has(X86_FEATURE_ARAT)) /* Always Reliable APIC Timer */ lapic_timer_reliable_states = LAPIC_TIMER_ALWAYS_RELIABLE; else { - smp_call_function(__setup_broadcast_timer, (void *)true, 1); + on_each_cpu(__setup_broadcast_timer, (void *)true, 1); register_cpu_notifier(&setup_broadcast_notifier); } @@ -398,69 +424,106 @@ static void intel_idle_cpuidle_devices_uninit(void) return; } /* - * intel_idle_cpuidle_devices_init() + * intel_idle_cpuidle_driver_init() + * allocate, initialize cpuidle_states + */ +static int intel_idle_cpuidle_driver_init(void) +{ + int cstate; + struct cpuidle_driver *drv = &intel_idle_driver; + + drv->state_count = 1; + + for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { + int num_substates; + + if (cstate > max_cstate) { + printk(PREFIX "max_cstate %d reached\n", + max_cstate); + break; + } + + /* does the state exist in CPUID.MWAIT? */ + num_substates = (mwait_substates >> ((cstate) * 4)) + & MWAIT_SUBSTATE_MASK; + if (num_substates == 0) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) { + /* does the driver not know about the state? */ + if (*cpuidle_state_table[cstate].name == '\0') + pr_debug(PREFIX "unaware of model 0x%x" + " MWAIT %d please" + " contact lenb@kernel.org", + boot_cpu_data.x86_model, cstate); + continue; + } + + if ((cstate > 2) && + !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) + mark_tsc_unstable("TSC halts in idle" + " states deeper than C2"); + + drv->states[drv->state_count] = /* structure copy */ + cpuidle_state_table[cstate]; + + drv->state_count += 1; + } + + if (auto_demotion_disable_flags) + on_each_cpu(auto_demotion_disable, NULL, 1); + + return 0; +} + + +/* + * intel_idle_cpu_init() * allocate, initialize, register cpuidle_devices + * @cpu: cpu/core to initialize */ -static int intel_idle_cpuidle_devices_init(void) +int intel_idle_cpu_init(int cpu) { - int i, cstate; + int cstate; struct cpuidle_device *dev; - intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); - if (intel_idle_cpuidle_devices == NULL) - return -ENOMEM; + dev = per_cpu_ptr(intel_idle_cpuidle_devices, cpu); - for_each_online_cpu(i) { - dev = per_cpu_ptr(intel_idle_cpuidle_devices, i); + dev->state_count = 1; - dev->state_count = 1; - - for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { - int num_substates; - - if (cstate > max_cstate) { - printk(PREFIX "max_cstate %d reached\n", - max_cstate); - break; - } - - /* does the state exist in CPUID.MWAIT? */ - num_substates = (mwait_substates >> ((cstate) * 4)) - & MWAIT_SUBSTATE_MASK; - if (num_substates == 0) - continue; - /* is the state not enabled? */ - if (cpuidle_state_table[cstate].enter == NULL) { - /* does the driver not know about the state? */ - if (*cpuidle_state_table[cstate].name == '\0') - pr_debug(PREFIX "unaware of model 0x%x" - " MWAIT %d please" - " contact lenb@kernel.org", - boot_cpu_data.x86_model, cstate); - continue; - } - - if ((cstate > 2) && - !boot_cpu_has(X86_FEATURE_NONSTOP_TSC)) - mark_tsc_unstable("TSC halts in idle" - " states deeper than C2"); + for (cstate = 1; cstate < MWAIT_MAX_NUM_CSTATES; ++cstate) { + int num_substates; - dev->states[dev->state_count] = /* structure copy */ - cpuidle_state_table[cstate]; + if (cstate > max_cstate) { + printk(PREFIX "max_cstate %d reached\n", + max_cstate); + break; + } + + /* does the state exist in CPUID.MWAIT? */ + num_substates = (mwait_substates >> ((cstate) * 4)) + & MWAIT_SUBSTATE_MASK; + if (num_substates == 0) + continue; + /* is the state not enabled? */ + if (cpuidle_state_table[cstate].enter == NULL) + continue; + + dev->states_usage[dev->state_count].driver_data = + (void *)get_driver_data(cstate); dev->state_count += 1; } + dev->cpu = cpu; - dev->cpu = i; - if (cpuidle_register_device(dev)) { - pr_debug(PREFIX "cpuidle_register_device %d failed!\n", - i); - intel_idle_cpuidle_devices_uninit(); - return -EIO; - } + if (cpuidle_register_device(dev)) { + pr_debug(PREFIX "cpuidle_register_device %d failed!\n", cpu); + intel_idle_cpuidle_devices_uninit(); + return -EIO; } + if (auto_demotion_disable_flags) - smp_call_function(auto_demotion_disable, NULL, 1); + smp_call_function_single(cpu, auto_demotion_disable, NULL, 1); return 0; } @@ -468,7 +531,7 @@ static int intel_idle_cpuidle_devices_init(void) static int __init intel_idle_init(void) { - int retval; + int retval, i; /* Do not load intel_idle at all for now if idle= is passed */ if (boot_option_idle_override != IDLE_NO_OVERRIDE) @@ -478,6 +541,7 @@ static int __init intel_idle_init(void) if (retval) return retval; + intel_idle_cpuidle_driver_init(); retval = cpuidle_register_driver(&intel_idle_driver); if (retval) { printk(KERN_DEBUG PREFIX "intel_idle yielding to %s", @@ -485,10 +549,16 @@ static int __init intel_idle_init(void) return retval; } - retval = intel_idle_cpuidle_devices_init(); - if (retval) { - cpuidle_unregister_driver(&intel_idle_driver); - return retval; + intel_idle_cpuidle_devices = alloc_percpu(struct cpuidle_device); + if (intel_idle_cpuidle_devices == NULL) + return -ENOMEM; + + for_each_online_cpu(i) { + retval = intel_idle_cpu_init(i); + if (retval) { + cpuidle_unregister_driver(&intel_idle_driver); + return retval; + } } return 0; @@ -500,7 +570,7 @@ static void __exit intel_idle_exit(void) cpuidle_unregister_driver(&intel_idle_driver); if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE) { - smp_call_function(__setup_broadcast_timer, (void *)false, 1); + on_each_cpu(__setup_broadcast_timer, (void *)false, 1); unregister_cpu_notifier(&setup_broadcast_notifier); } diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 691276bafd7..e9cf51b1343 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -216,7 +216,9 @@ static int addr4_resolve(struct sockaddr_in *src_in, neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev); if (!neigh || !(neigh->nud_state & NUD_VALID)) { + rcu_read_lock(); neigh_event_send(dst_get_neighbour(&rt->dst), NULL); + rcu_read_unlock(); ret = -ENODATA; if (neigh) goto release; @@ -274,15 +276,16 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, goto put; } + rcu_read_lock(); neigh = dst_get_neighbour(dst); if (!neigh || !(neigh->nud_state & NUD_VALID)) { if (neigh) neigh_event_send(neigh, NULL); ret = -ENODATA; - goto put; + } else { + ret = rdma_copy_addr(addr, dst->dev, neigh->ha); } - - ret = rdma_copy_addr(addr, dst->dev, neigh->ha); + rcu_read_unlock(); put: dst_release(dst); return ret; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 75ff821c0af..d0d4aa9f480 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2513,6 +2513,9 @@ static int cma_resolve_ib_udp(struct rdma_id_private *id_priv, req.private_data_len = sizeof(struct cma_hdr) + conn_param->private_data_len; + if (req.private_data_len < conn_param->private_data_len) + return -EINVAL; + req.private_data = kzalloc(req.private_data_len, GFP_ATOMIC); if (!req.private_data) return -ENOMEM; @@ -2562,6 +2565,9 @@ static int cma_connect_ib(struct rdma_id_private *id_priv, memset(&req, 0, sizeof req); offset = cma_user_data_offset(id_priv->id.ps); req.private_data_len = offset + conn_param->private_data_len; + if (req.private_data_len < conn_param->private_data_len) + return -EINVAL; + private_data = kzalloc(req.private_data_len, GFP_ATOMIC); if (!private_data) return -ENOMEM; diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c index de6d0774e60..c88b12beef2 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.c +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c @@ -1375,8 +1375,10 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) goto reject; } dst = &rt->dst; + rcu_read_lock(); neigh = dst_get_neighbour(dst); l2t = t3_l2t_get(tdev, neigh, neigh->dev); + rcu_read_unlock(); if (!l2t) { printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", __func__); @@ -1946,10 +1948,12 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } ep->dst = &rt->dst; + rcu_read_lock(); neigh = dst_get_neighbour(ep->dst); /* get a l2t entry */ ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev); + rcu_read_unlock(); if (!ep->l2t) { printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); err = -ENOMEM; diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index b36cdac9c55..0747004313a 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -542,8 +542,10 @@ static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb, (mpa_rev_to_use == 2 ? MPA_ENHANCED_RDMA_CONN : 0); mpa->private_data_size = htons(ep->plen); mpa->revision = mpa_rev_to_use; - if (mpa_rev_to_use == 1) + if (mpa_rev_to_use == 1) { ep->tried_with_mpa_v1 = 1; + ep->retry_with_mpa_v1 = 0; + } if (mpa_rev_to_use == 2) { mpa->private_data_size += @@ -1594,6 +1596,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) goto reject; } dst = &rt->dst; + rcu_read_lock(); neigh = dst_get_neighbour(dst); if (neigh->dev->flags & IFF_LOOPBACK) { pdev = ip_dev_find(&init_net, peer_ip); @@ -1620,6 +1623,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) rss_qid = dev->rdev.lldi.rxq_ids[ cxgb4_port_idx(neigh->dev) * step]; } + rcu_read_unlock(); if (!l2t) { printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", __func__); @@ -1820,6 +1824,7 @@ static int c4iw_reconnect(struct c4iw_ep *ep) } ep->dst = &rt->dst; + rcu_read_lock(); neigh = dst_get_neighbour(ep->dst); /* get a l2t entry */ @@ -1856,6 +1861,7 @@ static int c4iw_reconnect(struct c4iw_ep *ep) ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[ cxgb4_port_idx(neigh->dev) * step]; } + rcu_read_unlock(); if (!ep->l2t) { printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); err = -ENOMEM; @@ -2301,6 +2307,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) } ep->dst = &rt->dst; + rcu_read_lock(); neigh = dst_get_neighbour(ep->dst); /* get a l2t entry */ @@ -2339,6 +2346,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) ep->retry_with_mpa_v1 = 0; ep->tried_with_mpa_v1 = 0; } + rcu_read_unlock(); if (!ep->l2t) { printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); err = -ENOMEM; diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index f35a935267e..0f1607c8325 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -311,7 +311,7 @@ void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count) while (ptr != cq->sw_pidx) { cqe = &cq->sw_queue[ptr]; if (RQ_TYPE(cqe) && (CQE_OPCODE(cqe) != FW_RI_READ_RESP) && - (CQE_QPID(cqe) == wq->rq.qid) && cqe_completes_wr(cqe, wq)) + (CQE_QPID(cqe) == wq->sq.qid) && cqe_completes_wr(cqe, wq)) (*count)++; if (++ptr == cq->size) ptr = 0; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 77f3dbc0aaa..18836cdf1e1 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1244,7 +1244,8 @@ err_reg: err_counter: for (; i; --i) - mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]); + if (ibdev->counters[i - 1] != -1) + mlx4_counter_free(ibdev->dev, ibdev->counters[i - 1]); err_map: iounmap(ibdev->uar_map); @@ -1275,7 +1276,8 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) } iounmap(ibdev->uar_map); for (p = 0; p < ibdev->num_ports; ++p) - mlx4_counter_free(ibdev->dev, ibdev->counters[p]); + if (ibdev->counters[p] != -1) + mlx4_counter_free(ibdev->dev, ibdev->counters[p]); mlx4_foreach_port(p, dev, MLX4_PORT_TYPE_IB) mlx4_CLOSE_PORT(dev, p); diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index dfce9ea98a3..0a52d72371e 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -1377,9 +1377,11 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi neigh_release(neigh); } - if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) + if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) { + rcu_read_lock(); neigh_event_send(dst_get_neighbour(&rt->dst), NULL); - + rcu_read_unlock(); + } ip_rt_put(rt); return rc; } diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 574600ef5b4..a7403248d83 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -1285,7 +1285,7 @@ static int setup_ctxt(struct qib_pportdata *ppd, int ctxt, strlcpy(rcd->comm, current->comm, sizeof(rcd->comm)); ctxt_fp(fp) = rcd; qib_stats.sps_ctxts++; - dd->freectxts++; + dd->freectxts--; ret = 0; goto bail; @@ -1794,7 +1794,7 @@ static int qib_close(struct inode *in, struct file *fp) if (dd->pageshadow) unlock_expected_tids(rcd); qib_stats.sps_ctxts--; - dd->freectxts--; + dd->freectxts++; } mutex_unlock(&qib_mutex); diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 5bd2162b95d..1d5895941e1 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2307,19 +2307,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd) SYM_LSB(IBCCtrlA_0, MaxPktLen); ppd->cpspec->ibcctrl_a = ibc; /* without linkcmd or linkinitcmd! */ - /* initially come up waiting for TS1, without sending anything. */ - val = ppd->cpspec->ibcctrl_a | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE << - QLOGIC_IB_IBCC_LINKINITCMD_SHIFT); - - ppd->cpspec->ibcctrl_a = val; /* * Reset the PCS interface to the serdes (and also ibc, which is still * in reset from above). Writes new value of ibcctrl_a as last step. */ qib_7322_mini_pcs_reset(ppd); - qib_write_kreg(dd, kr_scratch, 0ULL); - /* clear the linkinit cmds */ - ppd->cpspec->ibcctrl_a &= ~SYM_MASK(IBCCtrlA_0, LinkInitCmd); if (!ppd->cpspec->ibcctrl_b) { unsigned lse = ppd->link_speed_enabled; @@ -2385,6 +2377,14 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd) ppd->cpspec->ibcctrl_a |= SYM_MASK(IBCCtrlA_0, IBLinkEn); set_vls(ppd); + /* initially come up DISABLED, without sending anything. */ + val = ppd->cpspec->ibcctrl_a | (QLOGIC_IB_IBCC_LINKINITCMD_DISABLE << + QLOGIC_IB_IBCC_LINKINITCMD_SHIFT); + qib_write_kreg_port(ppd, krp_ibcctrl_a, val); + qib_write_kreg(dd, kr_scratch, 0ULL); + /* clear the linkinit cmds */ + ppd->cpspec->ibcctrl_a = val & ~SYM_MASK(IBCCtrlA_0, LinkInitCmd); + /* be paranoid against later code motion, etc. */ spin_lock_irqsave(&dd->cspec->rcvmod_lock, flags); ppd->p_rcvctrl |= SYM_MASK(RcvCtrl_0, RcvIBPortEnable); @@ -5241,7 +5241,7 @@ static int qib_7322_ib_updown(struct qib_pportdata *ppd, int ibup, u64 ibcs) off */ if (ppd->dd->flags & QIB_HAS_QSFP) { qd->t_insert = get_jiffies_64(); - schedule_work(&qd->work); + queue_work(ib_wq, &qd->work); } spin_lock_irqsave(&ppd->sdma_lock, flags); if (__qib_sdma_running(ppd)) diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c index e06c4ed383f..fa71b1e666c 100644 --- a/drivers/infiniband/hw/qib/qib_qsfp.c +++ b/drivers/infiniband/hw/qib/qib_qsfp.c @@ -480,18 +480,6 @@ void qib_qsfp_init(struct qib_qsfp_data *qd, udelay(20); /* Generous RST dwell */ dd->f_gpio_mod(dd, mask, mask, mask); - /* Spec says module can take up to two seconds! */ - mask = QSFP_GPIO_MOD_PRS_N; - if (qd->ppd->hw_pidx) - mask <<= QSFP_GPIO_PORT2_SHIFT; - - /* Do not try to wait here. Better to let event handle it */ - if (!qib_qsfp_mod_present(qd->ppd)) - goto bail; - /* We see a module, but it may be unwise to look yet. Just schedule */ - qd->t_insert = get_jiffies_64(); - queue_work(ib_wq, &qd->work); -bail: return; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 0ef9af94997..4115be54ba3 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -57,21 +57,24 @@ struct ipoib_ah *ipoib_create_ah(struct net_device *dev, struct ib_pd *pd, struct ib_ah_attr *attr) { struct ipoib_ah *ah; + struct ib_ah *vah; ah = kmalloc(sizeof *ah, GFP_KERNEL); if (!ah) - return NULL; + return ERR_PTR(-ENOMEM); ah->dev = dev; ah->last_send = 0; kref_init(&ah->ref); - ah->ah = ib_create_ah(pd, attr); - if (IS_ERR(ah->ah)) { + vah = ib_create_ah(pd, attr); + if (IS_ERR(vah)) { kfree(ah); - ah = NULL; - } else + ah = (struct ipoib_ah *)vah; + } else { + ah->ah = vah; ipoib_dbg(netdev_priv(dev), "Created ah %p\n", ah->ah); + } return ah; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 7567b600023..83695b48b01 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -432,7 +432,7 @@ static void path_rec_completion(int status, spin_lock_irqsave(&priv->lock, flags); - if (ah) { + if (!IS_ERR_OR_NULL(ah)) { path->pathrec = *pathrec; old_ah = path->ah; @@ -555,6 +555,7 @@ static int path_rec_start(struct net_device *dev, return 0; } +/* called with rcu_read_lock */ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(dev); @@ -636,6 +637,7 @@ err_drop: spin_unlock_irqrestore(&priv->lock, flags); } +/* called with rcu_read_lock */ static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) { struct ipoib_dev_priv *priv = netdev_priv(skb->dev); @@ -720,13 +722,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) struct neighbour *n = NULL; unsigned long flags; + rcu_read_lock(); if (likely(skb_dst(skb))) n = dst_get_neighbour(skb_dst(skb)); if (likely(n)) { if (unlikely(!*to_ipoib_neigh(n))) { ipoib_path_lookup(skb, dev); - return NETDEV_TX_OK; + goto unlock; } neigh = *to_ipoib_neigh(n); @@ -749,17 +752,17 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) ipoib_neigh_free(dev, neigh); spin_unlock_irqrestore(&priv->lock, flags); ipoib_path_lookup(skb, dev); - return NETDEV_TX_OK; + goto unlock; } if (ipoib_cm_get(neigh)) { if (ipoib_cm_up(neigh)) { ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); - return NETDEV_TX_OK; + goto unlock; } } else if (neigh->ah) { ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha)); - return NETDEV_TX_OK; + goto unlock; } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { @@ -793,13 +796,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) phdr->hwaddr + 4); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; - return NETDEV_TX_OK; + goto unlock; } unicast_arp_send(skb, dev, phdr); } } - +unlock: + rcu_read_unlock(); return NETDEV_TX_OK; } @@ -837,7 +841,7 @@ static int ipoib_hard_header(struct sk_buff *skb, dst = skb_dst(skb); n = NULL; if (dst) - n = dst_get_neighbour(dst); + n = dst_get_neighbour_raw(dst); if ((!dst || !n) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 1b7a9768635..873bff97e69 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -240,8 +240,11 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, av.grh.dgid = mcast->mcmember.mgid; ah = ipoib_create_ah(dev, priv->pd, &av); - if (!ah) { - ipoib_warn(priv, "ib_address_create failed\n"); + if (IS_ERR(ah)) { + ipoib_warn(priv, "ib_address_create failed %ld\n", + -PTR_ERR(ah)); + /* use original error */ + return PTR_ERR(ah); } else { spin_lock_irq(&priv->lock); mcast->ah = ah; @@ -266,7 +269,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, skb->dev = dev; if (dst) - n = dst_get_neighbour(dst); + n = dst_get_neighbour_raw(dst); if (!dst || !n) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof (struct ipoib_pseudoheader)); @@ -722,6 +725,8 @@ out: if (mcast && mcast->ah) { struct dst_entry *dst = skb_dst(skb); struct neighbour *n = NULL; + + rcu_read_lock(); if (dst) n = dst_get_neighbour(dst); if (n && !*to_ipoib_neigh(n)) { @@ -734,7 +739,7 @@ out: list_add_tail(&neigh->list, &mcast->neigh_list); } } - + rcu_read_unlock(); spin_unlock_irqrestore(&priv->lock, flags); ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); return; diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index 80793f1608e..06517e60e50 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -115,8 +115,8 @@ static void decode_mg(struct cma3000_accl_data *data, int *datax, static irqreturn_t cma3000_thread_irq(int irq, void *dev_id) { struct cma3000_accl_data *data = dev_id; - int datax, datay, dataz; - u8 ctrl, mode, range, intr_status; + int datax, datay, dataz, intr_status; + u8 ctrl, mode, range; intr_status = CMA3000_READ(data, CMA3000_INTSTATUS, "interrupt status"); if (intr_status < 0) diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 09b93b11a27..e2a9867c19d 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -1210,18 +1210,28 @@ static int elantech_reconnect(struct psmouse *psmouse) */ static int elantech_set_properties(struct elantech_data *etd) { + /* This represents the version of IC body. */ int ver = (etd->fw_version & 0x0f0000) >> 16; + /* Early version of Elan touchpads doesn't obey the rule. */ if (etd->fw_version < 0x020030 || etd->fw_version == 0x020600) etd->hw_version = 1; - else if (etd->fw_version < 0x150600) - etd->hw_version = 2; - else if (ver == 5) - etd->hw_version = 3; - else if (ver == 6) - etd->hw_version = 4; - else - return -1; + else { + switch (ver) { + case 2: + case 4: + etd->hw_version = 2; + break; + case 5: + etd->hw_version = 3; + break; + case 6: + etd->hw_version = 4; + break; + default: + return -1; + } + } /* * Turn on packet checking by default. diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c index c5b12d2e955..86d6f39178b 100644 --- a/drivers/input/mouse/sentelic.c +++ b/drivers/input/mouse/sentelic.c @@ -2,7 +2,7 @@ * Finger Sensing Pad PS/2 mouse driver. * * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. - * Copyright (C) 2005-2010 Tai-hwa Liang, Sentelic Corporation. + * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -162,7 +162,7 @@ static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) - return -1; + goto out; if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { /* inversion is required */ @@ -261,7 +261,7 @@ static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) - return -1; + goto out; if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); @@ -309,7 +309,7 @@ static int fsp_get_buttons(struct psmouse *psmouse, int *btn) }; int val; - if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS, &val) == -1) return -EIO; *btn = buttons[(val & 0x30) >> 4]; diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h index ed1395ac7b8..2e4af24f8c1 100644 --- a/drivers/input/mouse/sentelic.h +++ b/drivers/input/mouse/sentelic.h @@ -2,7 +2,7 @@ * Finger Sensing Pad PS/2 mouse driver. * * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. - * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * Copyright (C) 2005-2011 Tai-hwa Liang, Sentelic Corporation. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,6 +33,7 @@ /* Finger-sensing Pad control registers */ #define FSP_REG_SYSCTL1 0x10 #define FSP_BIT_EN_REG_CLK BIT(5) +#define FSP_REG_TMOD_STATUS 0x20 #define FSP_REG_OPC_QDOWN 0x31 #define FSP_BIT_EN_OPC_TAG BIT(7) #define FSP_REG_OPTZ_XLO 0x34 diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index c080b828e5d..a6dcd18e9ad 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -24,6 +24,7 @@ */ #include <linux/module.h> +#include <linux/delay.h> #include <linux/dmi.h> #include <linux/input/mt.h> #include <linux/serio.h> @@ -1220,6 +1221,16 @@ static int synaptics_reconnect(struct psmouse *psmouse) do { psmouse_reset(psmouse); + if (retry) { + /* + * On some boxes, right after resuming, the touchpad + * needs some time to finish initializing (I assume + * it needs time to calibrate) and start responding + * to Synaptics-specific queries, so let's wait a + * bit. + */ + ssleep(1); + } error = synaptics_detect(psmouse, 0); } while (error && ++retry < 3); diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 4b2a42f9f0b..d4d08bd9205 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -24,6 +24,7 @@ #include <linux/irq.h> #include <linux/serio.h> #include <linux/slab.h> +#include <linux/module.h> #include <asm/mach-types.h> #include <plat/board-ams-delta.h> diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index bb9f5d31f0d..b4cfc6c8be8 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -431,6 +431,13 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), }, }, + { + /* Newer HP Pavilion dv4 models */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), + }, + }, { } }; @@ -560,6 +567,13 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V13"), }, }, + { + /* Newer HP Pavilion dv4 models */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv4 Notebook PC"), + }, + }, { } }; diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index da0d8761e77..2ee47d01a3b 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -1470,6 +1470,9 @@ static const struct wacom_features wacom_features_0xE3 = static const struct wacom_features wacom_features_0xE6 = { "Wacom ISDv4 E6", WACOM_PKGLEN_TPC2FG, 27760, 15694, 255, 0, TABLETPC2FG, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; +static const struct wacom_features wacom_features_0xEC = + { "Wacom ISDv4 EC", WACOM_PKGLEN_GRAPHIRE, 25710, 14500, 255, + 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x47 = { "Wacom Intuos2 6x8", WACOM_PKGLEN_INTUOS, 20320, 16240, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1611,6 +1614,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xE2) }, { USB_DEVICE_WACOM(0xE3) }, { USB_DEVICE_WACOM(0xE6) }, + { USB_DEVICE_WACOM(0xEC) }, { USB_DEVICE_WACOM(0x47) }, { USB_DEVICE_LENOVO(0x6004) }, { } diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index c0c7820d4c4..bdc447fd476 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -405,6 +405,9 @@ int dmar_disabled = 0; int dmar_disabled = 1; #endif /*CONFIG_INTEL_IOMMU_DEFAULT_ON*/ +int intel_iommu_enabled = 0; +EXPORT_SYMBOL_GPL(intel_iommu_enabled); + static int dmar_map_gfx = 1; static int dmar_forcedac; static int intel_iommu_strict; @@ -3524,7 +3527,7 @@ found: return 0; } -int dmar_parse_rmrr_atsr_dev(void) +int __init dmar_parse_rmrr_atsr_dev(void) { struct dmar_rmrr_unit *rmrr, *rmrr_n; struct dmar_atsr_unit *atsr, *atsr_n; @@ -3647,6 +3650,8 @@ int __init intel_iommu_init(void) bus_register_notifier(&pci_bus_type, &device_nb); + intel_iommu_enabled = 1; + return 0; } diff --git a/drivers/iommu/intr_remapping.c b/drivers/iommu/intr_remapping.c index 07c9f189f31..6777ca04947 100644 --- a/drivers/iommu/intr_remapping.c +++ b/drivers/iommu/intr_remapping.c @@ -773,7 +773,7 @@ int __init parse_ioapics_under_ir(void) return ir_supported; } -int ir_dev_scope_init(void) +int __init ir_dev_scope_init(void) { if (!intr_remapping_enabled) return 0; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 2fb2963df55..5b5fa5cdaa3 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -90,7 +90,7 @@ struct iommu_domain *iommu_domain_alloc(struct bus_type *bus) if (bus == NULL || bus->iommu_ops == NULL) return NULL; - domain = kmalloc(sizeof(*domain), GFP_KERNEL); + domain = kzalloc(sizeof(*domain), GFP_KERNEL); if (!domain) return NULL; diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index 9c192e79f80..288da5c1499 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/module.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> diff --git a/drivers/iommu/omap-iovmm.c b/drivers/iommu/omap-iovmm.c index e8fdb8830f6..46be456fcc0 100644 --- a/drivers/iommu/omap-iovmm.c +++ b/drivers/iommu/omap-iovmm.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include <linux/module.h> #include <linux/err.h> #include <linux/slab.h> #include <linux/vmalloc.h> diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index 33ec9e46777..9021182c4b7 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -242,6 +242,12 @@ static int isdn_divert_ioctl_unlocked(struct file *file, uint cmd, ulong arg) case IIOCDOCFINT: if (!divert_if.drv_to_name(dioctl.cf_ctrl.drvid)) return (-EINVAL); /* invalid driver */ + if (strnlen(dioctl.cf_ctrl.msn, sizeof(dioctl.cf_ctrl.msn)) == + sizeof(dioctl.cf_ctrl.msn)) + return -EINVAL; + if (strnlen(dioctl.cf_ctrl.fwd_nr, sizeof(dioctl.cf_ctrl.fwd_nr)) == + sizeof(dioctl.cf_ctrl.fwd_nr)) + return -EINVAL; if ((i = cf_command(dioctl.cf_ctrl.drvid, (cmd == IIOCDOCFACT) ? 1 : (cmd == IIOCDOCFDIS) ? 0 : 2, dioctl.cf_ctrl.cfproc, diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 1f73d7f7e02..2339d7396b9 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -2756,6 +2756,9 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg) char *c, *e; + if (strnlen(cfg->drvid, sizeof(cfg->drvid)) == + sizeof(cfg->drvid)) + return -EINVAL; drvidx = -1; chidx = -1; strcpy(drvid, cfg->drvid); diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 661b692573e..6d5628bb060 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -270,11 +270,8 @@ void led_blink_set(struct led_classdev *led_cdev, del_timer_sync(&led_cdev->blink_timer); if (led_cdev->blink_set && - !led_cdev->blink_set(led_cdev, delay_on, delay_off)) { - led_cdev->blink_delay_on = *delay_on; - led_cdev->blink_delay_off = *delay_off; + !led_cdev->blink_set(led_cdev, delay_on, delay_off)) return; - } /* blink with 1 Hz as default if nothing specified */ if (!*delay_on && !*delay_off) diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c index 817f37a875c..c9570fcf1cc 100644 --- a/drivers/macintosh/via-macii.c +++ b/drivers/macintosh/via-macii.c @@ -159,7 +159,7 @@ int macii_init(void) err = macii_init_via(); if (err) goto out; - err = request_irq(IRQ_MAC_ADB, macii_interrupt, IRQ_FLG_LOCK, "ADB", + err = request_irq(IRQ_MAC_ADB, macii_interrupt, 0, "ADB", macii_interrupt); if (err) goto out; diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c index 9ab5b0c34f0..34d02a91b29 100644 --- a/drivers/macintosh/via-maciisi.c +++ b/drivers/macintosh/via-maciisi.c @@ -122,8 +122,8 @@ maciisi_init(void) return err; } - if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, IRQ_FLG_LOCK | IRQ_FLG_FAST, - "ADB", maciisi_interrupt)) { + if (request_irq(IRQ_MAC_ADB, maciisi_interrupt, 0, "ADB", + maciisi_interrupt)) { printk(KERN_ERR "maciisi_init: can't get irq %d\n", IRQ_MAC_ADB); return -EAGAIN; } diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 7878712721b..6d03774b176 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1106,10 +1106,12 @@ void bitmap_write_all(struct bitmap *bitmap) */ int i; + spin_lock_irq(&bitmap->lock); for (i = 0; i < bitmap->file_pages; i++) set_page_attr(bitmap, bitmap->filemap[i], BITMAP_PAGE_NEEDWRITE); bitmap->allclean = 0; + spin_unlock_irq(&bitmap->lock); } static void bitmap_count_page(struct bitmap *bitmap, sector_t offset, int inc) @@ -1391,9 +1393,6 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto atomic_read(&bitmap->behind_writes), bitmap->mddev->bitmap_info.max_write_behind); } - if (bitmap->mddev->degraded) - /* Never clear bits or update events_cleared when degraded */ - success = 0; while (sectors) { sector_t blocks; @@ -1407,7 +1406,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, unsigned long secto return; } - if (success && + if (success && !bitmap->mddev->degraded && bitmap->events_cleared < bitmap->mddev->events) { bitmap->events_cleared = bitmap->mddev->events; bitmap->need_sync = 1; @@ -1605,7 +1604,9 @@ void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e) for (chunk = s; chunk <= e; chunk++) { sector_t sec = (sector_t)chunk << CHUNK_BLOCK_SHIFT(bitmap); bitmap_set_memory_bits(bitmap, sec, 1); + spin_lock_irq(&bitmap->lock); bitmap_file_set_bit(bitmap, sec); + spin_unlock_irq(&bitmap->lock); if (sec < bitmap->mddev->recovery_cp) /* We are asserting that the array is dirty, * so move the recovery_cp address back so diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index cb246667dd5..0a6806f80ab 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -14,6 +14,7 @@ #include <linux/vmalloc.h> #include <linux/version.h> #include <linux/shrinker.h> +#include <linux/module.h> #define DM_MSG_PREFIX "bufio" diff --git a/drivers/md/linear.c b/drivers/md/linear.c index c3273efd08c..627456542fb 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -230,6 +230,7 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev) return -EINVAL; rdev->raid_disk = rdev->saved_raid_disk; + rdev->saved_raid_disk = -1; newconf = linear_conf(mddev,mddev->raid_disks+1); diff --git a/drivers/md/md.c b/drivers/md/md.c index 84acfe7d10e..f47f1f8ac44 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -570,7 +570,7 @@ static void mddev_put(struct mddev *mddev) mddev->ctime == 0 && !mddev->hold_active) { /* Array is not configured at all, and not held active, * so destroy it */ - list_del(&mddev->all_mddevs); + list_del_init(&mddev->all_mddevs); bs = mddev->bio_set; mddev->bio_set = NULL; if (mddev->gendisk) { @@ -2546,7 +2546,8 @@ state_show(struct md_rdev *rdev, char *page) sep = ","; } if (test_bit(Blocked, &rdev->flags) || - rdev->badblocks.unacked_exist) { + (rdev->badblocks.unacked_exist + && !test_bit(Faulty, &rdev->flags))) { len += sprintf(page+len, "%sblocked", sep); sep = ","; } @@ -3788,6 +3789,8 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len) if (err) return err; else { + if (mddev->hold_active == UNTIL_IOCTL) + mddev->hold_active = 0; sysfs_notify_dirent_safe(mddev->sysfs_state); return len; } @@ -4487,11 +4490,20 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page) if (!entry->show) return -EIO; + spin_lock(&all_mddevs_lock); + if (list_empty(&mddev->all_mddevs)) { + spin_unlock(&all_mddevs_lock); + return -EBUSY; + } + mddev_get(mddev); + spin_unlock(&all_mddevs_lock); + rv = mddev_lock(mddev); if (!rv) { rv = entry->show(mddev, page); mddev_unlock(mddev); } + mddev_put(mddev); return rv; } @@ -4507,13 +4519,19 @@ md_attr_store(struct kobject *kobj, struct attribute *attr, return -EIO; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + spin_lock(&all_mddevs_lock); + if (list_empty(&mddev->all_mddevs)) { + spin_unlock(&all_mddevs_lock); + return -EBUSY; + } + mddev_get(mddev); + spin_unlock(&all_mddevs_lock); 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); } + mddev_put(mddev); return rv; } @@ -7342,8 +7360,7 @@ static int remove_and_add_spares(struct mddev *mddev) spares++; md_new_event(mddev); set_bit(MD_CHANGE_DEVS, &mddev->flags); - } else - break; + } } } } @@ -7840,6 +7857,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors, s + rdev->data_offset, sectors, acknowledged); if (rv) { /* Make sure they get written out promptly */ + sysfs_notify_dirent_safe(rdev->sysfs_state); set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags); md_wakeup_thread(rdev->mddev->thread); } diff --git a/drivers/md/persistent-data/dm-btree-remove.c b/drivers/md/persistent-data/dm-btree-remove.c index 65fd85ec651..023fbc2d389 100644 --- a/drivers/md/persistent-data/dm-btree-remove.c +++ b/drivers/md/persistent-data/dm-btree-remove.c @@ -8,7 +8,7 @@ #include "dm-btree-internal.h" #include "dm-transaction-manager.h" -#include <linux/module.h> +#include <linux/export.h> /* * Removing an entry from a btree diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index e0638be53ea..bd1e7ffbe26 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c @@ -8,7 +8,7 @@ #include "dm-space-map.h" #include "dm-transaction-manager.h" -#include <linux/module.h> +#include <linux/export.h> #include <linux/device-mapper.h> #define DM_MSG_PREFIX "btree" diff --git a/drivers/md/persistent-data/dm-space-map-checker.c b/drivers/md/persistent-data/dm-space-map-checker.c index bb44a937fe6..50ed53bf4aa 100644 --- a/drivers/md/persistent-data/dm-space-map-checker.c +++ b/drivers/md/persistent-data/dm-space-map-checker.c @@ -7,6 +7,7 @@ #include "dm-space-map-checker.h" #include <linux/device-mapper.h> +#include <linux/export.h> #ifdef CONFIG_DM_DEBUG_SPACE_MAPS diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c index aeff7852cf7..fc469ba9f62 100644 --- a/drivers/md/persistent-data/dm-space-map-disk.c +++ b/drivers/md/persistent-data/dm-space-map-disk.c @@ -12,7 +12,7 @@ #include <linux/list.h> #include <linux/slab.h> -#include <linux/module.h> +#include <linux/export.h> #include <linux/device-mapper.h> #define DM_MSG_PREFIX "space map disk" diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c index 728e89a3f97..6f8d38747d7 100644 --- a/drivers/md/persistent-data/dm-transaction-manager.c +++ b/drivers/md/persistent-data/dm-transaction-manager.c @@ -10,7 +10,7 @@ #include "dm-space-map-metadata.h" #include "dm-persistent-data-internal.h" -#include <linux/module.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/device-mapper.h> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 472aedfb07c..858fdbb7eb0 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3036,6 +3036,8 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) if (dev->written) s->written++; rdev = rcu_dereference(conf->disks[i].rdev); + if (rdev && test_bit(Faulty, &rdev->flags)) + rdev = NULL; if (rdev) { is_bad = is_badblock(rdev, sh->sector, STRIPE_SECTORS, &first_bad, &bad_sectors); @@ -3063,12 +3065,18 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) } } else if (test_bit(In_sync, &rdev->flags)) set_bit(R5_Insync, &dev->flags); - else if (!test_bit(Faulty, &rdev->flags)) { + else if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) /* in sync if before recovery_offset */ - if (sh->sector + STRIPE_SECTORS <= rdev->recovery_offset) - set_bit(R5_Insync, &dev->flags); - } - if (test_bit(R5_WriteError, &dev->flags)) { + set_bit(R5_Insync, &dev->flags); + else if (test_bit(R5_UPTODATE, &dev->flags) && + test_bit(R5_Expanded, &dev->flags)) + /* If we've reshaped into here, we assume it is Insync. + * We will shortly update recovery_offset to make + * it official. + */ + set_bit(R5_Insync, &dev->flags); + + if (rdev && test_bit(R5_WriteError, &dev->flags)) { clear_bit(R5_Insync, &dev->flags); if (!test_bit(Faulty, &rdev->flags)) { s->handle_bad_blocks = 1; @@ -3076,7 +3084,7 @@ static void analyse_stripe(struct stripe_head *sh, struct stripe_head_state *s) } else clear_bit(R5_WriteError, &dev->flags); } - if (test_bit(R5_MadeGood, &dev->flags)) { + if (rdev && test_bit(R5_MadeGood, &dev->flags)) { if (!test_bit(Faulty, &rdev->flags)) { s->handle_bad_blocks = 1; atomic_inc(&rdev->nr_pending); @@ -3110,7 +3118,7 @@ static void handle_stripe(struct stripe_head *sh) struct r5dev *pdev, *qdev; clear_bit(STRIPE_HANDLE, &sh->state); - if (test_and_set_bit(STRIPE_ACTIVE, &sh->state)) { + if (test_and_set_bit_lock(STRIPE_ACTIVE, &sh->state)) { /* already being handled, ensure it gets handled * again when current action finishes */ set_bit(STRIPE_HANDLE, &sh->state); @@ -3159,10 +3167,14 @@ static void handle_stripe(struct stripe_head *sh) /* check if the array has lost more than max_degraded devices and, * if so, some requests might need to be failed. */ - if (s.failed > conf->max_degraded && s.to_read+s.to_write+s.written) - handle_failed_stripe(conf, sh, &s, disks, &s.return_bi); - if (s.failed > conf->max_degraded && s.syncing) - handle_failed_sync(conf, sh, &s); + if (s.failed > conf->max_degraded) { + sh->check_state = 0; + sh->reconstruct_state = 0; + if (s.to_read+s.to_write+s.written) + handle_failed_stripe(conf, sh, &s, disks, &s.return_bi); + if (s.syncing) + handle_failed_sync(conf, sh, &s); + } /* * might be able to return some write requests if the parity blocks @@ -3371,7 +3383,7 @@ finish: return_io(s.return_bi); - clear_bit(STRIPE_ACTIVE, &sh->state); + clear_bit_unlock(STRIPE_ACTIVE, &sh->state); } static void raid5_activate_delayed(struct r5conf *conf) diff --git a/drivers/media/common/tuners/mxl5007t.c b/drivers/media/common/tuners/mxl5007t.c index 7eb1bf75cd0..5d02221e99d 100644 --- a/drivers/media/common/tuners/mxl5007t.c +++ b/drivers/media/common/tuners/mxl5007t.c @@ -488,9 +488,10 @@ static int mxl5007t_write_regs(struct mxl5007t_state *state, static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) { + u8 buf[2] = { 0xfb, reg }; struct i2c_msg msg[] = { { .addr = state->i2c_props.addr, .flags = 0, - .buf = ®, .len = 1 }, + .buf = buf, .len = 2 }, { .addr = state->i2c_props.addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, }; diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c index aacfe2387e2..4fc29730a12 100644 --- a/drivers/media/common/tuners/tda18218.c +++ b/drivers/media/common/tuners/tda18218.c @@ -141,7 +141,7 @@ static int tda18218_set_params(struct dvb_frontend *fe, switch (params->u.ofdm.bandwidth) { case BANDWIDTH_6_MHZ: LP_Fc = 0; - LO_Frac = params->frequency + 4000000; + LO_Frac = params->frequency + 3000000; break; case BANDWIDTH_7_MHZ: LP_Fc = 1; diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c index 2e8c288258a..34434557ef6 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-i2c.c @@ -398,7 +398,6 @@ static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, u8 i2c_r_data[24]; u8 i = 0; u8 fifo_status = 0; - int ret; int status = 0; mxl_i2c("read %d bytes", count); @@ -418,7 +417,7 @@ static int mxl111sf_i2c_readagain(struct mxl111sf_state *state, i2c_w_data[4+(i*3)] = 0x00; } - ret = mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); + mxl111sf_i2c_get_data(state, 0, i2c_w_data, i2c_r_data); /* Check for I2C NACK status */ if (mxl111sf_i2c_check_status(state) == 1) { diff --git a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c index 91dc1fc2825..b741b3a7a32 100644 --- a/drivers/media/dvb/dvb-usb/mxl111sf-phy.c +++ b/drivers/media/dvb/dvb-usb/mxl111sf-phy.c @@ -296,8 +296,7 @@ int mxl111sf_config_spi(struct mxl111sf_state *state, int onoff) goto fail; ret = mxl111sf_write_reg(state, 0x00, 0x00); - if (mxl_fail(ret)) - goto fail; + mxl_fail(ret); fail: return ret; } @@ -328,11 +327,13 @@ int mxl111sf_idac_config(struct mxl111sf_state *state, /* set hysteresis value reg: 0x0B<5:0> */ ret = mxl111sf_write_reg(state, V6_IDAC_HYSTERESIS_REG, (hysteresis_value & 0x3F)); + mxl_fail(ret); } ret = mxl111sf_write_reg(state, V6_IDAC_SETTINGS_REG, val); + mxl_fail(ret); - return val; + return ret; } /* diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 303f22ea04c..01bb8daf4b0 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -189,7 +189,7 @@ struct ati_remote { dma_addr_t inbuf_dma; dma_addr_t outbuf_dma; - unsigned char old_data[2]; /* Detect duplicate events */ + unsigned char old_data; /* Detect duplicate events */ unsigned long old_jiffies; unsigned long acc_jiffies; /* handle acceleration */ unsigned long first_jiffies; @@ -221,35 +221,35 @@ struct ati_remote { /* Translation table from hardware messages to input events. */ static const struct { short kind; - unsigned char data1, data2; + unsigned char data; int type; unsigned int code; int value; } ati_remote_tbl[] = { /* Directional control pad axes */ - {KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */ - {KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */ - {KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */ - {KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */ + {KIND_ACCEL, 0x70, EV_REL, REL_X, -1}, /* left */ + {KIND_ACCEL, 0x71, EV_REL, REL_X, 1}, /* right */ + {KIND_ACCEL, 0x72, EV_REL, REL_Y, -1}, /* up */ + {KIND_ACCEL, 0x73, EV_REL, REL_Y, 1}, /* down */ /* Directional control pad diagonals */ - {KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */ - {KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */ - {KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */ - {KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */ + {KIND_LU, 0x74, EV_REL, 0, 0}, /* left up */ + {KIND_RU, 0x75, EV_REL, 0, 0}, /* right up */ + {KIND_LD, 0x77, EV_REL, 0, 0}, /* left down */ + {KIND_RD, 0x76, EV_REL, 0, 0}, /* right down */ /* "Mouse button" buttons */ - {KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ - {KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ - {KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ - {KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ + {KIND_LITERAL, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */ + {KIND_LITERAL, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */ + {KIND_LITERAL, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */ + {KIND_LITERAL, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */ /* Artificial "doubleclick" events are generated by the hardware. * They are mapped to the "side" and "extra" mouse buttons here. */ - {KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ - {KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ + {KIND_FILTERED, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */ + {KIND_FILTERED, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */ /* Non-mouse events are handled by rc-core */ - {KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0} + {KIND_END, 0x00, EV_MAX + 1, 0, 0} }; /* Local function prototypes */ @@ -397,25 +397,6 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne } /* - * ati_remote_event_lookup - */ -static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2) -{ - int i; - - for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { - /* - * Decide if the table entry matches the remote input. - */ - if (ati_remote_tbl[i].data1 == d1 && - ati_remote_tbl[i].data2 == d2) - return i; - - } - return -1; -} - -/* * ati_remote_compute_accel * * Implements acceleration curve for directional control pad @@ -463,7 +444,15 @@ static void ati_remote_input_report(struct urb *urb) int index = -1; int acc; int remote_num; - unsigned char scancode[2]; + unsigned char scancode; + int i; + + /* + * data[0] = 0x14 + * data[1] = data[2] + data[3] + 0xd5 (a checksum byte) + * data[2] = the key code (with toggle bit in MSB with some models) + * data[3] = channel << 4 (the low 4 bits must be zero) + */ /* Deal with strange looking inputs */ if ( (urb->actual_length != 4) || (data[0] != 0x14) || @@ -472,6 +461,13 @@ static void ati_remote_input_report(struct urb *urb) return; } + if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) { + dbginfo(&ati_remote->interface->dev, + "wrong checksum in input: %02x %02x %02x %02x\n", + data[0], data[1], data[2], data[3]); + return; + } + /* Mask unwanted remote channels. */ /* note: remote_num is 0-based, channel 1 on remote == 0 here */ remote_num = (data[3] >> 4) & 0x0f; @@ -482,31 +478,30 @@ static void ati_remote_input_report(struct urb *urb) return; } - scancode[0] = (((data[1] - ((remote_num + 1) << 4)) & 0xf0) | (data[1] & 0x0f)); - /* - * Some devices (e.g. SnapStream Firefly) use 8080 as toggle code, - * so we have to clear them. The first bit is a bit tricky as the - * "non-toggled" state depends on remote_num, so we xor it with the - * second bit which is only used for toggle. + * MSB is a toggle code, though only used by some devices + * (e.g. SnapStream Firefly) */ - scancode[0] ^= (data[2] & 0x80); - - scancode[1] = data[2] & ~0x80; + scancode = data[2] & 0x7f; - /* Look up event code index in mouse translation table. */ - index = ati_remote_event_lookup(remote_num, scancode[0], scancode[1]); + /* Look up event code index in the mouse translation table. */ + for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) { + if (scancode == ati_remote_tbl[i].data) { + index = i; + break; + } + } if (index >= 0) { dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; mouse data %02x,%02x; index %d; keycode %d\n", - remote_num, data[1], data[2], index, ati_remote_tbl[index].code); + "channel 0x%02x; mouse data %02x; index %d; keycode %d\n", + remote_num, data[2], index, ati_remote_tbl[index].code); if (!dev) return; /* no mouse device */ } else dbginfo(&ati_remote->interface->dev, - "channel 0x%02x; key data %02x,%02x, scancode %02x,%02x\n", - remote_num, data[1], data[2], scancode[0], scancode[1]); + "channel 0x%02x; key data %02x, scancode %02x\n", + remote_num, data[2], scancode); if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) { @@ -523,8 +518,7 @@ static void ati_remote_input_report(struct urb *urb) unsigned long now = jiffies; /* Filter duplicate events which happen "too close" together. */ - if (ati_remote->old_data[0] == data[1] && - ati_remote->old_data[1] == data[2] && + if (ati_remote->old_data == data[2] && time_before(now, ati_remote->old_jiffies + msecs_to_jiffies(repeat_filter))) { ati_remote->repeat_count++; @@ -533,8 +527,7 @@ static void ati_remote_input_report(struct urb *urb) ati_remote->first_jiffies = now; } - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; + ati_remote->old_data = data[2]; ati_remote->old_jiffies = now; /* Ensure we skip at least the 4 first duplicate events (generated @@ -549,14 +542,13 @@ static void ati_remote_input_report(struct urb *urb) if (index < 0) { /* Not a mouse event, hand it to rc-core. */ - u32 rc_code = (scancode[0] << 8) | scancode[1]; /* * We don't use the rc-core repeat handling yet as * it would cause ghost repeats which would be a * regression for this driver. */ - rc_keydown_notimeout(ati_remote->rdev, rc_code, + rc_keydown_notimeout(ati_remote->rdev, scancode, data[2]); rc_keyup(ati_remote->rdev); return; @@ -607,8 +599,7 @@ static void ati_remote_input_report(struct urb *urb) input_sync(dev); ati_remote->old_jiffies = jiffies; - ati_remote->old_data[0] = data[1]; - ati_remote->old_data[1] = data[2]; + ati_remote->old_data = data[2]; } } diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index e1b8b2605c4..81506440ede 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -27,55 +27,55 @@ #include <media/rc-map.h> static struct rc_map_table ati_x10[] = { - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xc500, KEY_A }, - { 0xc601, KEY_B }, - { 0xde19, KEY_C }, - { 0xe01b, KEY_D }, - { 0xe621, KEY_E }, - { 0xe823, KEY_F }, + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x00, KEY_A }, + { 0x01, KEY_B }, + { 0x19, KEY_C }, + { 0x1b, KEY_D }, + { 0x21, KEY_E }, + { 0x23, KEY_F }, - { 0xdd18, KEY_KPENTER }, /* "check" */ - { 0xdb16, KEY_MENU }, /* "menu" */ - { 0xc702, KEY_POWER }, /* Power */ - { 0xc803, KEY_TV }, /* TV */ - { 0xc904, KEY_DVD }, /* DVD */ - { 0xca05, KEY_WWW }, /* WEB */ - { 0xcb06, KEY_BOOKMARKS }, /* "book" */ - { 0xcc07, KEY_EDIT }, /* "hand" */ - { 0xe11c, KEY_COFFEE }, /* "timer" */ - { 0xe520, KEY_FRONT }, /* "max" */ - { 0xe21d, KEY_LEFT }, /* left */ - { 0xe41f, KEY_RIGHT }, /* right */ - { 0xe722, KEY_DOWN }, /* down */ - { 0xdf1a, KEY_UP }, /* up */ - { 0xe31e, KEY_OK }, /* "OK" */ - { 0xce09, KEY_VOLUMEDOWN }, /* VOL + */ - { 0xcd08, KEY_VOLUMEUP }, /* VOL - */ - { 0xcf0a, KEY_MUTE }, /* MUTE */ - { 0xd00b, KEY_CHANNELUP }, /* CH + */ - { 0xd10c, KEY_CHANNELDOWN },/* CH - */ - { 0xec27, KEY_RECORD }, /* ( o) red */ - { 0xea25, KEY_PLAY }, /* ( >) */ - { 0xe924, KEY_REWIND }, /* (<<) */ - { 0xeb26, KEY_FORWARD }, /* (>>) */ - { 0xed28, KEY_STOP }, /* ([]) */ - { 0xee29, KEY_PAUSE }, /* ('') */ - { 0xf02b, KEY_PREVIOUS }, /* (<-) */ - { 0xef2a, KEY_NEXT }, /* (>+) */ - { 0xf22d, KEY_INFO }, /* PLAYING */ - { 0xf32e, KEY_HOME }, /* TOP */ - { 0xf42f, KEY_END }, /* END */ - { 0xf530, KEY_SELECT }, /* SELECT */ + { 0x18, KEY_KPENTER }, /* "check" */ + { 0x16, KEY_MENU }, /* "menu" */ + { 0x02, KEY_POWER }, /* Power */ + { 0x03, KEY_TV }, /* TV */ + { 0x04, KEY_DVD }, /* DVD */ + { 0x05, KEY_WWW }, /* WEB */ + { 0x06, KEY_BOOKMARKS }, /* "book" */ + { 0x07, KEY_EDIT }, /* "hand" */ + { 0x1c, KEY_COFFEE }, /* "timer" */ + { 0x20, KEY_FRONT }, /* "max" */ + { 0x1d, KEY_LEFT }, /* left */ + { 0x1f, KEY_RIGHT }, /* right */ + { 0x22, KEY_DOWN }, /* down */ + { 0x1a, KEY_UP }, /* up */ + { 0x1e, KEY_OK }, /* "OK" */ + { 0x09, KEY_VOLUMEDOWN }, /* VOL + */ + { 0x08, KEY_VOLUMEUP }, /* VOL - */ + { 0x0a, KEY_MUTE }, /* MUTE */ + { 0x0b, KEY_CHANNELUP }, /* CH + */ + { 0x0c, KEY_CHANNELDOWN },/* CH - */ + { 0x27, KEY_RECORD }, /* ( o) red */ + { 0x25, KEY_PLAY }, /* ( >) */ + { 0x24, KEY_REWIND }, /* (<<) */ + { 0x26, KEY_FORWARD }, /* (>>) */ + { 0x28, KEY_STOP }, /* ([]) */ + { 0x29, KEY_PAUSE }, /* ('') */ + { 0x2b, KEY_PREVIOUS }, /* (<-) */ + { 0x2a, KEY_NEXT }, /* (>+) */ + { 0x2d, KEY_INFO }, /* PLAYING */ + { 0x2e, KEY_HOME }, /* TOP */ + { 0x2f, KEY_END }, /* END */ + { 0x30, KEY_SELECT }, /* SELECT */ }; static struct rc_map_list ati_x10_map = { diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 09e2cc01d11..479cdb89781 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -25,70 +25,70 @@ #include <media/rc-map.h> static struct rc_map_table medion_x10[] = { - { 0xf12c, KEY_TV }, /* TV */ - { 0xf22d, KEY_VCR }, /* VCR */ - { 0xc904, KEY_DVD }, /* DVD */ - { 0xcb06, KEY_AUDIO }, /* MUSIC */ - - { 0xf32e, KEY_RADIO }, /* RADIO */ - { 0xca05, KEY_DIRECTORY }, /* PHOTO */ - { 0xf42f, KEY_INFO }, /* TV-PREVIEW */ - { 0xf530, KEY_LIST }, /* CHANNEL-LST */ - - { 0xe01b, KEY_SETUP }, /* SETUP */ - { 0xf631, KEY_VIDEO }, /* VIDEO DESKTOP */ - - { 0xcd08, KEY_VOLUMEDOWN }, /* VOL - */ - { 0xce09, KEY_VOLUMEUP }, /* VOL + */ - { 0xd00b, KEY_CHANNELUP }, /* CHAN + */ - { 0xd10c, KEY_CHANNELDOWN }, /* CHAN - */ - { 0xc500, KEY_MUTE }, /* MUTE */ - - { 0xf732, KEY_RED }, /* red */ - { 0xf833, KEY_GREEN }, /* green */ - { 0xf934, KEY_YELLOW }, /* yellow */ - { 0xfa35, KEY_BLUE }, /* blue */ - { 0xdb16, KEY_TEXT }, /* TXT */ - - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xe11c, KEY_SEARCH }, /* TV/RAD, CH SRC */ - { 0xe520, KEY_DELETE }, /* DELETE */ - - { 0xfb36, KEY_KEYBOARD }, /* RENAME */ - { 0xdd18, KEY_SCREEN }, /* SNAPSHOT */ - - { 0xdf1a, KEY_UP }, /* up */ - { 0xe722, KEY_DOWN }, /* down */ - { 0xe21d, KEY_LEFT }, /* left */ - { 0xe41f, KEY_RIGHT }, /* right */ - { 0xe31e, KEY_OK }, /* OK */ - - { 0xfc37, KEY_SELECT }, /* ACQUIRE IMAGE */ - { 0xfd38, KEY_EDIT }, /* EDIT IMAGE */ - - { 0xe924, KEY_REWIND }, /* rewind (<<) */ - { 0xea25, KEY_PLAY }, /* play ( >) */ - { 0xeb26, KEY_FORWARD }, /* forward (>>) */ - { 0xec27, KEY_RECORD }, /* record ( o) */ - { 0xed28, KEY_STOP }, /* stop ([]) */ - { 0xee29, KEY_PAUSE }, /* pause ('') */ - - { 0xe621, KEY_PREVIOUS }, /* prev */ - { 0xfe39, KEY_SWITCHVIDEOMODE }, /* F SCR */ - { 0xe823, KEY_NEXT }, /* next */ - { 0xde19, KEY_MENU }, /* MENU */ - { 0xff3a, KEY_LANGUAGE }, /* AUDIO */ - - { 0xc702, KEY_POWER }, /* POWER */ + { 0x2c, KEY_TV }, /* TV */ + { 0x2d, KEY_VCR }, /* VCR */ + { 0x04, KEY_DVD }, /* DVD */ + { 0x06, KEY_AUDIO }, /* MUSIC */ + + { 0x2e, KEY_RADIO }, /* RADIO */ + { 0x05, KEY_DIRECTORY }, /* PHOTO */ + { 0x2f, KEY_INFO }, /* TV-PREVIEW */ + { 0x30, KEY_LIST }, /* CHANNEL-LST */ + + { 0x1b, KEY_SETUP }, /* SETUP */ + { 0x31, KEY_VIDEO }, /* VIDEO DESKTOP */ + + { 0x08, KEY_VOLUMEDOWN }, /* VOL - */ + { 0x09, KEY_VOLUMEUP }, /* VOL + */ + { 0x0b, KEY_CHANNELUP }, /* CHAN + */ + { 0x0c, KEY_CHANNELDOWN }, /* CHAN - */ + { 0x00, KEY_MUTE }, /* MUTE */ + + { 0x32, KEY_RED }, /* red */ + { 0x33, KEY_GREEN }, /* green */ + { 0x34, KEY_YELLOW }, /* yellow */ + { 0x35, KEY_BLUE }, /* blue */ + { 0x16, KEY_TEXT }, /* TXT */ + + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x1c, KEY_SEARCH }, /* TV/RAD, CH SRC */ + { 0x20, KEY_DELETE }, /* DELETE */ + + { 0x36, KEY_KEYBOARD }, /* RENAME */ + { 0x18, KEY_SCREEN }, /* SNAPSHOT */ + + { 0x1a, KEY_UP }, /* up */ + { 0x22, KEY_DOWN }, /* down */ + { 0x1d, KEY_LEFT }, /* left */ + { 0x1f, KEY_RIGHT }, /* right */ + { 0x1e, KEY_OK }, /* OK */ + + { 0x37, KEY_SELECT }, /* ACQUIRE IMAGE */ + { 0x38, KEY_EDIT }, /* EDIT IMAGE */ + + { 0x24, KEY_REWIND }, /* rewind (<<) */ + { 0x25, KEY_PLAY }, /* play ( >) */ + { 0x26, KEY_FORWARD }, /* forward (>>) */ + { 0x27, KEY_RECORD }, /* record ( o) */ + { 0x28, KEY_STOP }, /* stop ([]) */ + { 0x29, KEY_PAUSE }, /* pause ('') */ + + { 0x21, KEY_PREVIOUS }, /* prev */ + { 0x39, KEY_SWITCHVIDEOMODE }, /* F SCR */ + { 0x23, KEY_NEXT }, /* next */ + { 0x19, KEY_MENU }, /* MENU */ + { 0x3a, KEY_LANGUAGE }, /* AUDIO */ + + { 0x02, KEY_POWER }, /* POWER */ }; static struct rc_map_list medion_x10_map = { diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index ef146520931..c7f33ec719b 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -22,63 +22,63 @@ #include <media/rc-map.h> static struct rc_map_table snapstream_firefly[] = { - { 0xf12c, KEY_ZOOM }, /* Maximize */ - { 0xc702, KEY_CLOSE }, - - { 0xd20d, KEY_1 }, - { 0xd30e, KEY_2 }, - { 0xd40f, KEY_3 }, - { 0xd510, KEY_4 }, - { 0xd611, KEY_5 }, - { 0xd712, KEY_6 }, - { 0xd813, KEY_7 }, - { 0xd914, KEY_8 }, - { 0xda15, KEY_9 }, - { 0xdc17, KEY_0 }, - { 0xdb16, KEY_BACK }, - { 0xdd18, KEY_KPENTER }, /* ent */ - - { 0xce09, KEY_VOLUMEUP }, - { 0xcd08, KEY_VOLUMEDOWN }, - { 0xcf0a, KEY_MUTE }, - { 0xd00b, KEY_CHANNELUP }, - { 0xd10c, KEY_CHANNELDOWN }, - { 0xc500, KEY_VENDOR }, /* firefly */ - - { 0xf32e, KEY_INFO }, - { 0xf42f, KEY_OPTION }, - - { 0xe21d, KEY_LEFT }, - { 0xe41f, KEY_RIGHT }, - { 0xe722, KEY_DOWN }, - { 0xdf1a, KEY_UP }, - { 0xe31e, KEY_OK }, - - { 0xe11c, KEY_MENU }, - { 0xe520, KEY_EXIT }, - - { 0xec27, KEY_RECORD }, - { 0xea25, KEY_PLAY }, - { 0xed28, KEY_STOP }, - { 0xe924, KEY_REWIND }, - { 0xeb26, KEY_FORWARD }, - { 0xee29, KEY_PAUSE }, - { 0xf02b, KEY_PREVIOUS }, - { 0xef2a, KEY_NEXT }, - - { 0xcb06, KEY_AUDIO }, /* Music */ - { 0xca05, KEY_IMAGES }, /* Photos */ - { 0xc904, KEY_DVD }, - { 0xc803, KEY_TV }, - { 0xcc07, KEY_VIDEO }, - - { 0xc601, KEY_HELP }, - { 0xf22d, KEY_MODE }, /* Mouse */ - - { 0xde19, KEY_A }, - { 0xe01b, KEY_B }, - { 0xe621, KEY_C }, - { 0xe823, KEY_D }, + { 0x2c, KEY_ZOOM }, /* Maximize */ + { 0x02, KEY_CLOSE }, + + { 0x0d, KEY_1 }, + { 0x0e, KEY_2 }, + { 0x0f, KEY_3 }, + { 0x10, KEY_4 }, + { 0x11, KEY_5 }, + { 0x12, KEY_6 }, + { 0x13, KEY_7 }, + { 0x14, KEY_8 }, + { 0x15, KEY_9 }, + { 0x17, KEY_0 }, + { 0x16, KEY_BACK }, + { 0x18, KEY_KPENTER }, /* ent */ + + { 0x09, KEY_VOLUMEUP }, + { 0x08, KEY_VOLUMEDOWN }, + { 0x0a, KEY_MUTE }, + { 0x0b, KEY_CHANNELUP }, + { 0x0c, KEY_CHANNELDOWN }, + { 0x00, KEY_VENDOR }, /* firefly */ + + { 0x2e, KEY_INFO }, + { 0x2f, KEY_OPTION }, + + { 0x1d, KEY_LEFT }, + { 0x1f, KEY_RIGHT }, + { 0x22, KEY_DOWN }, + { 0x1a, KEY_UP }, + { 0x1e, KEY_OK }, + + { 0x1c, KEY_MENU }, + { 0x20, KEY_EXIT }, + + { 0x27, KEY_RECORD }, + { 0x25, KEY_PLAY }, + { 0x28, KEY_STOP }, + { 0x24, KEY_REWIND }, + { 0x26, KEY_FORWARD }, + { 0x29, KEY_PAUSE }, + { 0x2b, KEY_PREVIOUS }, + { 0x2a, KEY_NEXT }, + + { 0x06, KEY_AUDIO }, /* Music */ + { 0x05, KEY_IMAGES }, /* Photos */ + { 0x04, KEY_DVD }, + { 0x03, KEY_TV }, + { 0x07, KEY_VIDEO }, + + { 0x01, KEY_HELP }, + { 0x2d, KEY_MODE }, /* Mouse */ + + { 0x19, KEY_A }, + { 0x1b, KEY_B }, + { 0x21, KEY_C }, + { 0x23, KEY_D }, }; static struct rc_map_list snapstream_firefly_map = { diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c index 39fc923fc46..1c6015a04f9 100644 --- a/drivers/media/video/au0828/au0828-cards.c +++ b/drivers/media/video/au0828/au0828-cards.c @@ -162,11 +162,14 @@ static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data) switch (tv.model) { case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */ case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ + case 72261: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ break; @@ -324,6 +327,10 @@ struct usb_device_id au0828_usb_id_table[] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, { USB_DEVICE(0x2040, 0x8200), .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, + { USB_DEVICE(0x2040, 0x7260), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7213), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { }, }; diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index 881e04c7ffe..2ca10dfec91 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -838,13 +838,13 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->usb_err = 0; /* do the specific subdriver stuff before endpoint selection */ - gspca_dev->alt = 0; + intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); + gspca_dev->alt = gspca_dev->cam.bulk ? intf->num_altsetting : 0; if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) goto unlock; } - intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; @@ -957,7 +957,7 @@ retry: ret = -EIO; goto out; } - alt = ep_tb[--alt_idx].alt; + gspca_dev->alt = ep_tb[--alt_idx].alt; } } out: diff --git a/drivers/media/video/m5mols/m5mols.h b/drivers/media/video/m5mols/m5mols.h index 89d09a8914f..82c8817bd32 100644 --- a/drivers/media/video/m5mols/m5mols.h +++ b/drivers/media/video/m5mols/m5mols.h @@ -162,7 +162,6 @@ struct m5mols_version { * @pad: media pad * @ffmt: current fmt according to resolution type * @res_type: current resolution type - * @code: current code * @irq_waitq: waitqueue for the capture * @work_irq: workqueue for the IRQ * @flags: state variable for the interrupt handler @@ -192,7 +191,6 @@ struct m5mols_info { struct media_pad pad; struct v4l2_mbus_framefmt ffmt[M5MOLS_RESTYPE_MAX]; int res_type; - enum v4l2_mbus_pixelcode code; wait_queue_head_t irq_waitq; struct work_struct work_irq; unsigned long flags; diff --git a/drivers/media/video/m5mols/m5mols_core.c b/drivers/media/video/m5mols/m5mols_core.c index 05ab3700647..e0f09e53180 100644 --- a/drivers/media/video/m5mols/m5mols_core.c +++ b/drivers/media/video/m5mols/m5mols_core.c @@ -334,7 +334,7 @@ int m5mols_mode(struct m5mols_info *info, u8 mode) int ret = -EINVAL; u8 reg; - if (mode < REG_PARAMETER && mode > REG_CAPTURE) + if (mode < REG_PARAMETER || mode > REG_CAPTURE) return ret; ret = m5mols_read_u8(sd, SYSTEM_SYSMODE, ®); @@ -511,9 +511,6 @@ static int m5mols_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, struct m5mols_info *info = to_m5mols(sd); struct v4l2_mbus_framefmt *format; - if (fmt->pad != 0) - return -EINVAL; - format = __find_format(info, fh, fmt->which, info->res_type); if (!format) return -EINVAL; @@ -532,9 +529,6 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, u32 resolution = 0; int ret; - if (fmt->pad != 0) - return -EINVAL; - ret = __find_resolution(sd, format, &type, &resolution); if (ret < 0) return ret; @@ -543,13 +537,14 @@ static int m5mols_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh, if (!sfmt) return 0; - *sfmt = m5mols_default_ffmt[type]; - sfmt->width = format->width; - sfmt->height = format->height; + + format->code = m5mols_default_ffmt[type].code; + format->colorspace = V4L2_COLORSPACE_JPEG; + format->field = V4L2_FIELD_NONE; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + *sfmt = *format; info->resolution = resolution; - info->code = format->code; info->res_type = type; } @@ -626,13 +621,14 @@ static int m5mols_start_monitor(struct m5mols_info *info) static int m5mols_s_stream(struct v4l2_subdev *sd, int enable) { struct m5mols_info *info = to_m5mols(sd); + u32 code = info->ffmt[info->res_type].code; if (enable) { int ret = -EINVAL; - if (is_code(info->code, M5MOLS_RESTYPE_MONITOR)) + if (is_code(code, M5MOLS_RESTYPE_MONITOR)) ret = m5mols_start_monitor(info); - if (is_code(info->code, M5MOLS_RESTYPE_CAPTURE)) + if (is_code(code, M5MOLS_RESTYPE_CAPTURE)) ret = m5mols_start_capture(info); return ret; diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c index cf2c0fb95f2..398f96ffd35 100644 --- a/drivers/media/video/mt9m111.c +++ b/drivers/media/video/mt9m111.c @@ -955,6 +955,7 @@ static int mt9m111_probe(struct i2c_client *client, mt9m111->rect.height = MT9M111_MAX_HEIGHT; mt9m111->fmt = &mt9m111_colour_fmts[0]; mt9m111->lastpage = -1; + mutex_init(&mt9m111->power_lock); ret = mt9m111_video_probe(client); if (ret) { diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c index 32114a3c0ca..7b34b11daf2 100644 --- a/drivers/media/video/mt9t112.c +++ b/drivers/media/video/mt9t112.c @@ -1083,8 +1083,10 @@ static int mt9t112_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); ret = mt9t112_camera_probe(client); - if (ret) + if (ret) { kfree(priv); + return ret; + } /* Cannot fail: using the default supported pixel code */ mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8); diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c index 9c5c19f142d..ee0d0b39cd1 100644 --- a/drivers/media/video/omap/omap_vout.c +++ b/drivers/media/video/omap/omap_vout.c @@ -38,6 +38,7 @@ #include <linux/irq.h> #include <linux/videodev2.h> #include <linux/dma-mapping.h> +#include <linux/slab.h> #include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> @@ -2169,6 +2170,14 @@ static int __init omap_vout_probe(struct platform_device *pdev) vid_dev->num_displays = 0; for_each_dss_dev(dssdev) { omap_dss_get_device(dssdev); + + if (!dssdev->driver) { + dev_warn(&pdev->dev, "no driver for display: %s\n", + dssdev->name); + omap_dss_put_device(dssdev); + continue; + } + vid_dev->displays[vid_dev->num_displays++] = dssdev; } diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c index e87ae2f634b..6a6cf388bae 100644 --- a/drivers/media/video/omap1_camera.c +++ b/drivers/media/video/omap1_camera.c @@ -24,6 +24,7 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> diff --git a/drivers/media/video/omap24xxcam-dma.c b/drivers/media/video/omap24xxcam-dma.c index 1d54b86c936..3ea38a8def8 100644 --- a/drivers/media/video/omap24xxcam-dma.c +++ b/drivers/media/video/omap24xxcam-dma.c @@ -506,7 +506,7 @@ int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma, unsigned long flags; struct sgdma_state *sg_state; - if ((sglen < 0) || ((sglen > 0) & !sglist)) + if ((sglen < 0) || ((sglen > 0) && !sglist)) return -EINVAL; spin_lock_irqsave(&sgdma->lock, flags); diff --git a/drivers/media/video/omap3isp/ispccdc.c b/drivers/media/video/omap3isp/ispccdc.c index b0b0fa5a357..54a4a3f22e2 100644 --- a/drivers/media/video/omap3isp/ispccdc.c +++ b/drivers/media/video/omap3isp/ispccdc.c @@ -1408,7 +1408,7 @@ static void ccdc_hs_vs_isr(struct isp_ccdc_device *ccdc) { struct isp_pipeline *pipe = to_isp_pipeline(&ccdc->video_out.video.entity); - struct video_device *vdev = &ccdc->subdev.devnode; + struct video_device *vdev = ccdc->subdev.devnode; struct v4l2_event event; memset(&event, 0, sizeof(event)); diff --git a/drivers/media/video/omap3isp/ispstat.c b/drivers/media/video/omap3isp/ispstat.c index 68d539456c5..bc0b2c7349b 100644 --- a/drivers/media/video/omap3isp/ispstat.c +++ b/drivers/media/video/omap3isp/ispstat.c @@ -496,7 +496,7 @@ static int isp_stat_bufs_alloc(struct ispstat *stat, u32 size) static void isp_stat_queue_event(struct ispstat *stat, int err) { - struct video_device *vdev = &stat->subdev.devnode; + struct video_device *vdev = stat->subdev.devnode; struct v4l2_event event; struct omap3isp_stat_event_status *status = (void *)event.u.data; diff --git a/drivers/media/video/omap3isp/ispvideo.c b/drivers/media/video/omap3isp/ispvideo.c index d1000723c5a..f2290578448 100644 --- a/drivers/media/video/omap3isp/ispvideo.c +++ b/drivers/media/video/omap3isp/ispvideo.c @@ -26,6 +26,7 @@ #include <asm/cacheflush.h> #include <linux/clk.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/sched.h> diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c index 9f2d26b1d4c..6806345ec2f 100644 --- a/drivers/media/video/ov6650.c +++ b/drivers/media/video/ov6650.c @@ -540,7 +540,7 @@ static u8 to_clkrc(struct v4l2_fract *timeperframe, static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { struct i2c_client *client = v4l2_get_subdevdata(sd); - struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); struct soc_camera_sense *sense = icd->sense; struct ov6650 *priv = to_ov6650(client); bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect); diff --git a/drivers/media/video/s5k6aa.c b/drivers/media/video/s5k6aa.c index 2446736b787..0df7f2a4181 100644 --- a/drivers/media/video/s5k6aa.c +++ b/drivers/media/video/s5k6aa.c @@ -19,6 +19,7 @@ #include <linux/gpio.h> #include <linux/i2c.h> #include <linux/media.h> +#include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/slab.h> diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index c8d91b0cd9b..2cc3b916672 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c @@ -98,6 +98,10 @@ static int fimc_capture_state_cleanup(struct fimc_dev *fimc, bool suspend) vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } set_bit(ST_CAPT_SUSPENDED, &fimc->state); + + fimc_hw_reset(fimc); + cap->buf_index = 0; + spin_unlock_irqrestore(&fimc->slock, flags); if (streaming) @@ -137,7 +141,7 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) struct fimc_dev *fimc = ctx->fimc_dev; int ret; - if (test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) + if (!test_bit(ST_CAPT_APPLY_CFG, &fimc->state)) return 0; spin_lock(&ctx->slock); @@ -150,7 +154,7 @@ int fimc_capture_config_update(struct fimc_ctx *ctx) fimc_hw_set_rotation(ctx); fimc_prepare_dma_offset(ctx, &ctx->d_frame); fimc_hw_set_out_dma(ctx); - set_bit(ST_CAPT_APPLY_CFG, &fimc->state); + clear_bit(ST_CAPT_APPLY_CFG, &fimc->state); } spin_unlock(&ctx->slock); return ret; @@ -164,7 +168,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) int min_bufs; int ret; - fimc_hw_reset(fimc); vid_cap->frame_count = 0; ret = fimc_init_capture(fimc); @@ -523,7 +526,7 @@ static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, max_w = rotation ? pl->out_rot_en_w : pl->out_rot_dis_w; min_w = ctx->state & FIMC_DST_CROP ? dst->width : var->min_out_pixsize; min_h = ctx->state & FIMC_DST_CROP ? dst->height : var->min_out_pixsize; - if (fimc->id == 1 && var->pix_hoff) + if (var->min_vsize_align == 1 && !rotation) align_h = fimc_fmt_is_rgb(ffmt->color) ? 0 : 1; depth = fimc_get_format_depth(ffmt); @@ -1239,6 +1242,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, mutex_lock(&fimc->lock); set_frame_bounds(ff, mf->width, mf->height); + fimc->vid_cap.mf = *mf; ff->fmt = ffmt; /* Reset the crop rectangle if required. */ @@ -1375,7 +1379,7 @@ static void fimc_destroy_capture_subdev(struct fimc_dev *fimc) media_entity_cleanup(&sd->entity); v4l2_device_unregister_subdev(sd); kfree(sd); - sd = NULL; + fimc->vid_cap.subdev = NULL; } /* Set default format at the sensor and host interface */ diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index 19ca6db38b2..07c6254faee 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c @@ -37,7 +37,7 @@ static char *fimc_clocks[MAX_FIMC_CLOCKS] = { static struct fimc_fmt fimc_formats[] = { { .name = "RGB565", - .fourcc = V4L2_PIX_FMT_RGB565X, + .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, .color = S5P_FIMC_RGB565, .memplanes = 1, @@ -1038,12 +1038,11 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) mod_x = 6; /* 64 x 32 pixels tile */ mod_y = 5; } else { - if (fimc->id == 1 && variant->pix_hoff) + if (variant->min_vsize_align == 1) mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1; else - mod_y = mod_x; + mod_y = ffs(variant->min_vsize_align) - 1; } - dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_w); v4l_bound_align_image(&pix->width, 16, max_w, mod_x, &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0); @@ -1226,10 +1225,10 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr) fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize; /* Get pixel alignment constraints. */ - if (fimc->id == 1 && fimc->variant->pix_hoff) + if (fimc->variant->min_vsize_align == 1) halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1; else - halign = ffs(min_size) - 1; + halign = ffs(fimc->variant->min_vsize_align) - 1; for (i = 0; i < f->fmt->colplanes; i++) depth += f->fmt->depth[i]; @@ -1615,7 +1614,6 @@ static int fimc_probe(struct platform_device *pdev) pdata = pdev->dev.platform_data; fimc->pdata = pdata; - set_bit(ST_LPM, &fimc->state); init_waitqueue_head(&fimc->irq_queue); spin_lock_init(&fimc->slock); @@ -1707,8 +1705,6 @@ static int fimc_runtime_resume(struct device *dev) /* Enable clocks and perform basic initalization */ clk_enable(fimc->clock[CLK_GATE]); fimc_hw_reset(fimc); - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); /* Resume the capture or mem-to-mem device */ if (fimc_capture_busy(fimc)) @@ -1750,8 +1746,6 @@ static int fimc_resume(struct device *dev) return 0; } fimc_hw_reset(fimc); - if (fimc->variant->out_buf_count > 4) - fimc_hw_set_dma_seq(fimc, 0xF); spin_unlock_irqrestore(&fimc->slock, flags); if (fimc_capture_busy(fimc)) @@ -1780,7 +1774,6 @@ static int __devexit fimc_remove(struct platform_device *pdev) struct fimc_dev *fimc = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - fimc_runtime_suspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); vb2_dma_contig_cleanup_ctx(fimc->alloc_ctx); @@ -1840,6 +1833,7 @@ static struct samsung_fimc_variant fimc0_variant_s5p = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[0], }; @@ -1849,6 +1843,7 @@ static struct samsung_fimc_variant fimc2_variant_s5p = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; @@ -1861,6 +1856,7 @@ static struct samsung_fimc_variant fimc0_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[1], }; @@ -1874,6 +1870,7 @@ static struct samsung_fimc_variant fimc1_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 1, + .min_vsize_align = 1, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; @@ -1884,6 +1881,7 @@ static struct samsung_fimc_variant fimc2_variant_s5pv210 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 8, + .min_vsize_align = 16, .out_buf_count = 4, .pix_limit = &s5p_pix_limit[2], }; @@ -1898,6 +1896,7 @@ static struct samsung_fimc_variant fimc0_variant_exynos4 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, + .min_vsize_align = 1, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[1], }; @@ -1910,6 +1909,7 @@ static struct samsung_fimc_variant fimc3_variant_exynos4 = { .min_inp_pixsize = 16, .min_out_pixsize = 16, .hor_offs_align = 2, + .min_vsize_align = 1, .out_buf_count = 32, .pix_limit = &s5p_pix_limit[3], }; diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index a6936dad5b1..c7f01c47b20 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h @@ -377,6 +377,7 @@ struct fimc_pix_limit { * @min_inp_pixsize: minimum input pixel size * @min_out_pixsize: minimum output pixel size * @hor_offs_align: horizontal pixel offset aligment + * @min_vsize_align: minimum vertical pixel size alignment * @out_buf_count: the number of buffers in output DMA sequence */ struct samsung_fimc_variant { @@ -390,6 +391,7 @@ struct samsung_fimc_variant { u16 min_inp_pixsize; u16 min_out_pixsize; u16 hor_offs_align; + u16 min_vsize_align; u16 out_buf_count; }; diff --git a/drivers/media/video/s5p-fimc/fimc-mdevice.c b/drivers/media/video/s5p-fimc/fimc-mdevice.c index cc337b1de91..615c862f036 100644 --- a/drivers/media/video/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/video/s5p-fimc/fimc-mdevice.c @@ -220,6 +220,7 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter, s_info->pdata->board_info, NULL); if (IS_ERR_OR_NULL(sd)) { + i2c_put_adapter(adapter); v4l2_err(&fmd->v4l2_dev, "Failed to acquire subdev\n"); return NULL; } @@ -234,12 +235,15 @@ static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd, static void fimc_md_unregister_sensor(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); + struct i2c_adapter *adapter; if (!client) return; v4l2_device_unregister_subdev(sd); + adapter = client->adapter; i2c_unregister_device(client); - i2c_put_adapter(client->adapter); + if (adapter) + i2c_put_adapter(adapter); } static int fimc_md_register_sensor_entities(struct fimc_md *fmd) @@ -381,20 +385,28 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd) static int fimc_md_register_video_nodes(struct fimc_md *fmd) { + struct video_device *vdev; int i, ret = 0; for (i = 0; i < FIMC_MAX_DEVS && !ret; i++) { if (!fmd->fimc[i]) continue; - if (fmd->fimc[i]->m2m.vfd) - ret = video_register_device(fmd->fimc[i]->m2m.vfd, - VFL_TYPE_GRABBER, -1); - if (ret) - break; - if (fmd->fimc[i]->vid_cap.vfd) - ret = video_register_device(fmd->fimc[i]->vid_cap.vfd, - VFL_TYPE_GRABBER, -1); + vdev = fmd->fimc[i]->m2m.vfd; + if (vdev) { + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret) + break; + v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n", + vdev->name, video_device_node_name(vdev)); + } + + vdev = fmd->fimc[i]->vid_cap.vfd; + if (vdev == NULL) + continue; + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + v4l2_info(&fmd->v4l2_dev, "Registered %s as /dev/%s\n", + vdev->name, video_device_node_name(vdev)); } return ret; @@ -502,7 +514,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) if (WARN(csis == NULL, "MIPI-CSI interface specified " "but s5p-csis module is not loaded!\n")) - continue; + return -EINVAL; ret = media_entity_create_link(&sensor->entity, 0, &csis->entity, CSIS_PAD_SINK, @@ -742,9 +754,6 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) struct fimc_md *fmd; int ret; - if (WARN(!pdev->dev.platform_data, "Platform data not specified!\n")) - return -EINVAL; - fmd = kzalloc(sizeof(struct fimc_md), GFP_KERNEL); if (!fmd) return -ENOMEM; @@ -782,9 +791,11 @@ static int __devinit fimc_md_probe(struct platform_device *pdev) if (ret) goto err3; - ret = fimc_md_register_sensor_entities(fmd); - if (ret) - goto err3; + if (pdev->dev.platform_data) { + ret = fimc_md_register_sensor_entities(fmd); + if (ret) + goto err3; + } ret = fimc_md_create_links(fmd); if (ret) goto err3; diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c index 20e664e3416..44f5c2d1920 100644 --- a/drivers/media/video/s5p-fimc/fimc-reg.c +++ b/drivers/media/video/s5p-fimc/fimc-reg.c @@ -35,6 +35,9 @@ void fimc_hw_reset(struct fimc_dev *dev) cfg = readl(dev->regs + S5P_CIGCTRL); cfg &= ~S5P_CIGCTRL_SWRST; writel(cfg, dev->regs + S5P_CIGCTRL); + + if (dev->variant->out_buf_count > 4) + fimc_hw_set_dma_seq(dev, 0xF); } static u32 fimc_hw_get_in_flip(struct fimc_ctx *ctx) @@ -251,7 +254,14 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) struct fimc_scaler *sc = &ctx->scaler; struct fimc_frame *src_frame = &ctx->s_frame; struct fimc_frame *dst_frame = &ctx->d_frame; - u32 cfg = 0; + + u32 cfg = readl(dev->regs + S5P_CISCCTRL); + + cfg &= ~(S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE | + S5P_CISCCTRL_SCALEUP_H | S5P_CISCCTRL_SCALEUP_V | + S5P_CISCCTRL_SCALERBYPASS | S5P_CISCCTRL_ONE2ONE | + S5P_CISCCTRL_INRGB_FMT_MASK | S5P_CISCCTRL_OUTRGB_FMT_MASK | + S5P_CISCCTRL_INTERLACE | S5P_CISCCTRL_RGB_EXT); if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW)) cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE); @@ -308,9 +318,9 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) fimc_hw_set_scaler(ctx); cfg = readl(dev->regs + S5P_CISCCTRL); + cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); if (variant->has_mainscaler_ext) { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); cfg |= S5P_CISCCTRL_MHRATIO_EXT(sc->main_hratio); cfg |= S5P_CISCCTRL_MVRATIO_EXT(sc->main_vratio); writel(cfg, dev->regs + S5P_CISCCTRL); @@ -323,7 +333,6 @@ void fimc_hw_set_mainscaler(struct fimc_ctx *ctx) cfg |= S5P_CIEXTEN_MVRATIO_EXT(sc->main_vratio); writel(cfg, dev->regs + S5P_CIEXTEN); } else { - cfg &= ~(S5P_CISCCTRL_MHRATIO_MASK | S5P_CISCCTRL_MVRATIO_MASK); cfg |= S5P_CISCCTRL_MHRATIO(sc->main_hratio); cfg |= S5P_CISCCTRL_MVRATIO(sc->main_vratio); writel(cfg, dev->regs + S5P_CISCCTRL); diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c index 725634d9736..844a4d7797b 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_dec.c @@ -220,8 +220,8 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c index ecef127dbc6..dff9dc79879 100644 --- a/drivers/media/video/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/video/s5p-mfc/s5p_mfc_enc.c @@ -61,7 +61,7 @@ static struct s5p_mfc_fmt formats[] = { .num_planes = 1, }, { - .name = "H264 Encoded Stream", + .name = "H263 Encoded Stream", .fourcc = V4L2_PIX_FMT_H263, .codec_mode = S5P_FIMV_CODEC_H263_ENC, .type = MFC_FMT_ENC, @@ -785,8 +785,8 @@ static int vidioc_querycap(struct file *file, void *priv, strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1); cap->bus_info[0] = 0; cap->version = KERNEL_VERSION(1, 0, 0); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_VIDEO_OUTPUT + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE_MPLANE + | V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_STREAMING; return 0; } diff --git a/drivers/media/video/s5p-tv/mixer_video.c b/drivers/media/video/s5p-tv/mixer_video.c index e16d3a4bc1d..b47d0c06ecf 100644 --- a/drivers/media/video/s5p-tv/mixer_video.c +++ b/drivers/media/video/s5p-tv/mixer_video.c @@ -16,6 +16,7 @@ #include <media/v4l2-ioctl.h> #include <linux/videodev2.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/version.h> #include <linux/timer.h> #include <media/videobuf2-dma-contig.h> diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c index f390682629c..c51decfcae1 100644 --- a/drivers/media/video/sh_mobile_ceu_camera.c +++ b/drivers/media/video/sh_mobile_ceu_camera.c @@ -566,8 +566,10 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) ret = sh_mobile_ceu_soft_reset(pcdev); csi2_sd = find_csi2(pcdev); - if (csi2_sd) - csi2_sd->grp_id = (long)icd; + if (csi2_sd) { + csi2_sd->grp_id = soc_camera_grp_id(icd); + v4l2_set_subdev_hostdata(csi2_sd, icd); + } ret = v4l2_subdev_call(csi2_sd, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) { @@ -768,7 +770,7 @@ static struct v4l2_subdev *find_bus_subdev(struct sh_mobile_ceu_dev *pcdev, { if (pcdev->csi2_pdev) { struct v4l2_subdev *csi2_sd = find_csi2(pcdev); - if (csi2_sd && csi2_sd->grp_id == (u32)icd) + if (csi2_sd && csi2_sd->grp_id == soc_camera_grp_id(icd)) return csi2_sd; } @@ -1089,8 +1091,9 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int /* Try 2560x1920, 1280x960, 640x480, 320x240 */ mf.width = 2560 >> shift; mf.height = 1920 >> shift; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - s_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, &mf); if (ret < 0) return ret; shift++; @@ -1389,7 +1392,8 @@ static int client_s_fmt(struct soc_camera_device *icd, bool ceu_1to1; int ret; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, s_mbus_fmt, mf); if (ret < 0) return ret; @@ -1426,8 +1430,9 @@ static int client_s_fmt(struct soc_camera_device *icd, tmp_h = min(2 * tmp_h, max_height); mf->width = tmp_w; mf->height = tmp_h; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - s_mbus_fmt, mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, mf); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); if (ret < 0) { @@ -1580,8 +1585,9 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, } if (interm_width < icd->user_width || interm_height < icd->user_height) { - ret = v4l2_device_call_until_err(sd->v4l2_dev, (int)icd, video, - s_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + s_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1867,7 +1873,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, mf.code = xlate->code; mf.colorspace = pix->colorspace; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), + video, try_mbus_fmt, &mf); if (ret < 0) return ret; @@ -1891,8 +1898,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, */ mf.width = 2560; mf.height = 1920; - ret = v4l2_device_call_until_err(sd->v4l2_dev, (long)icd, video, - try_mbus_fmt, &mf); + ret = v4l2_device_call_until_err(sd->v4l2_dev, + soc_camera_grp_id(icd), video, + try_mbus_fmt, &mf); if (ret < 0) { /* Shouldn't actually happen... */ dev_err(icd->parent, diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c index ea4f0473ed3..8a652b53ff7 100644 --- a/drivers/media/video/sh_mobile_csi2.c +++ b/drivers/media/video/sh_mobile_csi2.c @@ -143,7 +143,7 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, const struct v4l2_mbus_config *cfg) { struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - struct soc_camera_device *icd = (struct soc_camera_device *)sd->grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(sd); struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct v4l2_mbus_config client_cfg = {.type = V4L2_MBUS_CSI2, .flags = priv->mipi_flags}; @@ -202,7 +202,7 @@ static void sh_csi2_hwinit(struct sh_csi2 *priv) static int sh_csi2_client_connect(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; - struct soc_camera_device *icd = (struct soc_camera_device *)priv->subdev.grp_id; + struct soc_camera_device *icd = v4l2_get_subdev_hostdata(&priv->subdev); struct v4l2_subdev *client_sd = soc_camera_to_subdev(icd); struct device *dev = v4l2_get_subdevdata(&priv->subdev); struct v4l2_mbus_config cfg; diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c index b72580c3895..62e4312515c 100644 --- a/drivers/media/video/soc_camera.c +++ b/drivers/media/video/soc_camera.c @@ -1103,7 +1103,8 @@ static int soc_camera_probe(struct soc_camera_device *icd) } sd = soc_camera_to_subdev(icd); - sd->grp_id = (long)icd; + sd->grp_id = soc_camera_grp_id(icd); + v4l2_set_subdev_hostdata(sd, icd); if (v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler)) goto ectrl; diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c index 10c2364f3e8..254d3268884 100644 --- a/drivers/media/video/uvc/uvc_ctrl.c +++ b/drivers/media/video/uvc/uvc_ctrl.c @@ -1016,7 +1016,8 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, menu_info = &mapping->menu_info[query_menu->index]; - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { s32 bitmap; if (!ctrl->cached) { @@ -1225,7 +1226,8 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, /* Valid menu indices are reported by the GET_RES request for * UVC controls that support it. */ - if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) { + if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK && + (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) { if (!ctrl->cached) { ret = uvc_ctrl_populate_cache(chain, ctrl); if (ret < 0) diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c index f17f92b86a3..0f415dade05 100644 --- a/drivers/media/video/v4l2-ctrls.c +++ b/drivers/media/video/v4l2-ctrls.c @@ -821,8 +821,8 @@ static void send_event(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 changes) fill_event(&ev, ctrl, changes); list_for_each_entry(sev, &ctrl->ev_subs, node) - if (sev->fh && (sev->fh != fh || - (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK))) + if (sev->fh != fh || + (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK)) v4l2_event_queue_fh(sev->fh, &ev); } @@ -947,6 +947,7 @@ static void new_to_cur(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, if (ctrl->cluster[0]->has_volatiles) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; } + fh = NULL; } if (changed || update_inactive) { /* If a control was changed that was not one of the controls diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c index 46037f22552..c26ad963714 100644 --- a/drivers/media/video/v4l2-event.c +++ b/drivers/media/video/v4l2-event.c @@ -216,6 +216,9 @@ int v4l2_event_subscribe(struct v4l2_fh *fh, unsigned long flags; unsigned i; + if (sub->type == V4L2_EVENT_ALL) + return -EINVAL; + if (elems < 1) elems = 1; if (sub->type == V4L2_EVENT_CTRL) { @@ -283,6 +286,7 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, { struct v4l2_subscribed_event *sev; unsigned long flags; + int i; if (sub->type == V4L2_EVENT_ALL) { v4l2_event_unsubscribe_all(fh); @@ -293,8 +297,12 @@ int v4l2_event_unsubscribe(struct v4l2_fh *fh, sev = v4l2_event_subscribed(fh, sub->type, sub->id); if (sev != NULL) { + /* Remove any pending events for this subscription */ + for (i = 0; i < sev->in_use; i++) { + list_del(&sev->events[sev_pos(sev, i)].list); + fh->navailable--; + } list_del(&sev->list); - sev->fh = NULL; } spin_unlock_irqrestore(&fh->vdev->fh_lock, flags); diff --git a/drivers/media/video/videobuf2-core.c b/drivers/media/video/videobuf2-core.c index 979e544388c..95a3f5e82ae 100644 --- a/drivers/media/video/videobuf2-core.c +++ b/drivers/media/video/videobuf2-core.c @@ -131,6 +131,7 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n) continue; for (plane = 0; plane < vb->num_planes; ++plane) { + vb->v4l2_planes[plane].length = q->plane_sizes[plane]; vb->v4l2_planes[plane].m.mem_offset = off; dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n", @@ -264,6 +265,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers) q->num_buffers -= buffers; if (!q->num_buffers) q->memory = 0; + INIT_LIST_HEAD(&q->queued_list); } /** @@ -296,14 +298,14 @@ static bool __buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb) { unsigned int plane; for (plane = 0; plane < vb->num_planes; ++plane) { + void *mem_priv = vb->planes[plane].mem_priv; /* * If num_users() has not been provided, call_memop * will return 0, apparently nobody cares about this * case anyway. If num_users() returns more than 1, * we are not the only user of the plane's memory. */ - if (call_memop(q, plane, num_users, - vb->planes[plane].mem_priv) > 1) + if (mem_priv && call_memop(q, plane, num_users, mem_priv) > 1) return true; } return false; diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c index 4175544b491..ec10629a0b0 100644 --- a/drivers/mfd/ab5500-core.c +++ b/drivers/mfd/ab5500-core.c @@ -13,6 +13,7 @@ * TODO: Event handling with irq_chip. Waiting for PRCMU fw support. */ +#include <linux/module.h> #include <linux/mutex.h> #include <linux/err.h> #include <linux/platform_device.h> diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c index 6be1fe6b5f9..b7b2d3483fd 100644 --- a/drivers/mfd/ab5500-debugfs.c +++ b/drivers/mfd/ab5500-debugfs.c @@ -4,6 +4,7 @@ * Debugfs support for the AB5500 MFD driver */ +#include <linux/module.h> #include <linux/debugfs.h> #include <linux/seq_file.h> #include <linux/mfd/ab5500/ab5500.h> diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 1e9173804ed..d3d572b2317 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -620,6 +620,7 @@ static struct resource __devinitdata ab8500_fg_resources[] = { static struct resource __devinitdata ab8500_chargalg_resources[] = {}; +#ifdef CONFIG_DEBUG_FS static struct resource __devinitdata ab8500_debug_resources[] = { { .name = "IRQ_FIRST", @@ -634,6 +635,7 @@ static struct resource __devinitdata ab8500_debug_resources[] = { .flags = IORESOURCE_IRQ, }, }; +#endif static struct resource __devinitdata ab8500_usb_resources[] = { { diff --git a/drivers/mfd/adp5520.c b/drivers/mfd/adp5520.c index f1d88483112..8d816cce832 100644 --- a/drivers/mfd/adp5520.c +++ b/drivers/mfd/adp5520.c @@ -109,7 +109,7 @@ int adp5520_set_bits(struct device *dev, int reg, uint8_t bit_mask) ret = __adp5520_read(chip->client, reg, ®_val); - if (!ret && ((reg_val & bit_mask) == 0)) { + if (!ret && ((reg_val & bit_mask) != bit_mask)) { reg_val |= bit_mask; ret = __adp5520_write(chip->client, reg, reg_val); } diff --git a/drivers/mfd/da903x.c b/drivers/mfd/da903x.c index 1b79c37fd59..1924b857a0f 100644 --- a/drivers/mfd/da903x.c +++ b/drivers/mfd/da903x.c @@ -182,7 +182,7 @@ int da903x_set_bits(struct device *dev, int reg, uint8_t bit_mask) if (ret) goto out; - if ((reg_val & bit_mask) == 0) { + if ((reg_val & bit_mask) != bit_mask) { reg_val |= bit_mask; ret = __da903x_write(chip->client, reg, reg_val); } @@ -549,6 +549,7 @@ static int __devexit da903x_remove(struct i2c_client *client) struct da903x_chip *chip = i2c_get_clientdata(client); da903x_remove_subdevs(chip); + free_irq(client->irq, chip); kfree(chip); return 0; } diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 1e9ee533eac..ef39528088f 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -16,6 +16,7 @@ */ #include <linux/err.h> +#include <linux/io.h> #include <linux/irq.h> #include <linux/interrupt.h> #include <linux/kernel.h> diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index bba26d96c24..a5ddf31b60c 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -197,7 +197,7 @@ int tps6586x_set_bits(struct device *dev, int reg, uint8_t bit_mask) if (ret) goto out; - if ((reg_val & bit_mask) == 0) { + if ((reg_val & bit_mask) != bit_mask) { reg_val |= bit_mask; ret = __tps6586x_write(to_i2c_client(dev), reg, reg_val); } diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 6f5b8cf2f65..c1da84bc157 100644 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -120,7 +120,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) goto out; } - data &= mask; + data &= ~mask; err = tps65910_i2c_write(tps65910, reg, 1, &data); if (err) dev_err(tps65910->dev, "write to reg %x failed\n", reg); diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index bfbd66021af..61e70cfaa77 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -363,13 +363,13 @@ int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* * [MSG1]: fill the register address data @@ -420,13 +420,13 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); return -EPERM; } - sid = twl_map[mod_no].sid; - twl = &twl_modules[sid]; - if (unlikely(!inuse)) { - pr_err("%s: client %d is not initialized\n", DRIVER_NAME, sid); + pr_err("%s: not initialized\n", DRIVER_NAME); return -EPERM; } + sid = twl_map[mod_no].sid; + twl = &twl_modules[sid]; + mutex_lock(&twl->xfer_lock); /* [MSG1] fill the register address data */ msg = &twl->xfer_msg[0]; diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index f062c8cc6c3..29f11e0765f 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -432,6 +432,7 @@ struct sih_agent { u32 edge_change; struct mutex irq_lock; + char *irq_name; }; /*----------------------------------------------------------------------*/ @@ -589,7 +590,7 @@ static inline int sih_read_isr(const struct sih *sih) * Generic handler for SIH interrupts ... we "know" this is called * in task context, with IRQs enabled. */ -static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) +static irqreturn_t handle_twl4030_sih(int irq, void *data) { struct sih_agent *agent = irq_get_handler_data(irq); const struct sih *sih = agent->sih; @@ -602,7 +603,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) pr_err("twl4030: %s SIH, read ISR error %d\n", sih->name, isr); /* REVISIT: recover; eventually mask it all, etc */ - return; + return IRQ_HANDLED; } while (isr) { @@ -616,6 +617,7 @@ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) pr_err("twl4030: %s SIH, invalid ISR bit %d\n", sih->name, irq); } + return IRQ_HANDLED; } static unsigned twl4030_irq_next; @@ -668,18 +670,19 @@ int twl4030_sih_setup(int module) activate_irq(irq); } - status = irq_base; twl4030_irq_next += i; /* replace generic PIH handler (handle_simple_irq) */ irq = sih_mod + twl4030_irq_base; irq_set_handler_data(irq, agent); - irq_set_chained_handler(irq, handle_twl4030_sih); + agent->irq_name = kasprintf(GFP_KERNEL, "twl4030_%s", sih->name); + status = request_threaded_irq(irq, NULL, handle_twl4030_sih, 0, + agent->irq_name ?: sih->name, NULL); pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, irq, irq_base, twl4030_irq_next - 1); - return status; + return status < 0 ? status : irq_base; } /* FIXME need a call to reverse twl4030_sih_setup() ... */ @@ -733,8 +736,9 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) } /* install an irq handler to demultiplex the TWL4030 interrupt */ - status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih, 0, - "TWL4030-PIH", NULL); + status = request_threaded_irq(irq_num, NULL, handle_twl4030_pih, + IRQF_ONESHOT, + "TWL4030-PIH", NULL); if (status < 0) { pr_err("twl4030: could not claim irq%d: %d\n", irq_num, status); goto fail_rqirq; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 5d6ba132837..61894fced8e 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -239,6 +239,7 @@ static int wm8994_suspend(struct device *dev) switch (wm8994->type) { case WM8958: + case WM1811: ret = wm8994_reg_read(wm8994, WM8958_MIC_DETECT_1); if (ret < 0) { dev_err(dev, "Failed to read power status: %d\n", ret); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index d593878d66d..5664696f2d3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -472,7 +472,7 @@ config BMP085 module will be called bmp085. config PCH_PHUB - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB" + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" depends on PCI help This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of @@ -480,12 +480,13 @@ config PCH_PHUB processor. The Topcliff has MAC address and Option ROM data in SROM. This driver can access MAC address and Option ROM data in SROM. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor's IOH, + ML7213/ML7223/ML7831. + ML7213 which is for IVI(In-Vehicle Infotainment) use. + ML7223 IOH is for MP(Media Phone) use. + ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. To compile this driver as a module, choose M here: the module will be called pch_phub. diff --git a/drivers/misc/ad525x_dpot.h b/drivers/misc/ad525x_dpot.h index a662f5987b6..82b2cb77ae1 100644 --- a/drivers/misc/ad525x_dpot.h +++ b/drivers/misc/ad525x_dpot.h @@ -100,7 +100,7 @@ enum dpot_devid { AD5293_ID = DPOT_CONF(F_RDACS_RW | F_SPI_16BIT, BRDAC0, 10, 27), AD7376_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, BRDAC0, 7, 28), - AD8400_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_8BIT, + AD8400_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT, BRDAC0, 8, 29), AD8402_ID = DPOT_CONF(F_RDACS_WONLY | F_AD_APPDATA | F_SPI_16BIT, BRDAC0 | BRDAC1, 8, 30), diff --git a/drivers/misc/carma/carma-fpga-program.c b/drivers/misc/carma/carma-fpga-program.c index 7ce6065dc20..eb5cd28bc6d 100644 --- a/drivers/misc/carma/carma-fpga-program.c +++ b/drivers/misc/carma/carma-fpga-program.c @@ -945,8 +945,7 @@ static int fpga_of_remove(struct platform_device *op) /* CTL-CPLD Version Register */ #define CTL_CPLD_VERSION 0x2000 -static int fpga_of_probe(struct platform_device *op, - const struct of_device_id *match) +static int fpga_of_probe(struct platform_device *op) { struct device_node *of_node = op->dev.of_node; struct device *this_device; @@ -1107,7 +1106,7 @@ static struct of_device_id fpga_of_match[] = { {}, }; -static struct of_platform_driver fpga_of_driver = { +static struct platform_driver fpga_of_driver = { .probe = fpga_of_probe, .remove = fpga_of_remove, .driver = { @@ -1124,12 +1123,12 @@ static struct of_platform_driver fpga_of_driver = { static int __init fpga_init(void) { led_trigger_register_simple("fpga", &ledtrig_fpga); - return of_register_platform_driver(&fpga_of_driver); + return platform_driver_register(&fpga_of_driver); } static void __exit fpga_exit(void) { - of_unregister_platform_driver(&fpga_of_driver); + platform_driver_unregister(&fpga_of_driver); led_trigger_unregister_simple(ledtrig_fpga); } diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 3965821fef1..14e974b2a78 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c @@ -1249,8 +1249,7 @@ static bool dma_filter(struct dma_chan *chan, void *data) return true; } -static int data_of_probe(struct platform_device *op, - const struct of_device_id *match) +static int data_of_probe(struct platform_device *op) { struct device_node *of_node = op->dev.of_node; struct device *this_device; @@ -1401,7 +1400,7 @@ static struct of_device_id data_of_match[] = { {}, }; -static struct of_platform_driver data_of_driver = { +static struct platform_driver data_of_driver = { .probe = data_of_probe, .remove = data_of_remove, .driver = { @@ -1417,12 +1416,12 @@ static struct of_platform_driver data_of_driver = { static int __init data_init(void) { - return of_register_platform_driver(&data_of_driver); + return platform_driver_register(&data_of_driver); } static void __exit data_exit(void) { - of_unregister_platform_driver(&data_of_driver); + platform_driver_unregister(&data_of_driver); } MODULE_AUTHOR("Ira W. Snyder <iws@ovro.caltech.edu>"); diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 26cf12ca7f5..701edf65897 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig @@ -85,7 +85,7 @@ config EEPROM_93XX46 config EEPROM_DIGSY_MTC_CFG bool "DigsyMTC display configuration EEPROMs device" - depends on PPC_MPC5200_GPIO && GPIOLIB && SPI_GPIO + depends on GPIO_MPC5200 && SPI_GPIO help This option enables access to display configuration EEPROMs on digsy_mtc board. You have to additionally select Microwire diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c index dee33addcae..10fc4785dba 100644 --- a/drivers/misc/pch_phub.c +++ b/drivers/misc/pch_phub.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,10 +41,10 @@ #define PCH_PHUB_ROM_START_ADDR_EG20T 0x80 /* ROM data area start address offset (Intel EG20T PCH)*/ #define PCH_PHUB_ROM_START_ADDR_ML7213 0x400 /* ROM data area start address - offset(OKI SEMICONDUCTOR ML7213) + offset(LAPIS Semicon ML7213) */ #define PCH_PHUB_ROM_START_ADDR_ML7223 0x400 /* ROM data area start address - offset(OKI SEMICONDUCTOR ML7223) + offset(LAPIS Semicon ML7223) */ /* MAX number of INT_REDUCE_CONTROL registers */ @@ -73,6 +73,9 @@ #define PCI_DEVICE_ID_ROHM_ML7223_mPHUB 0x8012 /* for Bus-m */ #define PCI_DEVICE_ID_ROHM_ML7223_nPHUB 0x8002 /* for Bus-n */ +/* Macros for ML7831 */ +#define PCI_DEVICE_ID_ROHM_ML7831_PHUB 0x8801 + /* SROM ACCESS Macro */ #define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) @@ -115,6 +118,7 @@ * @pch_mac_start_address: MAC address area start address * @pch_opt_rom_start_address: Option ROM start address * @ioh_type: Save IOH type + * @pdev: pointer to pci device struct */ struct pch_phub_reg { u32 phub_id_reg; @@ -136,6 +140,7 @@ struct pch_phub_reg { u32 pch_mac_start_address; u32 pch_opt_rom_start_address; int ioh_type; + struct pci_dev *pdev; }; /* SROM SPEC for MAC address assignment offset */ @@ -471,7 +476,7 @@ static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) int retval; int i; - if (chip->ioh_type == 1) /* EG20T */ + if ((chip->ioh_type == 1) || (chip->ioh_type == 5)) /* EG20T or ML7831*/ retval = pch_phub_gbe_serial_rom_conf(chip); else /* ML7223 */ retval = pch_phub_gbe_serial_rom_conf_mp(chip); @@ -498,6 +503,7 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, unsigned int orom_size; int ret; int err; + ssize_t rom_size; struct pch_phub_reg *chip = dev_get_drvdata(container_of(kobj, struct device, kobj)); @@ -509,6 +515,10 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, } /* Get Rom signature */ + chip->pch_phub_extrom_base_address = pci_map_rom(chip->pdev, &rom_size); + if (!chip->pch_phub_extrom_base_address) + goto exrom_map_err; + pch_phub_read_serial_rom(chip, chip->pch_opt_rom_start_address, (unsigned char *)&rom_signature); rom_signature &= 0xff; @@ -539,10 +549,13 @@ static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, goto return_err; } return_ok: + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); mutex_unlock(&pch_phub_mutex); return addr_offset; return_err: + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); +exrom_map_err: mutex_unlock(&pch_phub_mutex); return_err_nomutex: return err; @@ -555,6 +568,7 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, int err; unsigned int addr_offset; int ret; + ssize_t rom_size; struct pch_phub_reg *chip = dev_get_drvdata(container_of(kobj, struct device, kobj)); @@ -571,6 +585,12 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, goto return_ok; } + chip->pch_phub_extrom_base_address = pci_map_rom(chip->pdev, &rom_size); + if (!chip->pch_phub_extrom_base_address) { + err = -ENOMEM; + goto exrom_map_err; + } + for (addr_offset = 0; addr_offset < count; addr_offset++) { if (PCH_PHUB_OROM_SIZE < off + addr_offset) goto return_ok; @@ -585,10 +605,14 @@ static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, } return_ok: + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); mutex_unlock(&pch_phub_mutex); return addr_offset; return_err: + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); + +exrom_map_err: mutex_unlock(&pch_phub_mutex); return err; } @@ -598,8 +622,14 @@ static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, { u8 mac[8]; struct pch_phub_reg *chip = dev_get_drvdata(dev); + ssize_t rom_size; + + chip->pch_phub_extrom_base_address = pci_map_rom(chip->pdev, &rom_size); + if (!chip->pch_phub_extrom_base_address) + return -ENOMEM; pch_phub_read_gbe_mac_addr(chip, mac); + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); return sprintf(buf, "%pM\n", mac); } @@ -608,6 +638,7 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u8 mac[6]; + ssize_t rom_size; struct pch_phub_reg *chip = dev_get_drvdata(dev); if (count != 18) @@ -617,7 +648,12 @@ static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], (u32 *)&mac[4], (u32 *)&mac[5]); + chip->pch_phub_extrom_base_address = pci_map_rom(chip->pdev, &rom_size); + if (!chip->pch_phub_extrom_base_address) + return -ENOMEM; + pch_phub_write_gbe_mac_addr(chip, mac); + pci_unmap_rom(chip->pdev, chip->pch_phub_extrom_base_address); return count; } @@ -640,7 +676,6 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, int retval; int ret; - ssize_t rom_size; struct pch_phub_reg *chip; chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); @@ -677,19 +712,7 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, "in pch_phub_base_address variable is %p\n", __func__, chip->pch_phub_base_address); - if (id->driver_data != 3) { - chip->pch_phub_extrom_base_address =\ - pci_map_rom(pdev, &rom_size); - if (chip->pch_phub_extrom_base_address == 0) { - dev_err(&pdev->dev, "%s: pci_map_rom FAILED", __func__); - ret = -ENOMEM; - goto err_pci_map; - } - dev_dbg(&pdev->dev, "%s : " - "pci_map_rom SUCCESS and value in " - "pch_phub_extrom_base_address variable is %p\n", - __func__, chip->pch_phub_extrom_base_address); - } + chip->pdev = pdev; /* Save pci device struct */ if (id->driver_data == 1) { /* EG20T PCH */ const char *board_name; @@ -763,6 +786,22 @@ static int __devinit pch_phub_probe(struct pci_dev *pdev, chip->pch_opt_rom_start_address =\ PCH_PHUB_ROM_START_ADDR_ML7223; chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_ML7223; + } else if (id->driver_data == 5) { /* ML7831 */ + retval = sysfs_create_file(&pdev->dev.kobj, + &dev_attr_pch_mac.attr); + if (retval) + goto err_sysfs_create; + + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); + if (retval) + goto exit_bin_attr; + + /* set the prefech value */ + iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); + /* set the interrupt delay value */ + iowrite32(0x25, chip->pch_phub_base_address + 0x44); + chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T; + chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T; } chip->ioh_type = id->driver_data; @@ -773,8 +812,6 @@ exit_bin_attr: sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); err_sysfs_create: - pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); -err_pci_map: pci_iounmap(pdev, chip->pch_phub_base_address); err_pci_iomap: pci_release_regions(pdev); @@ -792,7 +829,6 @@ static void __devexit pch_phub_remove(struct pci_dev *pdev) sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); - pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); pci_iounmap(pdev, chip->pch_phub_base_address); pci_release_regions(pdev); pci_disable_device(pdev); @@ -847,6 +883,7 @@ static struct pci_device_id pch_phub_pcidev_id[] = { { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7213_PHUB), 2, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_mPHUB), 3, }, { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7223_nPHUB), 4, }, + { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ROHM_ML7831_PHUB), 5, }, { } }; MODULE_DEVICE_TABLE(pci, pch_phub_pcidev_id); @@ -873,5 +910,5 @@ static void __exit pch_phub_pci_exit(void) module_init(pch_phub_pci_init); module_exit(pch_phub_pci_exit); -MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR IOH(ML7213/ML7223) PHUB"); +MODULE_DESCRIPTION("Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7223) PHUB"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c index cfbddbef11d..43d073bc1d9 100644 --- a/drivers/misc/spear13xx_pcie_gadget.c +++ b/drivers/misc/spear13xx_pcie_gadget.c @@ -903,6 +903,6 @@ static void __exit spear_pcie_gadget_exit(void) } module_exit(spear_pcie_gadget_exit); -MODULE_ALIAS("pcie-gadget-spear"); +MODULE_ALIAS("platform:pcie-gadget-spear"); MODULE_AUTHOR("Pratyush Anand"); MODULE_LICENSE("GPL"); diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a1cb21f9530..1e0e27cbe98 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1606,6 +1606,14 @@ static const struct mmc_fixup blk_fixups[] = MMC_QUIRK_BLK_NO_CMD23), MMC_FIXUP("MMC32G", 0x11, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_BLK_NO_CMD23), + + /* + * Some Micron MMC cards needs longer data read timeout than + * indicated in CSD. + */ + MMC_FIXUP(CID_NAME_ANY, 0x13, 0x200, add_quirk_mmc, + MMC_QUIRK_LONG_READ_TIME), + END_FIXUP }; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 5278ffb20e7..950b97d7412 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -529,6 +529,18 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card) data->timeout_clks = 0; } } + + /* + * Some cards require longer data read timeout than indicated in CSD. + * Address this by setting the read timeout to a "reasonably high" + * value. For the cards tested, 300ms has proven enough. If necessary, + * this value can be increased if other problematic cards require this. + */ + if (mmc_card_long_read_time(card) && data->flags & MMC_DATA_READ) { + data->timeout_ns = 300000000; + data->timeout_clks = 0; + } + /* * Some cards need very high timeouts if driven in SPI mode. * The worst observed timeout was 900ms after writing a @@ -1213,6 +1225,46 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) mmc_host_clk_release(host); } +static void mmc_poweroff_notify(struct mmc_host *host) +{ + struct mmc_card *card; + unsigned int timeout; + unsigned int notify_type = EXT_CSD_NO_POWER_NOTIFICATION; + int err = 0; + + card = host->card; + + /* + * Send power notify command only if card + * is mmc and notify state is powered ON + */ + if (card && mmc_card_mmc(card) && + (card->poweroff_notify_state == MMC_POWERED_ON)) { + + if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) { + notify_type = EXT_CSD_POWER_OFF_SHORT; + timeout = card->ext_csd.generic_cmd6_time; + card->poweroff_notify_state = MMC_POWEROFF_SHORT; + } else { + notify_type = EXT_CSD_POWER_OFF_LONG; + timeout = card->ext_csd.power_off_longtime; + card->poweroff_notify_state = MMC_POWEROFF_LONG; + } + + err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, + EXT_CSD_POWER_OFF_NOTIFICATION, + notify_type, timeout); + + if (err && err != -EBADMSG) + pr_err("Device failed to respond within %d poweroff " + "time. Forcefully powering down the device\n", + timeout); + + /* Set the card state to no notification after the poweroff */ + card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; + } +} + /* * Apply power to the MMC stack. This is a two-stage process. * First, we enable power to the card without the clock running. @@ -1269,42 +1321,12 @@ static void mmc_power_up(struct mmc_host *host) void mmc_power_off(struct mmc_host *host) { - struct mmc_card *card; - unsigned int notify_type; - unsigned int timeout; - int err; - mmc_host_clk_hold(host); - card = host->card; host->ios.clock = 0; host->ios.vdd = 0; - if (card && mmc_card_mmc(card) && - (card->poweroff_notify_state == MMC_POWERED_ON)) { - - if (host->power_notify_type == MMC_HOST_PW_NOTIFY_SHORT) { - notify_type = EXT_CSD_POWER_OFF_SHORT; - timeout = card->ext_csd.generic_cmd6_time; - card->poweroff_notify_state = MMC_POWEROFF_SHORT; - } else { - notify_type = EXT_CSD_POWER_OFF_LONG; - timeout = card->ext_csd.power_off_longtime; - card->poweroff_notify_state = MMC_POWEROFF_LONG; - } - - err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, - EXT_CSD_POWER_OFF_NOTIFICATION, - notify_type, timeout); - - if (err && err != -EBADMSG) - pr_err("Device failed to respond within %d poweroff " - "time. Forcefully powering down the device\n", - timeout); - - /* Set the card state to no notification after the poweroff */ - card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION; - } + mmc_poweroff_notify(host); /* * Reset ocr mask to be the highest possible voltage supported for @@ -2196,7 +2218,7 @@ int mmc_card_sleep(struct mmc_host *host) mmc_bus_get(host); - if (host->bus_ops && !host->bus_dead && host->bus_ops->awake) + if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep) err = host->bus_ops->sleep(host); mmc_bus_put(host); @@ -2302,8 +2324,17 @@ int mmc_suspend_host(struct mmc_host *host) * pre-claim the host. */ if (mmc_try_claim_host(host)) { - if (host->bus_ops->suspend) + if (host->bus_ops->suspend) { + /* + * For eMMC 4.5 device send notify command + * before sleep, because in sleep state eMMC 4.5 + * devices respond to only RESET and AWAKE cmd + */ + mmc_poweroff_notify(host); err = host->bus_ops->suspend(host); + } + mmc_do_release_host(host); + if (err == -ENOSYS || !host->bus_ops->resume) { /* * We simply "remove" the card in this case. @@ -2318,7 +2349,6 @@ int mmc_suspend_host(struct mmc_host *host) host->pm_flags = 0; err = 0; } - mmc_do_release_host(host); } else { err = -EBUSY; } diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index e8a5eb38748..d31c78b72b0 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -302,17 +302,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev) host->max_blk_size = 512; host->max_blk_count = PAGE_CACHE_SIZE / 512; - /* - * Enable runtime power management by default. This flag was added due - * to runtime power management causing disruption for some users, but - * the power on/off code has been improved since then. - * - * We'll enable this flag by default as an experiment, and if no - * problems are reported, we will follow up later and remove the flag - * altogether. - */ - host->caps = MMC_CAP_POWER_OFF_CARD; - return host; free: diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index dbf421a6279..d240427c124 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -876,17 +876,21 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, * set the notification byte in the ext_csd register of device */ if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) && - (card->poweroff_notify_state == MMC_NO_POWER_NOTIFICATION)) { + (card->ext_csd.rev >= 6)) { err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_POWER_OFF_NOTIFICATION, EXT_CSD_POWER_ON, card->ext_csd.generic_cmd6_time); if (err && err != -EBADMSG) goto free_card; - } - if (!err) - card->poweroff_notify_state = MMC_POWERED_ON; + /* + * The err can be -EBADMSG or 0, + * so check for success and update the flag + */ + if (!err) + card->poweroff_notify_state = MMC_POWERED_ON; + } /* * Activate high speed (if supported) diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 50b5f9926f6..0726e59fd41 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -675,7 +675,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data, unsigned int status) { /* First check for errors */ - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) { + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN)) { u32 remain, success; /* Terminate the DMA transfer */ @@ -754,8 +755,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, } if (!cmd->data || cmd->error) { - if (host->data) + if (host->data) { + /* Terminate the DMA transfer */ + if (dma_inprogress(host)) + mmci_dma_data_error(host); mmci_stop_data(host); + } mmci_request_end(host, cmd->mrq); } else if (!(cmd->data->flags & MMC_DATA_READ)) { mmci_start_data(host, cmd->data); @@ -955,8 +960,9 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); data = host->data; - if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN| - MCI_RXOVERRUN|MCI_DATAEND|MCI_DATABLOCKEND) && data) + if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR| + MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND| + MCI_DATABLOCKEND) && data) mmci_data_irq(host, data, status); cmd = host->cmd; diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c index 325ea61e12d..8e0fbe99404 100644 --- a/drivers/mmc/host/mxcmmc.c +++ b/drivers/mmc/host/mxcmmc.c @@ -732,6 +732,7 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) "failed to config DMA channel. Falling back to PIO\n"); dma_release_channel(host->dma); host->do_dma = 0; + host->dma = NULL; } } diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 101cd31c822..d5fe43d53c5 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -1010,6 +1010,7 @@ static void omap_hsmmc_dma_cleanup(struct omap_hsmmc_host *host, int errno) host->data->sg_len, omap_hsmmc_get_dma_dir(host, host->data)); omap_free_dma(dma_ch); + host->data->host_cookie = 0; } host->data = NULL; } @@ -1575,8 +1576,10 @@ static void omap_hsmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct mmc_data *data = mrq->data; if (host->use_dma) { - dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, - omap_hsmmc_get_dma_dir(host, data)); + if (data->host_cookie) + dma_unmap_sg(mmc_dev(host->mmc), data->sg, + data->sg_len, + omap_hsmmc_get_dma_dir(host, data)); data->host_cookie = 0; } } diff --git a/drivers/mmc/host/sdhci-cns3xxx.c b/drivers/mmc/host/sdhci-cns3xxx.c index 4b920b7621c..b4257e70061 100644 --- a/drivers/mmc/host/sdhci-cns3xxx.c +++ b/drivers/mmc/host/sdhci-cns3xxx.c @@ -15,6 +15,7 @@ #include <linux/delay.h> #include <linux/device.h> #include <linux/mmc/host.h> +#include <linux/module.h> #include <mach/cns3xxx.h> #include "sdhci-pltfm.h" @@ -108,13 +109,10 @@ static struct platform_driver sdhci_cns3xxx_driver = { .driver = { .name = "sdhci-cns3xxx", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_cns3xxx_probe, .remove = __devexit_p(sdhci_cns3xxx_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_cns3xxx_init(void) diff --git a/drivers/mmc/host/sdhci-dove.c b/drivers/mmc/host/sdhci-dove.c index f2d29dca442..a81312c91f7 100644 --- a/drivers/mmc/host/sdhci-dove.c +++ b/drivers/mmc/host/sdhci-dove.c @@ -82,13 +82,10 @@ static struct platform_driver sdhci_dove_driver = { .driver = { .name = "sdhci-dove", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_dove_probe, .remove = __devexit_p(sdhci_dove_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_dove_init(void) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ae57769ba50..38ebc4ea259 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,6 +32,7 @@ /* VENDOR SPEC register */ #define SDHCI_VENDOR_SPEC 0xC0 #define SDHCI_VENDOR_SPEC_SDIO_QUIRK 0x00000002 +#define SDHCI_WTMK_LVL 0x44 #define SDHCI_MIX_CTRL 0x48 /* @@ -476,6 +477,13 @@ static int __devinit sdhci_esdhc_imx_probe(struct platform_device *pdev) if (is_imx53_esdhc(imx_data)) imx_data->flags |= ESDHC_FLAG_MULTIBLK_NO_INT; + /* + * The imx6q ROM code will change the default watermark level setting + * to something insane. Change it back here. + */ + if (is_imx6q_usdhc(imx_data)) + writel(0x08100810, host->ioaddr + SDHCI_WTMK_LVL); + boarddata = &imx_data->boarddata; if (sdhci_esdhc_imx_probe_dt(pdev, boarddata) < 0) { if (!host->mmc->parent->platform_data) { @@ -591,14 +599,11 @@ static struct platform_driver sdhci_esdhc_imx_driver = { .name = "sdhci-esdhc-imx", .owner = THIS_MODULE, .of_match_table = imx_esdhc_dt_ids, + .pm = SDHCI_PLTFM_PMOPS, }, .id_table = imx_esdhc_devtype, .probe = sdhci_esdhc_imx_probe, .remove = __devexit_p(sdhci_esdhc_imx_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_esdhc_imx_init(void) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 59e9d003e58..01e5f627e0f 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -125,13 +125,10 @@ static struct platform_driver sdhci_esdhc_driver = { .name = "sdhci-esdhc", .owner = THIS_MODULE, .of_match_table = sdhci_esdhc_of_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_esdhc_probe, .remove = __devexit_p(sdhci_esdhc_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_esdhc_init(void) diff --git a/drivers/mmc/host/sdhci-of-hlwd.c b/drivers/mmc/host/sdhci-of-hlwd.c index 9b0d794a4f6..3619adc7d9f 100644 --- a/drivers/mmc/host/sdhci-of-hlwd.c +++ b/drivers/mmc/host/sdhci-of-hlwd.c @@ -87,13 +87,10 @@ static struct platform_driver sdhci_hlwd_driver = { .name = "sdhci-hlwd", .owner = THIS_MODULE, .of_match_table = sdhci_hlwd_of_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_hlwd_probe, .remove = __devexit_p(sdhci_hlwd_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_hlwd_init(void) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index d833d9c2f7e..6878a94626b 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -54,8 +54,7 @@ struct sdhci_pci_fixes { int (*probe_slot) (struct sdhci_pci_slot *); void (*remove_slot) (struct sdhci_pci_slot *, int); - int (*suspend) (struct sdhci_pci_chip *, - pm_message_t); + int (*suspend) (struct sdhci_pci_chip *); int (*resume) (struct sdhci_pci_chip *); }; @@ -549,7 +548,7 @@ static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead) jmicron_enable_mmc(slot->host, 0); } -static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state) +static int jmicron_suspend(struct sdhci_pci_chip *chip) { int i; @@ -993,8 +992,9 @@ static struct sdhci_ops sdhci_pci_ops = { #ifdef CONFIG_PM -static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int sdhci_pci_suspend(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; mmc_pm_flag_t slot_pm_flags; @@ -1010,7 +1010,7 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) if (!slot) continue; - ret = sdhci_suspend_host(slot->host, state); + ret = sdhci_suspend_host(slot->host); if (ret) { for (i--; i >= 0; i--) @@ -1026,7 +1026,7 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) } if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip, state); + ret = chip->fixes->suspend(chip); if (ret) { for (i = chip->num_slots - 1; i >= 0; i--) sdhci_resume_host(chip->slots[i]->host); @@ -1042,16 +1042,17 @@ static int sdhci_pci_suspend(struct pci_dev *pdev, pm_message_t state) } pci_set_power_state(pdev, PCI_D3hot); } else { - pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + pci_enable_wake(pdev, PCI_D3hot, 0); pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + pci_set_power_state(pdev, PCI_D3hot); } return 0; } -static int sdhci_pci_resume(struct pci_dev *pdev) +static int sdhci_pci_resume(struct device *dev) { + struct pci_dev *pdev = to_pci_dev(dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; int i, ret; @@ -1099,7 +1100,6 @@ static int sdhci_pci_runtime_suspend(struct device *dev) struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); struct sdhci_pci_chip *chip; struct sdhci_pci_slot *slot; - pm_message_t state = { .event = PM_EVENT_SUSPEND }; int i, ret; chip = pci_get_drvdata(pdev); @@ -1121,7 +1121,7 @@ static int sdhci_pci_runtime_suspend(struct device *dev) } if (chip->fixes && chip->fixes->suspend) { - ret = chip->fixes->suspend(chip, state); + ret = chip->fixes->suspend(chip); if (ret) { for (i = chip->num_slots - 1; i >= 0; i--) sdhci_runtime_resume_host(chip->slots[i]->host); @@ -1176,6 +1176,8 @@ static int sdhci_pci_runtime_idle(struct device *dev) #endif static const struct dev_pm_ops sdhci_pci_pm_ops = { + .suspend = sdhci_pci_suspend, + .resume = sdhci_pci_resume, .runtime_suspend = sdhci_pci_runtime_suspend, .runtime_resume = sdhci_pci_runtime_resume, .runtime_idle = sdhci_pci_runtime_idle, @@ -1428,8 +1430,6 @@ static struct pci_driver sdhci_driver = { .id_table = pci_ids, .probe = sdhci_pci_probe, .remove = __devexit_p(sdhci_pci_remove), - .suspend = sdhci_pci_suspend, - .resume = sdhci_pci_resume, .driver = { .pm = &sdhci_pci_pm_ops }, diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c index a9e12ea0558..03970bcb349 100644 --- a/drivers/mmc/host/sdhci-pltfm.c +++ b/drivers/mmc/host/sdhci-pltfm.c @@ -194,21 +194,25 @@ int sdhci_pltfm_unregister(struct platform_device *pdev) EXPORT_SYMBOL_GPL(sdhci_pltfm_unregister); #ifdef CONFIG_PM -int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state) +static int sdhci_pltfm_suspend(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); - return sdhci_suspend_host(host, state); + return sdhci_suspend_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_suspend); -int sdhci_pltfm_resume(struct platform_device *dev) +static int sdhci_pltfm_resume(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_resume_host(host); } -EXPORT_SYMBOL_GPL(sdhci_pltfm_resume); + +const struct dev_pm_ops sdhci_pltfm_pmops = { + .suspend = sdhci_pltfm_suspend, + .resume = sdhci_pltfm_resume, +}; +EXPORT_SYMBOL_GPL(sdhci_pltfm_pmops); #endif /* CONFIG_PM */ static int __init sdhci_pltfm_drv_init(void) diff --git a/drivers/mmc/host/sdhci-pltfm.h b/drivers/mmc/host/sdhci-pltfm.h index 3a9fc3f4084..37e0e184a0b 100644 --- a/drivers/mmc/host/sdhci-pltfm.h +++ b/drivers/mmc/host/sdhci-pltfm.h @@ -99,8 +99,10 @@ extern int sdhci_pltfm_register(struct platform_device *pdev, extern int sdhci_pltfm_unregister(struct platform_device *pdev); #ifdef CONFIG_PM -extern int sdhci_pltfm_suspend(struct platform_device *dev, pm_message_t state); -extern int sdhci_pltfm_resume(struct platform_device *dev); +extern const struct dev_pm_ops sdhci_pltfm_pmops; +#define SDHCI_PLTFM_PMOPS (&sdhci_pltfm_pmops) +#else +#define SDHCI_PLTFM_PMOPS NULL #endif #endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */ diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c index d4bf6d30c7b..7a039c3cb1f 100644 --- a/drivers/mmc/host/sdhci-pxav2.c +++ b/drivers/mmc/host/sdhci-pxav2.c @@ -218,13 +218,10 @@ static struct platform_driver sdhci_pxav2_driver = { .driver = { .name = "sdhci-pxav2", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav2_probe, .remove = __devexit_p(sdhci_pxav2_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_pxav2_init(void) { diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c index cff4ad3e7a5..15673a7ee6a 100644 --- a/drivers/mmc/host/sdhci-pxav3.c +++ b/drivers/mmc/host/sdhci-pxav3.c @@ -264,13 +264,10 @@ static struct platform_driver sdhci_pxav3_driver = { .driver = { .name = "sdhci-pxav3", .owner = THIS_MODULE, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_pxav3_probe, .remove = __devexit_p(sdhci_pxav3_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_pxav3_init(void) { diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index 3d00e722efc..0d33ff0d67f 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c @@ -622,33 +622,38 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev) #ifdef CONFIG_PM -static int sdhci_s3c_suspend(struct platform_device *dev, pm_message_t pm) +static int sdhci_s3c_suspend(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); - return sdhci_suspend_host(host, pm); + return sdhci_suspend_host(host); } -static int sdhci_s3c_resume(struct platform_device *dev) +static int sdhci_s3c_resume(struct device *dev) { - struct sdhci_host *host = platform_get_drvdata(dev); + struct sdhci_host *host = dev_get_drvdata(dev); return sdhci_resume_host(host); } +static const struct dev_pm_ops sdhci_s3c_pmops = { + .suspend = sdhci_s3c_suspend, + .resume = sdhci_s3c_resume, +}; + +#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops) + #else -#define sdhci_s3c_suspend NULL -#define sdhci_s3c_resume NULL +#define SDHCI_S3C_PMOPS NULL #endif static struct platform_driver sdhci_s3c_driver = { .probe = sdhci_s3c_probe, .remove = __devexit_p(sdhci_s3c_remove), - .suspend = sdhci_s3c_suspend, - .resume = sdhci_s3c_resume, .driver = { .owner = THIS_MODULE, .name = "s3c-sdhci", + .pm = SDHCI_S3C_PMOPS, }, }; diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c index 89699e861fc..e2e18d3f949 100644 --- a/drivers/mmc/host/sdhci-tegra.c +++ b/drivers/mmc/host/sdhci-tegra.c @@ -318,13 +318,10 @@ static struct platform_driver sdhci_tegra_driver = { .name = "sdhci-tegra", .owner = THIS_MODULE, .of_match_table = sdhci_tegra_dt_match, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_tegra_probe, .remove = __devexit_p(sdhci_tegra_remove), -#ifdef CONFIG_PM - .suspend = sdhci_pltfm_suspend, - .resume = sdhci_pltfm_resume, -#endif }; static int __init sdhci_tegra_init(void) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 6d8eea32354..19ed580f2ca 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2327,7 +2327,7 @@ out: #ifdef CONFIG_PM -int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state) +int sdhci_suspend_host(struct sdhci_host *host) { int ret; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 0a5b65460d8..a04d4d0c6fd 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -374,7 +374,7 @@ extern int sdhci_add_host(struct sdhci_host *host); extern void sdhci_remove_host(struct sdhci_host *host, int dead); #ifdef CONFIG_PM -extern int sdhci_suspend_host(struct sdhci_host *host, pm_message_t state); +extern int sdhci_suspend_host(struct sdhci_host *host); extern int sdhci_resume_host(struct sdhci_host *host); extern void sdhci_enable_irq_wakeups(struct sdhci_host *host); #endif diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 369366c8e20..d5505f3fe2a 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -908,7 +908,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) if (host->power) { pm_runtime_put(&host->pd->dev); host->power = false; - if (p->down_pwr) + if (p->down_pwr && ios->power_mode == MMC_POWER_OFF) p->down_pwr(host->pd); } host->state = STATE_IDLE; diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index d85a60cda16..4208b395806 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -798,7 +798,7 @@ static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) /* start bus clock */ tmio_mmc_clk_start(host); } else if (ios->power_mode != MMC_POWER_UP) { - if (host->set_pwr) + if (host->set_pwr && ios->power_mode == MMC_POWER_OFF) host->set_pwr(host->pdev, 0); if ((pdata->flags & TMIO_MMC_HAS_COLD_CD) && pdata->power) { diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c index e8f6e65183d..2ec978bc32b 100644 --- a/drivers/mmc/host/vub300.c +++ b/drivers/mmc/host/vub300.c @@ -259,7 +259,7 @@ static int firmware_rom_wait_states = 0x04; static int firmware_rom_wait_states = 0x1C; #endif -module_param(firmware_rom_wait_states, bool, 0644); +module_param(firmware_rom_wait_states, int, 0644); MODULE_PARM_DESC(firmware_rom_wait_states, "ROM wait states byte=RRRIIEEE (Reserved Internal External)"); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 66b616ebe53..318a869286a 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -12,27 +12,17 @@ menuconfig MTD if MTD -config MTD_DEBUG - bool "Debugging" - help - This turns on low-level debugging for the entire MTD sub-system. - Normally, you should say 'N'. - -config MTD_DEBUG_VERBOSE - int "Debugging verbosity (0 = quiet, 3 = noisy)" - depends on MTD_DEBUG - default "0" - help - Determines the verbosity level of the MTD debugging messages. - config MTD_TESTS - tristate "MTD tests support" + tristate "MTD tests support (DANGEROUS)" 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. + WARNING: some of the tests will ERASE entire MTD device which they + test. Do not use these tests unless you really know what you do. + config MTD_REDBOOT_PARTS tristate "RedBoot partition table parsing" ---help--- @@ -137,7 +127,8 @@ config MTD_AFS_PARTS 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. config MTD_OF_PARTS - def_bool y + tristate "OpenFirmware partitioning information support" + default Y depends on OF help This provides a partition parsing function which derives diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 39664c4229f..9aaac3ac89f 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -5,8 +5,8 @@ # Core functionality. obj-$(CONFIG_MTD) += mtd.o mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o -mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o +obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c index 302372c08b5..89a02f6f65d 100644 --- a/drivers/mtd/afs.c +++ b/drivers/mtd/afs.c @@ -162,8 +162,8 @@ afs_read_iis(struct mtd_info *mtd, struct image_info_struct *iis, u_int ptr) } static int parse_afs_partitions(struct mtd_info *mtd, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_partition *parts; u_int mask, off, idx, sz; diff --git a/drivers/mtd/ar7part.c b/drivers/mtd/ar7part.c index 95949b97de6..f40ea454755 100644 --- a/drivers/mtd/ar7part.c +++ b/drivers/mtd/ar7part.c @@ -47,7 +47,7 @@ struct ar7_bin_rec { static int create_mtd_partitions(struct mtd_info *master, struct mtd_partition **pparts, - unsigned long origin) + struct mtd_part_parser_data *data) { struct ar7_bin_rec header; unsigned int offset; diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 23175edd563..8d70895a58d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -145,8 +145,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) if (((major << 8) | minor) < 0x3131) { /* CFI version 1.0 => don't trust bootloc */ - DEBUG(MTD_DEBUG_LEVEL1, - "%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", + pr_debug("%s: JEDEC Vendor ID is 0x%02X Device ID is 0x%02X\n", map->name, cfi->mfr, cfi->id); /* AFAICS all 29LV400 with a bottom boot block have a device ID @@ -166,8 +165,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) * the 8-bit device ID. */ (cfi->mfr == CFI_MFR_MACRONIX)) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: Macronix MX29LV400C with bottom boot block" + pr_debug("%s: Macronix MX29LV400C with bottom boot block" " detected\n", map->name); extp->TopBottom = 2; /* bottom boot */ } else @@ -178,8 +176,7 @@ static void fixup_amd_bootblock(struct mtd_info *mtd) extp->TopBottom = 2; /* bottom boot */ } - DEBUG(MTD_DEBUG_LEVEL1, - "%s: AMD CFI PRI V%c.%c has no boot block field;" + pr_debug("%s: AMD CFI PRI V%c.%c has no boot block field;" " deduced %s from Device ID\n", map->name, major, minor, extp->TopBottom == 2 ? "bottom" : "top"); } @@ -191,7 +188,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd) struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; if (cfi->cfiq->BufWriteTimeoutTyp) { - DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); + pr_debug("Using buffer write method\n" ); mtd->write = cfi_amdstd_write_buffers; } } @@ -443,8 +440,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) mtd->writesize = 1; mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n", - __func__, mtd->writebufsize); + pr_debug("MTD %s(): write buffer size %d\n", __func__, + mtd->writebufsize); mtd->reboot_notifier.notifier_call = cfi_amdstd_reboot; @@ -1163,7 +1160,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); /* @@ -1174,7 +1171,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, */ oldd = map_read(map, adr); if (map_word_equal(map, oldd, datum)) { - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP\n", + pr_debug("MTD %s(): NOP\n", __func__); goto op_done; } @@ -1400,7 +1397,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, datum = map_word_load(map, buf); - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", + pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1587,7 +1584,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); XIP_INVAL_CACHED_RANGE(map, adr, map->size); @@ -1675,7 +1672,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, return ret; } - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + pr_debug("MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); XIP_INVAL_CACHED_RANGE(map, adr, len); @@ -1801,8 +1798,7 @@ static int do_atmel_lock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_LOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1837,8 +1833,7 @@ static int do_atmel_unlock(struct map_info *map, struct flchip *chip, goto out_unlock; chip->state = FL_UNLOCKING; - DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): LOCK 0x%08lx len %d\n", - __func__, adr, len); + pr_debug("MTD %s(): LOCK 0x%08lx len %d\n", __func__, adr, len); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index 5e3cc80128a..89c6595454a 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -34,8 +34,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, /* Refuse the operation if the we cannot look behind the chip */ if (chip->start < 0x400000) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): chip->start: %lx wanted >= 0x400000\n", + pr_debug( "MTD %s(): chip->start: %lx wanted >= 0x400000\n", __func__, chip->start ); return -EIO; } diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c index ea832ea0e4a..c443f527a53 100644 --- a/drivers/mtd/chips/jedec_probe.c +++ b/drivers/mtd/chips/jedec_probe.c @@ -1914,11 +1914,10 @@ static void jedec_reset(u32 base, struct map_info *map, struct cfi_private *cfi) * (oh and incidentaly the jedec spec - 3.5.3.3) the reset * sequence is *supposed* to be 0xaa at 0x5555, 0x55 at * 0x2aaa, 0xF0 at 0x5555 this will not affect the AMD chips - * as they will ignore the writes and dont care what address + * as they will ignore the writes and don't care what address * the F0 is written to */ if (cfi->addr_unlock1) { - DEBUG( MTD_DEBUG_LEVEL3, - "reset unlock called %x %x \n", + pr_debug( "reset unlock called %x %x \n", cfi->addr_unlock1,cfi->addr_unlock2); cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -1941,7 +1940,7 @@ static int cfi_jedec_setup(struct map_info *map, struct cfi_private *cfi, int in uint8_t uaddr; if (!(jedec_table[index].devtypes & cfi->device_type)) { - DEBUG(MTD_DEBUG_LEVEL1, "Rejecting potential %s with incompatible %d-bit device type\n", + pr_debug("Rejecting potential %s with incompatible %d-bit device type\n", jedec_table[index].name, 4 * (1<<cfi->device_type)); return 0; } @@ -2021,7 +2020,7 @@ static inline int jedec_match( uint32_t base, * there aren't. */ if (finfo->dev_id > 0xff) { - DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n", + pr_debug("%s(): ID is not 8bit\n", __func__); goto match_done; } @@ -2045,12 +2044,10 @@ static inline int jedec_match( uint32_t base, } /* the part size must fit in the memory window */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", + pr_debug("MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", __func__, base, 1 << finfo->dev_size, base + (1 << finfo->dev_size) ); if ( base + cfi_interleave(cfi) * ( 1 << finfo->dev_size ) > map->size ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", __func__, finfo->mfr_id, finfo->dev_id, 1 << finfo->dev_size ); goto match_done; @@ -2061,13 +2058,12 @@ static inline int jedec_match( uint32_t base, uaddr = finfo->uaddr; - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr && ( unlock_addrs[uaddr].addr1 / cfi->device_type != cfi->addr_unlock1 || unlock_addrs[uaddr].addr2 / cfi->device_type != cfi->addr_unlock2 ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): 0x%.4x 0x%.4x did not match\n", + pr_debug("MTD %s(): 0x%.4x 0x%.4x did not match\n", __func__, unlock_addrs[uaddr].addr1, unlock_addrs[uaddr].addr2); @@ -2083,15 +2079,13 @@ static inline int jedec_match( uint32_t base, * FIXME - write a driver that takes all of the chip info as * module parameters, doesn't probe but forces a load. */ - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): check ID's disappear when not in ID mode\n", + pr_debug("MTD %s(): check ID's disappear when not in ID mode\n", __func__ ); jedec_reset( base, map, cfi ); mfr = jedec_read_mfr( map, base, cfi ); id = jedec_read_id( map, base, cfi ); if ( mfr == cfi->mfr && id == cfi->id ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" + pr_debug("MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" "You might need to manually specify JEDEC parameters.\n", __func__, cfi->mfr, cfi->id ); goto match_done; @@ -2104,7 +2098,7 @@ static inline int jedec_match( uint32_t base, * Put the device back in ID mode - only need to do this if we * were truly frobbing a real device. */ - DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); + pr_debug("MTD %s(): return to ID mode\n", __func__ ); if (cfi->addr_unlock1) { cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, cfi->device_type, NULL); @@ -2167,13 +2161,11 @@ static int jedec_probe_chip(struct map_info *map, __u32 base, cfi->mfr = jedec_read_mfr(map, base, cfi); cfi->id = jedec_read_id(map, base, cfi); - DEBUG(MTD_DEBUG_LEVEL3, - "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + pr_debug("Search for id:(%02x %02x) interleave(%d) type(%d)\n", cfi->mfr, cfi->id, cfi_interleave(cfi), cfi->device_type); for (i = 0; i < ARRAY_SIZE(jedec_table); i++) { if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { - DEBUG( MTD_DEBUG_LEVEL3, - "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", + pr_debug("MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", __func__, cfi->mfr, cfi->id, cfi->addr_unlock1, cfi->addr_unlock2 ); if (!cfi_jedec_setup(map, cfi, i)) diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c index 8cf667da240..ddf9ec6d916 100644 --- a/drivers/mtd/cmdlinepart.c +++ b/drivers/mtd/cmdlinepart.c @@ -189,10 +189,7 @@ static struct mtd_partition * newpart(char *s, extra_mem_size; parts = kzalloc(alloc_size, GFP_KERNEL); if (!parts) - { - printk(KERN_ERR ERRP "out of memory\n"); return NULL; - } extra_mem = (unsigned char *)(parts + *num_parts); } /* enter this partition (offset will be calculated later if it is zero at this point) */ @@ -317,8 +314,8 @@ static int mtdpart_setup_real(char *s) * the first one in the chain if a NULL mtd_id is passed in. */ static int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { unsigned long offset; int i; diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig index 35081ce77fb..283d887f782 100644 --- a/drivers/mtd/devices/Kconfig +++ b/drivers/mtd/devices/Kconfig @@ -249,6 +249,16 @@ config MTD_DOC2001PLUS under "NAND Flash Device Drivers" (currently that driver does not support all Millennium Plus devices). +config MTD_DOCG3 + tristate "M-Systems Disk-On-Chip G3" + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + G3 devices. + + The driver provides access to G3 DiskOnChip, distributed by + M-Systems and now Sandisk. The support is very experimental, + and doesn't give access to any write operations. + config MTD_DOCPROBE tristate select MTD_DOCECC @@ -268,8 +278,7 @@ config MTD_DOCPROBE_ADVANCED config MTD_DOCPROBE_ADDRESS hex "Physical address of DiskOnChip" if MTD_DOCPROBE_ADVANCED depends on MTD_DOCPROBE - default "0x0000" if MTD_DOCPROBE_ADVANCED - default "0" if !MTD_DOCPROBE_ADVANCED + default "0x0" ---help--- By default, the probe for DiskOnChip devices will look for a DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile index f3226b1d38f..56c7cd462f1 100644 --- a/drivers/mtd/devices/Makefile +++ b/drivers/mtd/devices/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_MTD_DOC2000) += doc2000.o obj-$(CONFIG_MTD_DOC2001) += doc2001.o obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o +obj-$(CONFIG_MTD_DOCG3) += docg3.o obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o obj-$(CONFIG_MTD_DOCECC) += docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o @@ -17,3 +18,5 @@ obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o obj-$(CONFIG_MTD_M25P80) += m25p80.o obj-$(CONFIG_MTD_SST25L) += sst25l.o + +CFLAGS_docg3.o += -I$(src)
\ No newline at end of file diff --git a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c index f7fbf6025ef..e9fad915121 100644 --- a/drivers/mtd/devices/doc2000.c +++ b/drivers/mtd/devices/doc2000.c @@ -82,8 +82,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) void __iomem *docptr = doc->virtadr; unsigned long timeo = jiffies + (HZ * 10); - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { @@ -92,7 +91,7 @@ static int _DoC_WaitReady(struct DiskOnChip *doc) DoC_Delay(doc, 2); if (time_after(jiffies, timeo)) { - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return -EIO; } udelay(1); @@ -323,8 +322,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Reset the chip */ if (DoC_Command(doc, NAND_CMD_RESET, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (reset) for %d,%d returned true\n", + pr_debug("DoC_Command (reset) for %d,%d returned true\n", floor, chip); return 0; } @@ -332,8 +330,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) /* Read the NAND chip ID: 1. Send ReadID command */ if (DoC_Command(doc, NAND_CMD_READID, CDSN_CTRL_WP)) { - DEBUG(MTD_DEBUG_LEVEL2, - "DoC_Command (ReadID) for %d,%d returned true\n", + pr_debug("DoC_Command (ReadID) for %d,%d returned true\n", floor, chip); return 0; } @@ -699,7 +696,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk(KERN_ERR "DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { @@ -930,7 +927,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -1094,7 +1091,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, struct DiskOnChip *this = mtd->priv; int ret; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); mutex_lock(&this->lock); ret = doc_write_oob_nolock(mtd, ofs + ops->ooboffs, ops->len, diff --git a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c index 241192f05bc..a3f7a27499b 100644 --- a/drivers/mtd/devices/doc2001.c +++ b/drivers/mtd/devices/doc2001.c @@ -55,15 +55,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned short c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } @@ -464,7 +463,7 @@ static int doc_read (struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) { syndrome[i] = ReadDOC(docptr, ECCSyndrome0 + i); @@ -632,7 +631,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -690,7 +689,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c index 09ae0adc3ad..99351bc3e0e 100644 --- a/drivers/mtd/devices/doc2001plus.c +++ b/drivers/mtd/devices/doc2001plus.c @@ -61,15 +61,14 @@ static int _DoC_WaitReady(void __iomem * docptr) { unsigned int c = 0xffff; - DEBUG(MTD_DEBUG_LEVEL3, - "_DoC_WaitReady called for out-of-line wait\n"); + pr_debug("_DoC_WaitReady called for out-of-line wait\n"); /* Out-of-line routine to wait for chip response */ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) ; if (c == 0) - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + pr_debug("_DoC_WaitReady timed out.\n"); return (c == 0); } @@ -655,7 +654,7 @@ static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, #ifdef ECC_DEBUG printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); #endif - /* Read the ECC syndrom through the DiskOnChip ECC logic. + /* Read the ECC syndrome through the DiskOnChip ECC logic. These syndrome will be all ZERO when there is no error */ for (i = 0; i < 6; i++) syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); @@ -835,7 +834,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; @@ -920,7 +919,7 @@ static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, uint8_t *buf = ops->oobbuf; size_t len = ops->len; - BUG_ON(ops->mode != MTD_OOB_PLACE); + BUG_ON(ops->mode != MTD_OPS_PLACE_OOB); ofs += ops->ooboffs; diff --git a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c index 37ef29a73ee..4a1c39b6f37 100644 --- a/drivers/mtd/devices/docecc.c +++ b/drivers/mtd/devices/docecc.c @@ -2,7 +2,7 @@ * ECC algorithm for M-systems disk on chip. We use the excellent Reed * Solmon code of Phil Karn (karn@ka9q.ampr.org) available under the * GNU GPL License. The rest is simply to convert the disk on chip - * syndrom into a standard syndom. + * syndrome into a standard syndome. * * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c new file mode 100644 index 00000000000..bdcf5df982e --- /dev/null +++ b/drivers/mtd/devices/docg3.c @@ -0,0 +1,1114 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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/module.h> +#include <linux/errno.h> +#include <linux/platform_device.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> + +#include <linux/debugfs.h> +#include <linux/seq_file.h> + +#define CREATE_TRACE_POINTS +#include "docg3.h" + +/* + * This driver handles the DiskOnChip G3 flash memory. + * + * As no specification is available from M-Systems/Sandisk, this drivers lacks + * several functions available on the chip, as : + * - block erase + * - page write + * - IPL write + * - ECC fixing (lack of BCH algorith understanding) + * - powerdown / powerup + * + * The bus data width (8bits versus 16bits) is not handled (if_cfg flag), and + * the driver assumes a 16bits data bus. + * + * DocG3 relies on 2 ECC algorithms, which are handled in hardware : + * - a 1 byte Hamming code stored in the OOB for each page + * - a 7 bytes BCH code stored in the OOB for each page + * The BCH part is only used for check purpose, no correction is available as + * some information is missing. What is known is that : + * - BCH is in GF(2^14) + * - BCH is over data of 520 bytes (512 page + 7 page_info bytes + * + 1 hamming byte) + * - BCH can correct up to 4 bits (t = 4) + * - BCH syndroms are calculated in hardware, and checked in hardware as well + * + */ + +static inline u8 doc_readb(struct docg3 *docg3, u16 reg) +{ + u8 val = readb(docg3->base + reg); + + trace_docg3_io(0, 8, reg, (int)val); + return val; +} + +static inline u16 doc_readw(struct docg3 *docg3, u16 reg) +{ + u16 val = readw(docg3->base + reg); + + trace_docg3_io(0, 16, reg, (int)val); + return val; +} + +static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) +{ + writeb(val, docg3->base + reg); + trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) +{ + writew(val, docg3->base + reg); + trace_docg3_io(1, 16, reg, val); +} + +static inline void doc_flash_command(struct docg3 *docg3, u8 cmd) +{ + doc_writeb(docg3, cmd, DOC_FLASHCOMMAND); +} + +static inline void doc_flash_sequence(struct docg3 *docg3, u8 seq) +{ + doc_writeb(docg3, seq, DOC_FLASHSEQUENCE); +} + +static inline void doc_flash_address(struct docg3 *docg3, u8 addr) +{ + doc_writeb(docg3, addr, DOC_FLASHADDRESS); +} + +static char const *part_probes[] = { "cmdlinepart", "saftlpart", NULL }; + +static int doc_register_readb(struct docg3 *docg3, int reg) +{ + u8 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readb(docg3, reg); + doc_vdbg("Read register %04x : %02x\n", reg, val); + return val; +} + +static int doc_register_readw(struct docg3 *docg3, int reg) +{ + u16 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readw(docg3, reg); + doc_vdbg("Read register %04x : %04x\n", reg, val); + return val; +} + +/** + * doc_delay - delay docg3 operations + * @docg3: the device + * @nbNOPs: the number of NOPs to issue + * + * As no specification is available, the right timings between chip commands are + * unknown. The only available piece of information are the observed nops on a + * working docg3 chip. + * Therefore, doc_delay relies on a busy loop of NOPs, instead of scheduler + * friendlier msleep() functions or blocking mdelay(). + */ +static void doc_delay(struct docg3 *docg3, int nbNOPs) +{ + int i; + + doc_dbg("NOP x %d\n", nbNOPs); + for (i = 0; i < nbNOPs; i++) + doc_writeb(docg3, 0, DOC_NOP); +} + +static int is_prot_seq_error(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR); +} + +static int doc_is_ready(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & DOC_CTRL_FLASHREADY; +} + +static int doc_wait_ready(struct docg3 *docg3) +{ + int maxWaitCycles = 100; + + do { + doc_delay(docg3, 4); + cpu_relax(); + } while (!doc_is_ready(docg3) && maxWaitCycles--); + doc_delay(docg3, 2); + if (maxWaitCycles > 0) + return 0; + else + return -EIO; +} + +static int doc_reset_seq(struct docg3 *docg3) +{ + int ret; + + doc_writeb(docg3, 0x10, DOC_FLASHCONTROL); + doc_flash_sequence(docg3, DOC_SEQ_RESET); + doc_flash_command(docg3, DOC_CMD_RESET); + doc_delay(docg3, 2); + ret = doc_wait_ready(docg3); + + doc_dbg("doc_reset_seq() -> isReady=%s\n", ret ? "false" : "true"); + return ret; +} + +/** + * doc_read_data_area - Read data from data area + * @docg3: the device + * @buf: the buffer to fill in + * @len: the lenght to read + * @first: first time read, DOC_READADDRESS should be set + * + * Reads bytes from flash data. Handles the single byte / even bytes reads. + */ +static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, + int first) +{ + int i, cdr, len4; + u16 data16, *dst16; + u8 data8, *dst8; + + doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); + cdr = len & 0x3; + len4 = len - cdr; + + if (first) + doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS); + dst16 = buf; + for (i = 0; i < len4; i += 2) { + data16 = doc_readw(docg3, DOC_IOSPACE_DATA); + *dst16 = data16; + dst16++; + } + + if (cdr) { + doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE, + DOC_READADDRESS); + doc_delay(docg3, 1); + dst8 = (u8 *)dst16; + for (i = 0; i < cdr; i++) { + data8 = doc_readb(docg3, DOC_IOSPACE_DATA); + *dst8 = data8; + dst8++; + } + } +} + +/** + * doc_set_data_mode - Sets the flash to reliable data mode + * @docg3: the device + * + * The reliable data mode is a bit slower than the fast mode, but less errors + * occur. Entering the reliable mode cannot be done without entering the fast + * mode first. + */ +static void doc_set_reliable_mode(struct docg3 *docg3) +{ + doc_dbg("doc_set_reliable_mode()\n"); + doc_flash_sequence(docg3, DOC_SEQ_SET_MODE); + doc_flash_command(docg3, DOC_CMD_FAST_MODE); + doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE); + doc_delay(docg3, 2); +} + +/** + * doc_set_asic_mode - Set the ASIC mode + * @docg3: the device + * @mode: the mode + * + * The ASIC can work in 3 modes : + * - RESET: all registers are zeroed + * - NORMAL: receives and handles commands + * - POWERDOWN: minimal poweruse, flash parts shut off + */ +static void doc_set_asic_mode(struct docg3 *docg3, u8 mode) +{ + int i; + + for (i = 0; i < 12; i++) + doc_readb(docg3, DOC_IOSPACE_IPL); + + mode |= DOC_ASICMODE_MDWREN; + doc_dbg("doc_set_asic_mode(%02x)\n", mode); + doc_writeb(docg3, mode, DOC_ASICMODE); + doc_writeb(docg3, ~mode, DOC_ASICMODECONFIRM); + doc_delay(docg3, 1); +} + +/** + * doc_set_device_id - Sets the devices id for cascaded G3 chips + * @docg3: the device + * @id: the chip to select (amongst 0, 1, 2, 3) + * + * There can be 4 cascaded G3 chips. This function selects the one which will + * should be the active one. + */ +static void doc_set_device_id(struct docg3 *docg3, int id) +{ + u8 ctrl; + + doc_dbg("doc_set_device_id(%d)\n", id); + doc_writeb(docg3, id, DOC_DEVICESELECT); + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + + ctrl &= ~DOC_CTRL_VIOLATION; + ctrl |= DOC_CTRL_CE; + doc_writeb(docg3, ctrl, DOC_FLASHCONTROL); +} + +/** + * doc_set_extra_page_mode - Change flash page layout + * @docg3: the device + * + * Normally, the flash page is split into the data (512 bytes) and the out of + * band data (16 bytes). For each, 4 more bytes can be accessed, where the wear + * leveling counters are stored. To access this last area of 4 bytes, a special + * mode must be input to the flash ASIC. + * + * Returns 0 if no error occured, -EIO else. + */ +static int doc_set_extra_page_mode(struct docg3 *docg3) +{ + int fctrl; + + doc_dbg("doc_set_extra_page_mode()\n"); + doc_flash_sequence(docg3, DOC_SEQ_PAGE_SIZE_532); + doc_flash_command(docg3, DOC_CMD_PAGE_SIZE_532); + doc_delay(docg3, 2); + + fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + if (fctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR)) + return -EIO; + else + return 0; +} + +/** + * doc_seek - Set both flash planes to the specified block, page for reading + * @docg3: the device + * @block0: the first plane block index + * @block1: the second plane block index + * @page: the page index within the block + * @wear: if true, read will occur on the 4 extra bytes of the wear area + * @ofs: offset in page to read + * + * Programs the flash even and odd planes to the specific block and page. + * Alternatively, programs the flash to the wear area of the specified page. + */ +static int doc_read_seek(struct docg3 *docg3, int block0, int block1, int page, + int wear, int ofs) +{ + int sector, ret = 0; + + doc_dbg("doc_seek(blocks=(%d,%d), page=%d, ofs=%d, wear=%d)\n", + block0, block1, page, ofs, wear); + + if (!wear && (ofs < 2 * DOC_LAYOUT_PAGE_SIZE)) { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1); + doc_flash_command(docg3, DOC_CMD_READ_PLANE1); + doc_delay(docg3, 2); + } else { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2); + doc_flash_command(docg3, DOC_CMD_READ_PLANE2); + doc_delay(docg3, 2); + } + + doc_set_reliable_mode(docg3); + if (wear) + ret = doc_set_extra_page_mode(docg3); + if (ret) + goto out; + + sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_sequence(docg3, DOC_SEQ_READ); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_delay(docg3, 1); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 1); + + sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_delay(docg3, 1); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 2); + +out: + return ret; +} + +/** + * doc_read_page_ecc_init - Initialize hardware ECC engine + * @docg3: the device + * @len: the number of bytes covered by the ECC (BCH covered) + * + * The function does initialize the hardware ECC engine to compute the Hamming + * ECC (on 1 byte) and the BCH Syndroms (on 7 bytes). + * + * Return 0 if succeeded, -EIO on error + */ +static int doc_read_page_ecc_init(struct docg3 *docg3, int len) +{ + doc_writew(docg3, DOC_ECCCONF0_READ_MODE + | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE + | (len & DOC_ECCCONF0_DATA_BYTES_MASK), + DOC_ECCCONF0); + doc_delay(docg3, 4); + doc_register_readb(docg3, DOC_FLASHCONTROL); + return doc_wait_ready(docg3); +} + +/** + * doc_read_page_prepare - Prepares reading data from a flash page + * @docg3: the device + * @block0: the first plane block index on flash memory + * @block1: the second plane block index on flash memory + * @page: the page index in the block + * @offset: the offset in the page (must be a multiple of 4) + * + * Prepares the page to be read in the flash memory : + * - tell ASIC to map the flash pages + * - tell ASIC to be in read mode + * + * After a call to this method, a call to doc_read_page_finish is mandatory, + * to end the read cycle of the flash. + * + * Read data from a flash page. The length to be read must be between 0 and + * (page_size + oob_size + wear_size), ie. 532, and a multiple of 4 (because + * the extra bytes reading is not implemented). + * + * As pages are grouped by 2 (in 2 planes), reading from a page must be done + * in two steps: + * - one read of 512 bytes at offset 0 + * - one read of 512 bytes at offset 512 + 16 + * + * Returns 0 if successful, -EIO if a read error occured. + */ +static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, + int page, int offset) +{ + int wear_area = 0, ret = 0; + + doc_dbg("doc_read_page_prepare(blocks=(%d,%d), page=%d, ofsInPage=%d)\n", + block0, block1, page, offset); + if (offset >= DOC_LAYOUT_WEAR_OFFSET) + wear_area = 1; + if (!wear_area && offset > (DOC_LAYOUT_PAGE_OOB_SIZE * 2)) + return -EINVAL; + + doc_set_device_id(docg3, docg3->device_id); + ret = doc_reset_seq(docg3); + if (ret) + goto err; + + /* Program the flash address block and page */ + ret = doc_read_seek(docg3, block0, block1, page, wear_area, offset); + if (ret) + goto err; + + doc_flash_command(docg3, DOC_CMD_READ_ALL_PLANES); + doc_delay(docg3, 2); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_SET_ADDR_READ); + doc_delay(docg3, 1); + if (offset >= DOC_LAYOUT_PAGE_SIZE * 2) + offset -= 2 * DOC_LAYOUT_PAGE_SIZE; + doc_flash_address(docg3, offset >> 2); + doc_delay(docg3, 1); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_READ_FLASH); + + return 0; +err: + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); + return -EIO; +} + +/** + * doc_read_page_getbytes - Reads bytes from a prepared page + * @docg3: the device + * @len: the number of bytes to be read (must be a multiple of 4) + * @buf: the buffer to be filled in + * @first: 1 if first time read, DOC_READADDRESS should be set + * + */ +static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, + int first) +{ + doc_read_data_area(docg3, buf, len, first); + doc_delay(docg3, 2); + return len; +} + +/** + * doc_get_hw_bch_syndroms - Get hardware calculated BCH syndroms + * @docg3: the device + * @syns: the array of 7 integers where the syndroms will be stored + */ +static void doc_get_hw_bch_syndroms(struct docg3 *docg3, int *syns) +{ + int i; + + for (i = 0; i < DOC_ECC_BCH_SIZE; i++) + syns[i] = doc_register_readb(docg3, DOC_BCH_SYNDROM(i)); +} + +/** + * doc_read_page_finish - Ends reading of a flash page + * @docg3: the device + * + * As a side effect, resets the chip selector to 0. This ensures that after each + * read operation, the floor 0 is selected. Therefore, if the systems halts, the + * reboot will boot on floor 0, where the IPL is. + */ +static void doc_read_page_finish(struct docg3 *docg3) +{ + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); + doc_set_device_id(docg3, 0); +} + +/** + * calc_block_sector - Calculate blocks, pages and ofs. + + * @from: offset in flash + * @block0: first plane block index calculated + * @block1: second plane block index calculated + * @page: page calculated + * @ofs: offset in page + */ +static void calc_block_sector(loff_t from, int *block0, int *block1, int *page, + int *ofs) +{ + uint sector; + + sector = from / DOC_LAYOUT_PAGE_SIZE; + *block0 = sector / (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES) + * DOC_LAYOUT_NBPLANES; + *block1 = *block0 + 1; + *page = sector % (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES); + *page /= DOC_LAYOUT_NBPLANES; + if (sector % 2) + *ofs = DOC_LAYOUT_PAGE_OOB_SIZE; + else + *ofs = 0; +} + +/** + * doc_read - Read bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + * size + * @len: the number of bytes to read (must be a multiple of 4) + * @retlen: the number of bytes actually read + * @buf: the filled in buffer + * + * Reads flash memory pages. This function does not read the OOB chunk, but only + * the page data. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, readlen, ret, ofs = 0; + int syn[DOC_ECC_BCH_SIZE], eccconf1; + u8 oob[DOC_LAYOUT_OOB_SIZE]; + + ret = -EINVAL; + doc_dbg("doc_read(from=%lld, len=%zu, buf=%p)\n", from, len, buf); + if (from % DOC_LAYOUT_PAGE_SIZE) + goto err; + if (len % 4) + goto err; + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + goto err; + + *retlen = 0; + ret = 0; + readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + while (!ret && len > 0) { + readlen = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); + if (ret < 0) + goto err; + ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_COVERED_BYTES); + if (ret < 0) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, readlen, buf, 1); + if (ret < readlen) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, + oob, 0); + if (ret < DOC_LAYOUT_OOB_SIZE) + goto err_in_read; + + *retlen += readlen; + buf += readlen; + len -= readlen; + + ofs ^= DOC_LAYOUT_PAGE_OOB_SIZE; + if (ofs == 0) + page += 2; + if (page > DOC_ADDR_PAGE_MASK) { + page = 0; + block0 += 2; + block1 += 2; + } + + /* + * There should be a BCH bitstream fixing algorithm here ... + * By now, a page read failure is triggered by BCH error + */ + doc_get_hw_bch_syndroms(docg3, syn); + eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); + + doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oob[0], oob[1], oob[2], oob[3], oob[4], + oob[5], oob[6]); + doc_dbg("OOB - HAMMING: %02x\n", oob[7]); + doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oob[8], oob[9], oob[10], oob[11], oob[12], + oob[13], oob[14]); + doc_dbg("OOB - UNUSED: %02x\n", oob[15]); + doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); + doc_dbg("ECC BCH syndrom: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + syn[0], syn[1], syn[2], syn[3], syn[4], syn[5], syn[6]); + + ret = -EBADMSG; + if (block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) { + if (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) + goto err_in_read; + if (is_prot_seq_error(docg3)) + goto err_in_read; + } + doc_read_page_finish(docg3); + } + + return 0; +err_in_read: + doc_read_page_finish(docg3); +err: + return ret; +} + +/** + * doc_read_oob - Read out of band bytes from flash + * @mtd: the device + * @from: the offset from first block and first page, in bytes, aligned on page + * size + * @ops: the mtd oob structure + * + * Reads flash memory OOB area of pages. + * + * Returns 0 if read successfull, of -EIO, -EINVAL if an error occured + */ +static int doc_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ofs, ret; + u8 *buf = ops->oobbuf; + size_t len = ops->ooblen; + + doc_dbg("doc_read_oob(from=%lld, buf=%p, len=%zu)\n", from, buf, len); + if (len != DOC_LAYOUT_OOB_SIZE) + return -EINVAL; + + switch (ops->mode) { + case MTD_OPS_PLACE_OOB: + buf += ops->ooboffs; + break; + default: + break; + } + + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + return -EINVAL; + + ret = doc_read_page_prepare(docg3, block0, block1, page, + ofs + DOC_LAYOUT_PAGE_SIZE); + if (!ret) + ret = doc_read_page_ecc_init(docg3, DOC_LAYOUT_OOB_SIZE); + if (!ret) + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE, + buf, 1); + doc_read_page_finish(docg3); + + if (ret > 0) + ops->oobretlen = ret; + else + ops->oobretlen = 0; + return (ret > 0) ? 0 : ret; +} + +static int doc_reload_bbt(struct docg3 *docg3) +{ + int block = DOC_LAYOUT_BLOCK_BBT; + int ret = 0, nbpages, page; + u_char *buf = docg3->bbt; + + nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE); + for (page = 0; !ret && (page < nbpages); page++) { + ret = doc_read_page_prepare(docg3, block, block + 1, + page + DOC_LAYOUT_PAGE_BBT, 0); + if (!ret) + ret = doc_read_page_ecc_init(docg3, + DOC_LAYOUT_PAGE_SIZE); + if (!ret) + doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, + buf, 1); + buf += DOC_LAYOUT_PAGE_SIZE; + } + doc_read_page_finish(docg3); + return ret; +} + +/** + * doc_block_isbad - Checks whether a block is good or not + * @mtd: the device + * @from: the offset to find the correct block + * + * Returns 1 if block is bad, 0 if block is good + */ +static int doc_block_isbad(struct mtd_info *mtd, loff_t from) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ofs, is_good; + + calc_block_sector(from, &block0, &block1, &page, &ofs); + doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n", + from, block0, block1, page, ofs); + + if (block0 < DOC_LAYOUT_BLOCK_FIRST_DATA) + return 0; + if (block1 > docg3->max_block) + return -EINVAL; + + is_good = docg3->bbt[block0 >> 3] & (1 << (block0 & 0x7)); + return !is_good; +} + +/** + * doc_get_erase_count - Get block erase count + * @docg3: the device + * @from: the offset in which the block is. + * + * Get the number of times a block was erased. The number is the maximum of + * erase times between first and second plane (which should be equal normally). + * + * Returns The number of erases, or -EINVAL or -EIO on error. + */ +static int doc_get_erase_count(struct docg3 *docg3, loff_t from) +{ + u8 buf[DOC_LAYOUT_WEAR_SIZE]; + int ret, plane1_erase_count, plane2_erase_count; + int block0, block1, page, ofs; + + doc_dbg("doc_get_erase_count(from=%lld, buf=%p)\n", from, buf); + if (from % DOC_LAYOUT_PAGE_SIZE) + return -EINVAL; + calc_block_sector(from, &block0, &block1, &page, &ofs); + if (block1 > docg3->max_block) + return -EINVAL; + + ret = doc_reset_seq(docg3); + if (!ret) + ret = doc_read_page_prepare(docg3, block0, block1, page, + ofs + DOC_LAYOUT_WEAR_OFFSET); + if (!ret) + ret = doc_read_page_getbytes(docg3, DOC_LAYOUT_WEAR_SIZE, + buf, 1); + doc_read_page_finish(docg3); + + if (ret || (buf[0] != DOC_ERASE_MARK) || (buf[2] != DOC_ERASE_MARK)) + return -EIO; + plane1_erase_count = (u8)(~buf[1]) | ((u8)(~buf[4]) << 8) + | ((u8)(~buf[5]) << 16); + plane2_erase_count = (u8)(~buf[3]) | ((u8)(~buf[6]) << 8) + | ((u8)(~buf[7]) << 16); + + return max(plane1_erase_count, plane2_erase_count); +} + +/* + * Debug sysfs entries + */ +static int dbg_flashctrl_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + + int pos = 0; + u8 fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + + pos += seq_printf(s, + "FlashControl : 0x%02x (%s,CE# %s,%s,%s,flash %s)\n", + fctrl, + fctrl & DOC_CTRL_VIOLATION ? "protocol violation" : "-", + fctrl & DOC_CTRL_CE ? "active" : "inactive", + fctrl & DOC_CTRL_PROTECTION_ERROR ? "protection error" : "-", + fctrl & DOC_CTRL_SEQUENCE_ERROR ? "sequence error" : "-", + fctrl & DOC_CTRL_FLASHREADY ? "ready" : "not ready"); + return pos; +} +DEBUGFS_RO_ATTR(flashcontrol, dbg_flashctrl_show); + +static int dbg_asicmode_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + + int pos = 0; + int pctrl = doc_register_readb(docg3, DOC_ASICMODE); + int mode = pctrl & 0x03; + + pos += seq_printf(s, + "%04x : RAM_WE=%d,RSTIN_RESET=%d,BDETCT_RESET=%d,WRITE_ENABLE=%d,POWERDOWN=%d,MODE=%d%d (", + pctrl, + pctrl & DOC_ASICMODE_RAM_WE ? 1 : 0, + pctrl & DOC_ASICMODE_RSTIN_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_BDETCT_RESET ? 1 : 0, + pctrl & DOC_ASICMODE_MDWREN ? 1 : 0, + pctrl & DOC_ASICMODE_POWERDOWN ? 1 : 0, + mode >> 1, mode & 0x1); + + switch (mode) { + case DOC_ASICMODE_RESET: + pos += seq_printf(s, "reset"); + break; + case DOC_ASICMODE_NORMAL: + pos += seq_printf(s, "normal"); + break; + case DOC_ASICMODE_POWERDOWN: + pos += seq_printf(s, "powerdown"); + break; + } + pos += seq_printf(s, ")\n"); + return pos; +} +DEBUGFS_RO_ATTR(asic_mode, dbg_asicmode_show); + +static int dbg_device_id_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + int pos = 0; + int id = doc_register_readb(docg3, DOC_DEVICESELECT); + + pos += seq_printf(s, "DeviceId = %d\n", id); + return pos; +} +DEBUGFS_RO_ATTR(device_id, dbg_device_id_show); + +static int dbg_protection_show(struct seq_file *s, void *p) +{ + struct docg3 *docg3 = (struct docg3 *)s->private; + int pos = 0; + int protect = doc_register_readb(docg3, DOC_PROTECTION); + int dps0 = doc_register_readb(docg3, DOC_DPS0_STATUS); + int dps0_low = doc_register_readb(docg3, DOC_DPS0_ADDRLOW); + int dps0_high = doc_register_readb(docg3, DOC_DPS0_ADDRHIGH); + int dps1 = doc_register_readb(docg3, DOC_DPS1_STATUS); + int dps1_low = doc_register_readb(docg3, DOC_DPS1_ADDRLOW); + int dps1_high = doc_register_readb(docg3, DOC_DPS1_ADDRHIGH); + + pos += seq_printf(s, "Protection = 0x%02x (", + protect); + if (protect & DOC_PROTECT_FOUNDRY_OTP_LOCK) + pos += seq_printf(s, "FOUNDRY_OTP_LOCK,"); + if (protect & DOC_PROTECT_CUSTOMER_OTP_LOCK) + pos += seq_printf(s, "CUSTOMER_OTP_LOCK,"); + if (protect & DOC_PROTECT_LOCK_INPUT) + pos += seq_printf(s, "LOCK_INPUT,"); + if (protect & DOC_PROTECT_STICKY_LOCK) + pos += seq_printf(s, "STICKY_LOCK,"); + if (protect & DOC_PROTECT_PROTECTION_ENABLED) + pos += seq_printf(s, "PROTECTION ON,"); + if (protect & DOC_PROTECT_IPL_DOWNLOAD_LOCK) + pos += seq_printf(s, "IPL_DOWNLOAD_LOCK,"); + if (protect & DOC_PROTECT_PROTECTION_ERROR) + pos += seq_printf(s, "PROTECT_ERR,"); + else + pos += seq_printf(s, "NO_PROTECT_ERR"); + pos += seq_printf(s, ")\n"); + + pos += seq_printf(s, "DPS0 = 0x%02x : " + "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " + "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps0, dps0_low, dps0_high, + !!(dps0 & DOC_DPS_OTP_PROTECTED), + !!(dps0 & DOC_DPS_READ_PROTECTED), + !!(dps0 & DOC_DPS_WRITE_PROTECTED), + !!(dps0 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps0 & DOC_DPS_KEY_OK)); + pos += seq_printf(s, "DPS1 = 0x%02x : " + "Protected area [0x%x - 0x%x] : OTP=%d, READ=%d, " + "WRITE=%d, HW_LOCK=%d, KEY_OK=%d\n", + dps1, dps1_low, dps1_high, + !!(dps1 & DOC_DPS_OTP_PROTECTED), + !!(dps1 & DOC_DPS_READ_PROTECTED), + !!(dps1 & DOC_DPS_WRITE_PROTECTED), + !!(dps1 & DOC_DPS_HW_LOCK_ENABLED), + !!(dps1 & DOC_DPS_KEY_OK)); + return pos; +} +DEBUGFS_RO_ATTR(protection, dbg_protection_show); + +static int __init doc_dbg_register(struct docg3 *docg3) +{ + struct dentry *root, *entry; + + root = debugfs_create_dir("docg3", NULL); + if (!root) + return -ENOMEM; + + entry = debugfs_create_file("flashcontrol", S_IRUSR, root, docg3, + &flashcontrol_fops); + if (entry) + entry = debugfs_create_file("asic_mode", S_IRUSR, root, + docg3, &asic_mode_fops); + if (entry) + entry = debugfs_create_file("device_id", S_IRUSR, root, + docg3, &device_id_fops); + if (entry) + entry = debugfs_create_file("protection", S_IRUSR, root, + docg3, &protection_fops); + if (entry) { + docg3->debugfs_root = root; + return 0; + } else { + debugfs_remove_recursive(root); + return -ENOMEM; + } +} + +static void __exit doc_dbg_unregister(struct docg3 *docg3) +{ + debugfs_remove_recursive(docg3->debugfs_root); +} + +/** + * doc_set_driver_info - Fill the mtd_info structure and docg3 structure + * @chip_id: The chip ID of the supported chip + * @mtd: The structure to fill + */ +static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) +{ + struct docg3 *docg3 = mtd->priv; + int cfg; + + cfg = doc_register_readb(docg3, DOC_CONFIGURATION); + docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0); + + switch (chip_id) { + case DOC_CHIPID_G3: + mtd->name = "DiskOnChip G3"; + docg3->max_block = 2047; + break; + } + mtd->type = MTD_NANDFLASH; + /* + * Once write methods are added, the correct flags will be set. + * mtd->flags = MTD_CAP_NANDFLASH; + */ + mtd->flags = MTD_CAP_ROM; + mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE; + mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; + mtd->writesize = DOC_LAYOUT_PAGE_SIZE; + mtd->oobsize = DOC_LAYOUT_OOB_SIZE; + mtd->owner = THIS_MODULE; + mtd->erase = NULL; + mtd->point = NULL; + mtd->unpoint = NULL; + mtd->read = doc_read; + mtd->write = NULL; + mtd->read_oob = doc_read_oob; + mtd->write_oob = NULL; + mtd->sync = NULL; + mtd->block_isbad = doc_block_isbad; +} + +/** + * doc_probe - Probe the IO space for a DiskOnChip G3 chip + * @pdev: platform device + * + * Probes for a G3 chip at the specified IO space in the platform data + * ressources. + * + * Returns 0 on success, -ENOMEM, -ENXIO on error + */ +static int __init docg3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct docg3 *docg3; + struct mtd_info *mtd; + struct resource *ress; + int ret, bbt_nbpages; + u16 chip_id, chip_id_inv; + + ret = -ENOMEM; + docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL); + if (!docg3) + goto nomem1; + mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) + goto nomem2; + mtd->priv = docg3; + + ret = -ENXIO; + ress = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!ress) { + dev_err(dev, "No I/O memory resource defined\n"); + goto noress; + } + docg3->base = ioremap(ress->start, DOC_IOSPACE_SIZE); + + docg3->dev = &pdev->dev; + docg3->device_id = 0; + doc_set_device_id(docg3, docg3->device_id); + doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); + doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL); + + chip_id = doc_register_readw(docg3, DOC_CHIPID); + chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV); + + ret = -ENODEV; + if (chip_id != (u16)(~chip_id_inv)) { + doc_info("No device found at IO addr %p\n", + (void *)ress->start); + goto nochipfound; + } + + switch (chip_id) { + case DOC_CHIPID_G3: + doc_info("Found a G3 DiskOnChip at addr %p\n", + (void *)ress->start); + break; + default: + doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); + goto nochipfound; + } + + doc_set_driver_info(chip_id, mtd); + platform_set_drvdata(pdev, mtd); + + ret = -ENOMEM; + bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1, + 8 * DOC_LAYOUT_PAGE_SIZE); + docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL); + if (!docg3->bbt) + goto nochipfound; + doc_reload_bbt(docg3); + + ret = mtd_device_parse_register(mtd, part_probes, + NULL, NULL, 0); + if (ret) + goto register_error; + + doc_dbg_register(docg3); + return 0; + +register_error: + kfree(docg3->bbt); +nochipfound: + iounmap(docg3->base); +noress: + kfree(mtd); +nomem2: + kfree(docg3); +nomem1: + return ret; +} + +/** + * docg3_release - Release the driver + * @pdev: the platform device + * + * Returns 0 + */ +static int __exit docg3_release(struct platform_device *pdev) +{ + struct mtd_info *mtd = platform_get_drvdata(pdev); + struct docg3 *docg3 = mtd->priv; + + doc_dbg_unregister(docg3); + mtd_device_unregister(mtd); + iounmap(docg3->base); + kfree(docg3->bbt); + kfree(docg3); + kfree(mtd); + return 0; +} + +static struct platform_driver g3_driver = { + .driver = { + .name = "docg3", + .owner = THIS_MODULE, + }, + .remove = __exit_p(docg3_release), +}; + +static int __init docg3_init(void) +{ + return platform_driver_probe(&g3_driver, docg3_probe); +} +module_init(docg3_init); + + +static void __exit docg3_exit(void) +{ + platform_driver_unregister(&g3_driver); +} +module_exit(docg3_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>"); +MODULE_DESCRIPTION("MTD driver for DiskOnChip G3"); diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h new file mode 100644 index 00000000000..0d407be2459 --- /dev/null +++ b/drivers/mtd/devices/docg3.h @@ -0,0 +1,297 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _MTD_DOCG3_H +#define _MTD_DOCG3_H + +/* + * Flash memory areas : + * - 0x0000 .. 0x07ff : IPL + * - 0x0800 .. 0x0fff : Data area + * - 0x1000 .. 0x17ff : Registers + * - 0x1800 .. 0x1fff : Unknown + */ +#define DOC_IOSPACE_IPL 0x0000 +#define DOC_IOSPACE_DATA 0x0800 +#define DOC_IOSPACE_SIZE 0x2000 + +/* + * DOC G3 layout and adressing scheme + * A page address for the block "b", plane "P" and page "p": + * address = [bbbb bPpp pppp] + */ + +#define DOC_ADDR_PAGE_MASK 0x3f +#define DOC_ADDR_BLOCK_SHIFT 6 +#define DOC_LAYOUT_NBPLANES 2 +#define DOC_LAYOUT_PAGES_PER_BLOCK 64 +#define DOC_LAYOUT_PAGE_SIZE 512 +#define DOC_LAYOUT_OOB_SIZE 16 +#define DOC_LAYOUT_WEAR_SIZE 8 +#define DOC_LAYOUT_PAGE_OOB_SIZE \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_SIZE) +#define DOC_LAYOUT_WEAR_OFFSET (DOC_LAYOUT_PAGE_OOB_SIZE * 2) +#define DOC_LAYOUT_BLOCK_SIZE \ + (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE) +#define DOC_ECC_BCH_SIZE 7 +#define DOC_ECC_BCH_COVERED_BYTES \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ + \ + DOC_LAYOUT_OOB_HAMMING_SZ + DOC_LAYOUT_OOB_BCH_SZ) + +/* + * Blocks distribution + */ +#define DOC_LAYOUT_BLOCK_BBT 0 +#define DOC_LAYOUT_BLOCK_OTP 0 +#define DOC_LAYOUT_BLOCK_FIRST_DATA 6 + +#define DOC_LAYOUT_PAGE_BBT 4 + +/* + * Extra page OOB (16 bytes wide) layout + */ +#define DOC_LAYOUT_OOB_PAGEINFO_OFS 0 +#define DOC_LAYOUT_OOB_HAMMING_OFS 7 +#define DOC_LAYOUT_OOB_BCH_OFS 8 +#define DOC_LAYOUT_OOB_UNUSED_OFS 15 +#define DOC_LAYOUT_OOB_PAGEINFO_SZ 7 +#define DOC_LAYOUT_OOB_HAMMING_SZ 1 +#define DOC_LAYOUT_OOB_BCH_SZ 7 +#define DOC_LAYOUT_OOB_UNUSED_SZ 1 + + +#define DOC_CHIPID_G3 0x200 +#define DOC_ERASE_MARK 0xaa +/* + * Flash registers + */ +#define DOC_CHIPID 0x1000 +#define DOC_TEST 0x1004 +#define DOC_BUSLOCK 0x1006 +#define DOC_ENDIANCONTROL 0x1008 +#define DOC_DEVICESELECT 0x100a +#define DOC_ASICMODE 0x100c +#define DOC_CONFIGURATION 0x100e +#define DOC_INTERRUPTCONTROL 0x1010 +#define DOC_READADDRESS 0x101a +#define DOC_DATAEND 0x101e +#define DOC_INTERRUPTSTATUS 0x1020 + +#define DOC_FLASHSEQUENCE 0x1032 +#define DOC_FLASHCOMMAND 0x1034 +#define DOC_FLASHADDRESS 0x1036 +#define DOC_FLASHCONTROL 0x1038 +#define DOC_NOP 0x103e + +#define DOC_ECCCONF0 0x1040 +#define DOC_ECCCONF1 0x1042 +#define DOC_ECCPRESET 0x1044 +#define DOC_HAMMINGPARITY 0x1046 +#define DOC_BCH_SYNDROM(idx) (0x1048 + (idx << 1)) + +#define DOC_PROTECTION 0x1056 +#define DOC_DPS0_ADDRLOW 0x1060 +#define DOC_DPS0_ADDRHIGH 0x1062 +#define DOC_DPS1_ADDRLOW 0x1064 +#define DOC_DPS1_ADDRHIGH 0x1066 +#define DOC_DPS0_STATUS 0x106c +#define DOC_DPS1_STATUS 0x106e + +#define DOC_ASICMODECONFIRM 0x1072 +#define DOC_CHIPID_INV 0x1074 + +/* + * Flash sequences + * A sequence is preset before one or more commands are input to the chip. + */ +#define DOC_SEQ_RESET 0x00 +#define DOC_SEQ_PAGE_SIZE_532 0x03 +#define DOC_SEQ_SET_MODE 0x09 +#define DOC_SEQ_READ 0x12 +#define DOC_SEQ_SET_PLANE1 0x0e +#define DOC_SEQ_SET_PLANE2 0x10 +#define DOC_SEQ_PAGE_SETUP 0x1d + +/* + * Flash commands + */ +#define DOC_CMD_READ_PLANE1 0x00 +#define DOC_CMD_SET_ADDR_READ 0x05 +#define DOC_CMD_READ_ALL_PLANES 0x30 +#define DOC_CMD_READ_PLANE2 0x50 +#define DOC_CMD_READ_FLASH 0xe0 +#define DOC_CMD_PAGE_SIZE_532 0x3c + +#define DOC_CMD_PROG_BLOCK_ADDR 0x60 +#define DOC_CMD_PROG_CYCLE1 0x80 +#define DOC_CMD_PROG_CYCLE2 0x10 +#define DOC_CMD_ERASECYCLE2 0xd0 + +#define DOC_CMD_RELIABLE_MODE 0x22 +#define DOC_CMD_FAST_MODE 0xa2 + +#define DOC_CMD_RESET 0xff + +/* + * Flash register : DOC_FLASHCONTROL + */ +#define DOC_CTRL_VIOLATION 0x20 +#define DOC_CTRL_CE 0x10 +#define DOC_CTRL_UNKNOWN_BITS 0x08 +#define DOC_CTRL_PROTECTION_ERROR 0x04 +#define DOC_CTRL_SEQUENCE_ERROR 0x02 +#define DOC_CTRL_FLASHREADY 0x01 + +/* + * Flash register : DOC_ASICMODE + */ +#define DOC_ASICMODE_RESET 0x00 +#define DOC_ASICMODE_NORMAL 0x01 +#define DOC_ASICMODE_POWERDOWN 0x02 +#define DOC_ASICMODE_MDWREN 0x04 +#define DOC_ASICMODE_BDETCT_RESET 0x08 +#define DOC_ASICMODE_RSTIN_RESET 0x10 +#define DOC_ASICMODE_RAM_WE 0x20 + +/* + * Flash register : DOC_ECCCONF0 + */ +#define DOC_ECCCONF0_READ_MODE 0x8000 +#define DOC_ECCCONF0_AUTO_ECC_ENABLE 0x4000 +#define DOC_ECCCONF0_HAMMING_ENABLE 0x1000 +#define DOC_ECCCONF0_BCH_ENABLE 0x0800 +#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff + +/* + * Flash register : DOC_ECCCONF1 + */ +#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80 +#define DOC_ECCCONF1_UNKOWN1 0x40 +#define DOC_ECCCONF1_UNKOWN2 0x20 +#define DOC_ECCCONF1_UNKOWN3 0x10 +#define DOC_ECCCONF1_HAMMING_BITS_MASK 0x0f + +/* + * Flash register : DOC_PROTECTION + */ +#define DOC_PROTECT_FOUNDRY_OTP_LOCK 0x01 +#define DOC_PROTECT_CUSTOMER_OTP_LOCK 0x02 +#define DOC_PROTECT_LOCK_INPUT 0x04 +#define DOC_PROTECT_STICKY_LOCK 0x08 +#define DOC_PROTECT_PROTECTION_ENABLED 0x10 +#define DOC_PROTECT_IPL_DOWNLOAD_LOCK 0x20 +#define DOC_PROTECT_PROTECTION_ERROR 0x80 + +/* + * Flash register : DOC_DPS0_STATUS and DOC_DPS1_STATUS + */ +#define DOC_DPS_OTP_PROTECTED 0x01 +#define DOC_DPS_READ_PROTECTED 0x02 +#define DOC_DPS_WRITE_PROTECTED 0x04 +#define DOC_DPS_HW_LOCK_ENABLED 0x08 +#define DOC_DPS_KEY_OK 0x80 + +/* + * Flash register : DOC_CONFIGURATION + */ +#define DOC_CONF_IF_CFG 0x80 +#define DOC_CONF_MAX_ID_MASK 0x30 +#define DOC_CONF_VCCQ_3V 0x01 + +/* + * Flash register : DOC_READADDRESS + */ +#define DOC_READADDR_INC 0x8000 +#define DOC_READADDR_ONE_BYTE 0x4000 +#define DOC_READADDR_ADDR_MASK 0x1fff + +/** + * struct docg3 - DiskOnChip driver private data + * @dev: the device currently under control + * @base: mapped IO space + * @device_id: number of the cascaded DoCG3 device (0, 1, 2 or 3) + * @if_cfg: if true, reads are on 16bits, else reads are on 8bits + * @bbt: bad block table cache + * @debugfs_root: debugfs root node + */ +struct docg3 { + struct device *dev; + void __iomem *base; + unsigned int device_id:4; + unsigned int if_cfg:1; + int max_block; + u8 *bbt; + struct dentry *debugfs_root; +}; + +#define doc_err(fmt, arg...) dev_err(docg3->dev, (fmt), ## arg) +#define doc_info(fmt, arg...) dev_info(docg3->dev, (fmt), ## arg) +#define doc_dbg(fmt, arg...) dev_dbg(docg3->dev, (fmt), ## arg) +#define doc_vdbg(fmt, arg...) dev_vdbg(docg3->dev, (fmt), ## arg) + +#define DEBUGFS_RO_ATTR(name, show_fct) \ + static int name##_open(struct inode *inode, struct file *file) \ + { return single_open(file, show_fct, inode->i_private); } \ + static const struct file_operations name##_fops = { \ + .owner = THIS_MODULE, \ + .open = name##_open, \ + .llseek = seq_lseek, \ + .read = seq_read, \ + .release = single_release \ + }; +#endif + +/* + * Trace events part + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM docg3 + +#if !defined(_MTD_DOCG3_TRACE) || defined(TRACE_HEADER_MULTI_READ) +#define _MTD_DOCG3_TRACE + +#include <linux/tracepoint.h> + +TRACE_EVENT(docg3_io, + TP_PROTO(int op, int width, u16 reg, int val), + TP_ARGS(op, width, reg, val), + TP_STRUCT__entry( + __field(int, op) + __field(unsigned char, width) + __field(u16, reg) + __field(int, val)), + TP_fast_assign( + __entry->op = op; + __entry->width = width; + __entry->reg = reg; + __entry->val = val;), + TP_printk("docg3: %s%02d reg=%04x, val=%04x", + __entry->op ? "write" : "read", __entry->width, + __entry->reg, __entry->val) + ); +#endif + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE docg3 +#include <trace/define_trace.h> diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index d374603493a..45116bb3029 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -50,11 +50,6 @@ #include <linux/mtd/nand.h> #include <linux/mtd/doc2000.h> -/* Where to look for the devices? */ -#ifndef CONFIG_MTD_DOCPROBE_ADDRESS -#define CONFIG_MTD_DOCPROBE_ADDRESS 0 -#endif - static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS; module_param(doc_config_location, ulong, 0); diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c index 772a0ff89e0..3a11ea628e5 100644 --- a/drivers/mtd/devices/lart.c +++ b/drivers/mtd/devices/lart.c @@ -34,9 +34,6 @@ /* debugging */ //#define LART_DEBUG -/* partition support */ -#define HAVE_PARTITIONS - #include <linux/kernel.h> #include <linux/module.h> #include <linux/types.h> @@ -44,9 +41,7 @@ #include <linux/errno.h> #include <linux/string.h> #include <linux/mtd/mtd.h> -#ifdef HAVE_PARTITIONS #include <linux/mtd/partitions.h> -#endif #ifndef CONFIG_SA1100_LART #error This is for LART architecture only @@ -598,7 +593,6 @@ static struct mtd_erase_region_info erase_regions[] = { } }; -#ifdef HAVE_PARTITIONS static struct mtd_partition lart_partitions[] = { /* blob */ { @@ -619,7 +613,7 @@ static struct mtd_partition lart_partitions[] = { .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ } }; -#endif +#define NUM_PARTITIONS ARRAY_SIZE(lart_partitions) static int __init lart_flash_init (void) { @@ -668,7 +662,6 @@ static int __init lart_flash_init (void) result,mtd.eraseregions[result].erasesize,mtd.eraseregions[result].erasesize / 1024, result,mtd.eraseregions[result].numblocks); -#ifdef HAVE_PARTITIONS printk ("\npartitions = %d\n", ARRAY_SIZE(lart_partitions)); for (result = 0; result < ARRAY_SIZE(lart_partitions); result++) @@ -681,25 +674,16 @@ static int __init lart_flash_init (void) result,lart_partitions[result].offset, result,lart_partitions[result].size,lart_partitions[result].size / 1024); #endif -#endif -#ifndef HAVE_PARTITIONS - result = mtd_device_register(&mtd, NULL, 0); -#else result = mtd_device_register(&mtd, lart_partitions, ARRAY_SIZE(lart_partitions)); -#endif return (result); } static void __exit lart_flash_exit (void) { -#ifndef HAVE_PARTITIONS - mtd_device_unregister(&mtd); -#else mtd_device_unregister(&mtd); -#endif } module_init (lart_flash_init); diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 35180e475c4..884904d3f9d 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -30,6 +30,7 @@ #include <linux/mtd/cfi.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> +#include <linux/of_platform.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -88,7 +89,6 @@ struct m25p { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - unsigned partitioned:1; u16 page_size; u16 addr_width; u8 erase_opcode; @@ -209,9 +209,8 @@ static int wait_till_ready(struct m25p *flash) */ static int erase_chip(struct m25p *flash) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %lldKiB\n", - dev_name(&flash->spi->dev), __func__, - (long long)(flash->mtd.size >> 10)); + pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__, + (long long)(flash->mtd.size >> 10)); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -250,9 +249,8 @@ static int m25p_cmdsz(struct m25p *flash) */ static int erase_sector(struct m25p *flash, u32 offset) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: %s %dKiB at 0x%08x\n", - dev_name(&flash->spi->dev), __func__, - flash->mtd.erasesize / 1024, offset); + pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev), + __func__, flash->mtd.erasesize / 1024, offset); /* Wait until finished previous write command. */ if (wait_till_ready(flash)) @@ -286,9 +284,9 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr) u32 addr,len; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%llx, len %lld\n", - dev_name(&flash->spi->dev), __func__, "at", - (long long)instr->addr, (long long)instr->len); + pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev), + __func__, (long long)instr->addr, + (long long)instr->len); /* sanity checks */ if (instr->addr + instr->len > flash->mtd.size) @@ -348,9 +346,8 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "from", - (u32)from, len); + pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)from, len); /* sanity checks */ if (!len) @@ -417,9 +414,8 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, struct spi_transfer t[2]; struct spi_message m; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -510,9 +506,8 @@ static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, size_t actual; int cmd_sz, ret; - DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n", - dev_name(&flash->spi->dev), __func__, "to", - (u32)to, len); + pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev), + __func__, (u32)to, len); *retlen = 0; @@ -661,6 +656,7 @@ static const struct spi_device_id m25p_ids[] = { { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, { "at26f004", INFO(0x1f0400, 0, 64 * 1024, 8, SECT_4K) }, @@ -671,6 +667,7 @@ static const struct spi_device_id m25p_ids[] = { /* EON -- en25xxx */ { "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) }, { "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) }, + { "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) }, { "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) }, /* Intel/Numonyx -- xxxs33b */ @@ -788,8 +785,8 @@ static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 5); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", - dev_name(&spi->dev), tmp); + pr_debug("%s: error %d reading JEDEC ID\n", + dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } jedec = id[0]; @@ -825,8 +822,12 @@ static int __devinit m25p_probe(struct spi_device *spi) struct m25p *flash; struct flash_info *info; unsigned i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; + struct mtd_part_parser_data ppdata; + +#ifdef CONFIG_MTD_OF_PARTS + if (!of_device_is_available(spi->dev.of_node)) + return -ENODEV; +#endif /* Platform data helps sort out which chip type we have, as * well as how this board partitions it. If we don't have @@ -928,6 +929,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (info->flags & M25P_NO_ERASE) flash->mtd.flags |= MTD_NO_ERASE; + ppdata.of_node = spi->dev.of_node; flash->mtd.dev.parent = &spi->dev; flash->page_size = info->page_size; @@ -945,8 +947,7 @@ static int __devinit m25p_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -955,8 +956,7 @@ static int __devinit m25p_probe(struct spi_device *spi) if (flash->mtd.numeraseregions) for (i = 0; i < flash->mtd.numeraseregions; i++) - DEBUG(MTD_DEBUG_LEVEL2, - "mtd.eraseregions[%d] = { .offset = 0x%llx, " + pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, " ".erasesize = 0x%.8x (%uKiB), " ".numblocks = %d }\n", i, (long long)flash->mtd.eraseregions[i].offset, @@ -968,41 +968,9 @@ static int __devinit m25p_probe(struct spi_device *spi) /* partitions should match sector boundaries; and it may be good to * use readonly partitions for writeprotected sectors (BP2..BP0). */ - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] - = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, &parts, 0); - } - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - -#ifdef CONFIG_MTD_OF_PARTS - if (nr_parts <= 0 && spi->dev.of_node) { - nr_parts = of_mtd_parse_partitions(&spi->dev, - spi->dev.of_node, &parts); - } -#endif - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - flash->partitioned = 1; - } - - return mtd_device_register(&flash->mtd, parts, nr_parts) == 1 ? - -ENODEV : 0; + return mtd_device_parse_register(&flash->mtd, NULL, &ppdata, + data ? data->parts : NULL, + data ? data->nr_parts : 0); } diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index 13749d458a3..d75c7af18a6 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -17,6 +17,8 @@ #include <linux/mutex.h> #include <linux/err.h> #include <linux/math64.h> +#include <linux/of.h> +#include <linux/of_device.h> #include <linux/spi/spi.h> #include <linux/spi/flash.h> @@ -24,7 +26,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> - /* * DataFlash is a kind of SPI flash. Most AT45 chips have two buffers in * each chip, which may be used for double buffered I/O; but this driver @@ -98,6 +99,16 @@ struct dataflash { struct mtd_info mtd; }; +#ifdef CONFIG_OF +static const struct of_device_id dataflash_dt_ids[] = { + { .compatible = "atmel,at45", }, + { .compatible = "atmel,dataflash", }, + { /* sentinel */ } +}; +#else +#define dataflash_dt_ids NULL +#endif + /* ......................................................................... */ /* @@ -122,7 +133,7 @@ static int dataflash_waitready(struct spi_device *spi) for (;;) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n", + pr_debug("%s: status %d?\n", dev_name(&spi->dev), status); status = 0; } @@ -149,7 +160,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) uint8_t *command; uint32_t rem; - DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%llx len 0x%llx\n", + pr_debug("%s: erase addr=0x%llx len 0x%llx\n", dev_name(&spi->dev), (long long)instr->addr, (long long)instr->len); @@ -187,7 +198,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) command[2] = (uint8_t)(pageaddr >> 8); command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n", + pr_debug("ERASE %s: (%x) %x %x %x [%i]\n", do_block ? "block" : "page", command[0], command[1], command[2], command[3], pageaddr); @@ -238,8 +249,8 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, uint8_t *command; int status; - DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n", - dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len)); + pr_debug("%s: read 0x%x..0x%x\n", dev_name(&priv->spi->dev), + (unsigned)from, (unsigned)(from + len)); *retlen = 0; @@ -255,7 +266,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, command = priv->command; - DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n", + pr_debug("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); spi_message_init(&msg); @@ -287,7 +298,7 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, *retlen = msg.actual_length - 8; status = 0; } else - DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n", + pr_debug("%s: read %x..%x --> %d\n", dev_name(&priv->spi->dev), (unsigned)from, (unsigned)(from + len), status); @@ -314,7 +325,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, int status = -EINVAL; uint8_t *command; - DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n", + pr_debug("%s: write 0x%x..0x%x\n", dev_name(&spi->dev), (unsigned)to, (unsigned)(to + len)); *retlen = 0; @@ -340,7 +351,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, mutex_lock(&priv->lock); while (remaining > 0) { - DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n", + pr_debug("write @ %i:%i len=%i\n", pageaddr, offset, writelen); /* REVISIT: @@ -368,12 +379,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n", + pr_debug("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n", + pr_debug("%s: xfer %u -> %d\n", dev_name(&spi->dev), addr, status); (void) dataflash_waitready(priv->spi); @@ -386,7 +397,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = (addr & 0x000000FF); - DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n", + pr_debug("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); x[1].tx_buf = writebuf; @@ -395,7 +406,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, status = spi_sync(spi, &msg); spi_transfer_del(x + 1); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n", + pr_debug("%s: pgm %u/%u -> %d\n", dev_name(&spi->dev), addr, writelen, status); (void) dataflash_waitready(priv->spi); @@ -410,12 +421,12 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, command[2] = (addr & 0x0000FF00) >> 8; command[3] = 0; - DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n", + pr_debug("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); status = spi_sync(spi, &msg); if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n", + pr_debug("%s: compare %u -> %d\n", dev_name(&spi->dev), addr, status); status = dataflash_waitready(priv->spi); @@ -634,11 +645,10 @@ add_dataflash_otp(struct spi_device *spi, char *name, { struct dataflash *priv; struct mtd_info *device; + struct mtd_part_parser_data ppdata; struct flash_platform_data *pdata = spi->dev.platform_data; char *otp_tag = ""; int err = 0; - struct mtd_partition *parts; - int nr_parts = 0; priv = kzalloc(sizeof *priv, GFP_KERNEL); if (!priv) @@ -677,28 +687,11 @@ add_dataflash_otp(struct spi_device *spi, char *name, pagesize, otp_tag); dev_set_drvdata(&spi->dev, priv); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = { "cmdlinepart", NULL, }; - - nr_parts = parse_mtd_partitions(device, part_probes, &parts, - 0); - } + ppdata.of_node = spi->dev.of_node; + err = mtd_device_parse_register(device, NULL, &ppdata, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); - if (nr_parts <= 0 && pdata && pdata->parts) { - parts = pdata->parts; - nr_parts = pdata->nr_parts; - } - - if (nr_parts > 0) { - priv->partitioned = 1; - err = mtd_device_register(device, parts, nr_parts); - goto out; - } - - if (mtd_device_register(device, NULL, 0) == 1) - err = -ENODEV; - -out: if (!err) return 0; @@ -787,7 +780,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) */ tmp = spi_write_then_read(spi, &code, 1, id, 3); if (tmp < 0) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID\n", + pr_debug("%s: error %d reading JEDEC ID\n", dev_name(&spi->dev), tmp); return ERR_PTR(tmp); } @@ -804,7 +797,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) tmp < ARRAY_SIZE(dataflash_data); tmp++, info++) { if (info->jedec_id == jedec) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: OTP, sector protect%s\n", + pr_debug("%s: OTP, sector protect%s\n", dev_name(&spi->dev), (info->flags & SUP_POW2PS) ? ", binary pagesize" : "" @@ -812,8 +805,7 @@ static struct flash_info *__devinit jedec_probe(struct spi_device *spi) if (info->flags & SUP_POW2PS) { status = dataflash_status(spi); if (status < 0) { - DEBUG(MTD_DEBUG_LEVEL1, - "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); return ERR_PTR(status); } @@ -878,7 +870,7 @@ static int __devinit dataflash_probe(struct spi_device *spi) */ status = dataflash_status(spi); if (status <= 0 || status == 0xff) { - DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n", + pr_debug("%s: status error %d\n", dev_name(&spi->dev), status); if (status == 0 || status == 0xff) status = -ENODEV; @@ -914,14 +906,14 @@ static int __devinit dataflash_probe(struct spi_device *spi) break; /* obsolete AT45DB1282 not (yet?) supported */ default: - DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n", - dev_name(&spi->dev), status & 0x3c); + pr_debug("%s: unsupported device (%x)\n", dev_name(&spi->dev), + status & 0x3c); status = -ENODEV; } if (status < 0) - DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n", - dev_name(&spi->dev), status); + pr_debug("%s: add_dataflash --> %d\n", dev_name(&spi->dev), + status); return status; } @@ -931,7 +923,7 @@ static int __devexit dataflash_remove(struct spi_device *spi) struct dataflash *flash = dev_get_drvdata(&spi->dev); int status; - DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", dev_name(&spi->dev)); + pr_debug("%s: remove\n", dev_name(&spi->dev)); status = mtd_device_unregister(&flash->mtd); if (status == 0) { @@ -946,6 +938,7 @@ static struct spi_driver dataflash_driver = { .name = "mtd_dataflash", .bus = &spi_bus_type, .owner = THIS_MODULE, + .of_match_table = dataflash_dt_ids, }, .probe = dataflash_probe, diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c index 83e80c65d6e..d38ef3bffe8 100644 --- a/drivers/mtd/devices/sst25l.c +++ b/drivers/mtd/devices/sst25l.c @@ -52,8 +52,6 @@ struct sst25l_flash { struct spi_device *spi; struct mutex lock; struct mtd_info mtd; - - int partitioned; }; struct flash_info { @@ -381,8 +379,6 @@ static int __devinit sst25l_probe(struct spi_device *spi) struct sst25l_flash *flash; struct flash_platform_data *data; int ret, i; - struct mtd_partition *parts = NULL; - int nr_parts = 0; flash_info = sst25l_match_device(spi); if (!flash_info) @@ -414,8 +410,7 @@ static int __devinit sst25l_probe(struct spi_device *spi) dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name, (long long)flash->mtd.size >> 10); - DEBUG(MTD_DEBUG_LEVEL2, - "mtd .name = %s, .size = 0x%llx (%lldMiB) " + pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) " ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n", flash->mtd.name, (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20), @@ -423,37 +418,10 @@ static int __devinit sst25l_probe(struct spi_device *spi) flash->mtd.numeraseregions); - if (mtd_has_cmdlinepart()) { - static const char *part_probes[] = {"cmdlinepart", NULL}; - - nr_parts = parse_mtd_partitions(&flash->mtd, - part_probes, - &parts, 0); - } - - if (nr_parts <= 0 && data && data->parts) { - parts = data->parts; - nr_parts = data->nr_parts; - } - - if (nr_parts > 0) { - for (i = 0; i < nr_parts; i++) { - DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = " - "{.name = %s, .offset = 0x%llx, " - ".size = 0x%llx (%lldKiB) }\n", - i, parts[i].name, - (long long)parts[i].offset, - (long long)parts[i].size, - (long long)(parts[i].size >> 10)); - } - - flash->partitioned = 1; - return mtd_device_register(&flash->mtd, parts, - nr_parts); - } - - ret = mtd_device_register(&flash->mtd, NULL, 0); - if (ret == 1) { + ret = mtd_device_parse_register(&flash->mtd, NULL, 0, + data ? data->parts : NULL, + data ? data->nr_parts : 0); + if (ret) { kfree(flash); dev_set_drvdata(&spi->dev, NULL); return -ENODEV; diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 037b399df3f..c7382bb686c 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -339,7 +339,7 @@ static int erase_xfer(partition_t *part, struct erase_info *erase; xfer = &part->XferInfo[xfernum]; - DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset); xfer->state = XFER_ERASING; /* Is there a free erase slot? Always in MTD. */ @@ -415,7 +415,7 @@ static int prepare_xfer(partition_t *part, int i) xfer = &part->XferInfo[i]; xfer->state = XFER_FAILED; - DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); + pr_debug("ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset); /* Write the transfer unit header */ header = part->header; @@ -476,7 +476,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, eun = &part->EUNInfo[srcunit]; xfer = &part->XferInfo[xferunit]; - DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n", + pr_debug("ftl_cs: copying block 0x%x to 0x%x\n", eun->Offset, xfer->Offset); @@ -598,7 +598,7 @@ static int copy_erase_unit(partition_t *part, uint16_t srcunit, unit with the fewest erases, and usually pick the data unit with the most deleted blocks. But with a small probability, pick the oldest data unit instead. This means that we generally postpone - the next reclaimation as long as possible, but shuffle static + the next reclamation as long as possible, but shuffle static stuff around a bit for wear leveling. ======================================================================*/ @@ -609,8 +609,8 @@ static int reclaim_block(partition_t *part) uint32_t best; int queued, ret; - DEBUG(0, "ftl_cs: reclaiming space...\n"); - DEBUG(3, "NumTransferUnits == %x\n", part->header.NumTransferUnits); + pr_debug("ftl_cs: reclaiming space...\n"); + pr_debug("NumTransferUnits == %x\n", part->header.NumTransferUnits); /* Pick the least erased transfer unit */ best = 0xffffffff; xfer = 0xffff; do { @@ -618,22 +618,22 @@ static int reclaim_block(partition_t *part) for (i = 0; i < part->header.NumTransferUnits; i++) { int n=0; if (part->XferInfo[i].state == XFER_UNKNOWN) { - DEBUG(3,"XferInfo[%d].state == XFER_UNKNOWN\n",i); + pr_debug("XferInfo[%d].state == XFER_UNKNOWN\n",i); n=1; erase_xfer(part, i); } if (part->XferInfo[i].state == XFER_ERASING) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASING\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASING\n",i); n=1; queued = 1; } else if (part->XferInfo[i].state == XFER_ERASED) { - DEBUG(3,"XferInfo[%d].state == XFER_ERASED\n",i); + pr_debug("XferInfo[%d].state == XFER_ERASED\n",i); n=1; prepare_xfer(part, i); } if (part->XferInfo[i].state == XFER_PREPARED) { - DEBUG(3,"XferInfo[%d].state == XFER_PREPARED\n",i); + pr_debug("XferInfo[%d].state == XFER_PREPARED\n",i); n=1; if (part->XferInfo[i].EraseCount <= best) { best = part->XferInfo[i].EraseCount; @@ -641,12 +641,12 @@ static int reclaim_block(partition_t *part) } } if (!n) - DEBUG(3,"XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); + pr_debug("XferInfo[%d].state == %x\n",i, part->XferInfo[i].state); } if (xfer == 0xffff) { if (queued) { - DEBUG(1, "ftl_cs: waiting for transfer " + pr_debug("ftl_cs: waiting for transfer " "unit to be prepared...\n"); if (part->mbd.mtd->sync) part->mbd.mtd->sync(part->mbd.mtd); @@ -656,7 +656,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: no " "suitable transfer units!\n"); else - DEBUG(1, "ftl_cs: reclaim failed: no " + pr_debug("ftl_cs: reclaim failed: no " "suitable transfer units!\n"); return -EIO; @@ -666,7 +666,7 @@ static int reclaim_block(partition_t *part) eun = 0; if ((jiffies % shuffle_freq) == 0) { - DEBUG(1, "ftl_cs: recycling freshest block...\n"); + pr_debug("ftl_cs: recycling freshest block...\n"); best = 0xffffffff; for (i = 0; i < part->DataUnits; i++) if (part->EUNInfo[i].EraseCount <= best) { @@ -686,7 +686,7 @@ static int reclaim_block(partition_t *part) printk(KERN_NOTICE "ftl_cs: reclaim failed: " "no free blocks!\n"); else - DEBUG(1,"ftl_cs: reclaim failed: " + pr_debug("ftl_cs: reclaim failed: " "no free blocks!\n"); return -EIO; @@ -771,7 +771,7 @@ static uint32_t find_free(partition_t *part) printk(KERN_NOTICE "ftl_cs: bad free list!\n"); return 0; } - DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun); + pr_debug("ftl_cs: found free block at %d in %d\n", blk, eun); return blk; } /* find_free */ @@ -791,7 +791,7 @@ static int ftl_read(partition_t *part, caddr_t buffer, int ret; size_t offset, retlen; - DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", + pr_debug("ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -840,7 +840,7 @@ static int set_bam_entry(partition_t *part, uint32_t log_addr, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", + pr_debug("ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n", part, log_addr, virt_addr); bsize = 1 << part->header.EraseUnitSize; eun = log_addr / bsize; @@ -905,7 +905,7 @@ static int ftl_write(partition_t *part, caddr_t buffer, int ret; size_t retlen, offset; - DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n", + pr_debug("ftl_cs: ftl_write(0x%p, %ld, %ld)\n", part, sector, nblocks); if (!(part->state & FTL_FORMATTED)) { printk(KERN_NOTICE "ftl_cs: bad partition\n"); @@ -1011,7 +1011,7 @@ static int ftl_discardsect(struct mtd_blktrans_dev *dev, partition_t *part = (void *)dev; uint32_t bsize = 1 << part->header.EraseUnitSize; - DEBUG(1, "FTL erase sector %ld for %d sectors\n", + pr_debug("FTL erase sector %ld for %d sectors\n", sector, nr_sects); while (nr_sects) { diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index d7592e67d04..dd034efd187 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -63,14 +63,12 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); + pr_debug("INFTL: add_mtd for %s\n", mtd->name); inftl = kzalloc(sizeof(*inftl), GFP_KERNEL); - if (!inftl) { - printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); + if (!inftl) return; - } inftl->mbd.mtd = mtd; inftl->mbd.devnum = -1; @@ -133,7 +131,7 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev) { struct INFTLrecord *inftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("INFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); @@ -154,7 +152,7 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -174,7 +172,7 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & (mtd->writesize - 1); ops.ooblen = len; ops.oobbuf = buf; @@ -194,7 +192,7 @@ static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; @@ -215,16 +213,16 @@ static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) u16 pot = inftl->LastFreeEUN; int silly = inftl->nb_blocks; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=%p," - "desperate=%d)\n", inftl, desperate); + pr_debug("INFTL: INFTL_findfreeblock(inftl=%p,desperate=%d)\n", + inftl, desperate); /* * Normally, we force a fold to happen before we run out of free * blocks completely. */ if (!desperate && inftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " - "EUNs (%d)\n", inftl->numfreeEUNs); + pr_debug("INFTL: there are too few free EUNs (%d)\n", + inftl->numfreeEUNs); return BLOCK_NIL; } @@ -259,8 +257,8 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned struct inftl_oob oob; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d," - "pending=%d)\n", inftl, thisVUC, pendingblock); + pr_debug("INFTL: INFTL_foldchain(inftl=%p,thisVUC=%d,pending=%d)\n", + inftl, thisVUC, pendingblock); memset(BlockMap, 0xff, sizeof(BlockMap)); memset(BlockDeleted, 0, sizeof(BlockDeleted)); @@ -323,8 +321,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * Chain, and the Erase Unit into which we are supposed to be copying. * Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", - thisVUC, targetEUN); + pr_debug("INFTL: folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { unsigned char movebuf[SECTORSIZE]; @@ -349,14 +346,13 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (inftl->EraseSize * BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, &retlen, movebuf); if (ret != -EIO) - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " - "away on retry?\n"); + pr_debug("INFTL: error went away on retry?\n"); } memset(&oob, 0xff, sizeof(struct inftl_oob)); oob.b.Status = oob.b.Status1 = SECTOR_USED; @@ -372,8 +368,7 @@ static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned * is important, by doing oldest first if we crash/reboot then it * it is relatively simple to clean up the mess). */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", - thisVUC); + pr_debug("INFTL: want to erase virtual chain %d\n", thisVUC); for (;;) { /* Find oldest unit in chain. */ @@ -421,7 +416,7 @@ static u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) u16 ChainLength = 0, thislen; u16 chain, EUN; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=%p," + pr_debug("INFTL: INFTL_makefreeblock(inftl=%p," "pending=%d)\n", inftl, pendingblock); for (chain = 0; chain < inftl->nb_blocks; chain++) { @@ -484,8 +479,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) size_t retlen; int silly, silly2 = 3; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_findwriteunit(inftl=%p,block=%d)\n", + inftl, block); do { /* @@ -501,8 +496,8 @@ static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) blockofs, 8, &retlen, (char *)&bci); status = bci.Status | bci.Status1; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " - "EUN %d is %x\n", block , writeEUN, status); + pr_debug("INFTL: status of block %d in EUN %d is %x\n", + block , writeEUN, status); switch(status) { case SECTOR_FREE: @@ -555,9 +550,9 @@ hitused: * Hopefully we free something, lets try again. * This time we are desperate... */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " - "to find free EUN to accommodate write to " - "VUC %d\n", thisVUC); + pr_debug("INFTL: using desperate==1 to find free EUN " + "to accommodate write to VUC %d\n", + thisVUC); writeEUN = INFTL_findfreeblock(inftl, 1); if (writeEUN == BLOCK_NIL) { /* @@ -647,7 +642,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=%p," + pr_debug("INFTL: INFTL_trydeletechain(inftl=%p," "thisVUC=%d)\n", inftl, thisVUC); memset(BlockUsed, 0, sizeof(BlockUsed)); @@ -711,7 +706,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) * For each block in the chain free it and make it available * for future use. Erase from the oldest unit first. */ - DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); + pr_debug("INFTL: deleting empty VUC %d\n", thisVUC); for (;;) { u16 *prevEUN = &inftl->VUtable[thisVUC]; @@ -719,7 +714,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) /* If the chain is all gone already, we're done */ if (thisEUN == BLOCK_NIL) { - DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); + pr_debug("INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); return; } @@ -731,7 +726,7 @@ static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) thisEUN = *prevEUN; } - DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", + pr_debug("Deleting EUN %d from VUC %d\n", thisEUN, thisVUC); if (INFTL_formatblock(inftl, thisEUN) < 0) { @@ -767,7 +762,7 @@ static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) size_t retlen; struct inftl_bci bci; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=%p," + pr_debug("INFTL: INFTL_deleteblock(inftl=%p," "block=%d)\n", inftl, block); while (thisEUN < inftl->nb_blocks) { @@ -826,7 +821,7 @@ static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_oob oob; char *p, *pend; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_writeblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); /* Is block all zero? */ @@ -876,7 +871,7 @@ static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, struct inftl_bci bci; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=%p,block=%ld," + pr_debug("INFTL: inftl_readblock(inftl=%p,block=%ld," "buffer=%p)\n", inftl, block, buffer); while (thisEUN < inftl->nb_blocks) { @@ -922,7 +917,7 @@ foundit: int ret = mtd->read(mtd, ptr, SECTORSIZE, &retlen, buffer); /* Handle corrected bit flips gracefully */ - if (ret < 0 && ret != -EUCLEAN) + if (ret < 0 && !mtd_is_bitflip(ret)) return -EIO; } return 0; diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 104052e774b..2ff601f816c 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -53,7 +53,7 @@ static int find_boot_record(struct INFTLrecord *inftl) struct INFTLPartition *ip; size_t retlen; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=%p)\n", inftl); + pr_debug("INFTL: find_boot_record(inftl=%p)\n", inftl); /* * Assume logical EraseSize == physical erasesize for starting the @@ -139,24 +139,20 @@ static int find_boot_record(struct INFTLrecord *inftl) mh->FormatFlags = le32_to_cpu(mh->FormatFlags); mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk("INFTL: Media Header ->\n" - " bootRecordID = %s\n" - " NoOfBootImageBlocks = %d\n" - " NoOfBinaryPartitions = %d\n" - " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" - " FormatFlgs = %d\n" - " OsakVersion = 0x%x\n" - " PercentUsed = %d\n", - mh->bootRecordID, mh->NoOfBootImageBlocks, - mh->NoOfBinaryPartitions, - mh->NoOfBDTLPartitions, - mh->BlockMultiplierBits, mh->FormatFlags, - mh->OsakVersion, mh->PercentUsed); - } -#endif + pr_debug("INFTL: Media Header ->\n" + " bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = 0x%x\n" + " PercentUsed = %d\n", + mh->bootRecordID, mh->NoOfBootImageBlocks, + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->BlockMultiplierBits, mh->FormatFlags, + mh->OsakVersion, mh->PercentUsed); if (mh->NoOfBDTLPartitions == 0) { printk(KERN_WARNING "INFTL: Media Header sanity check " @@ -200,19 +196,15 @@ static int find_boot_record(struct INFTLrecord *inftl) ip->spareUnits = le32_to_cpu(ip->spareUnits); ip->Reserved0 = le32_to_cpu(ip->Reserved0); -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { - printk(" PARTITION[%d] ->\n" - " virtualUnits = %d\n" - " firstUnit = %d\n" - " lastUnit = %d\n" - " flags = 0x%x\n" - " spareUnits = %d\n", - i, ip->virtualUnits, ip->firstUnit, - ip->lastUnit, ip->flags, - ip->spareUnits); - } -#endif + pr_debug(" PARTITION[%d] ->\n" + " virtualUnits = %d\n" + " firstUnit = %d\n" + " lastUnit = %d\n" + " flags = 0x%x\n" + " spareUnits = %d\n", + i, ip->virtualUnits, ip->firstUnit, + ip->lastUnit, ip->flags, + ip->spareUnits); if (ip->Reserved0 != ip->firstUnit) { struct erase_info *instr = &inftl->instr; @@ -375,7 +367,7 @@ static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int INFTL_formatblock(struct INFTLrecord *inftl, int block) { @@ -385,8 +377,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block) struct mtd_info *mtd = inftl->mbd.mtd; int physblock; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p," - "block=%d)\n", inftl, block); + pr_debug("INFTL: INFTL_formatblock(inftl=%p,block=%d)\n", inftl, block); memset(instr, 0, sizeof(struct erase_info)); @@ -476,30 +467,30 @@ void INFTL_dumptables(struct INFTLrecord *s) { int i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("VUtable[%d] ->", s->nb_blocks); + pr_debug("VUtable[%d] ->", s->nb_blocks); for (i = 0; i < s->nb_blocks; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->VUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->VUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); + pr_debug("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); for (i = 0; i <= s->lastEUN; i++) { if ((i % 8) == 0) - printk("\n%04x: ", i); - printk("%04x ", s->PUtable[i]); + pr_debug("\n%04x: ", i); + pr_debug("%04x ", s->PUtable[i]); } - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); - printk("INFTL ->\n" + pr_debug("INFTL ->\n" " EraseSize = %d\n" " h/s/c = %d/%d/%d\n" " numvunits = %d\n" @@ -513,7 +504,7 @@ void INFTL_dumptables(struct INFTLrecord *s) s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); - printk("\n-------------------------------------------" + pr_debug("\n-------------------------------------------" "----------------------------------\n"); } @@ -521,25 +512,25 @@ void INFTL_dumpVUchains(struct INFTLrecord *s) { int logical, block, i; - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); - printk("INFTL Virtual Unit Chains:\n"); + pr_debug("INFTL Virtual Unit Chains:\n"); for (logical = 0; logical < s->nb_blocks; logical++) { block = s->VUtable[logical]; if (block > s->nb_blocks) continue; - printk(" LOGICAL %d --> %d ", logical, block); + pr_debug(" LOGICAL %d --> %d ", logical, block); for (i = 0; i < s->nb_blocks; i++) { if (s->PUtable[block] == BLOCK_NIL) break; block = s->PUtable[block]; - printk("%d ", block); + pr_debug("%d ", block); } - printk("\n"); + pr_debug("\n"); } - printk("-------------------------------------------" + pr_debug("-------------------------------------------" "----------------------------------\n"); } @@ -555,7 +546,7 @@ int INFTL_mount(struct INFTLrecord *s) int i; u8 *ANACtable, ANAC; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=%p)\n", s); + pr_debug("INFTL: INFTL_mount(inftl=%p)\n", s); /* Search for INFTL MediaHeader and Spare INFTL Media Header */ if (find_boot_record(s) < 0) { @@ -585,7 +576,7 @@ int INFTL_mount(struct INFTLrecord *s) * NOTEXPLORED state. Then at the end we will try to format it and * mark it as free. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); + pr_debug("INFTL: pass 1, explore each unit\n"); for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) continue; @@ -717,17 +708,14 @@ int INFTL_mount(struct INFTLrecord *s) logical_block = BLOCK_NIL; } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); -#endif + INFTL_dumptables(s); /* * Second pass, check for infinite loops in chains. These are * possible because we don't update the previous pointers when * we fold chains. No big deal, just fix them up in PUtable. */ - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); + pr_debug("INFTL: pass 2, validate virtual chains\n"); for (logical_block = 0; logical_block < s->numvunits; logical_block++) { block = s->VUtable[logical_block]; last_block = BLOCK_NIL; @@ -772,12 +760,8 @@ int INFTL_mount(struct INFTLrecord *s) } } -#ifdef CONFIG_MTD_DEBUG_VERBOSE - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumptables(s); - if (CONFIG_MTD_DEBUG_VERBOSE >= 2) - INFTL_dumpVUchains(s); -#endif + INFTL_dumptables(s); + INFTL_dumpVUchains(s); /* * Third pass, format unreferenced blocks and init free block count. @@ -785,7 +769,7 @@ int INFTL_mount(struct INFTLrecord *s) s->numfreeEUNs = 0; s->LastFreeEUN = BLOCK_NIL; - DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); + pr_debug("INFTL: pass 3, format unused blocks\n"); for (block = s->firstEUN; block <= s->lastEUN; block++) { if (s->PUtable[block] == BLOCK_NOTEXPLORED) { printk("INFTL: unreferenced block %d, formatting it\n", diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index c0c328c5b13..8e0c4bf9f7f 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -41,8 +41,6 @@ config MTD_PHYSMAP_START are mapped on your particular target board. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_LEN hex "Physical length of flash mapping" @@ -55,8 +53,6 @@ config MTD_PHYSMAP_LEN than the total amount of flash present. Refer to the memory map which should hopefully be in the documentation for your board. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_BANKWIDTH int "Bank width in octets" @@ -67,8 +63,6 @@ config MTD_PHYSMAP_BANKWIDTH in octets. For example, if you have a data bus width of 32 bits, you would set the bus width octet value to 4. This is used internally by the CFI drivers. - Ignore this option if you use run-time physmap configuration - (i.e., run-time calling physmap_configure()). config MTD_PHYSMAP_OF tristate "Flash device in physical memory map based on OF description" @@ -260,7 +254,6 @@ config MTD_BCM963XX config MTD_LANTIQ tristate "Lantiq SoC NOR support" depends on LANTIQ - select MTD_PARTITIONS help Support for NOR flash attached to the Lantiq SoC's External Bus Unit. @@ -339,10 +332,6 @@ config MTD_SOLUTIONENGINE This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -config MTD_ARM_INTEGRATOR - tristate "CFI Flash device mapped on ARM Integrator/P720T" - depends on ARM && MTD_CFI - config MTD_CDB89712 tristate "Cirrus CDB89712 evaluation board mappings" depends on MTD_CFI && ARCH_CDB89712 @@ -398,13 +387,6 @@ config MTD_AUTCPU12 This enables access to the NV-RAM on autronix autcpu12 board. If you have such a board, say 'Y'. -config MTD_EDB7312 - tristate "CFI Flash device mapped on EDB7312" - depends on ARCH_EDB7312 && MTD_CFI - help - This enables access to the CFI Flash on the Cogent EDB7312 board. - If you have such a board, say 'Y' here. - config MTD_IMPA7 tristate "JEDEC Flash device mapped on impA7" depends on ARM && MTD_JEDECPROBE @@ -412,14 +394,6 @@ config MTD_IMPA7 This enables access to the NOR Flash on the impA7 board of implementa GmbH. If you have such a board, say 'Y' here. -config MTD_CEIVA - tristate "JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame" - depends on MTD_JEDECPROBE && ARCH_CEIVA - help - This enables access to the flash chips on the Ceiva/Polaroid - PhotoMax Digital Picture Frame. - If you have such a device, say 'Y'. - config MTD_H720X tristate "Hynix evaluation board mappings" depends on MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index cb48b11afff..45dcb8b14f2 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -19,7 +19,6 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_MBX860) += mbx860.o -obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o @@ -40,7 +39,6 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o -obj-$(CONFIG_MTD_EDB7312) += edb7312.o obj-$(CONFIG_MTD_IMPA7) += impa7.o obj-$(CONFIG_MTD_FORTUNET) += fortunet.o obj-$(CONFIG_MTD_UCLINUX) += uclinux.o diff --git a/drivers/mtd/maps/bcm963xx-flash.c b/drivers/mtd/maps/bcm963xx-flash.c index 608967fe74c..736ca10ca9f 100644 --- a/drivers/mtd/maps/bcm963xx-flash.c +++ b/drivers/mtd/maps/bcm963xx-flash.c @@ -21,6 +21,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/module.h> #include <linux/mtd/map.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 67815eed2f0..6d6b2b5674e 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -41,7 +41,6 @@ struct async_state { uint32_t flash_ambctl0, flash_ambctl1; uint32_t save_ambctl0, save_ambctl1; unsigned long irq_flags; - struct mtd_partition *parts; }; static void switch_to_flash(struct async_state *state) @@ -165,18 +164,8 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev) return -ENXIO; } - ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); - if (ret > 0) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, ret); - state->parts = pdata->parts; - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); - mtd_device_register(state->mtd, pdata->parts, pdata->nr_parts); - } else { - pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); - mtd_device_register(state->mtd, NULL, 0); - } + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, state); @@ -188,7 +177,6 @@ static int __devexit bfin_flash_remove(struct platform_device *pdev) struct async_state *state = platform_get_drvdata(pdev); gpio_free(state->enet_flash_pin); mtd_device_unregister(state->mtd); - kfree(state->parts); map_destroy(state->mtd); kfree(state); return 0; diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c deleted file mode 100644 index 06f9c981572..00000000000 --- a/drivers/mtd/maps/ceiva.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Ceiva flash memory driver. - * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net> - * - * Note: this driver supports jedec compatible devices. Modification - * for CFI compatible devices should be straight forward: change - * jedec_probe to cfi_probe. - * - * Based on: sa1100-flash.c, which has the following copyright: - * Flash memory access on SA11x0 based devices - * - * (C) 2000 Nicolas Pitre <nico@fluxnic.net> - * - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/ioport.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/slab.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> -#include <linux/mtd/concat.h> - -#include <mach/hardware.h> -#include <asm/mach-types.h> -#include <asm/io.h> -#include <asm/sizes.h> - -/* - * This isn't complete yet, so... - */ -#define CONFIG_MTD_CEIVA_STATICMAP - -#ifdef CONFIG_MTD_CEIVA_STATICMAP -/* - * See include/linux/mtd/partitions.h for definition of the mtd_partition - * structure. - * - * Please note: - * 1. The flash size given should be the largest flash size that can - * be accommodated. - * - * 2. The bus width must defined in clps_setup_flash. - * - * The MTD layer will detect flash chip aliasing and reduce the size of - * the map accordingly. - * - */ - -#ifdef CONFIG_ARCH_CEIVA -/* Flash / Partition sizing */ -/* For the 28F8003, we use the block mapping to calcuate the sizes */ -#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128)) -#define BOOT_PARTITION_SIZE_KiB (16) -#define PARAMS_PARTITION_SIZE_KiB (8) -#define KERNEL_PARTITION_SIZE_KiB (4*128) -/* Use both remaining portion of first flash, and all of second flash */ -#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128) - -static struct mtd_partition ceiva_partitions[] = { - { - .name = "Ceiva BOOT partition", - .size = BOOT_PARTITION_SIZE_KiB*1024, - .offset = 0, - - },{ - .name = "Ceiva parameters partition", - .size = PARAMS_PARTITION_SIZE_KiB*1024, - .offset = (16 + 8) * 1024, - },{ - .name = "Ceiva kernel partition", - .size = (KERNEL_PARTITION_SIZE_KiB)*1024, - .offset = 0x20000, - - },{ - .name = "Ceiva root filesystem partition", - .offset = MTDPART_OFS_APPEND, - .size = (ROOT_PARTITION_SIZE_KiB)*1024, - } -}; -#endif - -static int __init clps_static_partitions(struct mtd_partition **parts) -{ - int nb_parts = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - *parts = ceiva_partitions; - nb_parts = ARRAY_SIZE(ceiva_partitions); - } -#endif - return nb_parts; -} -#endif - -struct clps_info { - unsigned long base; - unsigned long size; - int width; - void *vbase; - struct map_info *map; - struct mtd_info *mtd; - struct resource *res; -}; - -#define NR_SUBMTD 4 - -static struct clps_info info[NR_SUBMTD]; - -static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd) -{ - struct mtd_info *subdev[nr]; - struct map_info *maps; - int i, found = 0, ret = 0; - - /* - * Allocate the map_info structs in one go. - */ - maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL); - if (!maps) - return -ENOMEM; - /* - * Claim and then map the memory regions. - */ - for (i = 0; i < nr; i++) { - if (clps[i].base == (unsigned long)-1) - break; - - clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash"); - if (!clps[i].res) { - ret = -EBUSY; - break; - } - - clps[i].map = maps + i; - - clps[i].map->name = "clps flash"; - clps[i].map->phys = clps[i].base; - - clps[i].vbase = ioremap(clps[i].base, clps[i].size); - if (!clps[i].vbase) { - ret = -ENOMEM; - break; - } - - clps[i].map->virt = (void __iomem *)clps[i].vbase; - clps[i].map->bankwidth = clps[i].width; - clps[i].map->size = clps[i].size; - - simple_map_init(&clps[i].map); - - clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); - if (clps[i].mtd == NULL) { - ret = -ENXIO; - break; - } - clps[i].mtd->owner = THIS_MODULE; - subdev[i] = clps[i].mtd; - - printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " - "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20, - clps[i].width * 8); - found += 1; - } - - /* - * ENXIO is special. It means we didn't find a chip when - * we probed. We need to tear down the mapping, free the - * resource and mark it as such. - */ - if (ret == -ENXIO) { - iounmap(clps[i].vbase); - clps[i].vbase = NULL; - release_resource(clps[i].res); - clps[i].res = NULL; - } - - /* - * If we found one device, don't bother with concat support. - * If we found multiple devices, use concat if we have it - * available, otherwise fail. - */ - if (ret == 0 || ret == -ENXIO) { - if (found == 1) { - *rmtd = subdev[0]; - ret = 0; - } else if (found > 1) { - /* - * We detected multiple devices. Concatenate - * them together. - */ - *rmtd = mtd_concat_create(subdev, found, - "clps flash"); - if (*rmtd == NULL) - ret = -ENXIO; - } - } - - /* - * If we failed, clean up. - */ - if (ret) { - do { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } while (i--); - - kfree(maps); - } - - return ret; -} - -static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd) -{ - int i; - - mtd_device_unregister(mtd); - - if (mtd != clps[0].mtd) - mtd_concat_destroy(mtd); - - for (i = NR_SUBMTD; i >= 0; i--) { - if (clps[i].mtd) - map_destroy(clps[i].mtd); - if (clps[i].vbase) - iounmap(clps[i].vbase); - if (clps[i].res) - release_resource(clps[i].res); - } - kfree(clps[0].map); -} - -/* - * We define the memory space, size, and width for the flash memory - * space here. - */ - -static int __init clps_setup_flash(void) -{ - int nr = 0; - -#ifdef CONFIG_ARCH_CEIVA - if (machine_is_ceiva()) { - info[0].base = CS0_PHYS_BASE; - info[0].size = SZ_32M; - info[0].width = CEIVA_FLASH_WIDTH; - info[1].base = CS1_PHYS_BASE; - info[1].size = SZ_32M; - info[1].width = CEIVA_FLASH_WIDTH; - nr = 2; - } -#endif - return nr; -} - -static struct mtd_partition *parsed_parts; -static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; - -static void __init clps_locate_partitions(struct mtd_info *mtd) -{ - const char *part_type = NULL; - int nr_parts = 0; - do { - /* - * Partition selection stuff. - */ - nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); - if (nr_parts > 0) { - part_type = "command line"; - break; - } -#ifdef CONFIG_MTD_CEIVA_STATICMAP - nr_parts = clps_static_partitions(&parsed_parts); - if (nr_parts > 0) { - part_type = "static"; - break; - } - printk("found: %d partitions\n", nr_parts); -#endif - } while (0); - - if (nr_parts == 0) { - printk(KERN_NOTICE "clps flash: no partition info " - "available, registering whole flash\n"); - mtd_device_register(mtd, NULL, 0); - } else { - printk(KERN_NOTICE "clps flash: using %s partition " - "definition\n", part_type); - mtd_device_register(mtd, parsed_parts, nr_parts); - } - - /* Always succeeds. */ -} - -static void __exit clps_destroy_partitions(void) -{ - kfree(parsed_parts); -} - -static struct mtd_info *mymtd; - -static int __init clps_mtd_init(void) -{ - int ret; - int nr; - - nr = clps_setup_flash(); - if (nr < 0) - return nr; - - ret = clps_setup_mtd(info, nr, &mymtd); - if (ret) - return ret; - - clps_locate_partitions(mymtd); - - return 0; -} - -static void __exit clps_mtd_cleanup(void) -{ - clps_destroy_mtd(info, mymtd); - clps_destroy_partitions(); -} - -module_init(clps_mtd_init); -module_exit(clps_mtd_cleanup); - -MODULE_AUTHOR("Rob Scott"); -MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 7a9e1989c97..f43b365b848 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -145,14 +145,10 @@ static struct map_info dc21285_map = { /* Partition stuff */ -static struct mtd_partition *dc21285_parts; static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_dc21285(void) { - - int nrparts; - /* Determine bankwidth */ switch (*CSR_SA110_CNTL & (3<<14)) { case SA110_CNTL_ROMWIDTH_8: @@ -200,8 +196,7 @@ static int __init init_dc21285(void) dc21285_mtd->owner = THIS_MODULE; - nrparts = parse_mtd_partitions(dc21285_mtd, probes, &dc21285_parts, 0); - mtd_device_register(dc21285_mtd, dc21285_parts, nrparts); + mtd_device_parse_register(dc21285_mtd, probes, 0, NULL, 0); if(machine_is_ebsa285()) { /* @@ -224,8 +219,6 @@ static int __init init_dc21285(void) static void __exit cleanup_dc21285(void) { mtd_device_unregister(dc21285_mtd); - if (dc21285_parts) - kfree(dc21285_parts); map_destroy(dc21285_mtd); iounmap(dc21285_map.virt); } diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c deleted file mode 100644 index fe42a212bb3..00000000000 --- a/drivers/mtd/maps/edb7312.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Handle mapping of the NOR flash on Cogent EDB7312 boards - * - * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - -#define WINDOW_ADDR 0x00000000 /* physical properties of flash */ -#define WINDOW_SIZE 0x01000000 -#define BUSWIDTH 2 -#define FLASH_BLOCKSIZE_MAIN 0x20000 -#define FLASH_NUMBLOCKS_MAIN 128 -/* can be "cfi_probe", "jedec_probe", "map_rom", NULL }; */ -#define PROBETYPES { "cfi_probe", NULL } - -#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */ -#define MTDID "edb7312-nor" /* for mtdparts= partitioning */ - -static struct mtd_info *mymtd; - -struct map_info edb7312nor_map = { - .name = "NOR flash on EDB7312", - .size = WINDOW_SIZE, - .bankwidth = BUSWIDTH, - .phys = WINDOW_ADDR, -}; - -/* - * MTD partitioning stuff - */ -static struct mtd_partition static_partitions[3] = -{ - { - .name = "ARMboot", - .size = 0x40000, - .offset = 0 - }, - { - .name = "Kernel", - .size = 0x200000, - .offset = 0x40000 - }, - { - .name = "RootFS", - .size = 0xDC0000, - .offset = 0x240000 - }, -}; - -static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - -static int mtd_parts_nb = 0; -static struct mtd_partition *mtd_parts = 0; - -static int __init init_edb7312nor(void) -{ - static const char *rom_probe_types[] = PROBETYPES; - const char **type; - const char *part_type = 0; - - printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", - WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!edb7312nor_map.virt) { - printk(MSG_PREFIX "failed to ioremap\n"); - return -EIO; - } - - simple_map_init(&edb7312nor_map); - - mymtd = 0; - type = rom_probe_types; - for(; !mymtd && *type; type++) { - mymtd = do_map_probe(*type, &edb7312nor_map); - } - if (mymtd) { - mymtd->owner = THIS_MODULE; - - mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); - if (mtd_parts_nb > 0) - part_type = "detected"; - - if (mtd_parts_nb == 0) { - mtd_parts = static_partitions; - mtd_parts_nb = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - if (mtd_parts_nb == 0) - printk(KERN_NOTICE MSG_PREFIX "no partition info available\n"); - else - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", part_type); - /* Register the whole device first. */ - mtd_device_register(mymtd, NULL, 0); - mtd_device_register(mymtd, mtd_parts, mtd_parts_nb); - return 0; - } - - iounmap((void *)edb7312nor_map.virt); - return -ENXIO; -} - -static void __exit cleanup_edb7312nor(void) -{ - if (mymtd) { - mtd_device_unregister(mymtd); - map_destroy(mymtd); - } - if (edb7312nor_map.virt) { - iounmap((void *)edb7312nor_map.virt); - edb7312nor_map.virt = 0; - } -} - -module_init(init_edb7312nor); -module_exit(cleanup_edb7312nor); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("Generic configurable MTD map driver"); diff --git a/drivers/mtd/maps/gpio-addr-flash.c b/drivers/mtd/maps/gpio-addr-flash.c index 7568c5f8b8a..1ec66f031c5 100644 --- a/drivers/mtd/maps/gpio-addr-flash.c +++ b/drivers/mtd/maps/gpio-addr-flash.c @@ -187,7 +187,6 @@ static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; */ static int __devinit gpio_flash_probe(struct platform_device *pdev) { - int nr_parts; size_t i, arr_size; struct physmap_flash_data *pdata; struct resource *memory; @@ -252,20 +251,9 @@ static int __devinit gpio_flash_probe(struct platform_device *pdev) return -ENXIO; } - nr_parts = parse_mtd_partitions(state->mtd, part_probe_types, - &pdata->parts, 0); - if (nr_parts > 0) { - pr_devinit(KERN_NOTICE PFX "Using commandline partition definition\n"); - kfree(pdata->parts); - } else if (pdata->nr_parts) { - pr_devinit(KERN_NOTICE PFX "Using board partition definition\n"); - nr_parts = pdata->nr_parts; - } else { - pr_devinit(KERN_NOTICE PFX "no partition info available, registering whole flash at once\n"); - nr_parts = 0; - } - mtd_device_register(state->mtd, pdata->parts, nr_parts); + mtd_device_parse_register(state->mtd, part_probe_types, 0, + pdata->parts, pdata->nr_parts); return 0; } diff --git a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c index 7f035860a36..49c14187fc6 100644 --- a/drivers/mtd/maps/h720x-flash.c +++ b/drivers/mtd/maps/h720x-flash.c @@ -58,18 +58,11 @@ static struct mtd_partition h720x_partitions[] = { #define NUM_PARTITIONS ARRAY_SIZE(h720x_partitions) -static int nr_mtd_parts; -static struct mtd_partition *mtd_parts; -static const char *probes[] = { "cmdlinepart", NULL }; - /* * Initialize FLASH support */ static int __init h720x_mtd_init(void) { - - char *part_type = NULL; - h720x_map.virt = ioremap(h720x_map.phys, h720x_map.size); if (!h720x_map.virt) { @@ -92,16 +85,8 @@ static int __init h720x_mtd_init(void) if (mymtd) { mymtd->owner = THIS_MODULE; - nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); - if (nr_mtd_parts > 0) - part_type = "command line"; - if (nr_mtd_parts <= 0) { - mtd_parts = h720x_partitions; - nr_mtd_parts = NUM_PARTITIONS; - part_type = "builtin"; - } - printk(KERN_INFO "Using %s partition table\n", part_type); - mtd_device_register(mymtd, mtd_parts, nr_mtd_parts); + mtd_device_parse_register(mymtd, NULL, 0, + h720x_partitions, NUM_PARTITIONS); return 0; } @@ -120,10 +105,6 @@ static void __exit h720x_mtd_cleanup(void) map_destroy(mymtd); } - /* Free partition info, if commandline partition was used */ - if (mtd_parts && (mtd_parts != h720x_partitions)) - kfree (mtd_parts); - if (h720x_map.virt) { iounmap((void *)h720x_map.virt); h720x_map.virt = 0; diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c index 404a50cbafa..f47aedb2436 100644 --- a/drivers/mtd/maps/impa7.c +++ b/drivers/mtd/maps/impa7.c @@ -49,7 +49,7 @@ static struct map_info impa7_map[NUM_FLASHBANKS] = { /* * MTD partitioning stuff */ -static struct mtd_partition static_partitions[] = +static struct mtd_partition partitions[] = { { .name = "FileSystem", @@ -58,16 +58,10 @@ static struct mtd_partition static_partitions[] = }, }; -static int mtd_parts_nb[NUM_FLASHBANKS]; -static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; - -static const char *probes[] = { "cmdlinepart", NULL }; - static int __init init_impa7(void) { static const char *rom_probe_types[] = PROBETYPES; const char **type; - const char *part_type = 0; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { { WINDOW_ADDR0, WINDOW_SIZE0 }, @@ -97,23 +91,9 @@ static int __init init_impa7(void) if (impa7_mtd[i]) { impa7_mtd[i]->owner = THIS_MODULE; devicesfound++; - mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], - probes, - &mtd_parts[i], - 0); - if (mtd_parts_nb[i] > 0) { - part_type = "command line"; - } else { - mtd_parts[i] = static_partitions; - mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - mtd_device_register(impa7_mtd[i], - mtd_parts[i], mtd_parts_nb[i]); + mtd_device_parse_register(impa7_mtd[i], NULL, 0, + partitions, + ARRAY_SIZE(partitions)); } else iounmap((void *)impa7_map[i].virt); diff --git a/drivers/mtd/maps/intel_vr_nor.c b/drivers/mtd/maps/intel_vr_nor.c index d2f47be8754..08c239604ee 100644 --- a/drivers/mtd/maps/intel_vr_nor.c +++ b/drivers/mtd/maps/intel_vr_nor.c @@ -44,7 +44,6 @@ struct vr_nor_mtd { void __iomem *csr_base; struct map_info map; struct mtd_info *info; - int nr_parts; struct pci_dev *dev; }; @@ -71,13 +70,9 @@ static void __devexit vr_nor_destroy_partitions(struct vr_nor_mtd *p) static int __devinit vr_nor_init_partitions(struct vr_nor_mtd *p) { - struct mtd_partition *parts; - static const char *part_probes[] = { "cmdlinepart", NULL }; - /* register the flash bank */ /* partition the flash bank */ - p->nr_parts = parse_mtd_partitions(p->info, part_probes, &parts, 0); - return mtd_device_register(p->info, parts, p->nr_parts); + return mtd_device_parse_register(p->info, NULL, 0, NULL, 0); } static void __devexit vr_nor_destroy_mtd_setup(struct vr_nor_mtd *p) diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c index 1594a802631..437fcd2f352 100644 --- a/drivers/mtd/maps/ixp2000.c +++ b/drivers/mtd/maps/ixp2000.c @@ -38,7 +38,6 @@ struct ixp2000_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -125,8 +124,6 @@ static int ixp2000_flash_remove(struct platform_device *dev) if (info->map.map_priv_1) iounmap((void *) info->map.map_priv_1); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -229,13 +226,7 @@ static int ixp2000_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, probes, &info->partitions, 0); - if (err > 0) { - err = mtd_device_register(info->mtd, info->partitions, err); - if(err) - dev_err(&dev->dev, "Could not parse partitions\n"); - } - + err = mtd_device_parse_register(info->mtd, probes, 0, NULL, 0); if (err) goto Error; diff --git a/drivers/mtd/maps/ixp4xx.c b/drivers/mtd/maps/ixp4xx.c index 155b21942f4..30409015a3d 100644 --- a/drivers/mtd/maps/ixp4xx.c +++ b/drivers/mtd/maps/ixp4xx.c @@ -145,7 +145,6 @@ static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr) struct ixp4xx_flash_info { struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; struct resource *res; }; @@ -168,8 +167,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev) if (info->map.virt) iounmap(info->map.virt); - kfree(info->partitions); - if (info->res) { release_resource(info->res); kfree(info->res); @@ -185,8 +182,6 @@ static int ixp4xx_flash_probe(struct platform_device *dev) { struct flash_platform_data *plat = dev->dev.platform_data; struct ixp4xx_flash_info *info; - const char *part_type = NULL; - int nr_parts = 0; int err = -1; if (!plat) @@ -252,28 +247,12 @@ static int ixp4xx_flash_probe(struct platform_device *dev) /* Use the fast version */ info->map.write = ixp4xx_write16; - nr_parts = parse_mtd_partitions(info->mtd, probes, &info->partitions, - dev->resource->start); - if (nr_parts > 0) { - part_type = "dynamic"; - } else { - info->partitions = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - if (nr_parts == 0) - printk(KERN_NOTICE "IXP4xx flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "IXP4xx flash: using %s partition " - "definition\n", part_type); - - err = mtd_device_register(info->mtd, info->partitions, nr_parts); - if (err) + err = mtd_device_parse_register(info->mtd, probes, dev->resource->start, + plat->parts, plat->nr_parts); + if (err) { printk(KERN_ERR "Could not parse partitions\n"); - - if (err) goto Error; + } return 0; diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index 7e508969239..4f10e27ada5 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -107,16 +107,12 @@ ltq_copy_to(struct map_info *map, unsigned long to, spin_unlock_irqrestore(&ebu_lock, flags); } -static const char const *part_probe_types[] = { "cmdlinepart", NULL }; - static int __init ltq_mtd_probe(struct platform_device *pdev) { struct physmap_flash_data *ltq_mtd_data = dev_get_platdata(&pdev->dev); struct ltq_mtd *ltq_mtd; - struct mtd_partition *parts; struct resource *res; - int nr_parts = 0; struct cfi_private *cfi; int err; @@ -172,17 +168,8 @@ ltq_mtd_probe(struct platform_device *pdev) cfi->addr_unlock1 ^= 1; cfi->addr_unlock2 ^= 1; - nr_parts = parse_mtd_partitions(ltq_mtd->mtd, - part_probe_types, &parts, 0); - if (nr_parts > 0) { - dev_info(&pdev->dev, - "using %d partitions from cmdline", nr_parts); - } else { - nr_parts = ltq_mtd_data->nr_parts; - parts = ltq_mtd_data->parts; - } - - err = mtd_device_register(ltq_mtd->mtd, parts, nr_parts); + err = mtd_device_parse_register(ltq_mtd->mtd, NULL, 0, + ltq_mtd_data->parts, ltq_mtd_data->nr_parts); if (err) { dev_err(&pdev->dev, "failed to add partitions\n"); goto err_destroy; diff --git a/drivers/mtd/maps/latch-addr-flash.c b/drivers/mtd/maps/latch-addr-flash.c index 5936c466e90..119baa7d747 100644 --- a/drivers/mtd/maps/latch-addr-flash.c +++ b/drivers/mtd/maps/latch-addr-flash.c @@ -33,9 +33,6 @@ struct latch_addr_flash_info { /* cache; could be found out of res */ unsigned long win_mask; - int nr_parts; - struct mtd_partition *parts; - spinlock_t lock; }; @@ -97,8 +94,6 @@ static void lf_copy_from(struct map_info *map, void *to, static char *rom_probe_types[] = { "cfi_probe", NULL }; -static char *part_probe_types[] = { "cmdlinepart", NULL }; - static int latch_addr_flash_remove(struct platform_device *dev) { struct latch_addr_flash_info *info; @@ -112,8 +107,6 @@ static int latch_addr_flash_remove(struct platform_device *dev) latch_addr_data = dev->dev.platform_data; if (info->mtd != NULL) { - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -206,21 +199,8 @@ static int __devinit latch_addr_flash_probe(struct platform_device *dev) } info->mtd->owner = THIS_MODULE; - err = parse_mtd_partitions(info->mtd, (const char **)part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - return 0; - } - if (latch_addr_data->nr_parts) { - pr_notice("Using latch-addr-flash partition information\n"); - mtd_device_register(info->mtd, - latch_addr_data->parts, - latch_addr_data->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + mtd_device_parse_register(info->mtd, NULL, 0, + latch_addr_data->parts, latch_addr_data->nr_parts); return 0; iounmap: diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index bbe168b65c2..e8e9fec2355 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c @@ -22,22 +22,6 @@ #include <linux/mtd/map.h> #include <linux/mtd/mtd.h> -#ifdef CONFIG_MTD_DEBUG -static int debug = CONFIG_MTD_DEBUG_VERBOSE; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy"); -#undef DEBUG -#define DEBUG(n, format, arg...) \ - if (n <= debug) { \ - printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \ - } - -#else -#undef DEBUG -#define DEBUG(n, arg...) -static const int debug = 0; -#endif - #define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg) #define DRIVER_DESC "PCMCIA Flash memory card driver" @@ -105,13 +89,13 @@ static caddr_t remap_window(struct map_info *map, unsigned long to) int ret; if (!pcmcia_dev_present(dev->p_dev)) { - DEBUG(1, "device removed"); + pr_debug("device removed\n"); return 0; } offset = to & ~(dev->win_size-1); if (offset != dev->offset) { - DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x", + pr_debug("Remapping window from 0x%8.8x to 0x%8.8x\n", dev->offset, offset); ret = pcmcia_map_mem_page(dev->p_dev, win, offset); if (ret != 0) @@ -132,7 +116,7 @@ static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, addr, d.x[0]); return d; } @@ -147,7 +131,7 @@ static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(addr); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", ofs, addr, d.x[0]); + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, addr, d.x[0]); return d; } @@ -157,7 +141,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); while(len) { int toread = win_size - (from & (win_size-1)); caddr_t addr; @@ -169,7 +153,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread); + pr_debug("memcpy from %p to %p len = %d\n", addr, to, toread); memcpy_fromio(to, addr, toread); len -= toread; to += toread; @@ -185,7 +169,7 @@ static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, addr, d.x[0]); writeb(d.x[0], addr); } @@ -196,7 +180,7 @@ static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long if(!addr) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", adr, addr, d.x[0]); + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, addr, d.x[0]); writew(d.x[0], addr); } @@ -206,7 +190,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; unsigned long win_size = dev->win_size; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); while(len) { int towrite = win_size - (to & (win_size-1)); caddr_t addr; @@ -218,7 +202,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v if(!addr) return; - DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite); + pr_debug("memcpy from %p to %p len = %d\n", from, addr, towrite); memcpy_toio(addr, from, towrite); len -= towrite; to += towrite; @@ -240,7 +224,7 @@ static map_word pcmcia_read8(struct map_info *map, unsigned long ofs) return d; d.x[0] = readb(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -255,7 +239,7 @@ static map_word pcmcia_read16(struct map_info *map, unsigned long ofs) return d; d.x[0] = readw(win_base + ofs); - DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04lx", + pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, win_base + ofs, d.x[0]); return d; } @@ -268,7 +252,7 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %p from = %lu len = %zd", to, from, len); + pr_debug("to = %p from = %lu len = %zd\n", to, from, len); memcpy_fromio(to, win_base + from, len); } @@ -280,7 +264,7 @@ static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%02lx\n", adr, win_base + adr, d.x[0]); writeb(d.x[0], win_base + adr); } @@ -293,7 +277,7 @@ static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr) if(DEV_REMOVED(map)) return; - DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04lx", + pr_debug("adr = 0x%08lx (%p) data = 0x%04lx\n", adr, win_base + adr, d.x[0]); writew(d.x[0], win_base + adr); } @@ -306,7 +290,7 @@ static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *f if(DEV_REMOVED(map)) return; - DEBUG(3, "to = %lu from = %p len = %zd", to, from, len); + pr_debug("to = %lu from = %p len = %zd\n", to, from, len); memcpy_toio(win_base + to, from, len); } @@ -316,7 +300,7 @@ static void pcmciamtd_set_vpp(struct map_info *map, int on) struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1; struct pcmcia_device *link = dev->p_dev; - DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp); + pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp); pcmcia_fixup_vpp(link, on ? dev->vpp : 0); } @@ -325,7 +309,7 @@ static void pcmciamtd_release(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link = 0x%p", link); + pr_debug("link = 0x%p\n", link); if (link->resource[2]->end) { if(dev->win_base) { @@ -337,7 +321,6 @@ static void pcmciamtd_release(struct pcmcia_device *link) } -#ifdef CONFIG_MTD_DEBUG static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, tuple_t *tuple, void *priv_data) @@ -347,7 +330,7 @@ static int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_format_t *t = &parse.format; (void)t; /* Shut up, gcc */ - DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u", + pr_debug("Format type: %u, Error Detection: %u, offset = %u, length =%u\n", t->type, t->edc, t->offset, t->length); } return -ENOSPC; @@ -363,12 +346,11 @@ static int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev, if (!pcmcia_parse_tuple(tuple, &parse)) { cistpl_jedec_t *t = &parse.jedec; for (i = 0; i < t->nid; i++) - DEBUG(2, "JEDEC: 0x%02x 0x%02x", + pr_debug("JEDEC: 0x%02x 0x%02x\n", t->id[i].mfr, t->id[i].info); } return -ENOSPC; } -#endif static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, tuple_t *tuple, @@ -382,14 +364,14 @@ static int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev, if (pcmcia_parse_tuple(tuple, &parse)) return -EINVAL; - DEBUG(2, "Common memory:"); + pr_debug("Common memory:\n"); dev->pcmcia_map.size = t->dev[0].size; /* from here on: DEBUG only */ for (i = 0; i < t->ndev; i++) { - DEBUG(2, "Region %d, type = %u", i, t->dev[i].type); - DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp); - DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed); - DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size); + pr_debug("Region %d, type = %u\n", i, t->dev[i].type); + pr_debug("Region %d, wp = %u\n", i, t->dev[i].wp); + pr_debug("Region %d, speed = %u ns\n", i, t->dev[i].speed); + pr_debug("Region %d, size = %u bytes\n", i, t->dev[i].size); } return 0; } @@ -409,12 +391,12 @@ static int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev, dev->pcmcia_map.bankwidth = t->geo[0].buswidth; /* from here on: DEBUG only */ for (i = 0; i < t->ngeo; i++) { - DEBUG(2, "region: %d bankwidth = %u", i, t->geo[i].buswidth); - DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block); - DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block); - DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block); - DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition); - DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave); + pr_debug("region: %d bankwidth = %u\n", i, t->geo[i].buswidth); + pr_debug("region: %d erase_block = %u\n", i, t->geo[i].erase_block); + pr_debug("region: %d read_block = %u\n", i, t->geo[i].read_block); + pr_debug("region: %d write_block = %u\n", i, t->geo[i].write_block); + pr_debug("region: %d partition = %u\n", i, t->geo[i].partition); + pr_debug("region: %d interleave = %u\n", i, t->geo[i].interleave); } return 0; } @@ -432,13 +414,11 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if (p_dev->prod_id[i]) strcat(dev->mtd_name, p_dev->prod_id[i]); } - DEBUG(2, "Found name: %s", dev->mtd_name); + pr_debug("Found name: %s\n", dev->mtd_name); } -#ifdef CONFIG_MTD_DEBUG pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL); pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL); -#endif pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev); pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev); @@ -450,12 +430,12 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev if(force_size) { dev->pcmcia_map.size = force_size << 20; - DEBUG(2, "size forced to %dM", force_size); + pr_debug("size forced to %dM\n", force_size); } if(bankwidth) { dev->pcmcia_map.bankwidth = bankwidth; - DEBUG(2, "bankwidth forced to %d", bankwidth); + pr_debug("bankwidth forced to %d\n", bankwidth); } dev->pcmcia_map.name = dev->mtd_name; @@ -464,7 +444,7 @@ static void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev *new_name = 1; } - DEBUG(1, "Device: Size: %lu Width:%d Name: %s", + pr_debug("Device: Size: %lu Width:%d Name: %s\n", dev->pcmcia_map.size, dev->pcmcia_map.bankwidth << 3, dev->mtd_name); } @@ -479,7 +459,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static char *probes[] = { "jedec_probe", "cfi_probe" }; int new_name = 0; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); card_settings(dev, link, &new_name); @@ -512,11 +492,11 @@ static int pcmciamtd_config(struct pcmcia_device *link) do { int ret; - DEBUG(2, "requesting window with size = %luKiB memspeed = %d", + pr_debug("requesting window with size = %luKiB memspeed = %d\n", (unsigned long) resource_size(link->resource[2]) >> 10, mem_speed); ret = pcmcia_request_window(link, link->resource[2], mem_speed); - DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size); + pr_debug("ret = %d dev->win_size = %d\n", ret, dev->win_size); if(ret) { j++; link->resource[2]->start = 0; @@ -524,21 +504,21 @@ static int pcmciamtd_config(struct pcmcia_device *link) force_size << 20 : MAX_PCMCIA_ADDR; link->resource[2]->end >>= j; } else { - DEBUG(2, "Got window of size %luKiB", (unsigned long) + pr_debug("Got window of size %luKiB\n", (unsigned long) resource_size(link->resource[2]) >> 10); dev->win_size = resource_size(link->resource[2]); break; } } while (link->resource[2]->end >= 0x1000); - DEBUG(2, "dev->win_size = %d", dev->win_size); + pr_debug("dev->win_size = %d\n", dev->win_size); if(!dev->win_size) { dev_err(&dev->p_dev->dev, "Cannot allocate memory window\n"); pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); + pr_debug("Allocated a window of %dKiB\n", dev->win_size >> 10); /* Get write protect status */ dev->win_base = ioremap(link->resource[2]->start, @@ -549,7 +529,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) pcmciamtd_release(link); return -ENODEV; } - DEBUG(1, "mapped window dev = %p @ %pR, base = %p", + pr_debug("mapped window dev = %p @ %pR, base = %p\n", dev, link->resource[2], dev->win_base); dev->offset = 0; @@ -564,7 +544,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) } link->config_index = 0; - DEBUG(2, "Setting Configuration"); + pr_debug("Setting Configuration\n"); ret = pcmcia_enable_device(link); if (ret != 0) { if (dev->win_base) { @@ -580,17 +560,17 @@ static int pcmciamtd_config(struct pcmcia_device *link) mtd = do_map_probe("map_rom", &dev->pcmcia_map); } else { for(i = 0; i < ARRAY_SIZE(probes); i++) { - DEBUG(1, "Trying %s", probes[i]); + pr_debug("Trying %s\n", probes[i]); mtd = do_map_probe(probes[i], &dev->pcmcia_map); if(mtd) break; - DEBUG(1, "FAILED: %s", probes[i]); + pr_debug("FAILED: %s\n", probes[i]); } } if(!mtd) { - DEBUG(1, "Can not find an MTD"); + pr_debug("Can not find an MTD\n"); pcmciamtd_release(link); return -ENODEV; } @@ -617,7 +597,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) /* If the memory found is fits completely into the mapped PCMCIA window, use the faster non-remapping read/write functions */ if(mtd->size <= dev->win_size) { - DEBUG(1, "Using non remapping memory functions"); + pr_debug("Using non remapping memory functions\n"); dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base; if (dev->pcmcia_map.bankwidth == 1) { dev->pcmcia_map.read = pcmcia_read8; @@ -645,7 +625,7 @@ static int pcmciamtd_config(struct pcmcia_device *link) static int pcmciamtd_suspend(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_RESUME"); + pr_debug("EVENT_PM_RESUME\n"); /* get_lock(link); */ @@ -654,7 +634,7 @@ static int pcmciamtd_suspend(struct pcmcia_device *dev) static int pcmciamtd_resume(struct pcmcia_device *dev) { - DEBUG(2, "EVENT_PM_SUSPEND"); + pr_debug("EVENT_PM_SUSPEND\n"); /* free_lock(link); */ @@ -666,7 +646,7 @@ static void pcmciamtd_detach(struct pcmcia_device *link) { struct pcmciamtd_dev *dev = link->priv; - DEBUG(3, "link=0x%p", link); + pr_debug("link=0x%p\n", link); if(dev->mtd_info) { mtd_device_unregister(dev->mtd_info); @@ -686,7 +666,7 @@ static int pcmciamtd_probe(struct pcmcia_device *link) /* Create new memory card device */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - DEBUG(1, "dev=0x%p", dev); + pr_debug("dev=0x%p\n", dev); dev->p_dev = link; link->priv = dev; @@ -755,7 +735,7 @@ static int __init init_pcmciamtd(void) static void __exit exit_pcmciamtd(void) { - DEBUG(1, DRIVER_DESC " unloading"); + pr_debug(DRIVER_DESC " unloading"); pcmcia_unregister_driver(&pcmciamtd_driver); } diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c index f64cee4a3bf..66e8200079c 100644 --- a/drivers/mtd/maps/physmap.c +++ b/drivers/mtd/maps/physmap.c @@ -27,8 +27,6 @@ struct physmap_flash_info { struct mtd_info *mtd[MAX_RESOURCES]; struct mtd_info *cmtd; struct map_info map[MAX_RESOURCES]; - int nr_parts; - struct mtd_partition *parts; }; static int physmap_flash_remove(struct platform_device *dev) @@ -46,8 +44,6 @@ static int physmap_flash_remove(struct platform_device *dev) if (info->cmtd) { mtd_device_unregister(info->cmtd); - if (info->nr_parts) - kfree(info->parts); if (info->cmtd != info->mtd[0]) mtd_concat_destroy(info->cmtd); } @@ -175,23 +171,8 @@ static int physmap_flash_probe(struct platform_device *dev) if (err) goto err_out; - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->cmtd, info->parts, err); - info->nr_parts = err; - return 0; - } - - if (physmap_data->nr_parts) { - printk(KERN_NOTICE "Using physmap partition information\n"); - mtd_device_register(info->cmtd, physmap_data->parts, - physmap_data->nr_parts); - return 0; - } - - mtd_device_register(info->cmtd, NULL, 0); - + mtd_device_parse_register(info->cmtd, part_probe_types, 0, + physmap_data->parts, physmap_data->nr_parts); return 0; err_out: @@ -245,21 +226,6 @@ static struct platform_device physmap_flash = { .num_resources = 1, .resource = &physmap_flash_resource, }; - -void physmap_configure(unsigned long addr, unsigned long size, - int bankwidth, void (*set_vpp)(struct map_info *, int)) -{ - physmap_flash_resource.start = addr; - physmap_flash_resource.end = addr + size - 1; - physmap_flash_data.width = bankwidth; - physmap_flash_data.set_vpp = set_vpp; -} - -void physmap_set_partitions(struct mtd_partition *parts, int num_parts) -{ - physmap_flash_data.nr_parts = num_parts; - physmap_flash_data.parts = parts; -} #endif static int __init physmap_init(void) diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index d251d1db129..7d65f9d3e69 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -34,58 +34,10 @@ struct of_flash_list { struct of_flash { struct mtd_info *cmtd; - struct mtd_partition *parts; int list_size; /* number of elements in of_flash_list */ struct of_flash_list list[0]; }; -#define OF_FLASH_PARTS(info) ((info)->parts) -static int parse_obsolete_partitions(struct platform_device *dev, - struct of_flash *info, - struct device_node *dp) -{ - int i, plen, nr_parts; - const struct { - __be32 offset, len; - } *part; - const char *names; - - part = of_get_property(dp, "partitions", &plen); - if (!part) - return 0; /* No partitions found */ - - dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n"); - - nr_parts = plen / sizeof(part[0]); - - info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL); - if (!info->parts) - return -ENOMEM; - - names = of_get_property(dp, "partition-names", &plen); - - for (i = 0; i < nr_parts; i++) { - info->parts[i].offset = be32_to_cpu(part->offset); - info->parts[i].size = be32_to_cpu(part->len) & ~1; - if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */ - info->parts[i].mask_flags = MTD_WRITEABLE; - - if (names && (plen > 0)) { - int len = strlen(names) + 1; - - info->parts[i].name = (char *)names; - plen -= len; - names += len; - } else { - info->parts[i].name = "unnamed"; - } - - part++; - } - - return nr_parts; -} - static int of_flash_remove(struct platform_device *dev) { struct of_flash *info; @@ -101,11 +53,8 @@ static int of_flash_remove(struct platform_device *dev) mtd_concat_destroy(info->cmtd); } - if (info->cmtd) { - if (OF_FLASH_PARTS(info)) - kfree(OF_FLASH_PARTS(info)); + if (info->cmtd) mtd_device_unregister(info->cmtd); - } for (i = 0; i < info->list_size; i++) { if (info->list[i].mtd) @@ -165,7 +114,8 @@ static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev, specifies the list of partition probers to use. If none is given then the default is use. These take precedence over other device tree information. */ -static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL }; +static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", + "ofpart", "ofoldpart", NULL }; static const char ** __devinit of_get_probes(struct device_node *dp) { const char *cp; @@ -218,6 +168,7 @@ static int __devinit of_flash_probe(struct platform_device *dev) int reg_tuple_size; struct mtd_info **mtd_list = NULL; resource_size_t res_size; + struct mtd_part_parser_data ppdata; match = of_match_device(of_flash_match, &dev->dev); if (!match) @@ -331,29 +282,12 @@ static int __devinit of_flash_probe(struct platform_device *dev) if (err) goto err_out; + ppdata.of_node = dp; part_probe_types = of_get_probes(dp); - err = parse_mtd_partitions(info->cmtd, part_probe_types, - &info->parts, 0); - if (err < 0) { - of_free_probes(part_probe_types); - goto err_out; - } + mtd_device_parse_register(info->cmtd, part_probe_types, &ppdata, + NULL, 0); of_free_probes(part_probe_types); - if (err == 0) { - err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts); - if (err < 0) - goto err_out; - } - - if (err == 0) { - err = parse_obsolete_partitions(dev, info, dp); - if (err < 0) - goto err_out; - } - - mtd_device_register(info->cmtd, info->parts, err); - kfree(mtd_list); return 0; diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c index 9ca1eccba4b..45876d0e5b8 100644 --- a/drivers/mtd/maps/plat-ram.c +++ b/drivers/mtd/maps/plat-ram.c @@ -44,8 +44,6 @@ struct platram_info { struct device *dev; struct mtd_info *mtd; struct map_info map; - struct mtd_partition *partitions; - bool free_partitions; struct resource *area; struct platdata_mtd_ram *pdata; }; @@ -95,10 +93,6 @@ static int platram_remove(struct platform_device *pdev) if (info->mtd) { mtd_device_unregister(info->mtd); - if (info->partitions) { - if (info->free_partitions) - kfree(info->partitions); - } map_destroy(info->mtd); } @@ -228,28 +222,19 @@ static int platram_probe(struct platform_device *pdev) /* check to see if there are any available partitions, or wether * to add this device whole */ - if (!pdata->nr_partitions) { - /* try to probe using the supplied probe type */ - if (pdata->probes) { - err = parse_mtd_partitions(info->mtd, pdata->probes, - &info->partitions, 0); - info->free_partitions = 1; - if (err > 0) - err = mtd_device_register(info->mtd, - info->partitions, err); - } - } - /* use the static mapping */ - else - err = mtd_device_register(info->mtd, pdata->partitions, - pdata->nr_partitions); + err = mtd_device_parse_register(info->mtd, pdata->probes, 0, + pdata->partitions, pdata->nr_partitions); if (!err) dev_info(&pdev->dev, "registered mtd device\n"); - /* add the whole device. */ - err = mtd_device_register(info->mtd, NULL, 0); - if (err) - dev_err(&pdev->dev, "failed to register the entire device\n"); + if (pdata->nr_partitions) { + /* add the whole device. */ + err = mtd_device_register(info->mtd, NULL, 0); + if (err) { + dev_err(&pdev->dev, + "failed to register the entire device\n"); + } + } return err; diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 7ae137d4b99..2a25b6789af 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -41,8 +41,6 @@ static void pxa2xx_map_inval_cache(struct map_info *map, unsigned long from, } struct pxa2xx_flash_info { - struct mtd_partition *parts; - int nr_parts; struct mtd_info *mtd; struct map_info map; }; @@ -55,9 +53,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) { struct flash_platform_data *flash = pdev->dev.platform_data; struct pxa2xx_flash_info *info; - struct mtd_partition *parts; struct resource *res; - int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -71,8 +67,6 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) info->map.bankwidth = flash->width; info->map.phys = res->start; info->map.size = resource_size(res); - info->parts = flash->parts; - info->nr_parts = flash->nr_parts; info->map.virt = ioremap(info->map.phys, info->map.size); if (!info->map.virt) { @@ -104,18 +98,7 @@ static int __devinit pxa2xx_flash_probe(struct platform_device *pdev) } info->mtd->owner = THIS_MODULE; - ret = parse_mtd_partitions(info->mtd, probes, &parts, 0); - - if (ret > 0) { - info->nr_parts = ret; - info->parts = parts; - } - - if (!info->nr_parts) - printk("Registering %s as whole device\n", - info->map.name); - - mtd_device_register(info->mtd, info->parts, info->nr_parts); + mtd_device_parse_register(info->mtd, probes, 0, flash->parts, flash->nr_parts); platform_set_drvdata(pdev, info); return 0; @@ -133,7 +116,6 @@ static int __devexit pxa2xx_flash_remove(struct platform_device *dev) iounmap(info->map.virt); if (info->map.cached) iounmap(info->map.cached); - kfree(info->parts); kfree(info); return 0; } diff --git a/drivers/mtd/maps/rbtx4939-flash.c b/drivers/mtd/maps/rbtx4939-flash.c index 761fb459d2c..0237f197fd1 100644 --- a/drivers/mtd/maps/rbtx4939-flash.c +++ b/drivers/mtd/maps/rbtx4939-flash.c @@ -25,8 +25,6 @@ struct rbtx4939_flash_info { struct mtd_info *mtd; struct map_info map; - int nr_parts; - struct mtd_partition *parts; }; static int rbtx4939_flash_remove(struct platform_device *dev) @@ -41,8 +39,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) if (info->mtd) { struct rbtx4939_flash_data *pdata = dev->dev.platform_data; - if (info->nr_parts) - kfree(info->parts); mtd_device_unregister(info->mtd); map_destroy(info->mtd); } @@ -50,7 +46,6 @@ static int rbtx4939_flash_remove(struct platform_device *dev) } static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL }; -static const char *part_probe_types[] = { "cmdlinepart", NULL }; static int rbtx4939_flash_probe(struct platform_device *dev) { @@ -107,22 +102,11 @@ static int rbtx4939_flash_probe(struct platform_device *dev) info->mtd->owner = THIS_MODULE; if (err) goto err_out; + err = mtd_device_parse_register(info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); - err = parse_mtd_partitions(info->mtd, part_probe_types, - &info->parts, 0); - if (err > 0) { - mtd_device_register(info->mtd, info->parts, err); - info->nr_parts = err; - return 0; - } - - if (pdata->nr_parts) { - pr_notice("Using rbtx4939 partition information\n"); - mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); - return 0; - } - - mtd_device_register(info->mtd, NULL, 0); + if (err) + goto err_out; return 0; err_out: diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index a9b5e0e5c4c..fa9c0a9670c 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -131,10 +131,8 @@ struct sa_subdev_info { }; struct sa_info { - struct mtd_partition *parts; struct mtd_info *mtd; int num_subdev; - unsigned int nr_parts; struct sa_subdev_info subdev[0]; }; @@ -231,8 +229,6 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla mtd_concat_destroy(info->mtd); } - kfree(info->parts); - for (i = info->num_subdev - 1; i >= 0; i--) sa1100_destroy_subdev(&info->subdev[i]); kfree(info); @@ -341,10 +337,8 @@ static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static int __devinit sa1100_mtd_probe(struct platform_device *pdev) { struct flash_platform_data *plat = pdev->dev.platform_data; - struct mtd_partition *parts; - const char *part_type = NULL; struct sa_info *info; - int err, nr_parts = 0; + int err; if (!plat) return -ENODEV; @@ -358,26 +352,8 @@ static int __devinit sa1100_mtd_probe(struct platform_device *pdev) /* * Partition selection stuff. */ - nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0); - if (nr_parts > 0) { - info->parts = parts; - part_type = "dynamic"; - } else { - parts = plat->parts; - nr_parts = plat->nr_parts; - part_type = "static"; - } - - if (nr_parts == 0) - printk(KERN_NOTICE "SA1100 flash: no partition info " - "available, registering whole flash\n"); - else - printk(KERN_NOTICE "SA1100 flash: using %s partition " - "definition\n", part_type); - - mtd_device_register(info->mtd, parts, nr_parts); - - info->nr_parts = nr_parts; + mtd_device_parse_register(info->mtd, part_probes, 0, + plat->parts, plat->nr_parts); platform_set_drvdata(pdev, info); err = 0; diff --git a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c index cbf6bade935..496c40704af 100644 --- a/drivers/mtd/maps/solutionengine.c +++ b/drivers/mtd/maps/solutionengine.c @@ -19,8 +19,6 @@ static struct mtd_info *flash_mtd; static struct mtd_info *eprom_mtd; -static struct mtd_partition *parsed_parts; - struct map_info soleng_eprom_map = { .name = "Solution Engine EPROM", .size = 0x400000, @@ -51,12 +49,14 @@ static struct mtd_partition superh_se_partitions[] = { .size = MTDPART_SIZ_FULL, } }; +#define NUM_PARTITIONS ARRAY_SIZE(superh_se_partitions) +#else +#define superh_se_partitions NULL +#define NUM_PARTITIONS 0 #endif /* CONFIG_MTD_SUPERH_RESERVE */ static int __init init_soleng_maps(void) { - int nr_parts = 0; - /* First probe at offset 0 */ soleng_flash_map.phys = 0; soleng_flash_map.virt = (void __iomem *)P2SEGADDR(0); @@ -92,21 +92,8 @@ static int __init init_soleng_maps(void) mtd_device_register(eprom_mtd, NULL, 0); } - nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - -#ifdef CONFIG_MTD_SUPERH_RESERVE - if (nr_parts <= 0) { - printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", - CONFIG_MTD_SUPERH_RESERVE); - parsed_parts = superh_se_partitions; - nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); - } -#endif /* CONFIG_MTD_SUPERH_RESERVE */ - - if (nr_parts > 0) - mtd_device_register(flash_mtd, parsed_parts, nr_parts); - else - mtd_device_register(flash_mtd, NULL, 0); + mtd_device_parse_register(flash_mtd, probes, 0, + superh_se_partitions, NUM_PARTITIONS); return 0; } @@ -118,10 +105,7 @@ static void __exit cleanup_soleng_maps(void) map_destroy(eprom_mtd); } - if (parsed_parts) - mtd_device_unregister(flash_mtd); - else - mtd_device_unregister(flash_mtd); + mtd_device_unregister(flash_mtd); map_destroy(flash_mtd); } diff --git a/drivers/mtd/maps/wr_sbc82xx_flash.c b/drivers/mtd/maps/wr_sbc82xx_flash.c index 901ce968efa..aa7e0cb2893 100644 --- a/drivers/mtd/maps/wr_sbc82xx_flash.c +++ b/drivers/mtd/maps/wr_sbc82xx_flash.c @@ -20,7 +20,6 @@ #include <asm/immap_cpm2.h> static struct mtd_info *sbcmtd[3]; -static struct mtd_partition *sbcmtd_parts[3]; struct map_info sbc82xx_flash_map[3] = { {.name = "Boot flash"}, @@ -101,6 +100,7 @@ static int __init init_sbc82xx_flash(void) for (i=0; i<3; i++) { int8_t flashcs[3] = { 0, 6, 1 }; int nr_parts; + struct mtd_partition *defparts; printk(KERN_NOTICE "PowerQUICC II %s (%ld MiB on CS%d", sbc82xx_flash_map[i].name, @@ -113,7 +113,8 @@ static int __init init_sbc82xx_flash(void) } printk(" at %08lx)\n", sbc82xx_flash_map[i].phys); - sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, sbc82xx_flash_map[i].size); + sbc82xx_flash_map[i].virt = ioremap(sbc82xx_flash_map[i].phys, + sbc82xx_flash_map[i].size); if (!sbc82xx_flash_map[i].virt) { printk("Failed to ioremap\n"); @@ -129,24 +130,20 @@ static int __init init_sbc82xx_flash(void) sbcmtd[i]->owner = THIS_MODULE; - nr_parts = parse_mtd_partitions(sbcmtd[i], part_probes, - &sbcmtd_parts[i], 0); - if (nr_parts > 0) { - mtd_device_register(sbcmtd[i], sbcmtd_parts[i], - nr_parts); - continue; - } - /* No partitioning detected. Use default */ if (i == 2) { - mtd_device_register(sbcmtd[i], NULL, 0); + defparts = NULL; + nr_parts = 0; } else if (i == bigflash) { - mtd_device_register(sbcmtd[i], bigflash_parts, - ARRAY_SIZE(bigflash_parts)); + defparts = bigflash_parts; + nr_parts = ARRAY_SIZE(bigflash_parts); } else { - mtd_device_register(sbcmtd[i], smallflash_parts, - ARRAY_SIZE(smallflash_parts)); + defparts = smallflash_parts; + nr_parts = ARRAY_SIZE(smallflash_parts); } + + mtd_device_parse_register(sbcmtd[i], part_probes, 0, + defparts, nr_parts); } return 0; } @@ -159,12 +156,8 @@ static void __exit cleanup_sbc82xx_flash(void) if (!sbcmtd[i]) continue; - if (i<2 || sbcmtd_parts[i]) - mtd_device_unregister(sbcmtd[i]); - else - mtd_device_unregister(sbcmtd[i]); + mtd_device_unregister(sbcmtd[i]); - kfree(sbcmtd_parts[i]); map_destroy(sbcmtd[i]); iounmap((void *)sbc82xx_flash_map[i].virt); diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index ca385697446..ed8b5e744b1 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -426,6 +426,8 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) new->rq->queuedata = new; blk_queue_logical_block_size(new->rq, tr->blksize); + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, new->rq); + if (tr->discard) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); new->rq->limits.max_discard_sectors = UINT_MAX; diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 3326615ad66..7c1dc908a17 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -44,7 +44,7 @@ struct mtdblk_dev { enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; }; -static struct mutex mtdblks_lock; +static DEFINE_MUTEX(mtdblks_lock); /* * Cache stuff... @@ -119,7 +119,7 @@ static int write_cached_data (struct mtdblk_dev *mtdblk) if (mtdblk->cache_state != STATE_DIRTY) return 0; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" " + pr_debug("mtdblock: writing cached data for \"%s\" " "at 0x%lx, size 0x%x\n", mtd->name, mtdblk->cache_offset, mtdblk->cache_size); @@ -148,7 +148,7 @@ static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -218,7 +218,7 @@ static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, size_t retlen; int ret; - DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", + pr_debug("mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n", mtd->name, pos, len); if (!sect_size) @@ -283,7 +283,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); + pr_debug("mtdblock_open\n"); mutex_lock(&mtdblks_lock); if (mtdblk->count) { @@ -303,7 +303,7 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } @@ -312,7 +312,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) { struct mtdblk_dev *mtdblk = container_of(mbd, struct mtdblk_dev, mbd); - DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); + pr_debug("mtdblock_release\n"); mutex_lock(&mtdblks_lock); @@ -329,7 +329,7 @@ static int mtdblock_release(struct mtd_blktrans_dev *mbd) mutex_unlock(&mtdblks_lock); - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); + pr_debug("ok\n"); return 0; } @@ -389,8 +389,6 @@ static struct mtd_blktrans_ops mtdblock_tr = { static int __init init_mtdblock(void) { - mutex_init(&mtdblks_lock); - return register_mtd_blktrans(&mtdblock_tr); } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 61086ea3cc6..e7dc732ddab 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -43,7 +43,7 @@ static struct vfsmount *mtd_inode_mnt __read_mostly; /* * Data structure to hold the pointer to the mtd device as well - * as mode information ofr various use cases. + * as mode information of various use cases. */ struct mtd_file_info { struct mtd_info *mtd; @@ -86,7 +86,7 @@ static int mtd_open(struct inode *inode, struct file *file) struct mtd_file_info *mfi; struct inode *mtd_ino; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); + pr_debug("MTD_open\n"); /* You can't open the RO devices RW */ if ((file->f_mode & FMODE_WRITE) && (minor & 1)) @@ -151,7 +151,7 @@ static int mtd_close(struct inode *inode, struct file *file) struct mtd_file_info *mfi = file->private_data; struct mtd_info *mtd = mfi->mtd; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); + pr_debug("MTD_close\n"); /* Only sync if opened RW */ if ((file->f_mode & FMODE_WRITE) && mtd->sync) @@ -195,7 +195,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t size_t size = count; char *kbuf; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); + pr_debug("MTD_read\n"); if (*ppos + count > mtd->size) count = mtd->size - *ppos; @@ -211,17 +211,17 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t len = min_t(size_t, count, size); switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; ops.len = len; @@ -233,16 +233,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t default: ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); } - /* Nand returns -EBADMSG on ecc errors, but it returns + /* Nand returns -EBADMSG on ECC errors, but it returns * the data. For our userspace tools it is important - * to dump areas with ecc errors ! + * to dump areas with ECC errors! * For kernel internal usage it also might return -EUCLEAN * to signal the caller that a bitflip has occurred and has * been corrected by the ECC algorithm. * Userspace software which accesses NAND this way * must be aware of the fact that it deals with NAND */ - if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { + if (!ret || mtd_is_bitflip_or_eccerr(ret)) { *ppos += retlen; if (copy_to_user(buf, kbuf, retlen)) { kfree(kbuf); @@ -278,7 +278,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count int ret=0; int len; - DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); + pr_debug("MTD_write\n"); if (*ppos == mtd->size) return -ENOSPC; @@ -302,10 +302,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count } switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: ret = -EROFS; break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (!mtd->write_user_prot_reg) { ret = -EOPNOTSUPP; break; @@ -313,13 +313,14 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.datbuf = kbuf; ops.oobbuf = NULL; + ops.ooboffs = 0; ops.len = len; ret = mtd->write_oob(mtd, *ppos, &ops); @@ -367,13 +368,13 @@ static int otp_select_filemode(struct mtd_file_info *mfi, int mode) if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_FACTORY; + mfi->mode = MTD_FILE_MODE_OTP_FACTORY; break; case MTD_OTP_USER: if (!mtd->read_fact_prot_reg) ret = -EOPNOTSUPP; else - mfi->mode = MTD_MODE_OTP_USER; + mfi->mode = MTD_FILE_MODE_OTP_USER; break; default: ret = -EINVAL; @@ -390,6 +391,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, uint64_t start, uint32_t length, void __user *ptr, uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; uint32_t retlen; int ret = 0; @@ -409,9 +411,10 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -420,7 +423,7 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, if (IS_ERR(ops.oobbuf)) return PTR_ERR(ops.oobbuf); - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->write_oob(mtd, start, &ops); if (ops.oobretlen > 0xFFFFFFFFU) @@ -433,9 +436,11 @@ static int mtd_do_writeoob(struct file *file, struct mtd_info *mtd, return ret; } -static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, - uint32_t length, void __user *ptr, uint32_t __user *retp) +static int mtd_do_readoob(struct file *file, struct mtd_info *mtd, + uint64_t start, uint32_t length, void __user *ptr, + uint32_t __user *retp) { + struct mtd_file_info *mfi = file->private_data; struct mtd_oob_ops ops; int ret = 0; @@ -451,9 +456,10 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, return ret; ops.ooblen = length; - ops.ooboffs = start & (mtd->oobsize - 1); + ops.ooboffs = start & (mtd->writesize - 1); ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = (mfi->mode == MTD_FILE_MODE_RAW) ? MTD_OPS_RAW : + MTD_OPS_PLACE_OOB; if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) return -EINVAL; @@ -462,7 +468,7 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, if (!ops.oobbuf) return -ENOMEM; - start &= ~((uint64_t)mtd->oobsize - 1); + start &= ~((uint64_t)mtd->writesize - 1); ret = mtd->read_oob(mtd, start, &ops); if (put_user(ops.oobretlen, retp)) @@ -472,13 +478,29 @@ static int mtd_do_readoob(struct mtd_info *mtd, uint64_t start, ret = -EFAULT; kfree(ops.oobbuf); + + /* + * NAND returns -EBADMSG on ECC errors, but it returns the OOB + * data. For our userspace tools it is important to dump areas + * with ECC errors! + * For kernel internal usage it also might return -EUCLEAN + * to signal the caller that a bitflip has occured and has + * been corrected by the ECC algorithm. + * + * Note: currently the standard NAND function, nand_read_oob_std, + * does not calculate ECC for the OOB area, so do not rely on + * this behavior unless you have replaced it with your own. + */ + if (mtd_is_bitflip_or_eccerr(ret)) + return 0; + return ret; } /* * Copies (and truncates, if necessary) data from the larger struct, * nand_ecclayout, to the smaller, deprecated layout struct, - * nand_ecclayout_user. This is necessary only to suppport the deprecated + * nand_ecclayout_user. This is necessary only to support the deprecated * API ioctl ECCGETLAYOUT while allowing all new functionality to use * nand_ecclayout flexibly (i.e. the struct may change size in new * releases without requiring major rewrites). @@ -544,6 +566,55 @@ static int mtd_blkpg_ioctl(struct mtd_info *mtd, } } +static int mtd_write_ioctl(struct mtd_info *mtd, + struct mtd_write_req __user *argp) +{ + struct mtd_write_req req; + struct mtd_oob_ops ops; + void __user *usr_data, *usr_oob; + int ret; + + if (copy_from_user(&req, argp, sizeof(req)) || + !access_ok(VERIFY_READ, req.usr_data, req.len) || + !access_ok(VERIFY_READ, req.usr_oob, req.ooblen)) + return -EFAULT; + if (!mtd->write_oob) + return -EOPNOTSUPP; + + ops.mode = req.mode; + ops.len = (size_t)req.len; + ops.ooblen = (size_t)req.ooblen; + ops.ooboffs = 0; + + usr_data = (void __user *)(uintptr_t)req.usr_data; + usr_oob = (void __user *)(uintptr_t)req.usr_oob; + + if (req.usr_data) { + ops.datbuf = memdup_user(usr_data, ops.len); + if (IS_ERR(ops.datbuf)) + return PTR_ERR(ops.datbuf); + } else { + ops.datbuf = NULL; + } + + if (req.usr_oob) { + ops.oobbuf = memdup_user(usr_oob, ops.ooblen); + if (IS_ERR(ops.oobbuf)) { + kfree(ops.datbuf); + return PTR_ERR(ops.oobbuf); + } + } else { + ops.oobbuf = NULL; + } + + ret = mtd->write_oob(mtd, (loff_t)req.start, &ops); + + kfree(ops.datbuf); + kfree(ops.oobbuf); + + return ret; +} + static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct mtd_file_info *mfi = file->private_data; @@ -553,7 +624,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) u_long size; struct mtd_info_user info; - DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); + pr_debug("MTD_ioctl\n"); size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; if (cmd & IOC_IN) { @@ -601,8 +672,8 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) info.erasesize = mtd->erasesize; info.writesize = mtd->writesize; info.oobsize = mtd->oobsize; - /* The below fields are obsolete */ - info.ecctype = -1; + /* The below field is obsolete */ + info.padding = 0; if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) return -EFAULT; break; @@ -698,7 +769,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, buf.ptr, &buf_user->start); break; } @@ -725,12 +796,19 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, buf.length, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, (void __user *)(uintptr_t)buf.usr_ptr, &buf_user->length); break; } + case MEMWRITE: + { + ret = mtd_write_ioctl(mtd, + (struct mtd_write_req __user *)arg); + break; + } + case MEMLOCK: { struct erase_info_user einfo; @@ -827,7 +905,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) if (copy_from_user(&mode, argp, sizeof(int))) return -EFAULT; - mfi->mode = MTD_MODE_NORMAL; + mfi->mode = MTD_FILE_MODE_NORMAL; ret = otp_select_filemode(mfi, mode); @@ -843,11 +921,11 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) return -ENOMEM; ret = -EOPNOTSUPP; switch (mfi->mode) { - case MTD_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_FACTORY: if (mtd->get_fact_prot_info) ret = mtd->get_fact_prot_info(mtd, buf, 4096); break; - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_USER: if (mtd->get_user_prot_info) ret = mtd->get_user_prot_info(mtd, buf, 4096); break; @@ -871,7 +949,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) { struct otp_info oinfo; - if (mfi->mode != MTD_MODE_OTP_USER) + if (mfi->mode != MTD_FILE_MODE_OTP_USER) return -EINVAL; if (copy_from_user(&oinfo, argp, sizeof(oinfo))) return -EFAULT; @@ -882,7 +960,7 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) } #endif - /* This ioctl is being deprecated - it truncates the ecc layout */ + /* This ioctl is being deprecated - it truncates the ECC layout */ case ECCGETLAYOUT: { struct nand_ecclayout_user *usrlay; @@ -915,17 +993,17 @@ static int mtd_ioctl(struct file *file, u_int cmd, u_long arg) mfi->mode = 0; switch(arg) { - case MTD_MODE_OTP_FACTORY: - case MTD_MODE_OTP_USER: + case MTD_FILE_MODE_OTP_FACTORY: + case MTD_FILE_MODE_OTP_USER: ret = otp_select_filemode(mfi, arg); break; - case MTD_MODE_RAW: + case MTD_FILE_MODE_RAW: if (!mtd->read_oob || !mtd->write_oob) return -EOPNOTSUPP; mfi->mode = arg; - case MTD_MODE_NORMAL: + case MTD_FILE_MODE_NORMAL: break; default: ret = -EINVAL; @@ -1011,7 +1089,7 @@ static long mtd_compat_ioctl(struct file *file, unsigned int cmd, if (copy_from_user(&buf, argp, sizeof(buf))) ret = -EFAULT; else - ret = mtd_do_readoob(mtd, buf.start, + ret = mtd_do_readoob(file, mtd, buf.start, buf.length, compat_ptr(buf.ptr), &buf_user->start); break; diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e601672a530..6df4d4d4eb9 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -95,10 +95,10 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -279,10 +279,10 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -770,7 +770,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c /* * Set up the new "super" device's MTD object structure, check for - * incompatibilites between the subdevices. + * incompatibilities between the subdevices. */ concat->mtd.type = subdev[0]->type; concat->mtd.flags = subdev[0]->flags; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index c510aff289a..b01993ea260 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -362,7 +362,7 @@ int add_mtd_device(struct mtd_info *mtd) MTD_DEVT(i) + 1, NULL, "mtd%dro", i); - DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); + pr_debug("mtd: Giving out device %d to %s\n", i, mtd->name); /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ list_for_each_entry(not, &mtd_notifiers, list) @@ -429,27 +429,63 @@ out_error: } /** - * mtd_device_register - register an MTD device. + * mtd_device_parse_register - parse partitions and register an MTD device. * - * @master: the MTD device to register - * @parts: the partitions to register - only valid if nr_parts > 0 - * @nr_parts: the number of partitions in parts. If zero then the full MTD - * device is registered + * @mtd: the MTD device to register + * @types: the list of MTD partition probes to try, see + * 'parse_mtd_partitions()' for more information + * @parser_data: MTD partition parser-specific data + * @parts: fallback partition information to register, if parsing fails; + * only valid if %nr_parts > %0 + * @nr_parts: the number of partitions in parts, if zero then the full + * MTD device is registered if no partition info is found * - * Register an MTD device with the system and optionally, a number of - * partitions. If nr_parts is 0 then the whole device is registered, otherwise - * only the partitions are registered. To register both the full device *and* - * the partitions, call mtd_device_register() twice, once with nr_parts == 0 - * and once equal to the number of partitions. + * This function aggregates MTD partitions parsing (done by + * 'parse_mtd_partitions()') and MTD device and partitions registering. It + * basically follows the most common pattern found in many MTD drivers: + * + * * It first tries to probe partitions on MTD device @mtd using parsers + * specified in @types (if @types is %NULL, then the default list of parsers + * is used, see 'parse_mtd_partitions()' for more information). If none are + * found this functions tries to fallback to information specified in + * @parts/@nr_parts. + * * If any partitioning info was found, this function registers the found + * partitions. + * * If no partitions were found this function just registers the MTD device + * @mtd and exits. + * + * Returns zero in case of success and a negative error code in case of failure. */ -int mtd_device_register(struct mtd_info *master, - const struct mtd_partition *parts, - int nr_parts) +int mtd_device_parse_register(struct mtd_info *mtd, const char **types, + struct mtd_part_parser_data *parser_data, + const struct mtd_partition *parts, + int nr_parts) { - return parts ? add_mtd_partitions(master, parts, nr_parts) : - add_mtd_device(master); + int err; + struct mtd_partition *real_parts; + + err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); + if (err <= 0 && nr_parts && parts) { + real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, + GFP_KERNEL); + if (!real_parts) + err = -ENOMEM; + else + err = nr_parts; + } + + if (err > 0) { + err = add_mtd_partitions(mtd, real_parts, err); + kfree(real_parts); + } else if (err == 0) { + err = add_mtd_device(mtd); + if (err == 1) + err = -ENODEV; + } + + return err; } -EXPORT_SYMBOL_GPL(mtd_device_register); +EXPORT_SYMBOL_GPL(mtd_device_parse_register); /** * mtd_device_unregister - unregister an existing MTD device. diff --git a/drivers/mtd/mtdcore.h b/drivers/mtd/mtdcore.h index 0ed6126b4c1..961a3840854 100644 --- a/drivers/mtd/mtdcore.h +++ b/drivers/mtd/mtdcore.h @@ -15,6 +15,9 @@ extern int del_mtd_device(struct mtd_info *mtd); extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); extern int del_mtd_partitions(struct mtd_info *); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data); #define mtd_for_each_device(mtd) \ for ((mtd) = __mtd_next_device(0); \ diff --git a/drivers/mtd/mtdoops.c b/drivers/mtd/mtdoops.c index e3e40f44032..1e2fa623670 100644 --- a/drivers/mtd/mtdoops.c +++ b/drivers/mtd/mtdoops.c @@ -258,7 +258,7 @@ static void find_next_position(struct mtdoops_context *cxt) ret = mtd->read(mtd, page * record_size, MTDOOPS_HEADER_SIZE, &retlen, (u_char *) &count[0]); if (retlen != MTDOOPS_HEADER_SIZE || - (ret < 0 && ret != -EUCLEAN)) { + (ret < 0 && !mtd_is_bitflip(ret))) { printk(KERN_ERR "mtdoops: read failure at %ld (%td of %d read), err %d\n", page * record_size, retlen, MTDOOPS_HEADER_SIZE, ret); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 630be3e7da0..a0bd2de4752 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -73,9 +73,9 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, res = part->master->read(part->master, from + part->offset, len, retlen, buf); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; } return res; @@ -130,7 +130,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, if (ops->oobbuf) { size_t len, pages; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = mtd->oobavail; else len = mtd->oobsize; @@ -142,9 +142,9 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, res = part->master->read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected++; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed++; } return res; @@ -479,6 +479,19 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, (unsigned long long)cur_offset, (unsigned long long)slave->offset); } } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; + if (master->size - slave->offset >= slave->mtd.size) { + slave->mtd.size = master->size - slave->offset + - slave->mtd.size; + } else { + printk(KERN_ERR "mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n", + part->name, master->size - slave->offset, + slave->mtd.size); + /* register to preserve ordering */ + goto out_register; + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; @@ -693,6 +706,8 @@ static struct mtd_part_parser *get_partition_parser(const char *name) return ret; } +#define put_partition_parser(p) do { module_put((p)->owner); } while (0) + int register_mtd_parser(struct mtd_part_parser *p) { spin_lock(&part_parser_lock); @@ -712,19 +727,51 @@ int deregister_mtd_parser(struct mtd_part_parser *p) } EXPORT_SYMBOL_GPL(deregister_mtd_parser); +/* + * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you + * are changing this array! + */ +static const char *default_mtd_part_types[] = { + "cmdlinepart", + "ofpart", + NULL +}; + +/** + * parse_mtd_partitions - parse MTD partitions + * @master: the master partition (describes whole MTD device) + * @types: names of partition parsers to try or %NULL + * @pparts: array of partitions found is returned here + * @data: MTD partition parser-specific data + * + * This function tries to find partition on MTD device @master. It uses MTD + * partition parsers, specified in @types. However, if @types is %NULL, then + * the default list of parsers is used. The default list contains only the + * "cmdlinepart" and "ofpart" parsers ATM. + * + * This function may return: + * o a negative error code in case of failure + * o zero if no partitions were found + * o a positive number of found partitions, in which case on exit @pparts will + * point to an array containing this number of &struct mtd_info objects. + */ int parse_mtd_partitions(struct mtd_info *master, const char **types, - struct mtd_partition **pparts, unsigned long origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { struct mtd_part_parser *parser; int ret = 0; + if (!types) + types = default_mtd_part_types; + for ( ; ret <= 0 && *types; types++) { parser = get_partition_parser(*types); if (!parser && !request_module("%s", *types)) parser = get_partition_parser(*types); if (!parser) continue; - ret = (*parser->parse_fn)(master, pparts, origin); + ret = (*parser->parse_fn)(master, pparts, data); if (ret > 0) { printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", ret, parser->name, master->name); @@ -733,7 +780,6 @@ int parse_mtd_partitions(struct mtd_info *master, const char **types, } return ret; } -EXPORT_SYMBOL_GPL(parse_mtd_partitions); int mtd_is_partition(struct mtd_info *mtd) { diff --git a/drivers/mtd/mtdsuper.c b/drivers/mtd/mtdsuper.c index 89f8e66448a..a90bfe79916 100644 --- a/drivers/mtd/mtdsuper.c +++ b/drivers/mtd/mtdsuper.c @@ -27,12 +27,12 @@ static int get_sb_mtd_compare(struct super_block *sb, void *_mtd) struct mtd_info *mtd = _mtd; if (sb->s_mtd == mtd) { - DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n", + pr_debug("MTDSB: Match on device %d (\"%s\")\n", mtd->index, mtd->name); return 1; } - DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", + pr_debug("MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n", sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name); return 0; } @@ -71,7 +71,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, goto already_mounted; /* fresh new superblock */ - DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n", + pr_debug("MTDSB: New superblock for device %d (\"%s\")\n", mtd->index, mtd->name); sb->s_flags = flags; @@ -88,7 +88,7 @@ static struct dentry *mount_mtd_aux(struct file_system_type *fs_type, int flags, /* new mountpoint for an already mounted superblock */ already_mounted: - DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n", + pr_debug("MTDSB: Device %d (\"%s\") is already mounted\n", mtd->index, mtd->name); put_mtd_device(mtd); return dget(sb->s_root); @@ -109,7 +109,7 @@ static struct dentry *mount_mtd_nr(struct file_system_type *fs_type, int flags, mtd = get_mtd_device(NULL, mtdnr); if (IS_ERR(mtd)) { - DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr); + pr_debug("MTDSB: Device #%u doesn't appear to exist\n", mtdnr); return ERR_CAST(mtd); } @@ -132,7 +132,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, if (!dev_name) return ERR_PTR(-EINVAL); - DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name); + pr_debug("MTDSB: dev_name \"%s\"\n", dev_name); /* the preferred way of mounting in future; especially when * CONFIG_BLOCK=n - we specify the underlying MTD device by number or @@ -143,7 +143,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, struct mtd_info *mtd; /* mount by MTD device name */ - DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n", + pr_debug("MTDSB: mtd:%%s, name \"%s\"\n", dev_name + 4); mtd = get_mtd_device_nm(dev_name + 4); @@ -164,7 +164,7 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, mtdnr = simple_strtoul(dev_name + 3, &endptr, 0); if (!*endptr) { /* It was a valid number */ - DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n", + pr_debug("MTDSB: mtd%%d, mtdnr %d\n", mtdnr); return mount_mtd_nr(fs_type, flags, dev_name, data, @@ -180,10 +180,10 @@ struct dentry *mount_mtd(struct file_system_type *fs_type, int flags, bdev = lookup_bdev(dev_name); if (IS_ERR(bdev)) { ret = PTR_ERR(bdev); - DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret); + pr_debug("MTDSB: lookup_bdev() returned %d\n", ret); return ERR_PTR(ret); } - DEBUG(1, "MTDSB: lookup_bdev() returned 0\n"); + pr_debug("MTDSB: lookup_bdev() returned 0\n"); ret = -EINVAL; diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index fd788532761..bd9590c723e 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -86,7 +86,7 @@ struct swap_eb { unsigned int flags; unsigned int active_count; unsigned int erase_count; - unsigned int pad; /* speeds up pointer decremtnt */ + unsigned int pad; /* speeds up pointer decrement */ }; #define MTDSWAP_ECNT_MIN(rbroot) (rb_entry(rb_first(rbroot), struct swap_eb, \ @@ -314,7 +314,7 @@ static int mtdswap_read_oob(struct mtdswap_dev *d, loff_t from, { int ret = d->mtd->read_oob(d->mtd, from, ops); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) return ret; if (ret) { @@ -350,11 +350,11 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) ops.oobbuf = d->oob_buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ret = mtdswap_read_oob(d, offset, &ops); - if (ret && ret != -EUCLEAN) + if (ret && !mtd_is_bitflip(ret)) return ret; data = (struct mtdswap_oobdata *)d->oob_buf; @@ -363,7 +363,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb) if (le16_to_cpu(data->magic) == MTDSWAP_MAGIC_CLEAN) { eb->erase_count = le32_to_cpu(data->count); - if (ret == -EUCLEAN) + if (mtd_is_bitflip(ret)) ret = MTDSWAP_SCANNED_BITFLIP; else { if (le16_to_cpu(data2->magic) == MTDSWAP_MAGIC_DIRTY) @@ -389,7 +389,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, ops.ooboffs = 0; ops.oobbuf = (uint8_t *)&n; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; if (marker == MTDSWAP_TYPE_CLEAN) { @@ -408,7 +408,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb, if (ret) { dev_warn(d->dev, "Write OOB failed for block at %08llx " "error %d\n", offset, ret); - if (ret == -EIO || ret == -EBADMSG) + if (ret == -EIO || mtd_is_eccerr(ret)) mtdswap_handle_write_error(d, eb); return ret; } @@ -628,7 +628,7 @@ static int mtdswap_map_free_block(struct mtdswap_dev *d, unsigned int page, TREE_COUNT(d, CLEAN)--; ret = mtdswap_write_marker(d, eb, MTDSWAP_TYPE_DIRTY); - } while (ret == -EIO || ret == -EBADMSG); + } while (ret == -EIO || mtd_is_eccerr(ret)); if (ret) return ret; @@ -678,7 +678,7 @@ retry: ret = mtdswap_map_free_block(d, page, bp); eb = d->eb_data + (*bp / d->pages_per_eblk); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write = NULL; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -690,7 +690,7 @@ retry: writepos = (loff_t)*bp << PAGE_SHIFT; ret = mtd->write(mtd, writepos, PAGE_SIZE, &retlen, buf); - if (ret == -EIO || ret == -EBADMSG) { + if (ret == -EIO || mtd_is_eccerr(ret)) { d->curr_write_pos--; eb->active_count--; d->revmap[*bp] = PAGE_UNDEF; @@ -738,7 +738,7 @@ static int mtdswap_move_block(struct mtdswap_dev *d, unsigned int oldblock, retry: ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, d->page_buf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { oldeb = d->eb_data + oldblock / d->pages_per_eblk; oldeb->flags |= EBLOCK_READERR; @@ -931,7 +931,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = mtd->writesize; ops.ooblen = mtd->ecclayout->oobavail; ops.ooboffs = 0; @@ -1016,7 +1016,7 @@ static int mtdswap_gc(struct mtdswap_dev *d, unsigned int background) if (ret == 0) mtdswap_rb_add(d, eb, MTDSWAP_CLEAN); - else if (ret != -EIO && ret != -EBADMSG) + else if (ret != -EIO && !mtd_is_eccerr(ret)) mtdswap_rb_add(d, eb, MTDSWAP_DIRTY); return 0; @@ -1164,7 +1164,7 @@ retry: ret = mtd->read(mtd, readpos, PAGE_SIZE, &retlen, buf); d->mtd_read_count++; - if (ret == -EUCLEAN) { + if (mtd_is_bitflip(ret)) { eb->flags |= EBLOCK_BITFLIP; mtdswap_rb_add(d, eb, MTDSWAP_BITFLIP); ret = 0; @@ -1374,11 +1374,10 @@ static int mtdswap_init(struct mtdswap_dev *d, unsigned int eblocks, goto revmap_fail; eblk_bytes = sizeof(struct swap_eb)*d->eblks; - d->eb_data = vmalloc(eblk_bytes); + d->eb_data = vzalloc(eblk_bytes); if (!d->eb_data) goto eb_data_fail; - memset(d->eb_data, 0, eblk_bytes); for (i = 0; i < pages; i++) d->page_data[i] = BLOCK_UNDEF; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index dbfa0f7fb46..cce7b70824c 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -83,16 +83,9 @@ config MTD_NAND_DENALI_SCRATCH_REG_ADDR scratch register here to enable this feature. On Intel Moorestown boards, the scratch register is at 0xFF108018. -config MTD_NAND_EDB7312 - tristate "Support for Cirrus Logic EBD7312 evaluation board" - depends on ARCH_EDB7312 - help - This enables the driver for the Cirrus Logic EBD7312 evaluation - board to access the onboard NAND Flash. - config MTD_NAND_H1900 tristate "iPAQ H1900 flash" - depends on ARCH_PXA + depends on ARCH_PXA && BROKEN help This enables the driver for the iPAQ h1900 flash. @@ -116,10 +109,11 @@ config MTD_NAND_AMS_DELTA Support for NAND flash on Amstrad E3 (Delta). config MTD_NAND_OMAP2 - tristate "NAND Flash device on OMAP2 and OMAP3" - depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3) + tristate "NAND Flash device on OMAP2, OMAP3 and OMAP4" + depends on ARM && (ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4) help - Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms. + Support for NAND flash on Texas Instruments OMAP2, OMAP3 and OMAP4 + platforms. config MTD_NAND_IDS tristate @@ -423,6 +417,19 @@ config MTD_NAND_NANDSIM The simulator may simulate various NAND flash chips for the MTD nand layer. +config MTD_NAND_GPMI_NAND + bool "GPMI NAND Flash Controller driver" + depends on MTD_NAND && (SOC_IMX23 || SOC_IMX28) + select MTD_PARTITIONS + select MTD_CMDLINE_PARTS + help + Enables NAND Flash support for IMX23 or IMX28. + The GPMI controller is very powerful, with the help of BCH + module, it can do the hardware ECC. The GPMI supports several + NAND flashs at the same time. The GPMI may conflicts with other + block, such as SD card. So pay attention to it when you enable + the GPMI. + config MTD_NAND_PLATFORM tristate "Support for generic platform NAND driver" help diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 5745d831168..618f4ba2369 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_DENALI) += denali.o -obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o @@ -49,5 +48,6 @@ obj-$(CONFIG_MTD_NAND_BCM_UMI) += bcm_umi_nand.o nand_bcm_umi.o obj-$(CONFIG_MTD_NAND_MPC5121_NFC) += mpc5121_nfc.o obj-$(CONFIG_MTD_NAND_RICOH) += r852.o obj-$(CONFIG_MTD_NAND_JZ4740) += jz4740_nand.o +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/ nand-objs := nand_base.o nand_bbt.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 55da20ccc7a..23e5d77c39f 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -161,37 +161,6 @@ static int atmel_nand_device_ready(struct mtd_info *mtd) !!host->board->rdy_pin_active_low; } -/* - * Minimal-overhead PIO for data access. - */ -static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsb(nand_chip->IO_ADDR_R, buf, len); -} - -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2); -} - -static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesb(nand_chip->IO_ADDR_W, buf, len); -} - -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - __raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2); -} - static void dma_complete_func(void *completion) { complete(completion); @@ -266,33 +235,27 @@ err_buf: static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, buf, len, 1) == 0) return; - if (host->board->bus_width_16) - atmel_read_buf16(mtd, buf, len); - else - atmel_read_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_fromio(buf, chip->IO_ADDR_R, len); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct nand_chip *chip = mtd->priv; - struct atmel_nand_host *host = chip->priv; if (use_dma && len > mtd->oobsize) /* only use DMA for bigger than oob size: better performances */ if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0) return; - if (host->board->bus_width_16) - atmel_write_buf16(mtd, buf, len); - else - atmel_write_buf8(mtd, buf, len); + /* if no DMA operation possible, use PIO */ + memcpy_toio(chip->IO_ADDR_W, buf, len); } /* @@ -481,10 +444,6 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) } } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif - /* * Probe for the NAND device. */ @@ -496,8 +455,6 @@ static int __init atmel_nand_probe(struct platform_device *pdev) struct resource *regs; struct resource *mem; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { @@ -583,7 +540,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) if (on_flash_bbt) { printk(KERN_INFO "atmel_nand: Use On Flash BBT\n"); - nand_chip->options |= NAND_USE_FLASH_BBT; + nand_chip->bbt_options |= NAND_BBT_USE_FLASH; } if (!cpu_has_dma()) @@ -594,7 +551,7 @@ static int __init atmel_nand_probe(struct platform_device *pdev) dma_cap_zero(mask); dma_cap_set(DMA_MEMCPY, mask); - host->dma_chan = dma_request_channel(mask, 0, NULL); + host->dma_chan = dma_request_channel(mask, NULL, NULL); if (!host->dma_chan) { dev_err(host->dev, "Failed to request DMA channel\n"); use_dma = 0; @@ -655,27 +612,12 @@ static int __init atmel_nand_probe(struct platform_device *pdev) goto err_scan_tail; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "atmel_nand"; - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); -#endif - if (num_partitions <= 0 && host->board->partition_info) - partitions = host->board->partition_info(mtd->size, - &num_partitions); - - if ((!partitions) || (num_partitions == 0)) { - printk(KERN_ERR "atmel_nand: No partitions defined, or unsupported device.\n"); - res = -ENXIO; - goto err_no_partitions; - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, 0, + host->board->parts, host->board->num_parts); if (!res) return res; -err_no_partitions: - nand_release(mtd); err_scan_tail: err_scan_ident: err_no_card: diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index fa5736b9286..7dd3700f230 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c @@ -52,7 +52,7 @@ static const struct mtd_partition partition_info[] = { * au_read_byte - read one byte from the chip * @mtd: MTD device structure * - * read function for 8bit buswith + * read function for 8bit buswidth */ static u_char au_read_byte(struct mtd_info *mtd) { @@ -67,7 +67,7 @@ static u_char au_read_byte(struct mtd_info *mtd) * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 8it buswith + * write function for 8it buswidth */ static void au_write_byte(struct mtd_info *mtd, u_char byte) { @@ -77,11 +77,10 @@ static void au_write_byte(struct mtd_info *mtd, u_char byte) } /** - * au_read_byte16 - read one byte endianess aware from the chip + * au_read_byte16 - read one byte endianness aware from the chip * @mtd: MTD device structure * - * read function for 16bit buswith with - * endianess conversion + * read function for 16bit buswidth with endianness conversion */ static u_char au_read_byte16(struct mtd_info *mtd) { @@ -92,12 +91,11 @@ static u_char au_read_byte16(struct mtd_info *mtd) } /** - * au_write_byte16 - write one byte endianess aware to the chip + * au_write_byte16 - write one byte endianness aware to the chip * @mtd: MTD device structure * @byte: pointer to data byte to write * - * write function for 16bit buswith with - * endianess conversion + * write function for 16bit buswidth with endianness conversion */ static void au_write_byte16(struct mtd_info *mtd, u_char byte) { @@ -110,8 +108,7 @@ static void au_write_byte16(struct mtd_info *mtd, u_char byte) * au_read_word - read one word from the chip * @mtd: MTD device structure * - * read function for 16bit buswith without - * endianess conversion + * read function for 16bit buswidth without endianness conversion */ static u16 au_read_word(struct mtd_info *mtd) { @@ -127,7 +124,7 @@ static u16 au_read_word(struct mtd_info *mtd) * @buf: data buffer * @len: number of bytes to write * - * write function for 8bit buswith + * write function for 8bit buswidth */ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -146,7 +143,7 @@ static void au_write_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 8bit buswith + * read function for 8bit buswidth */ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) { @@ -165,7 +162,7 @@ static void au_read_buf(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 8bit buswith + * verify function for 8bit buswidth */ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) { @@ -187,7 +184,7 @@ static int au_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) * @buf: data buffer * @len: number of bytes to write * - * write function for 16bit buswith + * write function for 16bit buswidth */ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) { @@ -209,7 +206,7 @@ static void au_write_buf16(struct mtd_info *mtd, const u_char *buf, int len) * @buf: buffer to store date * @len: number of bytes to read * - * read function for 16bit buswith + * read function for 16bit buswidth */ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) { @@ -230,7 +227,7 @@ static void au_read_buf16(struct mtd_info *mtd, u_char *buf, int len) * @buf: buffer containing the data to compare * @len: number of bytes to compare * - * verify function for 16bit buswith + * verify function for 16bit buswidth */ static int au_verify_buf16(struct mtd_info *mtd, const u_char *buf, int len) { diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index eddc9a22498..2e42ec2e8ff 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c @@ -172,9 +172,9 @@ static int __init autcpu12_init(void) /* Enable the following for a flash based bad block table */ /* - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; */ - this->options = NAND_USE_FLASH_BBT; + this->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(autcpu12_mtd, 1)) { diff --git a/drivers/mtd/nand/bcm_umi_nand.c b/drivers/mtd/nand/bcm_umi_nand.c index 8c569e454dc..46b58d67284 100644 --- a/drivers/mtd/nand/bcm_umi_nand.c +++ b/drivers/mtd/nand/bcm_umi_nand.c @@ -52,8 +52,6 @@ static const __devinitconst char gBanner[] = KERN_INFO \ "BCM UMI MTD NAND Driver: 1.00\n"; -const char *part_probes[] = { "cmdlinepart", NULL }; - #if NAND_ECC_BCH static uint8_t scan_ff_pattern[] = { 0xff }; @@ -376,16 +374,18 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + if (!r) { + err = -ENXIO; + goto out_free; + } /* map physical address */ bcm_umi_io_base = ioremap(r->start, resource_size(r)); if (!bcm_umi_io_base) { printk(KERN_ERR "ioremap to access BCM UMI NAND chip failed\n"); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_free; } /* Get pointer to private data */ @@ -401,9 +401,8 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) /* Initialize the NAND hardware. */ if (bcm_umi_nand_inithw() < 0) { printk(KERN_ERR "BCM UMI NAND chip could not be initialized\n"); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; + err = -EIO; + goto out_unmap; } /* Set address of NAND IO lines */ @@ -436,7 +435,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) #if USE_DMA err = nand_dma_init(); if (err != 0) - return err; + goto out_unmap; #endif /* Figure out the size of the device that we have. @@ -447,9 +446,7 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_ident(board_mtd, 1, NULL); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Now that we know the nand size, we can setup the ECC layout */ @@ -468,13 +465,14 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) { printk(KERN_ERR "NAND - Unrecognized pagesize: %d\n", board_mtd->writesize); - return -EINVAL; + err = -EINVAL; + goto out_unmap; } } #if NAND_ECC_BCH if (board_mtd->writesize > 512) { - if (this->options & NAND_USE_FLASH_BBT) + if (this->bbt_options & NAND_BBT_USE_FLASH) largepage_bbt.options = NAND_BBT_SCAN2NDPAGE; this->badblock_pattern = &largepage_bbt; } @@ -485,33 +483,20 @@ static int __devinit bcm_umi_nand_probe(struct platform_device *pdev) err = nand_scan_tail(board_mtd); if (err) { printk(KERN_ERR "nand_scan failed: %d\n", err); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return err; + goto out_unmap; } /* Register the partitions */ - { - int nr_partitions; - struct mtd_partition *partition_info; - - board_mtd->name = "bcm_umi-nand"; - nr_partitions = - parse_mtd_partitions(board_mtd, part_probes, - &partition_info, 0); - - if (nr_partitions <= 0) { - printk(KERN_ERR "BCM UMI NAND: Too few partitions - %d\n", - nr_partitions); - iounmap(bcm_umi_io_base); - kfree(board_mtd); - return -EIO; - } - mtd_device_register(board_mtd, partition_info, nr_partitions); - } + board_mtd->name = "bcm_umi-nand"; + mtd_device_parse_register(board_mtd, NULL, 0, NULL, 0); /* Return happy */ return 0; +out_unmap: + iounmap(bcm_umi_io_base); +out_free: + kfree(board_mtd); + return err; } static int bcm_umi_nand_remove(struct platform_device *pdev) diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 7c8df837d3b..72d3f23490c 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -58,7 +58,6 @@ struct cafe_priv { struct nand_chip nand; - struct mtd_partition *parts; struct pci_dev *pdev; void __iomem *mmio; struct rs_control *rs; @@ -372,7 +371,7 @@ static int cafe_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, return 1; } /** - * cafe_nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read + * cafe_nand_read_page_syndrome - [REPLACEABLE] hardware ecc syndrome based page read * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data @@ -631,8 +630,6 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, struct cafe_priv *cafe; uint32_t ctrl; int err = 0; - struct mtd_partition *parts; - int nr_parts; /* Very old versions shared the same PCI ident for all three functions on the chip. Verify the class too... */ @@ -687,7 +684,8 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, cafe->nand.chip_delay = 0; /* Enable the following for a flash based bad block table */ - cafe->nand.options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; + cafe->nand.bbt_options = NAND_BBT_USE_FLASH; + cafe->nand.options = NAND_NO_AUTOINCR | NAND_OWN_BUFFERS; if (skipbbt) { cafe->nand.options |= NAND_SKIP_BBTSCAN; @@ -800,18 +798,9 @@ static int __devinit cafe_nand_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mtd); - /* We register the whole device first, separate from the partitions */ - mtd_device_register(mtd, NULL, 0); - -#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 partitions found\n", nr_parts); - mtd_device_register(mtd, parts, nr_parts); - } + mtd_device_parse_register(mtd, part_probes, 0, NULL, 0); + goto out; out_irq: diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index be33b0f4634..737ef9a04fd 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -51,8 +51,6 @@ static struct mtd_partition partition_info[] = { }; #define NUM_PARTITIONS (ARRAY_SIZE(partition_info)) -const char *part_probes[] = { "cmdlinepart", NULL }; - static u_char cmx270_read_byte(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; @@ -152,9 +150,6 @@ static int cmx270_device_ready(struct mtd_info *mtd) static int __init cmx270_init(void) { struct nand_chip *this; - const char *part_type; - struct mtd_partition *mtd_parts; - int mtd_parts_nb = 0; int ret; if (!(machine_is_armcore() && cpu_is_pxa27x())) @@ -223,23 +218,9 @@ static int __init cmx270_init(void) goto err_scan; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_mtd_partitions(cmx270_nand_mtd, part_probes, - &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (!mtd_parts_nb) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - /* Register the partitions */ - pr_notice("Using %s partition definition\n", part_type); - ret = mtd_device_register(cmx270_nand_mtd, mtd_parts, mtd_parts_nb); + ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); if (ret) goto err_scan; diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index f59ad1f2d5d..414afa79356 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -239,7 +239,8 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) this->ecc.correct = nand_correct_data; /* Enable the following for a flash based bad block table */ - this->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + this->bbt_options = NAND_BBT_USE_FLASH; + this->options = NAND_NO_AUTOINCR; /* Scan to find existence of the device */ if (nand_scan(new_mtd, 1)) { @@ -277,15 +278,11 @@ static int is_geode(void) return 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - static int __init cs553x_init(void) { int err = -ENXIO; int i; uint64_t val; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = NULL; /* If the CPU isn't a Geode GX or LX, abort */ if (!is_geode()) @@ -315,13 +312,9 @@ static int __init cs553x_init(void) do mtdconcat etc. if we want to. */ for (i = 0; i < NR_CS553X_CONTROLLERS; i++) { if (cs553x_mtd[i]) { - /* If any devices registered, return success. Else the last error. */ - mtd_parts_nb = parse_mtd_partitions(cs553x_mtd[i], part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - printk(KERN_NOTICE "Using command line partition definition\n"); - mtd_device_register(cs553x_mtd[i], mtd_parts, - mtd_parts_nb); + mtd_device_parse_register(cs553x_mtd[i], NULL, 0, + NULL, 0); err = 0; } } diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index 1f34951ae1a..c153e1f77f9 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -57,7 +57,6 @@ struct davinci_nand_info { struct device *dev; struct clk *clk; - bool partitioned; bool is_readmode; @@ -530,8 +529,6 @@ static int __init nand_davinci_probe(struct platform_device *pdev) int ret; uint32_t val; nand_ecc_modes_t ecc_mode; - struct mtd_partition *mtd_parts = NULL; - int mtd_parts_nb = 0; /* insist on board-specific configuration */ if (!pdata) @@ -581,7 +578,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev) info->chip.chip_delay = 0; info->chip.select_chip = nand_davinci_select_chip; - /* options such as NAND_USE_FLASH_BBT or 16-bit widths */ + /* options such as NAND_BBT_USE_FLASH */ + info->chip.bbt_options = pdata->bbt_options; + /* options such as 16-bit widths */ info->chip.options = pdata->options; info->chip.bbt_td = pdata->bbt_td; info->chip.bbt_md = pdata->bbt_md; @@ -751,33 +750,8 @@ syndrome_done: if (ret < 0) goto err_scan; - if (mtd_has_cmdlinepart()) { - static const char *probes[] __initconst = { - "cmdlinepart", NULL - }; - - mtd_parts_nb = parse_mtd_partitions(&info->mtd, probes, - &mtd_parts, 0); - } - - if (mtd_parts_nb <= 0) { - mtd_parts = pdata->parts; - mtd_parts_nb = pdata->nr_parts; - } - - /* Register any partitions */ - if (mtd_parts_nb > 0) { - ret = mtd_device_register(&info->mtd, mtd_parts, - mtd_parts_nb); - if (ret == 0) - info->partitioned = true; - } - - /* If there's no partition info, just package the whole chip - * as a single MTD device. - */ - if (!info->partitioned) - ret = mtd_device_register(&info->mtd, NULL, 0) ? -ENODEV : 0; + ret = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); if (ret < 0) goto err_scan; @@ -816,9 +790,6 @@ err_nomem: static int __exit nand_davinci_remove(struct platform_device *pdev) { struct davinci_nand_info *info = platform_get_drvdata(pdev); - int status; - - status = mtd_device_unregister(&info->mtd); spin_lock_irq(&davinci_nand_lock); if (info->chip.ecc.mode == NAND_ECC_HW_SYNDROME) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index d5276218945..3984d488f9a 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1346,6 +1346,7 @@ static void denali_hw_init(struct denali_nand_info *denali) * */ denali->bbtskipbytes = ioread32(denali->flash_reg + SPARE_AREA_SKIP_BYTES); + detect_max_banks(denali); denali_nand_reset(denali); iowrite32(0x0F, denali->flash_reg + RB_PIN_ENABLED); iowrite32(CHIP_EN_DONT_CARE__FLAG, @@ -1356,7 +1357,6 @@ static void denali_hw_init(struct denali_nand_info *denali) /* Should set value for these registers when init */ iowrite32(0, denali->flash_reg + TWO_ROW_ADDR_CYCLES); iowrite32(1, denali->flash_reg + ECC_ENABLE); - detect_max_banks(denali); denali_nand_timing_set(denali); denali_irq_init(denali); } @@ -1577,7 +1577,8 @@ static int denali_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) denali->nand.bbt_md = &bbt_mirror_descr; /* skip the scan for now until we have OOB read and write support */ - denali->nand.options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + denali->nand.bbt_options |= NAND_BBT_USE_FLASH; + denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; /* Denali Controller only support 15bit and 8bit ECC in MRST, @@ -1676,7 +1677,6 @@ static void denali_pci_remove(struct pci_dev *dev) struct denali_nand_info *denali = pci_get_drvdata(dev); nand_release(&denali->mtd); - mtd_device_unregister(&denali->mtd); denali_irq_cleanup(dev->irq, denali); diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index e1b84cb90f0..5780dbab611 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -133,7 +133,7 @@ static struct rs_control *rs_decoder; /* * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic * Reed-Solomon library code. * * Fabrice Bellard figured this out in the old docecc code. I added @@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); parity = ecc[1]; - /* Initialize the syndrom buffer */ + /* Initialize the syndrome buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; /* @@ -1032,7 +1032,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - if (no_ecc_failures && (ret == -EBADMSG)) { + if (no_ecc_failures && mtd_is_eccerr(ret)) { printk(KERN_ERR "suppressing ECC failure\n"); ret = 0; } @@ -1653,7 +1653,7 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; - nand->options = NAND_USE_FLASH_BBT; + nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; doc->virtadr = virtadr; diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c deleted file mode 100644 index 8400d0f6dad..00000000000 --- a/drivers/mtd/nand/edb7312.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * drivers/mtd/nand/edb7312.c - * - * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Overview: - * This is a device driver for the NAND flash device found on the - * CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is - * a 64Mibit (8MiB x 8 bits) NAND flash device. - */ - -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> -#include <asm/io.h> -#include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */ -#include <asm/sizes.h> -#include <asm/hardware/clps7111.h> - -/* - * MTD structure for EDB7312 board - */ -static struct mtd_info *ep7312_mtd = NULL; - -/* - * Values specific to the EDB7312 board (used with EP7312 processor) - */ -#define EP7312_FIO_PBASE 0x10000000 /* Phys address of flash */ -#define EP7312_PXDR 0x0001 /* - * IO offset to Port B data register - * where the CLE, ALE and NCE pins - * are wired to. - */ -#define EP7312_PXDDR 0x0041 /* - * IO offset to Port B data direction - * register so we can control the IO - * lines. - */ - -/* - * Module stuff - */ - -static unsigned long ep7312_fio_pbase = EP7312_FIO_PBASE; -static void __iomem *ep7312_pxdr = (void __iomem *)EP7312_PXDR; -static void __iomem *ep7312_pxddr = (void __iomem *)EP7312_PXDDR; - -/* - * Define static partitions for flash device - */ -static struct mtd_partition partition_info[] = { - {.name = "EP7312 Nand Flash", - .offset = 0, - .size = 8 * 1024 * 1024} -}; - -#define NUM_PARTITIONS 1 - -/* - * hardware specific access to control-lines - * - * NAND_NCE: bit 0 -> bit 6 (bit 7 = 1) - * NAND_CLE: bit 1 -> bit 4 - * NAND_ALE: bit 2 -> bit 5 - */ -static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *chip = mtd->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - unsigned char bits = 0x80; - - bits |= (ctrl & (NAND_CLE | NAND_ALE)) << 3; - bits |= (ctrl & NAND_NCE) ? 0x00 : 0x40; - - clps_writeb((clps_readb(ep7312_pxdr) & 0xF0) | bits, - ep7312_pxdr); - } - if (cmd != NAND_CMD_NONE) - writeb(cmd, chip->IO_ADDR_W); -} - -/* - * read device ready pin - */ -static int ep7312_device_ready(struct mtd_info *mtd) -{ - return 1; -} - -const char *part_probes[] = { "cmdlinepart", NULL }; - -/* - * Main initialization routine - */ -static int __init ep7312_init(void) -{ - struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; - void __iomem *ep7312_fio_base; - - /* Allocate memory for MTD device structure and private data */ - ep7312_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL); - if (!ep7312_mtd) { - printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); - return -ENOMEM; - } - - /* map physical address */ - ep7312_fio_base = ioremap(ep7312_fio_pbase, SZ_1K); - if (!ep7312_fio_base) { - printk("ioremap EDB7312 NAND flash failed\n"); - kfree(ep7312_mtd); - return -EIO; - } - - /* Get pointer to private data */ - this = (struct nand_chip *)(&ep7312_mtd[1]); - - /* Initialize structures */ - memset(ep7312_mtd, 0, sizeof(struct mtd_info)); - memset(this, 0, sizeof(struct nand_chip)); - - /* Link the private data with the MTD structure */ - ep7312_mtd->priv = this; - ep7312_mtd->owner = THIS_MODULE; - - /* - * Set GPIO Port B control register so that the pins are configured - * to be outputs for controlling the NAND flash. - */ - clps_writeb(0xf0, ep7312_pxddr); - - /* insert callbacks */ - this->IO_ADDR_R = ep7312_fio_base; - this->IO_ADDR_W = ep7312_fio_base; - this->cmd_ctrl = ep7312_hwcontrol; - this->dev_ready = ep7312_device_ready; - /* 15 us command delay time */ - this->chip_delay = 15; - - /* Scan to find existence of the device */ - if (nand_scan(ep7312_mtd, 1)) { - iounmap((void *)ep7312_fio_base); - kfree(ep7312_mtd); - return -ENXIO; - } - ep7312_mtd->name = "edb7312-nand"; - mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } - - /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ep7312_mtd, mtd_parts, mtd_parts_nb); - - /* Return happy */ - return 0; -} - -module_init(ep7312_init); - -/* - * Clean up routine - */ -static void __exit ep7312_cleanup(void) -{ - struct nand_chip *this = (struct nand_chip *)&ep7312_mtd[1]; - - /* Release resources, unregister device */ - nand_release(ap7312_mtd); - - /* Release io resource */ - iounmap(this->IO_ADDR_R); - - /* Free the MTD device structure */ - kfree(ep7312_mtd); -} - -module_exit(ep7312_cleanup); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board"); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 33d8aad8bba..eedd8ee2c9a 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -75,7 +75,6 @@ struct fsl_elbc_fcm_ctrl { unsigned int use_mdr; /* Non zero if the MDR is to be set */ unsigned int oob; /* Non zero if operating on OOB data */ unsigned int counter; /* counter for the initializations */ - char *oob_poi; /* Place to write ECC after read back */ }; /* These map to the positions used by the FCM hardware ECC generator */ @@ -244,6 +243,25 @@ static int fsl_elbc_run_command(struct mtd_info *mtd) return -EIO; } + if (chip->ecc.mode != NAND_ECC_HW) + return 0; + + if (elbc_fcm_ctrl->read_bytes == mtd->writesize + mtd->oobsize) { + uint32_t lteccr = in_be32(&lbc->lteccr); + /* + * if command was a full page read and the ELBC + * has the LTECCR register, then bits 12-15 (ppc order) of + * LTECCR indicates which 512 byte sub-pages had fixed errors. + * bits 28-31 are uncorrectable errors, marked elsewhere. + * for small page nand only 1 bit is used. + * if the ELBC doesn't have the lteccr register it reads 0 + */ + if (lteccr & 0x000F000F) + out_be32(&lbc->lteccr, 0x000F000F); /* clear lteccr */ + if (lteccr & 0x000F0000) + mtd->ecc_stats.corrected++; + } + return 0; } @@ -435,7 +453,6 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: { - int full_page; dev_vdbg(priv->dev, "fsl_elbc_cmdfunc: NAND_CMD_PAGEPROG " "writing %d bytes.\n", elbc_fcm_ctrl->index); @@ -445,34 +462,12 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command, * write so the HW generates the ECC. */ if (elbc_fcm_ctrl->oob || elbc_fcm_ctrl->column != 0 || - elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) { + elbc_fcm_ctrl->index != mtd->writesize + mtd->oobsize) out_be32(&lbc->fbcr, elbc_fcm_ctrl->index); - full_page = 0; - } else { + else out_be32(&lbc->fbcr, 0); - full_page = 1; - } fsl_elbc_run_command(mtd); - - /* Read back the page in order to fill in the ECC for the - * caller. Is this really needed? - */ - if (full_page && elbc_fcm_ctrl->oob_poi) { - out_be32(&lbc->fbcr, 3); - set_addr(mtd, 6, page_addr, 1); - - elbc_fcm_ctrl->read_bytes = mtd->writesize + 9; - - fsl_elbc_do_read(chip, 1); - fsl_elbc_run_command(mtd); - - memcpy_fromio(elbc_fcm_ctrl->oob_poi + 6, - &elbc_fcm_ctrl->addr[elbc_fcm_ctrl->index], 3); - elbc_fcm_ctrl->index += 3; - } - - elbc_fcm_ctrl->oob_poi = NULL; return; } @@ -752,13 +747,8 @@ static void fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { - struct fsl_elbc_mtd *priv = chip->priv; - struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl = priv->ctrl->nand; - fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); - - elbc_fcm_ctrl->oob_poi = chip->oob_poi; } static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) @@ -791,8 +781,8 @@ static int fsl_elbc_chip_init(struct fsl_elbc_mtd *priv) chip->bbt_md = &bbt_mirror_descr; /* set up nand options */ - chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT; + chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->controller = &elbc_fcm_ctrl->controller; chip->priv = priv; @@ -829,7 +819,6 @@ static int fsl_elbc_chip_remove(struct fsl_elbc_mtd *priv) elbc_fcm_ctrl->chips[priv->bank] = NULL; kfree(priv); - kfree(elbc_fcm_ctrl); return 0; } @@ -842,13 +831,14 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) struct resource res; struct fsl_elbc_fcm_ctrl *elbc_fcm_ctrl; static const char *part_probe_types[] - = { "cmdlinepart", "RedBoot", NULL }; - struct mtd_partition *parts; + = { "cmdlinepart", "RedBoot", "ofpart", NULL }; int ret; int bank; struct device *dev; struct device_node *node = pdev->dev.of_node; + struct mtd_part_parser_data ppdata; + ppdata.of_node = pdev->dev.of_node; if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV; lbc = fsl_lbc_ctrl_dev->regs; @@ -934,17 +924,8 @@ static int __devinit fsl_elbc_nand_probe(struct platform_device *pdev) /* First look for RedBoot table or partitions on the command * line, these take precedence over device tree information */ - ret = parse_mtd_partitions(&priv->mtd, part_probe_types, &parts, 0); - if (ret < 0) - goto err; - - if (ret == 0) { - ret = of_mtd_parse_partitions(priv->dev, node, &parts); - if (ret < 0) - goto err; - } - - mtd_device_register(&priv->mtd, parts, ret); + mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, + NULL, 0); printk(KERN_INFO "eLBC NAND device at 0x%llx, bank %d\n", (unsigned long long)res.start, priv->bank); diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 23752fd5bc5..b4f3cc9f32f 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c @@ -158,7 +158,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, { int ret; struct device_node *flash_np; - static const char *part_types[] = { "cmdlinepart", NULL, }; + struct mtd_part_parser_data ppdata; fun->chip.IO_ADDR_R = fun->io_base; fun->chip.IO_ADDR_W = fun->io_base; @@ -192,18 +192,12 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun, if (ret) goto err; - ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); - -#ifdef CONFIG_MTD_OF_PARTS - if (ret == 0) { - ret = of_mtd_parse_partitions(fun->dev, flash_np, &fun->parts); - if (ret < 0) - goto err; - } -#endif - ret = mtd_device_register(&fun->mtd, fun->parts, ret); + ppdata.of_node = flash_np; + ret = mtd_device_parse_register(&fun->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); + if (ret) + kfree(fun->mtd.name); return ret; } diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index e9b275ac381..e53b7606413 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -146,7 +146,7 @@ static struct mtd_partition partition_info_16KB_blk[] = { { .name = "Root File System", .offset = 0x460000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; @@ -173,13 +173,10 @@ static struct mtd_partition partition_info_128KB_blk[] = { { .name = "Root File System", .offset = 0x800000, - .size = 0, + .size = MTDPART_SIZ_FULL, }, }; -#ifdef CONFIG_MTD_CMDLINE_PARTS -const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /** * struct fsmc_nand_data - structure for FSMC NAND device state @@ -187,8 +184,6 @@ const char *part_probes[] = { "cmdlinepart", NULL }; * @pid: Part ID on the AMBA PrimeCell format * @mtd: MTD info for a NAND flash. * @nand: Chip related info for a NAND flash. - * @partitions: Partition info for a NAND Flash. - * @nr_partitions: Total number of partition of a NAND flash. * * @ecc_place: ECC placing locations in oobfree type format. * @bank: Bank number for probed device. @@ -203,8 +198,6 @@ struct fsmc_nand_data { u32 pid; struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *partitions; - unsigned int nr_partitions; struct fsmc_eccplace *ecc_place; unsigned int bank; @@ -716,65 +709,17 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) * platform data, * default partition information present in driver. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS /* - * Check if partition info passed via command line + * Check for partition info passed */ host->mtd.name = "nand"; - host->nr_partitions = parse_mtd_partitions(&host->mtd, part_probes, - &host->partitions, 0); - if (host->nr_partitions <= 0) { -#endif - /* - * Check if partition info passed via command line - */ - if (pdata->partitions) { - host->partitions = pdata->partitions; - host->nr_partitions = pdata->nr_partitions; - } else { - struct mtd_partition *partition; - int i; - - /* Select the default partitions info */ - switch (host->mtd.size) { - case 0x01000000: - case 0x02000000: - case 0x04000000: - host->partitions = partition_info_16KB_blk; - host->nr_partitions = - sizeof(partition_info_16KB_blk) / - sizeof(struct mtd_partition); - break; - case 0x08000000: - case 0x10000000: - case 0x20000000: - case 0x40000000: - host->partitions = partition_info_128KB_blk; - host->nr_partitions = - sizeof(partition_info_128KB_blk) / - sizeof(struct mtd_partition); - break; - default: - ret = -ENXIO; - pr_err("Unsupported NAND size\n"); - goto err_probe; - } - - partition = host->partitions; - for (i = 0; i < host->nr_partitions; i++, partition++) { - if (partition->size == 0) { - partition->size = host->mtd.size - - partition->offset; - break; - } - } - } -#ifdef CONFIG_MTD_CMDLINE_PARTS - } -#endif - - ret = mtd_device_register(&host->mtd, host->partitions, - host->nr_partitions); + ret = mtd_device_parse_register(&host->mtd, NULL, 0, + host->mtd.size <= 0x04000000 ? + partition_info_16KB_blk : + partition_info_128KB_blk, + host->mtd.size <= 0x04000000 ? + ARRAY_SIZE(partition_info_16KB_blk) : + ARRAY_SIZE(partition_info_128KB_blk)); if (ret) goto err_probe; @@ -822,7 +767,7 @@ static int fsmc_nand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (host) { - mtd_device_unregister(&host->mtd); + nand_release(&host->mtd); clk_disable(host->clk); clk_put(host->clk); diff --git a/drivers/mtd/nand/gpmi-nand/Makefile b/drivers/mtd/nand/gpmi-nand/Makefile new file mode 100644 index 00000000000..3a462487c35 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi_nand.o +gpmi_nand-objs += gpmi-nand.o +gpmi_nand-objs += gpmi-lib.o diff --git a/drivers/mtd/nand/gpmi-nand/bch-regs.h b/drivers/mtd/nand/gpmi-nand/bch-regs.h new file mode 100644 index 00000000000..4effb8c579d --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/bch-regs.h @@ -0,0 +1,84 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_BCH_REGS_H +#define __GPMI_NAND_BCH_REGS_H + +#define HW_BCH_CTRL 0x00000000 +#define HW_BCH_CTRL_SET 0x00000004 +#define HW_BCH_CTRL_CLR 0x00000008 +#define HW_BCH_CTRL_TOG 0x0000000c + +#define BM_BCH_CTRL_COMPLETE_IRQ_EN (1 << 8) +#define BM_BCH_CTRL_COMPLETE_IRQ (1 << 0) + +#define HW_BCH_STATUS0 0x00000010 +#define HW_BCH_MODE 0x00000020 +#define HW_BCH_ENCODEPTR 0x00000030 +#define HW_BCH_DATAPTR 0x00000040 +#define HW_BCH_METAPTR 0x00000050 +#define HW_BCH_LAYOUTSELECT 0x00000070 + +#define HW_BCH_FLASH0LAYOUT0 0x00000080 + +#define BP_BCH_FLASH0LAYOUT0_NBLOCKS 24 +#define BM_BCH_FLASH0LAYOUT0_NBLOCKS (0xff << BP_BCH_FLASH0LAYOUT0_NBLOCKS) +#define BF_BCH_FLASH0LAYOUT0_NBLOCKS(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_NBLOCKS) & BM_BCH_FLASH0LAYOUT0_NBLOCKS) + +#define BP_BCH_FLASH0LAYOUT0_META_SIZE 16 +#define BM_BCH_FLASH0LAYOUT0_META_SIZE (0xff << BP_BCH_FLASH0LAYOUT0_META_SIZE) +#define BF_BCH_FLASH0LAYOUT0_META_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_META_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_META_SIZE) + +#define BP_BCH_FLASH0LAYOUT0_ECC0 12 +#define BM_BCH_FLASH0LAYOUT0_ECC0 (0xf << BP_BCH_FLASH0LAYOUT0_ECC0) +#define BF_BCH_FLASH0LAYOUT0_ECC0(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_ECC0) & BM_BCH_FLASH0LAYOUT0_ECC0) + +#define BP_BCH_FLASH0LAYOUT0_DATA0_SIZE 0 +#define BM_BCH_FLASH0LAYOUT0_DATA0_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE) +#define BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT0_DATA0_SIZE)\ + & BM_BCH_FLASH0LAYOUT0_DATA0_SIZE) + +#define HW_BCH_FLASH0LAYOUT1 0x00000090 + +#define BP_BCH_FLASH0LAYOUT1_PAGE_SIZE 16 +#define BM_BCH_FLASH0LAYOUT1_PAGE_SIZE \ + (0xffff << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) +#define BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_PAGE_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_PAGE_SIZE) + +#define BP_BCH_FLASH0LAYOUT1_ECCN 12 +#define BM_BCH_FLASH0LAYOUT1_ECCN (0xf << BP_BCH_FLASH0LAYOUT1_ECCN) +#define BF_BCH_FLASH0LAYOUT1_ECCN(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_ECCN) & BM_BCH_FLASH0LAYOUT1_ECCN) + +#define BP_BCH_FLASH0LAYOUT1_DATAN_SIZE 0 +#define BM_BCH_FLASH0LAYOUT1_DATAN_SIZE \ + (0xfff << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#define BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(v) \ + (((v) << BP_BCH_FLASH0LAYOUT1_DATAN_SIZE) \ + & BM_BCH_FLASH0LAYOUT1_DATAN_SIZE) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c new file mode 100644 index 00000000000..de4db7604a3 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -0,0 +1,1057 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/mtd/gpmi-nand.h> +#include <linux/delay.h> +#include <linux/clk.h> +#include <mach/mxs.h> + +#include "gpmi-nand.h" +#include "gpmi-regs.h" +#include "bch-regs.h" + +struct timing_threshod timing_default_threshold = { + .max_data_setup_cycles = (BM_GPMI_TIMING0_DATA_SETUP >> + BP_GPMI_TIMING0_DATA_SETUP), + .internal_data_setup_in_ns = 0, + .max_sample_delay_factor = (BM_GPMI_CTRL1_RDN_DELAY >> + BP_GPMI_CTRL1_RDN_DELAY), + .max_dll_clock_period_in_ns = 32, + .max_dll_delay_in_ns = 16, +}; + +/* + * Clear the bit and poll it cleared. This is usually called with + * a reset address and mask being either SFTRST(bit 31) or CLKGATE + * (bit 30). + */ +static int clear_poll_bit(void __iomem *addr, u32 mask) +{ + int timeout = 0x400; + + /* clear the bit */ + __mxs_clrl(mask, addr); + + /* + * SFTRST needs 3 GPMI clocks to settle, the reference manual + * recommends to wait 1us. + */ + udelay(1); + + /* poll the bit becoming clear */ + while ((readl(addr) & mask) && --timeout) + /* nothing */; + + return !timeout; +} + +#define MODULE_CLKGATE (1 << 30) +#define MODULE_SFTRST (1 << 31) +/* + * The current mxs_reset_block() will do two things: + * [1] enable the module. + * [2] reset the module. + * + * In most of the cases, it's ok. But there is a hardware bug in the BCH block. + * If you try to soft reset the BCH block, it becomes unusable until + * the next hard reset. This case occurs in the NAND boot mode. When the board + * boots by NAND, the ROM of the chip will initialize the BCH blocks itself. + * So If the driver tries to reset the BCH again, the BCH will not work anymore. + * You will see a DMA timeout in this case. + * + * To avoid this bug, just add a new parameter `just_enable` for + * the mxs_reset_block(), and rewrite it here. + */ +int gpmi_reset_block(void __iomem *reset_addr, bool just_enable) +{ + int ret; + int timeout = 0x400; + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear CLKGATE */ + __mxs_clrl(MODULE_CLKGATE, reset_addr); + + if (!just_enable) { + /* set SFTRST to reset the block */ + __mxs_setl(MODULE_SFTRST, reset_addr); + udelay(1); + + /* poll CLKGATE becoming set */ + while ((!(readl(reset_addr) & MODULE_CLKGATE)) && --timeout) + /* nothing */; + if (unlikely(!timeout)) + goto error; + } + + /* clear and poll SFTRST */ + ret = clear_poll_bit(reset_addr, MODULE_SFTRST); + if (unlikely(ret)) + goto error; + + /* clear and poll CLKGATE */ + ret = clear_poll_bit(reset_addr, MODULE_CLKGATE); + if (unlikely(ret)) + goto error; + + return 0; + +error: + pr_err("%s(%p): module reset timeout\n", __func__, reset_addr); + return -ETIMEDOUT; +} + +int gpmi_init(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + int ret; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + ret = gpmi_reset_block(r->gpmi_regs, false); + if (ret) + goto err_out; + + /* Choose NAND mode. */ + writel(BM_GPMI_CTRL1_GPMI_MODE, r->gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Set the IRQ polarity. */ + writel(BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY, + r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Disable Write-Protection. */ + writel(BM_GPMI_CTRL1_DEV_RESET, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Select BCH ECC. */ + writel(BM_GPMI_CTRL1_BCH_MODE, r->gpmi_regs + HW_GPMI_CTRL1_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* This function is very useful. It is called only when the bug occur. */ +void gpmi_dump_info(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *geo = &this->bch_geometry; + u32 reg; + int i; + + pr_err("Show GPMI registers :\n"); + for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) { + reg = readl(r->gpmi_regs + i * 0x10); + pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg); + } + + /* start to print out the BCH info */ + pr_err("BCH Geometry :\n"); + pr_err("GF length : %u\n", geo->gf_len); + pr_err("ECC Strength : %u\n", geo->ecc_strength); + pr_err("Page Size in Bytes : %u\n", geo->page_size); + pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size); + pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size); + pr_err("ECC Chunk Count : %u\n", geo->ecc_chunk_count); + pr_err("Payload Size in Bytes : %u\n", geo->payload_size); + pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size); + pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset); + pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset); + pr_err("Block Mark Bit Offset : %u\n", geo->block_mark_bit_offset); +} + +/* Configures the geometry for BCH. */ +int bch_set_geometry(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct bch_geometry *bch_geo = &this->bch_geometry; + unsigned int block_count; + unsigned int block_size; + unsigned int metadata_size; + unsigned int ecc_strength; + unsigned int page_size; + int ret; + + if (common_nfc_set_geometry(this)) + return !0; + + block_count = bch_geo->ecc_chunk_count - 1; + block_size = bch_geo->ecc_chunk_size; + metadata_size = bch_geo->metadata_size; + ecc_strength = bch_geo->ecc_strength >> 1; + page_size = bch_geo->page_size; + + ret = clk_enable(r->clock); + if (ret) + goto err_out; + + ret = gpmi_reset_block(r->bch_regs, true); + if (ret) + goto err_out; + + /* Configure layout 0. */ + writel(BF_BCH_FLASH0LAYOUT0_NBLOCKS(block_count) + | BF_BCH_FLASH0LAYOUT0_META_SIZE(metadata_size) + | BF_BCH_FLASH0LAYOUT0_ECC0(ecc_strength) + | BF_BCH_FLASH0LAYOUT0_DATA0_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT0); + + writel(BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size) + | BF_BCH_FLASH0LAYOUT1_ECCN(ecc_strength) + | BF_BCH_FLASH0LAYOUT1_DATAN_SIZE(block_size), + r->bch_regs + HW_BCH_FLASH0LAYOUT1); + + /* Set *all* chip selects to use layout 0. */ + writel(0, r->bch_regs + HW_BCH_LAYOUTSELECT); + + /* Enable interrupts. */ + writel(BM_BCH_CTRL_COMPLETE_IRQ_EN, + r->bch_regs + HW_BCH_CTRL_SET); + + clk_disable(r->clock); + return 0; +err_out: + return ret; +} + +/* Converts time in nanoseconds to cycles. */ +static unsigned int ns_to_cycles(unsigned int time, + unsigned int period, unsigned int min) +{ + unsigned int k; + + k = (time + period - 1) / period; + return max(k, min); +} + +/* Apply timing to current hardware conditions. */ +static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this, + struct gpmi_nfc_hardware_timing *hw) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct timing_threshod *nfc = &timing_default_threshold; + struct nand_chip *nand = &this->nand; + struct nand_timing target = this->timing; + bool improved_timing_is_available; + unsigned long clock_frequency_in_hz; + unsigned int clock_period_in_ns; + bool dll_use_half_periods; + unsigned int dll_delay_shift; + unsigned int max_sample_delay_in_ns; + unsigned int address_setup_in_cycles; + unsigned int data_setup_in_ns; + unsigned int data_setup_in_cycles; + unsigned int data_hold_in_cycles; + int ideal_sample_delay_in_ns; + unsigned int sample_delay_factor; + int tEYE; + unsigned int min_prop_delay_in_ns = pdata->min_prop_delay_in_ns; + unsigned int max_prop_delay_in_ns = pdata->max_prop_delay_in_ns; + + /* + * If there are multiple chips, we need to relax the timings to allow + * for signal distortion due to higher capacitance. + */ + if (nand->numchips > 2) { + target.data_setup_in_ns += 10; + target.data_hold_in_ns += 10; + target.address_setup_in_ns += 10; + } else if (nand->numchips > 1) { + target.data_setup_in_ns += 5; + target.data_hold_in_ns += 5; + target.address_setup_in_ns += 5; + } + + /* Check if improved timing information is available. */ + improved_timing_is_available = + (target.tREA_in_ns >= 0) && + (target.tRLOH_in_ns >= 0) && + (target.tRHOH_in_ns >= 0) ; + + /* Inspect the clock. */ + clock_frequency_in_hz = nfc->clock_frequency_in_hz; + clock_period_in_ns = 1000000000 / clock_frequency_in_hz; + + /* + * The NFC quantizes setup and hold parameters in terms of clock cycles. + * Here, we quantize the setup and hold timing parameters to the + * next-highest clock period to make sure we apply at least the + * specified times. + * + * For data setup and data hold, the hardware interprets a value of zero + * as the largest possible delay. This is not what's intended by a zero + * in the input parameter, so we impose a minimum of one cycle. + */ + data_setup_in_cycles = ns_to_cycles(target.data_setup_in_ns, + clock_period_in_ns, 1); + data_hold_in_cycles = ns_to_cycles(target.data_hold_in_ns, + clock_period_in_ns, 1); + address_setup_in_cycles = ns_to_cycles(target.address_setup_in_ns, + clock_period_in_ns, 0); + + /* + * The clock's period affects the sample delay in a number of ways: + * + * (1) The NFC HAL tells us the maximum clock period the sample delay + * DLL can tolerate. If the clock period is greater than half that + * maximum, we must configure the DLL to be driven by half periods. + * + * (2) We need to convert from an ideal sample delay, in ns, to a + * "sample delay factor," which the NFC uses. This factor depends on + * whether we're driving the DLL with full or half periods. + * Paraphrasing the reference manual: + * + * AD = SDF x 0.125 x RP + * + * where: + * + * AD is the applied delay, in ns. + * SDF is the sample delay factor, which is dimensionless. + * RP is the reference period, in ns, which is a full clock period + * if the DLL is being driven by full periods, or half that if + * the DLL is being driven by half periods. + * + * Let's re-arrange this in a way that's more useful to us: + * + * 8 + * SDF = AD x ---- + * RP + * + * The reference period is either the clock period or half that, so this + * is: + * + * 8 AD x DDF + * SDF = AD x ----- = -------- + * f x P P + * + * where: + * + * f is 1 or 1/2, depending on how we're driving the DLL. + * P is the clock period. + * DDF is the DLL Delay Factor, a dimensionless value that + * incorporates all the constants in the conversion. + * + * DDF will be either 8 or 16, both of which are powers of two. We can + * reduce the cost of this conversion by using bit shifts instead of + * multiplication or division. Thus: + * + * AD << DDS + * SDF = --------- + * P + * + * or + * + * AD = (SDF >> DDS) x P + * + * where: + * + * DDS is the DLL Delay Shift, the logarithm to base 2 of the DDF. + */ + if (clock_period_in_ns > (nfc->max_dll_clock_period_in_ns >> 1)) { + dll_use_half_periods = true; + dll_delay_shift = 3 + 1; + } else { + dll_use_half_periods = false; + dll_delay_shift = 3; + } + + /* + * Compute the maximum sample delay the NFC allows, under current + * conditions. If the clock is running too slowly, no sample delay is + * possible. + */ + if (clock_period_in_ns > nfc->max_dll_clock_period_in_ns) + max_sample_delay_in_ns = 0; + else { + /* + * Compute the delay implied by the largest sample delay factor + * the NFC allows. + */ + max_sample_delay_in_ns = + (nfc->max_sample_delay_factor * clock_period_in_ns) >> + dll_delay_shift; + + /* + * Check if the implied sample delay larger than the NFC + * actually allows. + */ + if (max_sample_delay_in_ns > nfc->max_dll_delay_in_ns) + max_sample_delay_in_ns = nfc->max_dll_delay_in_ns; + } + + /* + * Check if improved timing information is available. If not, we have to + * use a less-sophisticated algorithm. + */ + if (!improved_timing_is_available) { + /* + * Fold the read setup time required by the NFC into the ideal + * sample delay. + */ + ideal_sample_delay_in_ns = target.gpmi_sample_delay_in_ns + + nfc->internal_data_setup_in_ns; + + /* + * The ideal sample delay may be greater than the maximum + * allowed by the NFC. If so, we can trade off sample delay time + * for more data setup time. + * + * In each iteration of the following loop, we add a cycle to + * the data setup time and subtract a corresponding amount from + * the sample delay until we've satisified the constraints or + * can't do any better. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + data_setup_in_cycles++; + ideal_sample_delay_in_ns -= clock_period_in_ns; + + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + } + + /* + * Compute the sample delay factor that corresponds most closely + * to the ideal sample delay. If the result is too large for the + * NFC, use the maximum value. + * + * Notice that we use the ns_to_cycles function to compute the + * sample delay factor. We do this because the form of the + * computation is the same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* Skip to the part where we return our results. */ + goto return_results; + } + + /* + * If control arrives here, we have more detailed timing information, + * so we can use a better algorithm. + */ + + /* + * Fold the read setup time required by the NFC into the maximum + * propagation delay. + */ + max_prop_delay_in_ns += nfc->internal_data_setup_in_ns; + + /* + * Earlier, we computed the number of clock cycles required to satisfy + * the data setup time. Now, we need to know the actual nanoseconds. + */ + data_setup_in_ns = clock_period_in_ns * data_setup_in_cycles; + + /* + * Compute tEYE, the width of the data eye when reading from the NAND + * Flash. The eye width is fundamentally determined by the data setup + * time, perturbed by propagation delays and some characteristics of the + * NAND Flash device. + * + * start of the eye = max_prop_delay + tREA + * end of the eye = min_prop_delay + tRHOH + data_setup + */ + tEYE = (int)min_prop_delay_in_ns + (int)target.tRHOH_in_ns + + (int)data_setup_in_ns; + + tEYE -= (int)max_prop_delay_in_ns + (int)target.tREA_in_ns; + + /* + * The eye must be open. If it's not, we can try to open it by + * increasing its main forcer, the data setup time. + * + * In each iteration of the following loop, we increase the data setup + * time by a single clock cycle. We do this until either the eye is + * open or we run into NFC limits. + */ + while ((tEYE <= 0) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + } + + /* + * When control arrives here, the eye is open. The ideal time to sample + * the data is in the center of the eye: + * + * end of the eye + start of the eye + * --------------------------------- - data_setup + * 2 + * + * After some algebra, this simplifies to the code immediately below. + */ + ideal_sample_delay_in_ns = + ((int)max_prop_delay_in_ns + + (int)target.tREA_in_ns + + (int)min_prop_delay_in_ns + + (int)target.tRHOH_in_ns - + (int)data_setup_in_ns) >> 1; + + /* + * The following figure illustrates some aspects of a NAND Flash read: + * + * + * __ _____________________________________ + * RDN \_________________/ + * + * <---- tEYE -----> + * /-----------------\ + * Read Data ----------------------------< >--------- + * \-----------------/ + * ^ ^ ^ ^ + * | | | | + * |<--Data Setup -->|<--Delay Time -->| | + * | | | | + * | | | + * | |<-- Quantized Delay Time -->| + * | | | + * + * + * We have some issues we must now address: + * + * (1) The *ideal* sample delay time must not be negative. If it is, we + * jam it to zero. + * + * (2) The *ideal* sample delay time must not be greater than that + * allowed by the NFC. If it is, we can increase the data setup + * time, which will reduce the delay between the end of the data + * setup and the center of the eye. It will also make the eye + * larger, which might help with the next issue... + * + * (3) The *quantized* sample delay time must not fall either before the + * eye opens or after it closes (the latter is the problem + * illustrated in the above figure). + */ + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * Extend the data setup as needed to reduce the ideal sample delay + * below the maximum permitted by the NFC. + */ + while ((ideal_sample_delay_in_ns > max_sample_delay_in_ns) && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + } + + /* + * Compute the sample delay factor that corresponds to the ideal sample + * delay. If the result is too large, then use the maximum allowed + * value. + * + * Notice that we use the ns_to_cycles function to compute the sample + * delay factor. We do this because the form of the computation is the + * same as that for calculating cycles. + */ + sample_delay_factor = + ns_to_cycles(ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + + /* + * These macros conveniently encapsulate a computation we'll use to + * continuously evaluate whether or not the data sample delay is inside + * the eye. + */ + #define IDEAL_DELAY ((int) ideal_sample_delay_in_ns) + + #define QUANTIZED_DELAY \ + ((int) ((sample_delay_factor * clock_period_in_ns) >> \ + dll_delay_shift)) + + #define DELAY_ERROR (abs(QUANTIZED_DELAY - IDEAL_DELAY)) + + #define SAMPLE_IS_NOT_WITHIN_THE_EYE (DELAY_ERROR > (tEYE >> 1)) + + /* + * While the quantized sample time falls outside the eye, reduce the + * sample delay or extend the data setup to move the sampling point back + * toward the eye. Do not allow the number of data setup cycles to + * exceed the maximum allowed by the NFC. + */ + while (SAMPLE_IS_NOT_WITHIN_THE_EYE && + (data_setup_in_cycles < nfc->max_data_setup_cycles)) { + /* + * If control arrives here, the quantized sample delay falls + * outside the eye. Check if it's before the eye opens, or after + * the eye closes. + */ + if (QUANTIZED_DELAY > IDEAL_DELAY) { + /* + * If control arrives here, the quantized sample delay + * falls after the eye closes. Decrease the quantized + * delay time and then go back to re-evaluate. + */ + if (sample_delay_factor != 0) + sample_delay_factor--; + continue; + } + + /* + * If control arrives here, the quantized sample delay falls + * before the eye opens. Shift the sample point by increasing + * data setup time. This will also make the eye larger. + */ + + /* Give a cycle to data setup. */ + data_setup_in_cycles++; + /* Synchronize the data setup time with the cycles. */ + data_setup_in_ns += clock_period_in_ns; + /* Adjust tEYE accordingly. */ + tEYE += clock_period_in_ns; + + /* + * Decrease the ideal sample delay by one half cycle, to keep it + * in the middle of the eye. + */ + ideal_sample_delay_in_ns -= (clock_period_in_ns >> 1); + + /* ...and one less period for the delay time. */ + ideal_sample_delay_in_ns -= clock_period_in_ns; + + /* Jam a negative ideal sample delay to zero. */ + if (ideal_sample_delay_in_ns < 0) + ideal_sample_delay_in_ns = 0; + + /* + * We have a new ideal sample delay, so re-compute the quantized + * delay. + */ + sample_delay_factor = + ns_to_cycles( + ideal_sample_delay_in_ns << dll_delay_shift, + clock_period_in_ns, 0); + + if (sample_delay_factor > nfc->max_sample_delay_factor) + sample_delay_factor = nfc->max_sample_delay_factor; + } + + /* Control arrives here when we're ready to return our results. */ +return_results: + hw->data_setup_in_cycles = data_setup_in_cycles; + hw->data_hold_in_cycles = data_hold_in_cycles; + hw->address_setup_in_cycles = address_setup_in_cycles; + hw->use_half_periods = dll_use_half_periods; + hw->sample_delay_factor = sample_delay_factor; + + /* Return success. */ + return 0; +} + +/* Begin the I/O */ +void gpmi_begin(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + struct timing_threshod *nfc = &timing_default_threshold; + unsigned char *gpmi_regs = r->gpmi_regs; + unsigned int clock_period_in_ns; + uint32_t reg; + unsigned int dll_wait_time_in_us; + struct gpmi_nfc_hardware_timing hw; + int ret; + + /* Enable the clock. */ + ret = clk_enable(r->clock); + if (ret) { + pr_err("We failed in enable the clk\n"); + goto err_out; + } + + /* set ready/busy timeout */ + writel(0x500 << BP_GPMI_TIMING1_BUSY_TIMEOUT, + gpmi_regs + HW_GPMI_TIMING1); + + /* Get the timing information we need. */ + nfc->clock_frequency_in_hz = clk_get_rate(r->clock); + clock_period_in_ns = 1000000000 / nfc->clock_frequency_in_hz; + + gpmi_nfc_compute_hardware_timing(this, &hw); + + /* Set up all the simple timing parameters. */ + reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) | + BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles) | + BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles) ; + + writel(reg, gpmi_regs + HW_GPMI_TIMING0); + + /* + * DLL_ENABLE must be set to 0 when setting RDN_DELAY or HALF_PERIOD. + */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* Clear out the DLL control fields. */ + writel(BM_GPMI_CTRL1_RDN_DELAY, gpmi_regs + HW_GPMI_CTRL1_CLR); + writel(BM_GPMI_CTRL1_HALF_PERIOD, gpmi_regs + HW_GPMI_CTRL1_CLR); + + /* If no sample delay is called for, return immediately. */ + if (!hw.sample_delay_factor) + return; + + /* Configure the HALF_PERIOD flag. */ + if (hw.use_half_periods) + writel(BM_GPMI_CTRL1_HALF_PERIOD, + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Set the delay factor. */ + writel(BF_GPMI_CTRL1_RDN_DELAY(hw.sample_delay_factor), + gpmi_regs + HW_GPMI_CTRL1_SET); + + /* Enable the DLL. */ + writel(BM_GPMI_CTRL1_DLL_ENABLE, gpmi_regs + HW_GPMI_CTRL1_SET); + + /* + * After we enable the GPMI DLL, we have to wait 64 clock cycles before + * we can use the GPMI. + * + * Calculate the amount of time we need to wait, in microseconds. + */ + dll_wait_time_in_us = (clock_period_in_ns * 64) / 1000; + + if (!dll_wait_time_in_us) + dll_wait_time_in_us = 1; + + /* Wait for the DLL to settle. */ + udelay(dll_wait_time_in_us); + +err_out: + return; +} + +void gpmi_end(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + clk_disable(r->clock); +} + +/* Clears a BCH interrupt. */ +void gpmi_clear_bch(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + writel(BM_BCH_CTRL_COMPLETE_IRQ, r->bch_regs + HW_BCH_CTRL_CLR); +} + +/* Returns the Ready/Busy status of the given chip. */ +int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip) +{ + struct resources *r = &this->resources; + uint32_t mask = 0; + uint32_t reg = 0; + + if (GPMI_IS_MX23(this)) { + mask = MX23_BM_GPMI_DEBUG_READY0 << chip; + reg = readl(r->gpmi_regs + HW_GPMI_DEBUG); + } else if (GPMI_IS_MX28(this)) { + mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip); + reg = readl(r->gpmi_regs + HW_GPMI_STAT); + } else + pr_err("unknow arch.\n"); + return reg & mask; +} + +static inline void set_dma_type(struct gpmi_nand_data *this, + enum dma_ops_type type) +{ + this->last_dma_type = this->dma_type; + this->dma_type = type; +} + +int gpmi_send_command(struct gpmi_nand_data *this) +{ + struct dma_chan *channel = get_dma_chan(this); + struct dma_async_tx_descriptor *desc; + struct scatterlist *sgl; + int chip = this->current_chip; + u32 pio[3]; + + /* [1] send out the PIO words */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__WRITE) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_CLE) + | BM_GPMI_CTRL0_ADDRESS_INCREMENT + | BF_GPMI_CTRL0_XFER_COUNT(this->command_length); + pio[1] = pio[2] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send out the COMMAND + ADDRESS string stored in @buffer */ + sgl = &this->cmd_sgl; + + sg_init_one(sgl, this->cmd_buffer, this->command_length); + dma_map_sg(this->dev, sgl, 1, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, + sgl, 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_COMMAND); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + uint32_t command_mode; + uint32_t address; + u32 pio[2]; + + /* [1] PIO */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] send DMA request */ + prepare_data_dma(this, DMA_TO_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_TO_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + /* [3] submit the DMA */ + set_dma_type(this, DMA_FOR_WRITE_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_read_data(struct gpmi_nand_data *this) +{ + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[2]; + + /* [1] : send PIO */ + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(BV_GPMI_CTRL0_COMMAND_MODE__READ) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(BV_GPMI_CTRL0_ADDRESS__NAND_DATA) + | BF_GPMI_CTRL0_XFER_COUNT(this->upper_len); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] : send DMA request */ + prepare_data_dma(this, DMA_FROM_DEVICE); + desc = channel->device->device_prep_slave_sg(channel, &this->data_sgl, + 1, DMA_FROM_DEVICE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] : submit the DMA */ + set_dma_type(this, DMA_FOR_READ_DATA); + return start_dma_without_bch_irq(this, desc); +} + +int gpmi_send_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* A DMA descriptor that does an ECC page read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WRITE; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE | + BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 0); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} + +int gpmi_read_page(struct gpmi_nand_data *this, + dma_addr_t payload, dma_addr_t auxiliary) +{ + struct bch_geometry *geo = &this->bch_geometry; + uint32_t command_mode; + uint32_t address; + uint32_t ecc_command; + uint32_t buffer_mask; + struct dma_async_tx_descriptor *desc; + struct dma_chan *channel = get_dma_chan(this); + int chip = this->current_chip; + u32 pio[6]; + + /* [1] Wait for the chip to report ready. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(0); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 0); + if (!desc) { + pr_err("step 1 error\n"); + return -1; + } + + /* [2] Enable the BCH block and read. */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + ecc_command = BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE; + buffer_mask = BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE + | BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + + pio[1] = 0; + pio[2] = BM_GPMI_ECCCTRL_ENABLE_ECC + | BF_GPMI_ECCCTRL_ECC_CMD(ecc_command) + | BF_GPMI_ECCCTRL_BUFFER_MASK(buffer_mask); + pio[3] = geo->page_size; + pio[4] = payload; + pio[5] = auxiliary; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, + ARRAY_SIZE(pio), DMA_NONE, 1); + if (!desc) { + pr_err("step 2 error\n"); + return -1; + } + + /* [3] Disable the BCH block */ + command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY; + address = BV_GPMI_CTRL0_ADDRESS__NAND_DATA; + + pio[0] = BF_GPMI_CTRL0_COMMAND_MODE(command_mode) + | BM_GPMI_CTRL0_WORD_LENGTH + | BF_GPMI_CTRL0_CS(chip, this) + | BF_GPMI_CTRL0_LOCK_CS(LOCK_CS_ENABLE, this) + | BF_GPMI_CTRL0_ADDRESS(address) + | BF_GPMI_CTRL0_XFER_COUNT(geo->page_size); + pio[1] = 0; + desc = channel->device->device_prep_slave_sg(channel, + (struct scatterlist *)pio, 2, DMA_NONE, 1); + if (!desc) { + pr_err("step 3 error\n"); + return -1; + } + + /* [4] submit the DMA */ + set_dma_type(this, DMA_FOR_READ_ECC_PAGE); + return start_dma_with_bch_irq(this, desc); +} diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c new file mode 100644 index 00000000000..493ec2fcf97 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -0,0 +1,1619 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include <linux/clk.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/mtd/gpmi-nand.h> +#include <linux/mtd/partitions.h> +#include "gpmi-nand.h" + +/* add our owner bbt descriptor */ +static uint8_t scan_ff_pattern[] = { 0xff }; +static struct nand_bbt_descr gpmi_bbt_descr = { + .options = 0, + .offs = 0, + .len = 1, + .pattern = scan_ff_pattern +}; + +/* We will use all the (page + OOB). */ +static struct nand_ecclayout gpmi_hw_ecclayout = { + .eccbytes = 0, + .eccpos = { 0, }, + .oobfree = { {.offset = 0, .length = 0} } +}; + +static irqreturn_t bch_irq(int irq, void *cookie) +{ + struct gpmi_nand_data *this = cookie; + + gpmi_clear_bch(this); + complete(&this->bch_done); + return IRQ_HANDLED; +} + +/* + * Calculate the ECC strength by hand: + * E : The ECC strength. + * G : the length of Galois Field. + * N : The chunk count of per page. + * O : the oobsize of the NAND chip. + * M : the metasize of per page. + * + * The formula is : + * E * G * N + * ------------ <= (O - M) + * 8 + * + * So, we get E by: + * (O - M) * 8 + * E <= ------------- + * G * N + */ +static inline int get_ecc_strength(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + int ecc_strength; + + ecc_strength = ((mtd->oobsize - geo->metadata_size) * 8) + / (geo->gf_len * geo->ecc_chunk_count); + + /* We need the minor even number. */ + return round_down(ecc_strength, 2); +} + +int common_nfc_set_geometry(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct mtd_info *mtd = &this->mtd; + unsigned int metadata_size; + unsigned int status_size; + unsigned int block_mark_bit_offset; + + /* + * The size of the metadata can be changed, though we set it to 10 + * bytes now. But it can't be too large, because we have to save + * enough space for BCH. + */ + geo->metadata_size = 10; + + /* The default for the length of Galois Field. */ + geo->gf_len = 13; + + /* The default for chunk size. There is no oobsize greater then 512. */ + geo->ecc_chunk_size = 512; + while (geo->ecc_chunk_size < mtd->oobsize) + geo->ecc_chunk_size *= 2; /* keep C >= O */ + + geo->ecc_chunk_count = mtd->writesize / geo->ecc_chunk_size; + + /* We use the same ECC strength for all chunks. */ + geo->ecc_strength = get_ecc_strength(this); + if (!geo->ecc_strength) { + pr_err("We get a wrong ECC strength.\n"); + return -EINVAL; + } + + geo->page_size = mtd->writesize + mtd->oobsize; + geo->payload_size = mtd->writesize; + + /* + * The auxiliary buffer contains the metadata and the ECC status. The + * metadata is padded to the nearest 32-bit boundary. The ECC status + * contains one byte for every ECC chunk, and is also padded to the + * nearest 32-bit boundary. + */ + metadata_size = ALIGN(geo->metadata_size, 4); + status_size = ALIGN(geo->ecc_chunk_count, 4); + + geo->auxiliary_size = metadata_size + status_size; + geo->auxiliary_status_offset = metadata_size; + + if (!this->swap_block_mark) + return 0; + + /* + * We need to compute the byte and bit offsets of + * the physical block mark within the ECC-based view of the page. + * + * NAND chip with 2K page shows below: + * (Block Mark) + * | | + * | D | + * |<---->| + * V V + * +---+----------+-+----------+-+----------+-+----------+-+ + * | M | data |E| data |E| data |E| data |E| + * +---+----------+-+----------+-+----------+-+----------+-+ + * + * The position of block mark moves forward in the ECC-based view + * of page, and the delta is: + * + * E * G * (N - 1) + * D = (---------------- + M) + * 8 + * + * With the formula to compute the ECC strength, and the condition + * : C >= O (C is the ecc chunk size) + * + * It's easy to deduce to the following result: + * + * E * G (O - M) C - M C - M + * ----------- <= ------- <= -------- < --------- + * 8 N N (N - 1) + * + * So, we get: + * + * E * G * (N - 1) + * D = (---------------- + M) < C + * 8 + * + * The above inequality means the position of block mark + * within the ECC-based view of the page is still in the data chunk, + * and it's NOT in the ECC bits of the chunk. + * + * Use the following to compute the bit position of the + * physical block mark within the ECC-based view of the page: + * (page_size - D) * 8 + * + * --Huang Shijie + */ + block_mark_bit_offset = mtd->writesize * 8 - + (geo->ecc_strength * geo->gf_len * (geo->ecc_chunk_count - 1) + + geo->metadata_size * 8); + + geo->block_mark_byte_offset = block_mark_bit_offset / 8; + geo->block_mark_bit_offset = block_mark_bit_offset % 8; + return 0; +} + +struct dma_chan *get_dma_chan(struct gpmi_nand_data *this) +{ + int chipnr = this->current_chip; + + return this->dma_chans[chipnr]; +} + +/* Can we use the upper's buffer directly for DMA? */ +void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr) +{ + struct scatterlist *sgl = &this->data_sgl; + int ret; + + this->direct_dma_map_ok = true; + + /* first try to map the upper buffer directly */ + sg_init_one(sgl, this->upper_buf, this->upper_len); + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) { + /* We have to use our own DMA buffer. */ + sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE); + + if (dr == DMA_TO_DEVICE) + memcpy(this->data_buffer_dma, this->upper_buf, + this->upper_len); + + ret = dma_map_sg(this->dev, sgl, 1, dr); + if (ret == 0) + pr_err("map failed.\n"); + + this->direct_dma_map_ok = false; + } +} + +/* This will be called after the DMA operation is finished. */ +static void dma_irq_callback(void *param) +{ + struct gpmi_nand_data *this = param; + struct completion *dma_c = &this->dma_done; + + complete(dma_c); + + switch (this->dma_type) { + case DMA_FOR_COMMAND: + dma_unmap_sg(this->dev, &this->cmd_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_FROM_DEVICE); + if (this->direct_dma_map_ok == false) + memcpy(this->upper_buf, this->data_buffer_dma, + this->upper_len); + break; + + case DMA_FOR_WRITE_DATA: + dma_unmap_sg(this->dev, &this->data_sgl, 1, DMA_TO_DEVICE); + break; + + case DMA_FOR_READ_ECC_PAGE: + case DMA_FOR_WRITE_ECC_PAGE: + /* We have to wait the BCH interrupt to finish. */ + break; + + default: + pr_err("in wrong DMA operation.\n"); + } +} + +int start_dma_without_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *dma_c = &this->dma_done; + int err; + + init_completion(dma_c); + + desc->callback = dma_irq_callback; + desc->callback_param = this; + dmaengine_submit(desc); + + /* Wait for the interrupt from the DMA block. */ + err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +/* + * This function is used in BCH reading or BCH writing pages. + * It will wait for the BCH interrupt as long as ONE second. + * Actually, we must wait for two interrupts : + * [1] firstly the DMA interrupt and + * [2] secondly the BCH interrupt. + */ +int start_dma_with_bch_irq(struct gpmi_nand_data *this, + struct dma_async_tx_descriptor *desc) +{ + struct completion *bch_c = &this->bch_done; + int err; + + /* Prepare to receive an interrupt from the BCH block. */ + init_completion(bch_c); + + /* start the DMA */ + start_dma_without_bch_irq(this, desc); + + /* Wait for the interrupt from the BCH block. */ + err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); + if (!err) { + pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type); + gpmi_dump_info(this); + return -ETIMEDOUT; + } + return 0; +} + +static int __devinit +acquire_register_block(struct gpmi_nand_data *this, const char *res_name) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + struct resource *r; + void *p; + + r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + p = ioremap(r->start, resource_size(r)); + if (!p) { + pr_err("Can't remap %s\n", res_name); + return -ENOMEM; + } + + if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME)) + res->gpmi_regs = p; + else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME)) + res->bch_regs = p; + else + pr_err("unknown resource name : %s\n", res_name); + + return 0; +} + +static void release_register_block(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + if (res->gpmi_regs) + iounmap(res->gpmi_regs); + if (res->bch_regs) + iounmap(res->bch_regs); + res->gpmi_regs = NULL; + res->bch_regs = NULL; +} + +static int __devinit +acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h) +{ + struct platform_device *pdev = this->pdev; + struct resources *res = &this->resources; + const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME; + struct resource *r; + int err; + + r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + if (!r) { + pr_err("Can't get resource for %s\n", res_name); + return -ENXIO; + } + + err = request_irq(r->start, irq_h, 0, res_name, this); + if (err) { + pr_err("Can't own %s\n", res_name); + return err; + } + + res->bch_low_interrupt = r->start; + res->bch_high_interrupt = r->end; + return 0; +} + +static void release_bch_irq(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int i = res->bch_low_interrupt; + + for (; i <= res->bch_high_interrupt; i++) + free_irq(i, this); +} + +static bool gpmi_dma_filter(struct dma_chan *chan, void *param) +{ + struct gpmi_nand_data *this = param; + struct resource *r = this->private; + + if (!mxs_dma_is_apbh(chan)) + return false; + /* + * only catch the GPMI dma channels : + * for mx23 : MX23_DMA_GPMI0 ~ MX23_DMA_GPMI3 + * (These four channels share the same IRQ!) + * + * for mx28 : MX28_DMA_GPMI0 ~ MX28_DMA_GPMI7 + * (These eight channels share the same IRQ!) + */ + if (r->start <= chan->chan_id && chan->chan_id <= r->end) { + chan->private = &this->dma_data; + return true; + } + return false; +} + +static void release_dma_channels(struct gpmi_nand_data *this) +{ + unsigned int i; + for (i = 0; i < DMA_CHANS; i++) + if (this->dma_chans[i]) { + dma_release_channel(this->dma_chans[i]); + this->dma_chans[i] = NULL; + } +} + +static int __devinit acquire_dma_channels(struct gpmi_nand_data *this) +{ + struct platform_device *pdev = this->pdev; + struct gpmi_nand_platform_data *pdata = this->pdata; + struct resources *res = &this->resources; + struct resource *r, *r_dma; + unsigned int i; + + r = platform_get_resource_byname(pdev, IORESOURCE_DMA, + GPMI_NAND_DMA_CHANNELS_RES_NAME); + r_dma = platform_get_resource_byname(pdev, IORESOURCE_IRQ, + GPMI_NAND_DMA_INTERRUPT_RES_NAME); + if (!r || !r_dma) { + pr_err("Can't get resource for DMA\n"); + return -ENXIO; + } + + /* used in gpmi_dma_filter() */ + this->private = r; + + for (i = r->start; i <= r->end; i++) { + struct dma_chan *dma_chan; + dma_cap_mask_t mask; + + if (i - r->start >= pdata->max_chip_count) + break; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* get the DMA interrupt */ + if (r_dma->start == r_dma->end) { + /* only register the first. */ + if (i == r->start) + this->dma_data.chan_irq = r_dma->start; + else + this->dma_data.chan_irq = NO_IRQ; + } else + this->dma_data.chan_irq = r_dma->start + (i - r->start); + + dma_chan = dma_request_channel(mask, gpmi_dma_filter, this); + if (!dma_chan) + goto acquire_err; + + /* fill the first empty item */ + this->dma_chans[i - r->start] = dma_chan; + } + + res->dma_low_channel = r->start; + res->dma_high_channel = i; + return 0; + +acquire_err: + pr_err("Can't acquire DMA channel %u\n", i); + release_dma_channels(this); + return -EINVAL; +} + +static int __devinit acquire_resources(struct gpmi_nand_data *this) +{ + struct resources *res = &this->resources; + int ret; + + ret = acquire_register_block(this, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_register_block(this, GPMI_NAND_BCH_REGS_ADDR_RES_NAME); + if (ret) + goto exit_regs; + + ret = acquire_bch_irq(this, bch_irq); + if (ret) + goto exit_regs; + + ret = acquire_dma_channels(this); + if (ret) + goto exit_dma_channels; + + res->clock = clk_get(&this->pdev->dev, NULL); + if (IS_ERR(res->clock)) { + pr_err("can not get the clock\n"); + ret = -ENOENT; + goto exit_clock; + } + return 0; + +exit_clock: + release_dma_channels(this); +exit_dma_channels: + release_bch_irq(this); +exit_regs: + release_register_block(this); + return ret; +} + +static void release_resources(struct gpmi_nand_data *this) +{ + struct resources *r = &this->resources; + + clk_put(r->clock); + release_register_block(this); + release_bch_irq(this); + release_dma_channels(this); +} + +static int __devinit init_hardware(struct gpmi_nand_data *this) +{ + int ret; + + /* + * This structure contains the "safe" GPMI timing that should succeed + * with any NAND Flash device + * (although, with less-than-optimal performance). + */ + struct nand_timing safe_timing = { + .data_setup_in_ns = 80, + .data_hold_in_ns = 60, + .address_setup_in_ns = 25, + .gpmi_sample_delay_in_ns = 6, + .tREA_in_ns = -1, + .tRLOH_in_ns = -1, + .tRHOH_in_ns = -1, + }; + + /* Initialize the hardwares. */ + ret = gpmi_init(this); + if (ret) + return ret; + + this->timing = safe_timing; + return 0; +} + +static int read_page_prepare(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(destination)) { + dma_addr_t dest_phys; + + dest_phys = dma_map_single(dev, destination, + length, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dest_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = destination; + *use_phys = dest_phys; + this->direct_dma_map_ok = true; + return 0; + } + +map_failed: + *use_virt = alt_virt; + *use_phys = alt_phys; + this->direct_dma_map_ok = false; + return 0; +} + +static inline void read_page_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (this->direct_dma_map_ok) + dma_unmap_single(this->dev, used_phys, length, DMA_FROM_DEVICE); +} + +static inline void read_page_swap_end(struct gpmi_nand_data *this, + void *destination, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + void *used_virt, dma_addr_t used_phys) +{ + if (!this->direct_dma_map_ok) + memcpy(destination, alt_virt, length); +} + +static int send_page_prepare(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void **use_virt, dma_addr_t *use_phys) +{ + struct device *dev = this->dev; + + if (virt_addr_valid(source)) { + dma_addr_t source_phys; + + source_phys = dma_map_single(dev, (void *)source, length, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, source_phys)) { + if (alt_size < length) { + pr_err("Alternate buffer is too small\n"); + return -ENOMEM; + } + goto map_failed; + } + *use_virt = source; + *use_phys = source_phys; + return 0; + } +map_failed: + /* + * Copy the content of the source buffer into the alternate + * buffer and set up the return values accordingly. + */ + memcpy(alt_virt, source, length); + + *use_virt = alt_virt; + *use_phys = alt_phys; + return 0; +} + +static void send_page_end(struct gpmi_nand_data *this, + const void *source, unsigned length, + void *alt_virt, dma_addr_t alt_phys, unsigned alt_size, + const void *used_virt, dma_addr_t used_phys) +{ + struct device *dev = this->dev; + if (used_virt == source) + dma_unmap_single(dev, used_phys, length, DMA_TO_DEVICE); +} + +static void gpmi_free_dma_buffer(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + + if (this->page_buffer_virt && virt_addr_valid(this->page_buffer_virt)) + dma_free_coherent(dev, this->page_buffer_size, + this->page_buffer_virt, + this->page_buffer_phys); + kfree(this->cmd_buffer); + kfree(this->data_buffer_dma); + + this->cmd_buffer = NULL; + this->data_buffer_dma = NULL; + this->page_buffer_virt = NULL; + this->page_buffer_size = 0; +} + +/* Allocate the DMA buffers */ +static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this) +{ + struct bch_geometry *geo = &this->bch_geometry; + struct device *dev = this->dev; + + /* [1] Allocate a command buffer. PAGE_SIZE is enough. */ + this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->cmd_buffer == NULL) + goto error_alloc; + + /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */ + this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA); + if (this->data_buffer_dma == NULL) + goto error_alloc; + + /* + * [3] Allocate the page buffer. + * + * Both the payload buffer and the auxiliary buffer must appear on + * 32-bit boundaries. We presume the size of the payload buffer is a + * power of two and is much larger than four, which guarantees the + * auxiliary buffer will appear on a 32-bit boundary. + */ + this->page_buffer_size = geo->payload_size + geo->auxiliary_size; + this->page_buffer_virt = dma_alloc_coherent(dev, this->page_buffer_size, + &this->page_buffer_phys, GFP_DMA); + if (!this->page_buffer_virt) + goto error_alloc; + + + /* Slice up the page buffer. */ + this->payload_virt = this->page_buffer_virt; + this->payload_phys = this->page_buffer_phys; + this->auxiliary_virt = this->payload_virt + geo->payload_size; + this->auxiliary_phys = this->payload_phys + geo->payload_size; + return 0; + +error_alloc: + gpmi_free_dma_buffer(this); + pr_err("allocate DMA buffer ret!!\n"); + return -ENOMEM; +} + +static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* + * Every operation begins with a command byte and a series of zero or + * more address bytes. These are distinguished by either the Address + * Latch Enable (ALE) or Command Latch Enable (CLE) signals being + * asserted. When MTD is ready to execute the command, it will deassert + * both latch enables. + * + * Rather than run a separate DMA operation for every single byte, we + * queue them up and run a single DMA operation for the entire series + * of command and data bytes. NAND_CMD_NONE means the END of the queue. + */ + if ((ctrl & (NAND_ALE | NAND_CLE))) { + if (data != NAND_CMD_NONE) + this->cmd_buffer[this->command_length++] = data; + return; + } + + if (!this->command_length) + return; + + ret = gpmi_send_command(this); + if (ret) + pr_err("Chip: %u, Error %d\n", this->current_chip, ret); + + this->command_length = 0; +} + +static int gpmi_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + return gpmi_is_ready(this, this->current_chip); +} + +static void gpmi_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + if ((this->current_chip < 0) && (chipnr >= 0)) + gpmi_begin(this); + else if ((this->current_chip >= 0) && (chipnr < 0)) + gpmi_end(this); + + this->current_chip = chipnr; +} + +static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = buf; + this->upper_len = len; + + gpmi_read_data(this); +} + +static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + + pr_debug("len is %d\n", len); + this->upper_buf = (uint8_t *)buf; + this->upper_len = len; + + gpmi_send_data(this); +} + +static uint8_t gpmi_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + uint8_t *buf = this->data_buffer_dma; + + gpmi_read_buf(mtd, buf, 1); + return buf[0]; +} + +/* + * Handles block mark swapping. + * It can be called in swapping the block mark, or swapping it back, + * because the the operations are the same. + */ +static void block_mark_swapping(struct gpmi_nand_data *this, + void *payload, void *auxiliary) +{ + struct bch_geometry *nfc_geo = &this->bch_geometry; + unsigned char *p; + unsigned char *a; + unsigned int bit; + unsigned char mask; + unsigned char from_data; + unsigned char from_oob; + + if (!this->swap_block_mark) + return; + + /* + * If control arrives here, we're swapping. Make some convenience + * variables. + */ + bit = nfc_geo->block_mark_bit_offset; + p = payload + nfc_geo->block_mark_byte_offset; + a = auxiliary; + + /* + * Get the byte from the data area that overlays the block mark. Since + * the ECC engine applies its own view to the bits in the page, the + * physical block mark won't (in general) appear on a byte boundary in + * the data. + */ + from_data = (p[0] >> bit) | (p[1] << (8 - bit)); + + /* Get the byte from the OOB. */ + from_oob = a[0]; + + /* Swap them. */ + a[0] = from_data; + + mask = (0x1 << bit) - 1; + p[0] = (p[0] & mask) | (from_oob << bit); + + mask = ~0 << bit; + p[1] = (p[1] & mask) | (from_oob >> (8 - bit)); +} + +static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int page) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + void *payload_virt; + dma_addr_t payload_phys; + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + unsigned int i; + unsigned char *status; + unsigned int failed; + unsigned int corrected; + int ret; + + pr_debug("page number is : %d\n", page); + ret = read_page_prepare(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate DMA buffer\n"); + ret = -ENOMEM; + return ret; + } + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* go! */ + ret = gpmi_read_page(this, payload_phys, auxiliary_phys); + read_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + if (ret) { + pr_err("Error in ECC-based read: %d\n", ret); + goto exit_nfc; + } + + /* handle the block mark swapping */ + block_mark_swapping(this, payload_virt, auxiliary_virt); + + /* Loop over status bytes, accumulating ECC status. */ + failed = 0; + corrected = 0; + status = auxiliary_virt + nfc_geo->auxiliary_status_offset; + + for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) { + if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED)) + continue; + + if (*status == STATUS_UNCORRECTABLE) { + failed++; + continue; + } + corrected += *status; + } + + /* + * Propagate ECC status to the owning MTD only when failed or + * corrected times nearly reaches our ECC correction threshold. + */ + if (failed || corrected >= (nfc_geo->ecc_strength - 1)) { + mtd->ecc_stats.failed += failed; + mtd->ecc_stats.corrected += corrected; + } + + /* + * It's time to deliver the OOB bytes. See gpmi_ecc_read_oob() for + * details about our policy for delivering the OOB. + * + * We fill the caller's buffer with set bits, and then copy the block + * mark to th caller's buffer. Note that, if block mark swapping was + * necessary, it has already been done, so we can rely on the first + * byte of the auxiliary buffer to contain the block mark. + */ + memset(chip->oob_poi, ~0, mtd->oobsize); + chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0]; + + read_page_swap_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); +exit_nfc: + return ret; +} + +static void gpmi_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf) +{ + struct gpmi_nand_data *this = chip->priv; + struct bch_geometry *nfc_geo = &this->bch_geometry; + const void *payload_virt; + dma_addr_t payload_phys; + const void *auxiliary_virt; + dma_addr_t auxiliary_phys; + int ret; + + pr_debug("ecc write page.\n"); + if (this->swap_block_mark) { + /* + * If control arrives here, we're doing block mark swapping. + * Since we can't modify the caller's buffers, we must copy them + * into our own. + */ + memcpy(this->payload_virt, buf, mtd->writesize); + payload_virt = this->payload_virt; + payload_phys = this->payload_phys; + + memcpy(this->auxiliary_virt, chip->oob_poi, + nfc_geo->auxiliary_size); + auxiliary_virt = this->auxiliary_virt; + auxiliary_phys = this->auxiliary_phys; + + /* Handle block mark swapping. */ + block_mark_swapping(this, + (void *) payload_virt, (void *) auxiliary_virt); + } else { + /* + * If control arrives here, we're not doing block mark swapping, + * so we can to try and use the caller's buffers. + */ + ret = send_page_prepare(this, + buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + &payload_virt, &payload_phys); + if (ret) { + pr_err("Inadequate payload DMA buffer\n"); + return; + } + + ret = send_page_prepare(this, + chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + &auxiliary_virt, &auxiliary_phys); + if (ret) { + pr_err("Inadequate auxiliary DMA buffer\n"); + goto exit_auxiliary; + } + } + + /* Ask the NFC. */ + ret = gpmi_send_page(this, payload_phys, auxiliary_phys); + if (ret) + pr_err("Error in ECC-based write: %d\n", ret); + + if (!this->swap_block_mark) { + send_page_end(this, chip->oob_poi, mtd->oobsize, + this->auxiliary_virt, this->auxiliary_phys, + nfc_geo->auxiliary_size, + auxiliary_virt, auxiliary_phys); +exit_auxiliary: + send_page_end(this, buf, mtd->writesize, + this->payload_virt, this->payload_phys, + nfc_geo->payload_size, + payload_virt, payload_phys); + } +} + +/* + * There are several places in this driver where we have to handle the OOB and + * block marks. This is the function where things are the most complicated, so + * this is where we try to explain it all. All the other places refer back to + * here. + * + * These are the rules, in order of decreasing importance: + * + * 1) Nothing the caller does can be allowed to imperil the block mark. + * + * 2) In read operations, the first byte of the OOB we return must reflect the + * true state of the block mark, no matter where that block mark appears in + * the physical page. + * + * 3) ECC-based read operations return an OOB full of set bits (since we never + * allow ECC-based writes to the OOB, it doesn't matter what ECC-based reads + * return). + * + * 4) "Raw" read operations return a direct view of the physical bytes in the + * page, using the conventional definition of which bytes are data and which + * are OOB. This gives the caller a way to see the actual, physical bytes + * in the page, without the distortions applied by our ECC engine. + * + * + * What we do for this specific read operation depends on two questions: + * + * 1) Are we doing a "raw" read, or an ECC-based read? + * + * 2) Are we using block mark swapping or transcription? + * + * There are four cases, illustrated by the following Karnaugh map: + * + * | Raw | ECC-based | + * -------------+-------------------------+-------------------------+ + * | Read the conventional | | + * | OOB at the end of the | | + * Swapping | page and return it. It | | + * | contains exactly what | | + * | we want. | Read the block mark and | + * -------------+-------------------------+ return it in a buffer | + * | Read the conventional | full of set bits. | + * | OOB at the end of the | | + * | page and also the block | | + * Transcribing | mark in the metadata. | | + * | Copy the block mark | | + * | into the first byte of | | + * | the OOB. | | + * -------------+-------------------------+-------------------------+ + * + * Note that we break rule #4 in the Transcribing/Raw case because we're not + * giving an accurate view of the actual, physical bytes in the page (we're + * overwriting the block mark). That's OK because it's more important to follow + * rule #2. + * + * It turns out that knowing whether we want an "ECC-based" or "raw" read is not + * easy. When reading a page, for example, the NAND Flash MTD code calls our + * ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an + * ECC-based or raw view of the page is implicit in which function it calls + * (there is a similar pair of ECC-based/raw functions for writing). + * + * Since MTD assumes the OOB is not covered by ECC, there is no pair of + * ECC-based/raw functions for reading or or writing the OOB. The fact that the + * caller wants an ECC-based or raw view of the page is not propagated down to + * this driver. + */ +static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + struct gpmi_nand_data *this = chip->priv; + + pr_debug("page number is %d\n", page); + /* clear the OOB buffer */ + memset(chip->oob_poi, ~0, mtd->oobsize); + + /* Read out the conventional OOB. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + + /* + * Now, we want to make sure the block mark is correct. In the + * Swapping/Raw case, we already have it. Otherwise, we need to + * explicitly read it. + */ + if (!this->swap_block_mark) { + /* Read the block mark into the first byte of the OOB buffer. */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + chip->oob_poi[0] = chip->read_byte(mtd); + } + + /* + * Return true, indicating that the next call to this function must send + * a command. + */ + return true; +} + +static int +gpmi_ecc_write_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) +{ + /* + * The BCH will use all the (page + oob). + * Our gpmi_hw_ecclayout can only prohibit the JFFS2 to write the oob. + * But it can not stop some ioctls such MEMWRITEOOB which uses + * MTD_OPS_PLACE_OOB. So We have to implement this function to prohibit + * these ioctls too. + */ + return -EPERM; +} + +static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int block, ret = 0; + uint8_t *block_mark; + int column, page, status, chipnr; + + /* Get block number */ + block = (int)(ofs >> chip->bbt_erase_shift); + if (chip->bbt) + chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); + + /* Do we have a flash based bad block table ? */ + if (chip->options & NAND_BBT_USE_FLASH) + ret = nand_update_bbt(mtd, ofs); + else { + chipnr = (int)(ofs >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + column = this->swap_block_mark ? mtd->writesize : 0; + + /* Write the block mark. */ + block_mark = this->data_buffer_dma; + block_mark[0] = 0; /* bad block marker */ + + /* Shift to get page */ + page = (int)(ofs >> chip->page_shift); + + chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); + chip->write_buf(mtd, block_mark, 1); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + ret = -EIO; + + chip->select_chip(mtd, -1); + } + if (!ret) + mtd->ecc_stats.badblocks++; + + return ret; +} + +static int __devinit nand_boot_set_geometry(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *geometry = &this->rom_geometry; + + /* + * Set the boot block stride size. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->stride_size_in_pages = 64; + + /* + * Set the search area stride exponent. + * + * In principle, we should be reading this from the OTP bits, since + * that's where the ROM is going to get it. In fact, we don't have any + * way to read the OTP bits, so we go with the default and hope for the + * best. + */ + geometry->search_area_stride_exponent = 2; + return 0; +} + +static const char *fingerprint = "STMP"; +static int __devinit mx23_check_transcription_stamp(struct gpmi_nand_data *this) +{ + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct device *dev = this->dev; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int search_area_size_in_strides; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int found_an_ncb_fingerprint = false; + + /* Compute the number of strides in a search area. */ + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* + * Loop through the first search area, looking for the NCB fingerprint. + */ + dev_dbg(dev, "Scanning for an NCB fingerprint...\n"); + + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + dev_dbg(dev, "Looking for a fingerprint in page 0x%x\n", page); + + /* + * Read the NCB fingerprint. The fingerprint is four bytes long + * and starts in the 12th byte of the page. + */ + chip->cmdfunc(mtd, NAND_CMD_READ0, 12, page); + chip->read_buf(mtd, buffer, strlen(fingerprint)); + + /* Look for the fingerprint. */ + if (!memcmp(buffer, fingerprint, strlen(fingerprint))) { + found_an_ncb_fingerprint = true; + break; + } + + } + + chip->select_chip(mtd, saved_chip_number); + + if (found_an_ncb_fingerprint) + dev_dbg(dev, "\tFound a fingerprint\n"); + else + dev_dbg(dev, "\tNo fingerprint found\n"); + return found_an_ncb_fingerprint; +} + +/* Writes a transcription stamp. */ +static int __devinit mx23_write_transcription_stamp(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct boot_rom_geometry *rom_geo = &this->rom_geometry; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + unsigned int block_size_in_pages; + unsigned int search_area_size_in_strides; + unsigned int search_area_size_in_pages; + unsigned int search_area_size_in_blocks; + unsigned int block; + unsigned int stride; + unsigned int page; + loff_t byte; + uint8_t *buffer = chip->buffers->databuf; + int saved_chip_number; + int status; + + /* Compute the search area geometry. */ + block_size_in_pages = mtd->erasesize / mtd->writesize; + search_area_size_in_strides = 1 << rom_geo->search_area_stride_exponent; + search_area_size_in_pages = search_area_size_in_strides * + rom_geo->stride_size_in_pages; + search_area_size_in_blocks = + (search_area_size_in_pages + (block_size_in_pages - 1)) / + block_size_in_pages; + + dev_dbg(dev, "Search Area Geometry :\n"); + dev_dbg(dev, "\tin Blocks : %u\n", search_area_size_in_blocks); + dev_dbg(dev, "\tin Strides: %u\n", search_area_size_in_strides); + dev_dbg(dev, "\tin Pages : %u\n", search_area_size_in_pages); + + /* Select chip 0. */ + saved_chip_number = this->current_chip; + chip->select_chip(mtd, 0); + + /* Loop over blocks in the first search area, erasing them. */ + dev_dbg(dev, "Erasing the search area...\n"); + + for (block = 0; block < search_area_size_in_blocks; block++) { + /* Compute the page address. */ + page = block * block_size_in_pages; + + /* Erase this block. */ + dev_dbg(dev, "\tErasing block 0x%x\n", block); + chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page); + chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1); + + /* Wait for the erase to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Erase failed.\n", __func__); + } + + /* Write the NCB fingerprint into the page buffer. */ + memset(buffer, ~0, mtd->writesize); + memset(chip->oob_poi, ~0, mtd->oobsize); + memcpy(buffer + 12, fingerprint, strlen(fingerprint)); + + /* Loop through the first search area, writing NCB fingerprints. */ + dev_dbg(dev, "Writing NCB fingerprints...\n"); + for (stride = 0; stride < search_area_size_in_strides; stride++) { + /* Compute the page and byte addresses. */ + page = stride * rom_geo->stride_size_in_pages; + byte = page * mtd->writesize; + + /* Write the first page of the current stride. */ + dev_dbg(dev, "Writing an NCB fingerprint in page 0x%x\n", page); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + chip->ecc.write_page_raw(mtd, chip, buffer); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* Wait for the write to finish. */ + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + dev_err(dev, "[%s] Write failed.\n", __func__); + } + + /* Deselect chip 0. */ + chip->select_chip(mtd, saved_chip_number); + return 0; +} + +static int __devinit mx23_boot_init(struct gpmi_nand_data *this) +{ + struct device *dev = this->dev; + struct nand_chip *chip = &this->nand; + struct mtd_info *mtd = &this->mtd; + unsigned int block_count; + unsigned int block; + int chipnr; + int page; + loff_t byte; + uint8_t block_mark; + int ret = 0; + + /* + * If control arrives here, we can't use block mark swapping, which + * means we're forced to use transcription. First, scan for the + * transcription stamp. If we find it, then we don't have to do + * anything -- the block marks are already transcribed. + */ + if (mx23_check_transcription_stamp(this)) + return 0; + + /* + * If control arrives here, we couldn't find a transcription stamp, so + * so we presume the block marks are in the conventional location. + */ + dev_dbg(dev, "Transcribing bad block marks...\n"); + + /* Compute the number of blocks in the entire medium. */ + block_count = chip->chipsize >> chip->phys_erase_shift; + + /* + * Loop over all the blocks in the medium, transcribing block marks as + * we go. + */ + for (block = 0; block < block_count; block++) { + /* + * Compute the chip, page and byte addresses for this block's + * conventional mark. + */ + chipnr = block >> (chip->chip_shift - chip->phys_erase_shift); + page = block << (chip->phys_erase_shift - chip->page_shift); + byte = block << chip->phys_erase_shift; + + /* Send the command to read the conventional block mark. */ + chip->select_chip(mtd, chipnr); + chip->cmdfunc(mtd, NAND_CMD_READ0, mtd->writesize, page); + block_mark = chip->read_byte(mtd); + chip->select_chip(mtd, -1); + + /* + * Check if the block is marked bad. If so, we need to mark it + * again, but this time the result will be a mark in the + * location where we transcribe block marks. + */ + if (block_mark != 0xff) { + dev_dbg(dev, "Transcribing mark in block %u\n", block); + ret = chip->block_markbad(mtd, byte); + if (ret) + dev_err(dev, "Failed to mark block bad with " + "ret %d\n", ret); + } + } + + /* Write the stamp that indicates we've transcribed the block marks. */ + mx23_write_transcription_stamp(this); + return 0; +} + +static int __devinit nand_boot_init(struct gpmi_nand_data *this) +{ + nand_boot_set_geometry(this); + + /* This is ROM arch-specific initilization before the BBT scanning. */ + if (GPMI_IS_MX23(this)) + return mx23_boot_init(this); + return 0; +} + +static int __devinit gpmi_set_geometry(struct gpmi_nand_data *this) +{ + int ret; + + /* Free the temporary DMA memory for reading ID. */ + gpmi_free_dma_buffer(this); + + /* Set up the NFC geometry which is used by BCH. */ + ret = bch_set_geometry(this); + if (ret) { + pr_err("set geometry ret : %d\n", ret); + return ret; + } + + /* Alloc the new DMA buffers according to the pagesize and oobsize */ + return gpmi_alloc_dma_buffer(this); +} + +static int gpmi_pre_bbt_scan(struct gpmi_nand_data *this) +{ + int ret; + + /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */ + if (GPMI_IS_MX23(this)) + this->swap_block_mark = false; + else + this->swap_block_mark = true; + + /* Set up the medium geometry */ + ret = gpmi_set_geometry(this); + if (ret) + return ret; + + /* NAND boot init, depends on the gpmi_set_geometry(). */ + return nand_boot_init(this); +} + +static int gpmi_scan_bbt(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + struct gpmi_nand_data *this = chip->priv; + int ret; + + /* Prepare for the BBT scan. */ + ret = gpmi_pre_bbt_scan(this); + if (ret) + return ret; + + /* use the default BBT implementation */ + return nand_default_bbt(mtd); +} + +void gpmi_nfc_exit(struct gpmi_nand_data *this) +{ + nand_release(&this->mtd); + gpmi_free_dma_buffer(this); +} + +static int __devinit gpmi_nfc_init(struct gpmi_nand_data *this) +{ + struct gpmi_nand_platform_data *pdata = this->pdata; + struct mtd_info *mtd = &this->mtd; + struct nand_chip *chip = &this->nand; + int ret; + + /* init current chip */ + this->current_chip = -1; + + /* init the MTD data structures */ + mtd->priv = chip; + mtd->name = "gpmi-nand"; + mtd->owner = THIS_MODULE; + + /* init the nand_chip{}, we don't support a 16-bit NAND Flash bus. */ + chip->priv = this; + chip->select_chip = gpmi_select_chip; + chip->cmd_ctrl = gpmi_cmd_ctrl; + chip->dev_ready = gpmi_dev_ready; + chip->read_byte = gpmi_read_byte; + chip->read_buf = gpmi_read_buf; + chip->write_buf = gpmi_write_buf; + chip->ecc.read_page = gpmi_ecc_read_page; + chip->ecc.write_page = gpmi_ecc_write_page; + chip->ecc.read_oob = gpmi_ecc_read_oob; + chip->ecc.write_oob = gpmi_ecc_write_oob; + chip->scan_bbt = gpmi_scan_bbt; + chip->badblock_pattern = &gpmi_bbt_descr; + chip->block_markbad = gpmi_block_markbad; + chip->options |= NAND_NO_SUBPAGE_WRITE; + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 1; + chip->ecc.layout = &gpmi_hw_ecclayout; + + /* Allocate a temporary DMA buffer for reading ID in the nand_scan() */ + this->bch_geometry.payload_size = 1024; + this->bch_geometry.auxiliary_size = 128; + ret = gpmi_alloc_dma_buffer(this); + if (ret) + goto err_out; + + ret = nand_scan(mtd, pdata->max_chip_count); + if (ret) { + pr_err("Chip scan failed\n"); + goto err_out; + } + + ret = mtd_device_parse_register(mtd, NULL, NULL, + pdata->partitions, pdata->partition_count); + if (ret) + goto err_out; + return 0; + +err_out: + gpmi_nfc_exit(this); + return ret; +} + +static int __devinit gpmi_nand_probe(struct platform_device *pdev) +{ + struct gpmi_nand_platform_data *pdata = pdev->dev.platform_data; + struct gpmi_nand_data *this; + int ret; + + this = kzalloc(sizeof(*this), GFP_KERNEL); + if (!this) { + pr_err("Failed to allocate per-device memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, this); + this->pdev = pdev; + this->dev = &pdev->dev; + this->pdata = pdata; + + if (pdata->platform_init) { + ret = pdata->platform_init(); + if (ret) + goto platform_init_error; + } + + ret = acquire_resources(this); + if (ret) + goto exit_acquire_resources; + + ret = init_hardware(this); + if (ret) + goto exit_nfc_init; + + ret = gpmi_nfc_init(this); + if (ret) + goto exit_nfc_init; + + return 0; + +exit_nfc_init: + release_resources(this); +platform_init_error: +exit_acquire_resources: + platform_set_drvdata(pdev, NULL); + kfree(this); + return ret; +} + +static int __exit gpmi_nand_remove(struct platform_device *pdev) +{ + struct gpmi_nand_data *this = platform_get_drvdata(pdev); + + gpmi_nfc_exit(this); + release_resources(this); + platform_set_drvdata(pdev, NULL); + kfree(this); + return 0; +} + +static const struct platform_device_id gpmi_ids[] = { + { + .name = "imx23-gpmi-nand", + .driver_data = IS_MX23, + }, { + .name = "imx28-gpmi-nand", + .driver_data = IS_MX28, + }, {}, +}; + +static struct platform_driver gpmi_nand_driver = { + .driver = { + .name = "gpmi-nand", + }, + .probe = gpmi_nand_probe, + .remove = __exit_p(gpmi_nand_remove), + .id_table = gpmi_ids, +}; + +static int __init gpmi_nand_init(void) +{ + int err; + + err = platform_driver_register(&gpmi_nand_driver); + if (err == 0) + printk(KERN_INFO "GPMI NAND driver registered. (IMX)\n"); + else + pr_err("i.MX GPMI NAND driver registration failed\n"); + return err; +} + +static void __exit gpmi_nand_exit(void) +{ + platform_driver_unregister(&gpmi_nand_driver); +} + +module_init(gpmi_nand_init); +module_exit(gpmi_nand_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("i.MX GPMI NAND Flash Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.h b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h new file mode 100644 index 00000000000..e023bccb778 --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.h @@ -0,0 +1,273 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * Copyright (C) 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __DRIVERS_MTD_NAND_GPMI_NAND_H +#define __DRIVERS_MTD_NAND_GPMI_NAND_H + +#include <linux/mtd/nand.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <mach/dma.h> + +struct resources { + void *gpmi_regs; + void *bch_regs; + unsigned int bch_low_interrupt; + unsigned int bch_high_interrupt; + unsigned int dma_low_channel; + unsigned int dma_high_channel; + struct clk *clock; +}; + +/** + * struct bch_geometry - BCH geometry description. + * @gf_len: The length of Galois Field. (e.g., 13 or 14) + * @ecc_strength: A number that describes the strength of the ECC + * algorithm. + * @page_size: The size, in bytes, of a physical page, including + * both data and OOB. + * @metadata_size: The size, in bytes, of the metadata. + * @ecc_chunk_size: The size, in bytes, of a single ECC chunk. Note + * the first chunk in the page includes both data and + * metadata, so it's a bit larger than this value. + * @ecc_chunk_count: The number of ECC chunks in the page, + * @payload_size: The size, in bytes, of the payload buffer. + * @auxiliary_size: The size, in bytes, of the auxiliary buffer. + * @auxiliary_status_offset: The offset into the auxiliary buffer at which + * the ECC status appears. + * @block_mark_byte_offset: The byte offset in the ECC-based page view at + * which the underlying physical block mark appears. + * @block_mark_bit_offset: The bit offset into the ECC-based page view at + * which the underlying physical block mark appears. + */ +struct bch_geometry { + unsigned int gf_len; + unsigned int ecc_strength; + unsigned int page_size; + unsigned int metadata_size; + unsigned int ecc_chunk_size; + unsigned int ecc_chunk_count; + unsigned int payload_size; + unsigned int auxiliary_size; + unsigned int auxiliary_status_offset; + unsigned int block_mark_byte_offset; + unsigned int block_mark_bit_offset; +}; + +/** + * struct boot_rom_geometry - Boot ROM geometry description. + * @stride_size_in_pages: The size of a boot block stride, in pages. + * @search_area_stride_exponent: The logarithm to base 2 of the size of a + * search area in boot block strides. + */ +struct boot_rom_geometry { + unsigned int stride_size_in_pages; + unsigned int search_area_stride_exponent; +}; + +/* DMA operations types */ +enum dma_ops_type { + DMA_FOR_COMMAND = 1, + DMA_FOR_READ_DATA, + DMA_FOR_WRITE_DATA, + DMA_FOR_READ_ECC_PAGE, + DMA_FOR_WRITE_ECC_PAGE +}; + +/** + * struct nand_timing - Fundamental timing attributes for NAND. + * @data_setup_in_ns: The data setup time, in nanoseconds. Usually the + * maximum of tDS and tWP. A negative value + * indicates this characteristic isn't known. + * @data_hold_in_ns: The data hold time, in nanoseconds. Usually the + * maximum of tDH, tWH and tREH. A negative value + * indicates this characteristic isn't known. + * @address_setup_in_ns: The address setup time, in nanoseconds. Usually + * the maximum of tCLS, tCS and tALS. A negative + * value indicates this characteristic isn't known. + * @gpmi_sample_delay_in_ns: A GPMI-specific timing parameter. A negative value + * indicates this characteristic isn't known. + * @tREA_in_ns: tREA, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRLOH_in_ns: tRLOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + * @tRHOH_in_ns: tRHOH, in nanoseconds, from the data sheet. A + * negative value indicates this characteristic isn't + * known. + */ +struct nand_timing { + int8_t data_setup_in_ns; + int8_t data_hold_in_ns; + int8_t address_setup_in_ns; + int8_t gpmi_sample_delay_in_ns; + int8_t tREA_in_ns; + int8_t tRLOH_in_ns; + int8_t tRHOH_in_ns; +}; + +struct gpmi_nand_data { + /* System Interface */ + struct device *dev; + struct platform_device *pdev; + struct gpmi_nand_platform_data *pdata; + + /* Resources */ + struct resources resources; + + /* Flash Hardware */ + struct nand_timing timing; + + /* BCH */ + struct bch_geometry bch_geometry; + struct completion bch_done; + + /* NAND Boot issue */ + bool swap_block_mark; + struct boot_rom_geometry rom_geometry; + + /* MTD / NAND */ + struct nand_chip nand; + struct mtd_info mtd; + + /* General-use Variables */ + int current_chip; + unsigned int command_length; + + /* passed from upper layer */ + uint8_t *upper_buf; + int upper_len; + + /* for DMA operations */ + bool direct_dma_map_ok; + + struct scatterlist cmd_sgl; + char *cmd_buffer; + + struct scatterlist data_sgl; + char *data_buffer_dma; + + void *page_buffer_virt; + dma_addr_t page_buffer_phys; + unsigned int page_buffer_size; + + void *payload_virt; + dma_addr_t payload_phys; + + void *auxiliary_virt; + dma_addr_t auxiliary_phys; + + /* DMA channels */ +#define DMA_CHANS 8 + struct dma_chan *dma_chans[DMA_CHANS]; + struct mxs_dma_data dma_data; + enum dma_ops_type last_dma_type; + enum dma_ops_type dma_type; + struct completion dma_done; + + /* private */ + void *private; +}; + +/** + * struct gpmi_nfc_hardware_timing - GPMI hardware timing parameters. + * @data_setup_in_cycles: The data setup time, in cycles. + * @data_hold_in_cycles: The data hold time, in cycles. + * @address_setup_in_cycles: The address setup time, in cycles. + * @use_half_periods: Indicates the clock is running slowly, so the + * NFC DLL should use half-periods. + * @sample_delay_factor: The sample delay factor. + */ +struct gpmi_nfc_hardware_timing { + uint8_t data_setup_in_cycles; + uint8_t data_hold_in_cycles; + uint8_t address_setup_in_cycles; + bool use_half_periods; + uint8_t sample_delay_factor; +}; + +/** + * struct timing_threshod - Timing threshold + * @max_data_setup_cycles: The maximum number of data setup cycles that + * can be expressed in the hardware. + * @internal_data_setup_in_ns: The time, in ns, that the NFC hardware requires + * for data read internal setup. In the Reference + * Manual, see the chapter "High-Speed NAND + * Timing" for more details. + * @max_sample_delay_factor: The maximum sample delay factor that can be + * expressed in the hardware. + * @max_dll_clock_period_in_ns: The maximum period of the GPMI clock that the + * sample delay DLL hardware can possibly work + * with (the DLL is unusable with longer periods). + * If the full-cycle period is greater than HALF + * this value, the DLL must be configured to use + * half-periods. + * @max_dll_delay_in_ns: The maximum amount of delay, in ns, that the + * DLL can implement. + * @clock_frequency_in_hz: The clock frequency, in Hz, during the current + * I/O transaction. If no I/O transaction is in + * progress, this is the clock frequency during + * the most recent I/O transaction. + */ +struct timing_threshod { + const unsigned int max_chip_count; + const unsigned int max_data_setup_cycles; + const unsigned int internal_data_setup_in_ns; + const unsigned int max_sample_delay_factor; + const unsigned int max_dll_clock_period_in_ns; + const unsigned int max_dll_delay_in_ns; + unsigned long clock_frequency_in_hz; + +}; + +/* Common Services */ +extern int common_nfc_set_geometry(struct gpmi_nand_data *); +extern struct dma_chan *get_dma_chan(struct gpmi_nand_data *); +extern void prepare_data_dma(struct gpmi_nand_data *, + enum dma_data_direction dr); +extern int start_dma_without_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); +extern int start_dma_with_bch_irq(struct gpmi_nand_data *, + struct dma_async_tx_descriptor *); + +/* GPMI-NAND helper function library */ +extern int gpmi_init(struct gpmi_nand_data *); +extern void gpmi_clear_bch(struct gpmi_nand_data *); +extern void gpmi_dump_info(struct gpmi_nand_data *); +extern int bch_set_geometry(struct gpmi_nand_data *); +extern int gpmi_is_ready(struct gpmi_nand_data *, unsigned chip); +extern int gpmi_send_command(struct gpmi_nand_data *); +extern void gpmi_begin(struct gpmi_nand_data *); +extern void gpmi_end(struct gpmi_nand_data *); +extern int gpmi_read_data(struct gpmi_nand_data *); +extern int gpmi_send_data(struct gpmi_nand_data *); +extern int gpmi_send_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); +extern int gpmi_read_page(struct gpmi_nand_data *, + dma_addr_t payload, dma_addr_t auxiliary); + +/* BCH : Status Block Completion Codes */ +#define STATUS_GOOD 0x00 +#define STATUS_ERASED 0xff +#define STATUS_UNCORRECTABLE 0xfe + +/* Use the platform_id to distinguish different Archs. */ +#define IS_MX23 0x1 +#define IS_MX28 0x2 +#define GPMI_IS_MX23(x) ((x)->pdev->id_entry->driver_data == IS_MX23) +#define GPMI_IS_MX28(x) ((x)->pdev->id_entry->driver_data == IS_MX28) +#endif diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-regs.h b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h new file mode 100644 index 00000000000..83431240e2f --- /dev/null +++ b/drivers/mtd/nand/gpmi-nand/gpmi-regs.h @@ -0,0 +1,172 @@ +/* + * Freescale GPMI NAND Flash Driver + * + * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2008 Embedded Alley Solutions, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef __GPMI_NAND_GPMI_REGS_H +#define __GPMI_NAND_GPMI_REGS_H + +#define HW_GPMI_CTRL0 0x00000000 +#define HW_GPMI_CTRL0_SET 0x00000004 +#define HW_GPMI_CTRL0_CLR 0x00000008 +#define HW_GPMI_CTRL0_TOG 0x0000000c + +#define BP_GPMI_CTRL0_COMMAND_MODE 24 +#define BM_GPMI_CTRL0_COMMAND_MODE (3 << BP_GPMI_CTRL0_COMMAND_MODE) +#define BF_GPMI_CTRL0_COMMAND_MODE(v) \ + (((v) << BP_GPMI_CTRL0_COMMAND_MODE) & BM_GPMI_CTRL0_COMMAND_MODE) +#define BV_GPMI_CTRL0_COMMAND_MODE__WRITE 0x0 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ 0x1 +#define BV_GPMI_CTRL0_COMMAND_MODE__READ_AND_COMPARE 0x2 +#define BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY 0x3 + +#define BM_GPMI_CTRL0_WORD_LENGTH (1 << 23) +#define BV_GPMI_CTRL0_WORD_LENGTH__16_BIT 0x0 +#define BV_GPMI_CTRL0_WORD_LENGTH__8_BIT 0x1 + +/* + * Difference in LOCK_CS between imx23 and imx28 : + * This bit may impact the _POWER_ consumption. So some chips + * do not set it. + */ +#define MX23_BP_GPMI_CTRL0_LOCK_CS 22 +#define MX28_BP_GPMI_CTRL0_LOCK_CS 27 +#define LOCK_CS_ENABLE 0x1 +#define BF_GPMI_CTRL0_LOCK_CS(v, x) 0x0 + +/* Difference in CS between imx23 and imx28 */ +#define BP_GPMI_CTRL0_CS 20 +#define MX23_BM_GPMI_CTRL0_CS (3 << BP_GPMI_CTRL0_CS) +#define MX28_BM_GPMI_CTRL0_CS (7 << BP_GPMI_CTRL0_CS) +#define BF_GPMI_CTRL0_CS(v, x) (((v) << BP_GPMI_CTRL0_CS) & \ + (GPMI_IS_MX23((x)) \ + ? MX23_BM_GPMI_CTRL0_CS \ + : MX28_BM_GPMI_CTRL0_CS)) + +#define BP_GPMI_CTRL0_ADDRESS 17 +#define BM_GPMI_CTRL0_ADDRESS (3 << BP_GPMI_CTRL0_ADDRESS) +#define BF_GPMI_CTRL0_ADDRESS(v) \ + (((v) << BP_GPMI_CTRL0_ADDRESS) & BM_GPMI_CTRL0_ADDRESS) +#define BV_GPMI_CTRL0_ADDRESS__NAND_DATA 0x0 +#define BV_GPMI_CTRL0_ADDRESS__NAND_CLE 0x1 +#define BV_GPMI_CTRL0_ADDRESS__NAND_ALE 0x2 + +#define BM_GPMI_CTRL0_ADDRESS_INCREMENT (1 << 16) +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__DISABLED 0x0 +#define BV_GPMI_CTRL0_ADDRESS_INCREMENT__ENABLED 0x1 + +#define BP_GPMI_CTRL0_XFER_COUNT 0 +#define BM_GPMI_CTRL0_XFER_COUNT (0xffff << BP_GPMI_CTRL0_XFER_COUNT) +#define BF_GPMI_CTRL0_XFER_COUNT(v) \ + (((v) << BP_GPMI_CTRL0_XFER_COUNT) & BM_GPMI_CTRL0_XFER_COUNT) + +#define HW_GPMI_COMPARE 0x00000010 + +#define HW_GPMI_ECCCTRL 0x00000020 +#define HW_GPMI_ECCCTRL_SET 0x00000024 +#define HW_GPMI_ECCCTRL_CLR 0x00000028 +#define HW_GPMI_ECCCTRL_TOG 0x0000002c + +#define BP_GPMI_ECCCTRL_ECC_CMD 13 +#define BM_GPMI_ECCCTRL_ECC_CMD (3 << BP_GPMI_ECCCTRL_ECC_CMD) +#define BF_GPMI_ECCCTRL_ECC_CMD(v) \ + (((v) << BP_GPMI_ECCCTRL_ECC_CMD) & BM_GPMI_ECCCTRL_ECC_CMD) +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_DECODE 0x0 +#define BV_GPMI_ECCCTRL_ECC_CMD__BCH_ENCODE 0x1 + +#define BM_GPMI_ECCCTRL_ENABLE_ECC (1 << 12) +#define BV_GPMI_ECCCTRL_ENABLE_ECC__ENABLE 0x1 +#define BV_GPMI_ECCCTRL_ENABLE_ECC__DISABLE 0x0 + +#define BP_GPMI_ECCCTRL_BUFFER_MASK 0 +#define BM_GPMI_ECCCTRL_BUFFER_MASK (0x1ff << BP_GPMI_ECCCTRL_BUFFER_MASK) +#define BF_GPMI_ECCCTRL_BUFFER_MASK(v) \ + (((v) << BP_GPMI_ECCCTRL_BUFFER_MASK) & BM_GPMI_ECCCTRL_BUFFER_MASK) +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_AUXONLY 0x100 +#define BV_GPMI_ECCCTRL_BUFFER_MASK__BCH_PAGE 0x1FF + +#define HW_GPMI_ECCCOUNT 0x00000030 +#define HW_GPMI_PAYLOAD 0x00000040 +#define HW_GPMI_AUXILIARY 0x00000050 +#define HW_GPMI_CTRL1 0x00000060 +#define HW_GPMI_CTRL1_SET 0x00000064 +#define HW_GPMI_CTRL1_CLR 0x00000068 +#define HW_GPMI_CTRL1_TOG 0x0000006c + +#define BM_GPMI_CTRL1_BCH_MODE (1 << 18) + +#define BP_GPMI_CTRL1_DLL_ENABLE 17 +#define BM_GPMI_CTRL1_DLL_ENABLE (1 << BP_GPMI_CTRL1_DLL_ENABLE) + +#define BP_GPMI_CTRL1_HALF_PERIOD 16 +#define BM_GPMI_CTRL1_HALF_PERIOD (1 << BP_GPMI_CTRL1_HALF_PERIOD) + +#define BP_GPMI_CTRL1_RDN_DELAY 12 +#define BM_GPMI_CTRL1_RDN_DELAY (0xf << BP_GPMI_CTRL1_RDN_DELAY) +#define BF_GPMI_CTRL1_RDN_DELAY(v) \ + (((v) << BP_GPMI_CTRL1_RDN_DELAY) & BM_GPMI_CTRL1_RDN_DELAY) + +#define BM_GPMI_CTRL1_DEV_RESET (1 << 3) +#define BV_GPMI_CTRL1_DEV_RESET__ENABLED 0x0 +#define BV_GPMI_CTRL1_DEV_RESET__DISABLED 0x1 + +#define BM_GPMI_CTRL1_ATA_IRQRDY_POLARITY (1 << 2) +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVELOW 0x0 +#define BV_GPMI_CTRL1_ATA_IRQRDY_POLARITY__ACTIVEHIGH 0x1 + +#define BM_GPMI_CTRL1_CAMERA_MODE (1 << 1) +#define BV_GPMI_CTRL1_GPMI_MODE__NAND 0x0 +#define BV_GPMI_CTRL1_GPMI_MODE__ATA 0x1 + +#define BM_GPMI_CTRL1_GPMI_MODE (1 << 0) + +#define HW_GPMI_TIMING0 0x00000070 + +#define BP_GPMI_TIMING0_ADDRESS_SETUP 16 +#define BM_GPMI_TIMING0_ADDRESS_SETUP (0xff << BP_GPMI_TIMING0_ADDRESS_SETUP) +#define BF_GPMI_TIMING0_ADDRESS_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_ADDRESS_SETUP) & BM_GPMI_TIMING0_ADDRESS_SETUP) + +#define BP_GPMI_TIMING0_DATA_HOLD 8 +#define BM_GPMI_TIMING0_DATA_HOLD (0xff << BP_GPMI_TIMING0_DATA_HOLD) +#define BF_GPMI_TIMING0_DATA_HOLD(v) \ + (((v) << BP_GPMI_TIMING0_DATA_HOLD) & BM_GPMI_TIMING0_DATA_HOLD) + +#define BP_GPMI_TIMING0_DATA_SETUP 0 +#define BM_GPMI_TIMING0_DATA_SETUP (0xff << BP_GPMI_TIMING0_DATA_SETUP) +#define BF_GPMI_TIMING0_DATA_SETUP(v) \ + (((v) << BP_GPMI_TIMING0_DATA_SETUP) & BM_GPMI_TIMING0_DATA_SETUP) + +#define HW_GPMI_TIMING1 0x00000080 +#define BP_GPMI_TIMING1_BUSY_TIMEOUT 16 + +#define HW_GPMI_TIMING2 0x00000090 +#define HW_GPMI_DATA 0x000000a0 + +/* MX28 uses this to detect READY. */ +#define HW_GPMI_STAT 0x000000b0 +#define MX28_BP_GPMI_STAT_READY_BUSY 24 +#define MX28_BM_GPMI_STAT_READY_BUSY (0xff << MX28_BP_GPMI_STAT_READY_BUSY) +#define MX28_BF_GPMI_STAT_READY_BUSY(v) \ + (((v) << MX28_BP_GPMI_STAT_READY_BUSY) & MX28_BM_GPMI_STAT_READY_BUSY) + +/* MX23 uses this to detect READY. */ +#define HW_GPMI_DEBUG 0x000000c0 +#define MX23_BP_GPMI_DEBUG_READY0 28 +#define MX23_BM_GPMI_DEBUG_READY0 (1 << MX23_BP_GPMI_DEBUG_READY0) +#endif diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 02a03e67109..5dc6f0d92f1 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c @@ -81,9 +81,6 @@ static int h1910_device_ready(struct mtd_info *mtd) static int __init h1910_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *nandaddr; if (!machine_is_h1900()) @@ -136,22 +133,10 @@ static int __init h1910_init(void) iounmap((void *)nandaddr); return -ENXIO; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(h1910_nand_mtd, &mtd_parts, "h1910-nand"); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; -#endif - if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(h1910_nand_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(h1910_nand_mtd, NULL, 0, + partition_info, NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 6e813daed06..e2664073a89 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -251,10 +251,6 @@ static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, return 0; } -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = {"cmdline", NULL}; -#endif - static int jz_nand_ioremap_resource(struct platform_device *pdev, const char *name, struct resource **res, void __iomem **base) { @@ -299,8 +295,6 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) struct nand_chip *chip; struct mtd_info *mtd; struct jz_nand_platform_data *pdata = pdev->dev.platform_data; - struct mtd_partition *partition_info; - int num_partitions = 0; nand = kzalloc(sizeof(*nand), GFP_KERNEL); if (!nand) { @@ -373,15 +367,9 @@ static int __devinit jz_nand_probe(struct platform_device *pdev) goto err_gpio_free; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partition_info, 0); -#endif - if (num_partitions <= 0 && pdata) { - num_partitions = pdata->num_partitions; - partition_info = pdata->partitions; - } - ret = mtd_device_register(mtd, partition_info, num_partitions); + ret = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->partitions : NULL, + pdata ? pdata->num_partitions : 0); if (ret) { dev_err(&pdev->dev, "Failed to add mtd device\n"); diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index eb1fbac63eb..5ede6470634 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -131,8 +131,6 @@ struct mpc5121_nfc_prv { static void mpc5121_nfc_done(struct mtd_info *mtd); -static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL }; - /* Read NFC register */ static inline u16 nfc_read(struct mtd_info *mtd, uint reg) { @@ -656,13 +654,13 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) struct mpc5121_nfc_prv *prv; struct resource res; struct mtd_info *mtd; - struct mtd_partition *parts; struct nand_chip *chip; unsigned long regs_paddr, regs_size; const __be32 *chips_no; int resettime = 0; int retval = 0; int rev, len; + struct mtd_part_parser_data ppdata; /* * Check SoC revision. This driver supports only NFC @@ -727,6 +725,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) } mtd->name = "MPC5121 NAND"; + ppdata.of_node = dn; chip->dev_ready = mpc5121_nfc_dev_ready; chip->cmdfunc = mpc5121_nfc_command; chip->read_byte = mpc5121_nfc_read_byte; @@ -735,7 +734,8 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) chip->write_buf = mpc5121_nfc_write_buf; chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; /* Support external chip-select logic on ADS5121 board */ @@ -837,19 +837,7 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op) dev_set_drvdata(dev, mtd); /* Register device in MTD */ - retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0); -#ifdef CONFIG_MTD_OF_PARTS - if (retval == 0) - retval = of_mtd_parse_partitions(dev, dn, &parts); -#endif - if (retval < 0) { - dev_err(dev, "Error parsing MTD partitions!\n"); - devm_free_irq(dev, prv->irq, mtd); - retval = -EINVAL; - goto error; - } - - retval = mtd_device_register(mtd, parts, retval); + retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (retval) { dev_err(dev, "Error adding MTD device!\n"); devm_free_irq(dev, prv->irq, mtd); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 90df34c4d26..74a43b818d0 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -41,7 +41,7 @@ #define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) #define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) -#define nfc_is_v3_2() cpu_is_mx51() +#define nfc_is_v3_2() (cpu_is_mx51() || cpu_is_mx53()) #define nfc_is_v3() nfc_is_v3_2() /* Addresses for NFC registers */ @@ -143,7 +143,6 @@ struct mxc_nand_host { struct mtd_info mtd; struct nand_chip nand; - struct mtd_partition *parts; struct device *dev; void *spare0; @@ -350,8 +349,7 @@ static void wait_op_done(struct mxc_nand_host *host, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: INT not set\n", - __func__); + pr_debug("%s: INT not set\n", __func__); } } @@ -371,7 +369,7 @@ static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) * waits for completion. */ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) { - DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq); + pr_debug("send_cmd(host, 0x%x, %d)\n", cmd, useirq); writew(cmd, NFC_V1_V2_FLASH_CMD); writew(NFC_CMD, NFC_V1_V2_CONFIG2); @@ -387,8 +385,7 @@ static void send_cmd_v1_v2(struct mxc_nand_host *host, uint16_t cmd, int useirq) udelay(1); } if (max_retries < 0) - DEBUG(MTD_DEBUG_LEVEL0, "%s: RESET failed\n", - __func__); + pr_debug("%s: RESET failed\n", __func__); } else { /* Wait for operation to complete */ wait_op_done(host, useirq); @@ -411,7 +408,7 @@ static void send_addr_v3(struct mxc_nand_host *host, uint16_t addr, int islast) * a NAND command. */ static void send_addr_v1_v2(struct mxc_nand_host *host, uint16_t addr, int islast) { - DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); + pr_debug("send_addr(host, 0x%x %d)\n", addr, islast); writew(addr, NFC_V1_V2_FLASH_ADDR); writew(NFC_ADDR, NFC_V1_V2_CONFIG2); @@ -561,8 +558,7 @@ static int mxc_nand_correct_data_v1(struct mtd_info *mtd, u_char *dat, uint16_t ecc_status = readw(NFC_V1_V2_ECC_STATUS_RESULT); if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + pr_debug("MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); return -1; } @@ -849,7 +845,7 @@ static void preset_v1_v2(struct mtd_info *mtd) writew(0xffff, NFC_V21_UNLOCKEND_BLKADDR3); } else if (nfc_is_v1()) { writew(0x0, NFC_V1_UNLOCKSTART_BLKADDR); - writew(0x4000, NFC_V1_UNLOCKEND_BLKADDR); + writew(0xffff, NFC_V1_UNLOCKEND_BLKADDR); } else BUG(); @@ -932,8 +928,7 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, struct nand_chip *nand_chip = mtd->priv; struct mxc_nand_host *host = nand_chip->priv; - DEBUG(MTD_DEBUG_LEVEL3, - "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + pr_debug("mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", command, column, page_addr); /* Reset command state information */ @@ -1044,7 +1039,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) struct mxc_nand_platform_data *pdata = pdev->dev.platform_data; struct mxc_nand_host *host; struct resource *res; - int err = 0, __maybe_unused nr_parts = 0; + int err = 0; struct nand_ecclayout *oob_smallpage, *oob_largepage; /* Allocate memory for MTD device structure and private data */ @@ -1179,7 +1174,7 @@ static int __init mxcnd_probe(struct platform_device *pdev) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; /* update flash based bbt */ - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; } init_completion(&host->op_completion); @@ -1231,16 +1226,8 @@ static int __init mxcnd_probe(struct platform_device *pdev) } /* Register the partitions */ - nr_parts = - parse_mtd_partitions(mtd, part_probes, &host->parts, 0); - if (nr_parts > 0) - mtd_device_register(mtd, host->parts, nr_parts); - else if (pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else { - pr_info("Registering %s as whole device\n", mtd->name); - mtd_device_register(mtd, NULL, 0); - } + mtd_device_parse_register(mtd, part_probes, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, host); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a46e9bb847b..3ed9c5e4d34 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@ * TODO: * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ecc support. + * if we have HW ECC support. * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * BBT table is not serialized, has to be fixed @@ -113,21 +113,19 @@ static int check_offs_len(struct mtd_info *mtd, /* Start address must align on block boundary */ if (ofs & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Unaligned address\n", __func__); + pr_debug("%s: unaligned address\n", __func__); ret = -EINVAL; } /* Length must align on block boundary */ if (len & ((1 << chip->phys_erase_shift) - 1)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Length not block aligned\n", - __func__); + pr_debug("%s: length not block aligned\n", __func__); ret = -EINVAL; } /* Do not allow past end of device */ if (ofs + len > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", - __func__); + pr_debug("%s: past end of device\n", __func__); ret = -EINVAL; } @@ -136,9 +134,9 @@ static int check_offs_len(struct mtd_info *mtd, /** * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device. */ static void nand_release_device(struct mtd_info *mtd) { @@ -157,9 +155,9 @@ static void nand_release_device(struct mtd_info *mtd) /** * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth */ static uint8_t nand_read_byte(struct mtd_info *mtd) { @@ -169,10 +167,11 @@ static uint8_t nand_read_byte(struct mtd_info *mtd) /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd: MTD device structure + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswidth with endianness conversion. * - * Default read function for 16bit buswith with - * endianess conversion */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { @@ -182,10 +181,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) /** * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswidth without endianness conversion. */ static u16 nand_read_word(struct mtd_info *mtd) { @@ -195,8 +193,8 @@ static u16 nand_read_word(struct mtd_info *mtd) /** * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */ @@ -218,11 +216,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) /** * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 8bit buswith + * Default write function for 8bit buswidth. */ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -235,11 +233,11 @@ static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth. */ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -252,11 +250,11 @@ static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswidth. */ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -271,11 +269,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 16bit buswith + * Default write function for 16bit buswidth. */ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -291,11 +289,11 @@ static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 16bit buswith + * Default read function for 16bit buswidth. */ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -310,11 +308,11 @@ static void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswidth. */ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -332,9 +330,9 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected * * Check, if the block is bad. */ @@ -344,7 +342,7 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) struct nand_chip *chip = mtd->priv; u16 bad; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -384,11 +382,11 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /** * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver. */ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -396,7 +394,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) uint8_t buf[2] = { 0, 0 }; int block, ret, i = 0; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; /* Get block number */ @@ -404,33 +402,31 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); - /* Do we have a flash based bad block table ? */ - if (chip->options & NAND_USE_FLASH_BBT) + /* Do we have a flash based bad block table? */ + if (chip->bbt_options & NAND_BBT_USE_FLASH) ret = nand_update_bbt(mtd, ofs); else { + struct mtd_oob_ops ops; + nand_get_device(chip, mtd, FL_WRITING); - /* Write to first two pages and to byte 1 and 6 if necessary. - * If we write to more than one location, the first error - * encountered quits the procedure. We write two bytes per - * location, so we dont have to mess with 16 bit access. + /* + * Write to first two pages if necessary. If we write to more + * than one location, the first error encountered quits the + * procedure. We write two bytes per location, so we dont have + * to mess with 16 bit access. */ + ops.len = ops.ooblen = 2; + ops.datbuf = NULL; + ops.oobbuf = buf; + ops.ooboffs = chip->badblockpos & ~0x01; + ops.mode = MTD_OPS_PLACE_OOB; do { - chip->ops.len = chip->ops.ooblen = 2; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = buf; - chip->ops.ooboffs = chip->badblockpos & ~0x01; - - ret = nand_do_write_oob(mtd, ofs, &chip->ops); + ret = nand_do_write_oob(mtd, ofs, &ops); - if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { - chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS - & ~0x01; - ret = nand_do_write_oob(mtd, ofs, &chip->ops); - } i++; ofs += mtd->writesize; - } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && + } while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); nand_release_device(mtd); @@ -443,16 +439,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected. */ static int nand_check_wp(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - /* broken xD cards report WP despite being writable */ + /* Broken xD cards report WP despite being writable */ if (chip->options & NAND_BROKEN_XD) return 0; @@ -463,10 +459,10 @@ static int nand_check_wp(struct mtd_info *mtd) /** * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. @@ -485,8 +481,8 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, /** * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. - * @mtd: MTD device structure - * @timeo: Timeout + * @mtd: MTD device structure + * @timeo: Timeout * * Helper function for nand_wait_ready used when needing to wait in interrupt * context. @@ -505,10 +501,7 @@ static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) } } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is caught later. */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -519,7 +512,7 @@ void nand_wait_ready(struct mtd_info *mtd) return panic_nand_wait_ready(mtd, 400); led_trigger_event(nand_led_trigger, LED_FULL); - /* wait until command is processed or timeout occures */ + /* Wait until command is processed or timeout occurs */ do { if (chip->dev_ready(mtd)) break; @@ -531,13 +524,13 @@ EXPORT_SYMBOL_GPL(nand_wait_ready); /** * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page). */ static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -545,9 +538,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, register struct nand_chip *chip = mtd->priv; int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - /* - * Write out the command to the device. - */ + /* Write out the command to the device */ if (command == NAND_CMD_SEQIN) { int readcmd; @@ -567,9 +558,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, } chip->cmd_ctrl(mtd, command, ctrl); - /* - * Address cycle, when necessary - */ + /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Serially input address */ if (column != -1) { @@ -590,8 +579,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status and sequential in needs no delay + * Program and erase have their own busy handlers status and sequential + * in needs no delay */ switch (command) { @@ -625,8 +614,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, return; } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -634,14 +625,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /** * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. */ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -683,8 +674,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status, sequential in, and deplete1 need no delay + * Program and erase have their own busy handlers status, sequential + * in, and deplete1 need no delay. */ switch (command) { @@ -698,14 +689,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_DEPLETE1: return; - /* - * read error status commands require only a short delay - */ case NAND_CMD_STATUS_ERROR: case NAND_CMD_STATUS_ERROR0: case NAND_CMD_STATUS_ERROR1: case NAND_CMD_STATUS_ERROR2: case NAND_CMD_STATUS_ERROR3: + /* Read error status commands require only a short delay */ udelay(chip->chip_delay); return; @@ -739,7 +728,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, default: /* * If we don't have access to the busy pin, we apply the given - * command delay + * command delay. */ if (!chip->dev_ready) { udelay(chip->chip_delay); @@ -747,8 +736,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -756,25 +747,25 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /** * panic_nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Used when in panic, no locks are taken. */ static void panic_nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) { - /* Hardware controller shared among independend devices */ + /* Hardware controller shared among independent devices */ chip->controller->active = chip; chip->state = new_state; } /** * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -812,10 +803,10 @@ retry: } /** - * panic_nand_wait - [GENERIC] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure - * @timeo: Timeout + * panic_nand_wait - [GENERIC] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure + * @timeo: timeout * * Wait for command done. This is a helper function for nand_wait used when * we are in interrupt context. May happen when in panic and trying to write @@ -838,13 +829,13 @@ static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs. */ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { @@ -859,8 +850,10 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) led_trigger_event(nand_led_trigger, LED_FULL); - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in any + * case on any machine. + */ ndelay(100); if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) @@ -890,16 +883,15 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) /** * __nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock - * @invert: when = 0, unlock the range of blocks within the lower and - * upper boundary address - * when = 1, unlock the range of blocks outside the boundaries - * of the lower and upper boundary address + * @invert: when = 0, unlock the range of blocks within the lower and + * upper boundary address + * when = 1, unlock the range of blocks outside the boundaries + * of the lower and upper boundary address * - * return - unlock status + * Returs unlock status. */ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len, int invert) @@ -919,10 +911,9 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; } @@ -932,12 +923,11 @@ static int __nand_unlock(struct mtd_info *mtd, loff_t ofs, /** * nand_unlock - [REPLACEABLE] unlocks specified locked blocks - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - unlock status + * Returns unlock status. */ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -945,7 +935,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -964,7 +954,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); ret = -EIO; goto out; @@ -981,18 +971,16 @@ EXPORT_SYMBOL(nand_unlock); /** * nand_lock - [REPLACEABLE] locks all blocks present in the device - * * @mtd: mtd info * @ofs: offset to start unlock from * @len: length to unlock * - * return - lock status + * This feature is not supported in many NAND parts. 'Micron' NAND parts do + * have this feature, but it allows only to lock all blocks, not for specified + * range for block. Implementing 'lock' feature by making use of 'unlock', for + * now. * - * This feature is not supported in many NAND parts. 'Micron' NAND parts - * do have this feature, but it allows only to lock all blocks, not for - * specified range for block. - * - * Implementing 'lock' feature by making use of 'unlock', for now. + * Returns lock status. */ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -1000,7 +988,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) int chipnr, status, page; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", + pr_debug("%s: start = 0x%012llx, len = %llu\n", __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) @@ -1015,7 +1003,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", + pr_debug("%s: device is write protected!\n", __func__); status = MTD_ERASE_FAILED; ret = -EIO; @@ -1028,10 +1016,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Call wait ready function */ status = chip->waitfunc(mtd, chip); - udelay(1000); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Error status = 0x%08x\n", + pr_debug("%s: error status = 0x%08x\n", __func__, status); ret = -EIO; goto out; @@ -1047,13 +1034,13 @@ out: EXPORT_SYMBOL(nand_lock); /** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1064,11 +1051,11 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ @@ -1107,11 +1094,11 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, } /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1148,12 +1135,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -1166,12 +1153,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - /* Column address wihin the page aligned to ECC size (256bytes). */ + /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; - /* Data size aligned to ECC ecc.size*/ + /* Data size aligned to ECC ecc.size */ datafrag_len = num_steps * chip->ecc.size; eccfrag_len = num_steps * chip->ecc.bytes; @@ -1183,13 +1170,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, p = bufpoi + data_col_addr; chip->read_buf(mtd, p, datafrag_len); - /* Calculate ECC */ + /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - /* The performance is faster if to position offsets - according to ecc.pos. Let make sure here that - there are no gaps in ecc positions */ + /* + * The performance is faster if we position offsets according to + * ecc.pos. Let's make sure that there are no gaps in ECC positions. + */ for (i = 0; i < eccfrag_len - 1; i++) { if (eccpos[i + start_step * chip->ecc.bytes] + 1 != eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -1201,8 +1189,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { - /* send the command to read the particular ecc bytes */ - /* take care about buswidth alignment in read_buf */ + /* + * Send the command to read the particular ECC bytes take care + * about buswidth alignment in read_buf. + */ index = start_step * chip->ecc.bytes; aligned_pos = eccpos[index] & ~(busw - 1); @@ -1235,13 +1225,13 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ECC controllers which need a special oob layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1280,18 +1270,17 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1329,14 +1318,14 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, } /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @page: page number to read * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) @@ -1384,29 +1373,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer */ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ + /* Read request not from offset 0? */ if (unlikely(roffs)) { if (roffs >= free->length) { roffs -= free->length; @@ -1432,11 +1421,10 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure * * Internal function. Called with chip held. */ @@ -1451,7 +1439,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? + uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *bufpoi, *oob, *buf; @@ -1473,7 +1461,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); - /* Is the current page in the buffer ? */ + /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; @@ -1483,7 +1471,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, } /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) + if (unlikely(ops->mode == MTD_OPS_RAW)) ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, page); else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob) @@ -1492,14 +1480,22 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else ret = chip->ecc.read_page(mtd, chip, bufpoi, page); - if (ret < 0) + if (ret < 0) { + if (!aligned) + /* Invalidate page cache */ + chip->pagebuf = -1; break; + } /* Transfer not aligned data */ if (!aligned) { if (!NAND_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed)) + !(mtd->ecc_stats.failed - stats.failed) && + (ops->mode != MTD_OPS_RAW)) chip->pagebuf = realpage; + else + /* Invalidate page cache */ + chip->pagebuf = -1; memcpy(buf, chip->buffers->databuf + col, bytes); } @@ -1539,7 +1535,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (!readlen) break; - /* For subsequent reads align to page boundary. */ + /* For subsequent reads align to page boundary */ col = 0; /* Increment page address */ realpage++; @@ -1552,8 +1548,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; @@ -1574,18 +1571,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /** * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read. */ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -1596,13 +1594,14 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, nand_get_device(chip, mtd, FL_READING); - chip->ops.len = len; - chip->ops.datbuf = buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_read_ops(mtd, from, &chip->ops); + ret = nand_do_read_ops(mtd, from, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); @@ -1610,11 +1609,11 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, } /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1628,12 +1627,12 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read + * @sndcmd: flag whether to issue read command or not */ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page, int sndcmd) @@ -1667,10 +1666,10 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1690,11 +1689,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - * with syndrome - only for large page flash ! - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC + * with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1749,34 +1748,37 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, } /** - * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area. */ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { int page, realpage, chipnr, sndcmd = 1; struct nand_chip *chip = mtd->priv; + struct mtd_ecc_stats stats; int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", + pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); - if (ops->mode == MTD_OOB_AUTO) + stats = mtd->ecc_stats; + + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start read " - "outside oob\n", __func__); + pr_debug("%s: attempt to start read outside oob\n", + __func__); return -EINVAL; } @@ -1784,8 +1786,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, if (unlikely(from >= mtd->size || ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - (from >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end " - "of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } @@ -1797,7 +1799,10 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; while (1) { - sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); + if (ops->mode == MTD_OPS_RAW) + sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); + else + sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); @@ -1830,24 +1835,29 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, chipnr); } - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. + /* + * Check, if the chip supports auto page increment or if we + * have hit a block boundary. */ if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) sndcmd = 1; } ops->oobretlen = ops->ooblen; - return 0; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data. */ static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1859,17 +1869,17 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, /* Do not allow reads past end of device */ if (ops->datbuf && (from + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt read " - "beyond end of device\n", __func__); + pr_debug("%s: attempt to read beyond end of device\n", + __func__); return -EINVAL; } nand_get_device(chip, mtd, FL_READING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -1888,12 +1898,12 @@ out: /** - * nand_write_page_raw - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1903,10 +1913,10 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw_syndrome - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * * We need a special oob layout and handling even when ECC isn't checked. */ @@ -1942,10 +1952,10 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, chip->write_buf(mtd, oob, size); } /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1957,7 +1967,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; - /* Software ecc calculation */ + /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -1968,10 +1978,10 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer */ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -1996,13 +2006,13 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static void nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) @@ -2041,12 +2051,12 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, /** * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @page: page number to write - * @cached: cached programming - * @raw: use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw) @@ -2061,8 +2071,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, chip->ecc.write_page(mtd, chip, buf); /* - * Cached progamming disabled for now, Not sure if its worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + * Cached progamming disabled for now. Not sure if it's worth the + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). */ cached = 0; @@ -2072,7 +2082,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are - * available + * available. */ if ((status & NAND_STATUS_FAIL) && (chip->errstat)) status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -2096,29 +2106,37 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd->priv; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(chip->oob_poi + ops->ooboffs, oob, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0 ? */ + /* Write request not from offset 0? */ if (unlikely(woffs)) { if (woffs >= free->length) { woffs -= free->length; @@ -2146,12 +2164,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** - * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure * - * NAND write with ECC + * NAND write with ECC. */ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2161,7 +2179,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? + uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *oob = ops->oobbuf; @@ -2172,10 +2190,10 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (!writelen) return 0; - /* reject writes, which are not page aligned */ + /* Reject writes, which are not page aligned */ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) { - printk(KERN_NOTICE "%s: Attempt to write not " - "page aligned data\n", __func__); + pr_notice("%s: attempt to write non page aligned data\n", + __func__); return -EINVAL; } @@ -2201,10 +2219,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - /* If we're not given explicit OOB data, let it be 0xFF */ - if (likely(!oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; @@ -2214,7 +2228,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; - /* Partial page write ? */ + /* Partial page write? */ if (unlikely(column || writelen < (mtd->writesize - 1))) { cached = 0; bytes = min_t(int, bytes - column, (int) writelen); @@ -2226,12 +2240,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(chip, oob, len, ops); + oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); } ret = chip->write_page(mtd, chip, wbuf, page, cached, - (ops->mode == MTD_OOB_RAW)); + (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2260,11 +2277,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /** * panic_nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * * NAND write with ECC. Used when performing writes in interrupt context, this * may for example be called by mtdoops when writing an oops while in panic. @@ -2273,6 +2290,7 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2281,36 +2299,38 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, if (!len) return 0; - /* Wait for the device to get ready. */ + /* Wait for the device to get ready */ panic_nand_wait(mtd, chip, 400); - /* Grab the device. */ + /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; return ret; } /** * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * - * NAND write with ECC + * NAND write with ECC. */ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; /* Do not allow reads past end of device */ @@ -2321,13 +2341,14 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, nand_get_device(chip, mtd, FL_WRITING); - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; + ops.mode = 0; - ret = nand_do_write_ops(mtd, to, &chip->ops); + ret = nand_do_write_ops(mtd, to, &ops); - *retlen = chip->ops.retlen; + *retlen = ops.retlen; nand_release_device(mtd); @@ -2336,11 +2357,11 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, /** * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure * - * NAND write out-of-band + * NAND write out-of-band. */ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2348,24 +2369,24 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, int chipnr, page, status, len; struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; /* Do not allow write past end of page */ if ((ops->ooboffs + ops->ooblen) > len) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to write " - "past end of page\n", __func__); + pr_debug("%s: attempt to write past end of page\n", + __func__); return -EINVAL; } if (unlikely(ops->ooboffs >= len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt to start " - "write outside oob\n", __func__); + pr_debug("%s: attempt to start write outside oob\n", + __func__); return -EINVAL; } @@ -2374,8 +2395,8 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ops->ooboffs + ops->ooblen > ((mtd->size >> chip->page_shift) - (to >> chip->page_shift)) * len)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } @@ -2401,10 +2422,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - memset(chip->oob_poi, 0xff, mtd->oobsize); - nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - memset(chip->oob_poi, 0xff, mtd->oobsize); + nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); + + if (ops->mode == MTD_OPS_RAW) + status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); if (status) return status; @@ -2416,9 +2439,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, /** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure */ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2430,17 +2453,17 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, /* Do not allow writes past end of device */ if (ops->datbuf && (to + ops->len) > mtd->size) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond " - "end of device\n", __func__); + pr_debug("%s: attempt to write beyond end of device\n", + __func__); return -EINVAL; } nand_get_device(chip, mtd, FL_WRITING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -2458,11 +2481,11 @@ out: } /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * single_erase_cmd - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * Standard erase command for NAND chips + * Standard erase command for NAND chips. */ static void single_erase_cmd(struct mtd_info *mtd, int page) { @@ -2473,12 +2496,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) } /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks. */ static void multi_erase_cmd(struct mtd_info *mtd, int page) { @@ -2493,10 +2515,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page) /** * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction + * @mtd: MTD device structure + * @instr: erase instruction * - * Erase one ore more blocks + * Erase one ore more blocks. */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { @@ -2505,12 +2527,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) #define BBT_PAGE_MASK 0xffffff3f /** - * nand_erase_nand - [Internal] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * @allowbbt: allow erasing the bbt area + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area * - * Erase one ore more blocks + * Erase one ore more blocks. */ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) @@ -2521,9 +2543,9 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, unsigned int bbt_masked_page = 0xffffffff; loff_t len; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start = 0x%012llx, len = %llu\n", - __func__, (unsigned long long)instr->addr, - (unsigned long long)instr->len); + pr_debug("%s: start = 0x%012llx, len = %llu\n", + __func__, (unsigned long long)instr->addr, + (unsigned long long)instr->len); if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; @@ -2545,8 +2567,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* Check, if it is write protected */ if (nand_check_wp(mtd)) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Device is write protected!!!\n", - __func__); + pr_debug("%s: device is write protected!\n", + __func__); instr->state = MTD_ERASE_FAILED; goto erase_exit; } @@ -2555,7 +2577,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually - * erased to avoid recusrsive updates + * erased to avoid recursive updates. */ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2566,20 +2588,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, instr->state = MTD_ERASING; while (len) { - /* - * heck if we have a bad block, we do not erase bad blocks ! - */ + /* Heck if we have a bad block, we do not erase bad blocks! */ if (nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "%s: attempt to erase a bad block " - "at page 0x%08x\n", __func__, page); + pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } /* * Invalidate the page cache, if we erase the block which - * contains the current cached page + * contains the current cached page. */ if (page <= chip->pagebuf && chip->pagebuf < (page + pages_per_block)) @@ -2599,8 +2619,8 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { - DEBUG(MTD_DEBUG_LEVEL0, "%s: Failed erase, " - "page 0x%08x\n", __func__, page); + pr_debug("%s: failed erase, page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; instr->fail_addr = ((loff_t)page << chip->page_shift); @@ -2609,7 +2629,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh, set the BBT rewrite flag to the - * page being erased + * page being erased. */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2628,7 +2648,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh and BBT-PERCHIP, set the BBT - * page mask to see if this BBT should be rewritten + * page mask to see if this BBT should be rewritten. */ if (bbt_masked_page != 0xffffffff && (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2651,7 +2671,7 @@ erase_exit: /* * If BBT requires refresh and erase was successful, rewrite any - * selected bad block tables + * selected bad block tables. */ if (bbt_masked_page == 0xffffffff || ret) return ret; @@ -2659,10 +2679,10 @@ erase_exit: for (chipnr = 0; chipnr < chip->numchips; chipnr++) { if (!rewrite_bbt[chipnr]) continue; - /* update the BBT for chip */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " - "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, - rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); + /* Update the BBT for chip */ + pr_debug("%s: nand_update_bbt (%d:0x%0llx 0x%0x)\n", + __func__, chipnr, rewrite_bbt[chipnr], + chip->bbt_td->pages[chipnr]); nand_update_bbt(mtd, rewrite_bbt[chipnr]); } @@ -2672,15 +2692,15 @@ erase_exit: /** * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function. */ static void nand_sync(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_SYNCING); @@ -2690,8 +2710,8 @@ static void nand_sync(struct mtd_info *mtd) /** * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { @@ -2704,8 +2724,8 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) /** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start */ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -2714,7 +2734,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_block_isbad(mtd, ofs); if (ret) { - /* If it was bad already, return success and do nothing. */ + /* If it was bad already, return success and do nothing */ if (ret > 0) return 0; return ret; @@ -2725,7 +2745,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_suspend - [MTD Interface] Suspend the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static int nand_suspend(struct mtd_info *mtd) { @@ -2736,7 +2756,7 @@ static int nand_suspend(struct mtd_info *mtd) /** * nand_resume - [MTD Interface] Resume the NAND flash - * @mtd: MTD device structure + * @mtd: MTD device structure */ static void nand_resume(struct mtd_info *mtd) { @@ -2745,13 +2765,11 @@ static void nand_resume(struct mtd_info *mtd) if (chip->state == FL_PM_SUSPENDED) nand_release_device(mtd); else - printk(KERN_ERR "%s called for a chip which is not " - "in suspended state\n", __func__); + pr_err("%s called for a chip which is not in suspended state\n", + __func__); } -/* - * Set default functions - */ +/* Set default functions */ static void nand_set_defaults(struct nand_chip *chip, int busw) { /* check for proper chip_delay setup, set 20us if not */ @@ -2793,23 +2811,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */ static void sanitize_string(uint8_t *s, size_t len) { ssize_t i; - /* null terminate */ + /* Null terminate */ s[len - 1] = 0; - /* remove non printable chars */ + /* Remove non printable chars */ for (i = 0; i < len - 1; i++) { if (s[i] < ' ' || s[i] > 127) s[i] = '?'; } - /* remove trailing spaces */ + /* Remove trailing spaces */ strim(s); } @@ -2826,28 +2842,28 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) } /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, - int busw) + int *busw) { struct nand_onfi_params *p = &chip->onfi_params; int i; int val; - /* try ONFI for unknow chip or LP */ + /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - printk(KERN_INFO "ONFI flash detected\n"); + pr_info("ONFI flash detected\n"); chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { - printk(KERN_INFO "ONFI param page %d valid\n", i); + pr_info("ONFI param page %d valid\n", i); break; } } @@ -2855,7 +2871,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (i == 3) return 0; - /* check version */ + /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 5)) chip->onfi_version = 23; @@ -2871,8 +2887,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 0; if (!chip->onfi_version) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", - __func__, val); + pr_info("%s: unsupported ONFI version: %d\n", __func__, val); return 0; } @@ -2884,9 +2899,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, mtd->erasesize = le32_to_cpu(p->pages_per_block) * mtd->writesize; mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page); chip->chipsize = (uint64_t)le32_to_cpu(p->blocks_per_lun) * mtd->erasesize; - busw = 0; + *busw = 0; if (le16_to_cpu(p->features) & 1) - busw = NAND_BUSWIDTH_16; + *busw = NAND_BUSWIDTH_16; chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= (NAND_NO_READRDY | @@ -2896,7 +2911,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, } /* - * Get the flash and manufacturer id and lookup if the type is supported + * Get the flash and manufacturer id and lookup if the type is supported. */ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, @@ -2913,7 +2928,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up + * after power-up. */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2924,7 +2939,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id = chip->read_byte(mtd); *dev_id = chip->read_byte(mtd); - /* Try again to make sure, as some systems the bus-hold or other + /* + * Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. @@ -2936,9 +2952,9 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - printk(KERN_INFO "%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); + pr_info("%s: second ID read did not match " + "%02x,%02x against %02x,%02x\n", __func__, + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -2952,7 +2968,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->onfi_version = 0; if (!type->name || !type->pagesize) { /* Check is chip is ONFI compliant */ - ret = nand_flash_detect_onfi(mtd, chip, busw); + ret = nand_flash_detect_onfi(mtd, chip, &busw); if (ret) goto ident_done; } @@ -2973,7 +2989,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; if (!type->pagesize && chip->init_size) { - /* set the pagesize, oobsize, erasesize by the driver*/ + /* Set the pagesize, oobsize, erasesize by the driver */ busw = chip->init_size(mtd, chip, id_data); } else if (!type->pagesize) { int extid; @@ -3033,7 +3049,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } } else { /* - * Old devices have chip data hardcoded in the device id table + * Old devices have chip data hardcoded in the device id table. */ mtd->erasesize = type->erasesize; mtd->writesize = type->pagesize; @@ -3043,7 +3059,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, /* * Check for Spansion/AMD ID + repeating 5th, 6th byte since * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table + * listed in nand_ids table. * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) */ if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && @@ -3057,15 +3073,16 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->options &= ~NAND_CHIPOPTIONS_MSK; chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. + /* + * Check if chip is not a Samsung device. Do not clear the + * options for chips which do not have an extended id. */ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; ident_done: /* - * Set chip as a default. Board drivers can override it, if necessary + * Set chip as a default. Board drivers can override it, if necessary. */ chip->options |= NAND_NO_AUTOINCR; @@ -3077,21 +3094,21 @@ ident_done: /* * Check, if buswidth is correct. Hardware drivers should set - * chip correct ! + * chip correct! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); + pr_info("NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("NAND bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); return ERR_PTR(-EINVAL); } /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1. */ + /* Convert chipsize to number of pages per chip -1 */ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = @@ -3121,7 +3138,7 @@ ident_done: if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX)) - chip->options |= NAND_BBT_SCANLASTPAGE; + chip->bbt_options |= NAND_BBT_SCANLASTPAGE; else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && (*maf_id == NAND_MFR_SAMSUNG || *maf_id == NAND_MFR_HYNIX || @@ -3129,17 +3146,7 @@ ident_done: *maf_id == NAND_MFR_AMD)) || (mtd->writesize == 2048 && *maf_id == NAND_MFR_MICRON)) - chip->options |= NAND_BBT_SCAN2NDPAGE; - - /* - * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 - */ - if (!(busw & NAND_BUSWIDTH_16) && - *maf_id == NAND_MFR_STMICRO && - mtd->writesize == 2048) { - chip->options |= NAND_BBT_SCANBYTE1AND6; - chip->badblockpos = 0; - } + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) @@ -3147,12 +3154,11 @@ ident_done: else chip->erase_cmd = single_erase_cmd; - /* Do not replace user supplied command function ! */ + /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - /* TODO onfi flash name */ - printk(KERN_INFO "NAND device: Manufacturer ID:" + pr_info("NAND device: Manufacturer ID:" " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, chip->onfi_version ? chip->onfi_params.model : type->name); @@ -3162,12 +3168,12 @@ ident_done: /** * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * @table: Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */ @@ -3189,7 +3195,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (IS_ERR(type)) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) - printk(KERN_WARNING "No NAND device found.\n"); + pr_warn("No NAND device found\n"); chip->select_chip(mtd, -1); return PTR_ERR(type); } @@ -3207,7 +3213,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, break; } if (i > 1) - printk(KERN_INFO "%d NAND chips detected\n", i); + pr_info("%d NAND chips detected\n", i); /* Store the number of chips and calc total size for mtd */ chip->numchips = i; @@ -3220,11 +3226,11 @@ EXPORT_SYMBOL(nand_scan_ident); /** * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * @mtd: MTD device structure * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate. */ int nand_scan_tail(struct mtd_info *mtd) { @@ -3240,7 +3246,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* - * If no default placement scheme is given, select an appropriate one + * If no default placement scheme is given, select an appropriate one. */ if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { @@ -3257,8 +3263,8 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.layout = &nand_oob_128; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + pr_warn("No oob scheme defined for oobsize %d\n", + mtd->oobsize); BUG(); } } @@ -3267,7 +3273,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->write_page = nand_write_page; /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is + * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ @@ -3276,15 +3282,15 @@ int nand_scan_tail(struct mtd_info *mtd) /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: - /* Use standard hwecc read page function ? */ + /* Use standard hwecc read page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc; if (!chip->ecc.write_page) @@ -3305,11 +3311,11 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } - /* Use standard syndrome read/write page function ? */ + /* Use standard syndrome read/write page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.write_page) @@ -3325,9 +3331,9 @@ int nand_scan_tail(struct mtd_info *mtd) if (mtd->writesize >= chip->ecc.size) break; - printk(KERN_WARNING "%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - chip->ecc.size, mtd->writesize); + pr_warn("%d byte HW ECC not possible on " + "%d byte page size, fallback to SW ECC\n", + chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: @@ -3347,7 +3353,7 @@ int nand_scan_tail(struct mtd_info *mtd) case NAND_ECC_SOFT_BCH: if (!mtd_nand_has_bch()) { - printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); + pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); BUG(); } chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3362,8 +3368,8 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Board driver should supply ecc.size and ecc.bytes values to * select how many bits are correctable; see nand_bch_init() - * for details. - * Otherwise, default to 4 bits for large page devices + * for details. Otherwise, default to 4 bits for large page + * devices. */ if (!chip->ecc.size && (mtd->oobsize >= 64)) { chip->ecc.size = 512; @@ -3374,14 +3380,14 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.bytes, &chip->ecc.layout); if (!chip->ecc.priv) { - printk(KERN_WARNING "BCH ECC initialization failed!\n"); + pr_warn("BCH ECC initialization failed!\n"); BUG(); } break; case NAND_ECC_NONE: - printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " - "This is not recommended !!\n"); + pr_warn("NAND_ECC_NONE selected by board driver. " + "This is not recommended!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; @@ -3393,14 +3399,19 @@ int nand_scan_tail(struct mtd_info *mtd) break; default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", - chip->ecc.mode); + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } + /* For many systems, the standard OOB write also works for raw */ + if (!chip->ecc.read_oob_raw) + chip->ecc.read_oob_raw = chip->ecc.read_oob; + if (!chip->ecc.write_oob_raw) + chip->ecc.write_oob_raw = chip->ecc.write_oob; + /* * The number of bytes available for a client to place data into - * the out of band area + * the out of band area. */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3411,19 +3422,16 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Set the number of read / write steps for one page depending on ECC - * mode + * mode. */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ecc parameters\n"); + pr_warn("Invalid ECC parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - /* - * Allow subpage writes up to ecc.steps. Not possible for MLC - * FLASH. - */ + /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { switch (chip->ecc.steps) { @@ -3481,9 +3489,11 @@ int nand_scan_tail(struct mtd_info *mtd) } EXPORT_SYMBOL(nand_scan_tail); -/* is_module_text_address() isn't exported, and it's mostly a pointless +/* + * is_module_text_address() isn't exported, and it's mostly a pointless * test if this is a module _anyway_ -- they'd have to try _really_ hard - * to call us from in-kernel code if the core NAND support is modular. */ + * to call us from in-kernel code if the core NAND support is modular. + */ #ifdef MODULE #define caller_is_module() (1) #else @@ -3493,15 +3503,13 @@ EXPORT_SYMBOL(nand_scan_tail); /** * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller. */ int nand_scan(struct mtd_info *mtd, int maxchips) { @@ -3509,8 +3517,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /* Many callers got this wrong, so check for it for a while... */ if (!mtd->owner && caller_is_module()) { - printk(KERN_CRIT "%s called with NULL mtd->owner!\n", - __func__); + pr_crit("%s called with NULL mtd->owner!\n", __func__); BUG(); } @@ -3523,8 +3530,8 @@ EXPORT_SYMBOL(nand_scan); /** * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure -*/ + * @mtd: MTD device structure + */ void nand_release(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 4165857752c..69148ae3bf5 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -14,7 +14,7 @@ * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory * marked good / bad blocks. This information is used to create a memory BBT. * Once a new bad block is discovered then the "factory" information is updated * on the device. @@ -36,9 +36,9 @@ * The table is marked in the OOB area with an ident pattern and a version * number which indicates which of both tables is more up to date. If the NAND * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched. * * The table uses 2 bits per block * 11b: block is good @@ -81,17 +81,15 @@ static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) /** * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { int i, end = 0; @@ -110,32 +108,8 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc p += end; /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - - /* Check both positions 1 and 6 for pattern? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += NAND_SMALL_BADBLOCK_POS - td->offs; - /* Check region between positions 1 and 6 */ - for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; - i++) { - if (*p++ != 0xff) - return -1; - } - } - else { - p += NAND_SMALL_BADBLOCK_POS - td->offs; - } - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - } + if (memcmp(p, td->pattern, td->len)) + return -1; if (td->options & NAND_BBT_SCANEMPTY) { p += td->len; @@ -150,14 +124,13 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check + * @buf: the buffer to search + * @td: search pattern descriptor * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) { int i; @@ -168,21 +141,14 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) if (p[td->offs + i] != td->pattern[i]) return -1; } - /* Need to check location 1 AND 6? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - for (i = 0; i < td->len; i++) { - if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) - return -1; - } - } return 0; } /** * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation + * @td: BBT descriptor used for computation * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area. */ static u32 add_marker_len(struct nand_bbt_descr *td) { @@ -199,34 +165,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table * * Read the bad block table starting from page. - * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) { - int res, i, j, act = 0; + int res, ret = 0, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t) ((1 << bits) - 1); + uint8_t msk = (uint8_t)((1 << bits) - 1); u32 marker_len; int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; marker_len = add_marker_len(td); - from = ((loff_t) page) << this->page_shift; + from = ((loff_t)page) << this->page_shift; while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); if (marker_len) { /* * In case the BBT marker is not in the OOB area it @@ -238,11 +203,18 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, } res = mtd->read(mtd, from, len, &retlen, buf); if (res < 0) { - if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -253,17 +225,19 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: reserved block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; } - /* 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%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* + * Leave it for now, if it's matured we can + * move this message to pr_debug. + */ + pr_info("nand_read_bbt: bad block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else @@ -274,20 +248,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen -= len; from += len; } - return 0; + return ret; } /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + * NAND_BBT_PERCHIP option is set * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct nand_chip *this = mtd->priv; @@ -313,9 +287,7 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc return 0; } -/* - * BBT marker is in the first page, no OOB. - */ +/* BBT marker is in the first page, no OOB */ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, struct nand_bbt_descr *td) { @@ -329,35 +301,26 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return mtd->read(mtd, offs, len, &retlen, buf); } -/* - * Scan read raw data from flash - */ +/* Scan read raw data from flash */ static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; - while (len > 0) { - if (len <= mtd->writesize) { - ops.oobbuf = buf + len; - ops.datbuf = buf; - ops.len = len; - return mtd->read_oob(mtd, offs, &ops); - } else { - ops.oobbuf = buf + mtd->writesize; - ops.datbuf = buf; - ops.len = mtd->writesize; - res = mtd->read_oob(mtd, offs, &ops); + ops.datbuf = buf; + ops.len = min(len, (size_t)mtd->writesize); + ops.oobbuf = buf + ops.len; - if (res) - return res; - } + res = mtd->read_oob(mtd, offs, &ops); + + if (res) + return res; buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; @@ -374,15 +337,13 @@ static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, return scan_read_raw_oob(mtd, buf, offs, len); } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.datbuf = buf; @@ -403,15 +364,14 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. - * -*/ + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { @@ -422,8 +382,8 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + td->pages[0], td->version[0]); } /* Read the mirror version, if available */ @@ -431,15 +391,13 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, mtd->writesize, td); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + md->pages[0], md->version[0]); } return 1; } -/* - * Scan a given block full - */ +/* Scan a given block full */ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, size_t readlen, int scanlen, int len) @@ -447,7 +405,8 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, int ret, j; ret = scan_read_raw_oob(mtd, buf, offs, readlen); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; for (j = 0; j < len; j++, buf += scanlen) { @@ -457,9 +416,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, return 0; } -/* - * Scan a given block partially - */ +/* Scan a given block partially */ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, int len) { @@ -470,16 +427,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.oobbuf = buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; for (j = 0; j < len; j++) { /* - * Read the full oob until read_oob is fixed to - * handle single byte reads for 16 bit - * buswidth + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. */ ret = mtd->read_oob(mtd, offs, &ops); - if (ret) + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; if (check_short_pattern(buf, bd)) @@ -492,14 +449,14 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. */ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) @@ -510,7 +467,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, loff_t from; size_t readlen; - printk(KERN_INFO "Scanning device for bad blocks\n"); + pr_info("Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) len = 1 << (this->bbt_erase_shift - this->page_shift); @@ -530,14 +487,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, } if (chip == -1) { - /* Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful */ + /* + * Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful + */ numblocks = mtd->size >> (this->bbt_erase_shift - 1); startblock = 0; from = 0; } else { if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); return -EINVAL; } @@ -547,7 +506,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, from = (loff_t)startblock << (this->bbt_erase_shift - 1); } - if (this->options & NAND_BBT_SCANLASTPAGE) + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) from += mtd->erasesize - (mtd->writesize * len); for (i = startblock; i < numblocks;) { @@ -566,8 +525,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%012llx\n", - i >> 1, (unsigned long long)from); + pr_warn("Bad eraseblock %d at 0x%012llx\n", + i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -579,20 +538,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block. */ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -603,7 +560,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int bbtblocks; int blocktopage = this->bbt_erase_shift - this->page_shift; - /* Search direction top -> down ? */ + /* Search direction top -> down? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; @@ -612,7 +569,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr dir = 1; } - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -651,23 +608,23 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) - printk(KERN_WARNING "Bad block table not found for chip %d\n", i); + pr_warn("Bad block table not found for chip %d\n", i); else - printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], - td->version[i]); + pr_info("Bad block table found at page %d, version " + "0x%02X\n", td->pages[i], td->version[i]); } return 0; } /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Search and read the bad block table(s) -*/ + * Search and read the bad block table(s). + */ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) { /* Search the primary table */ @@ -683,16 +640,14 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt /** * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all * - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) @@ -711,14 +666,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ops.ooblen = mtd->oobsize; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; if (!rcode) rcode = 0xff; - /* Write bad block table per chip rather than per device ? */ + /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -732,8 +687,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page + /* + * There was already a version of the table, reuse the page * This applies for absolute placement too, as we have the * page nr. in td->pages. */ @@ -742,8 +697,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, goto write; } - /* Automatic placement of the bad block table */ - /* Search direction top -> down ? */ + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = numblocks * (chip + 1) - 1; dir = -1; @@ -767,7 +724,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (!md || md->pages[chip] != page) goto write; } - printk(KERN_ERR "No space left to write bad block table\n"); + pr_err("No space left to write bad block table\n"); return -ENOSPC; write: @@ -792,24 +749,22 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, bbtoffs = chip * (numblocks >> 2); - to = ((loff_t) page) << this->page_shift; + to = ((loff_t)page) << this->page_shift; - /* Must we save the block contents ? */ + /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ - to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; res = mtd->read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error " - "reading block for writing " - "the bad block table\n"); + pr_info("nand_bbt: error reading block " + "for writing the bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error " - "while reading block for writing " - "bad block table\n"); + pr_warn("nand_bbt: ECC error while reading " + "block for writing bad block table\n"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; @@ -822,19 +777,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); } else if (td->options & NAND_BBT_NO_OOB) { ooboffs = 0; offs = td->len; - /* the version byte */ + /* The version byte */ if (td->options & NAND_BBT_VERSION) offs++; /* Calc length */ - len = (size_t) (numblocks >> sft); + len = (size_t)(numblocks >> sft); len += offs; - /* Make it page aligned ! */ + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len); @@ -842,8 +797,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memcpy(buf, td->pattern, td->len); } else { /* Calc length */ - len = (size_t) (numblocks >> sft); - /* Make it page aligned ! */ + len = (size_t)(numblocks >> sft); + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + @@ -857,13 +812,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (td->options & NAND_BBT_VERSION) buf[ooboffs + td->veroffs] = td->version[chip]; - /* walk through the memory table */ + /* Walk through the memory table */ for (i = 0; i < numblocks;) { uint8_t dat; dat = this->bbt[bbtoffs + (i >> 2)]; for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks ! */ + /* Do not store the reserved bbt blocks! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; @@ -884,8 +839,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%012llx, version " - "0x%02X\n", (unsigned long long)to, td->version[chip]); + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -893,19 +848,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, return 0; outerr: - printk(KERN_WARNING - "nand_bbt: Error while writing bad block table %d\n", res); + pr_warn("nand_bbt: error while writing bad block table %d\n", res); return res; } /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -916,25 +870,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { - int i, chips, writeops, chipsel, res; + int i, chips, writeops, create, chipsel, res, res2; struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; else @@ -942,86 +895,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc for (i = 0; i < chips; i++) { writeops = 0; + create = 0; rd = NULL; rd2 = NULL; - /* Per chip or per device ? */ + res = res2 = 0; + /* Per chip or per device? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available ? */ + /* Mirrored table available? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { + create = 1; writeops = 0x03; - goto create; - } - - if (td->pages[i] == -1) { + } else if (td->pages[i] == -1) { rd = md; - td->version[i] = md->version[i]; - writeops = 1; - goto writecheck; - } - - if (md->pages[i] == -1) { + writeops = 0x01; + } else if (md->pages[i] == -1) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; - goto writecheck; - } - - if (td->version[i] == md->version[i]) { + writeops = 0x02; + } else if (td->version[i] == md->version[i]) { rd = td; if (!(td->options & NAND_BBT_VERSION)) rd2 = md; - goto writecheck; - } - - if (((int8_t) (td->version[i] - md->version[i])) > 0) { + } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; + writeops = 0x02; } else { rd = md; - td->version[i] = md->version[i]; - writeops = 1; + writeops = 0x01; } - - goto writecheck; - } else { if (td->pages[i] == -1) { + create = 1; writeops = 0x01; - goto create; + } else { + rd = td; } - rd = td; - goto writecheck; } - create: - /* Create the bad block table by scanning the device ? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - /* Create the table in memory by scanning the chip(s) */ - if (!(this->options & NAND_CREATE_EMPTY_BBT)) - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - writecheck: - /* read back first ? */ - if (rd) - read_abs_bbt(mtd, buf, rd, chipsel); - /* If they weren't versioned, read both. */ - if (rd2) - read_abs_bbt(mtd, buf, rd2, chipsel); - - /* Write the bad block table to the device ? */ + if (create) { + /* Create the bad block table by scanning the device? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + } + + /* Read back first? */ + if (rd) { + res = read_abs_bbt(mtd, buf, rd, chipsel); + if (mtd_is_eccerr(res)) { + /* Mark table as invalid */ + rd->pages[i] = -1; + rd->version[i] = 0; + i--; + continue; + } + } + /* If they weren't versioned, read both */ + if (rd2) { + res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + if (mtd_is_eccerr(res2)) { + /* Mark table as invalid */ + rd2->pages[i] = -1; + rd2->version[i] = 0; + i--; + continue; + } + } + + /* Scrub the flash table(s)? */ + if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) + writeops = 0x03; + + /* Update version numbers before writing */ + if (md) { + td->version[i] = max(td->version[i], md->version[i]); + md->version[i] = td->version[i]; + } + + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } - /* Write the mirror bad block table to the device ? */ + /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) @@ -1033,20 +998,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; uint8_t oldval, newval; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1083,9 +1047,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) update = 1; block += 2; } - /* If we want reserved blocks to be recorded to flash, and some - new ones have been marked, then we need to update the stored - bbts. This should only happen once. */ + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ if (update && td->reserved_block_code) nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } @@ -1093,8 +1059,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify + * @mtd: MTD device structure + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. @@ -1112,16 +1078,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) pattern_len = bd->len; bits = bd->options & NAND_BBT_NRBITS_MSK; - BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && - !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && + !(this->bbt_options & NAND_BBT_USE_FLASH)); BUG_ON(!bits); if (bd->options & NAND_BBT_VERSION) pattern_len++; if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); - BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); BUG_ON(bd->offs); if (bd->options & NAND_BBT_VERSION) BUG_ON(bd->veroffs != bd->len); @@ -1141,18 +1107,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place. * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -1162,19 +1126,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) and clear the memory bad block table */ + /* + * Allocate memory (2bit per block) and clear the memory bad block + * table. + */ this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) { - printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); + if (!this->bbt) return -ENOMEM; - } - /* If no primary table decriptor is given, scan the device - * to build a memory based bad block table + /* + * If no primary table decriptor is given, scan the device to build a + * memory based bad block table. */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } @@ -1188,13 +1154,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { - printk(KERN_ERR "nand_bbt: Out of memory\n"); kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } - /* Is the bbt at a given page ? */ + /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { res = read_abs_bbts(mtd, buf, td, md); } else { @@ -1216,15 +1181,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; + int len, res = 0; int chip, chipsel; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1237,14 +1202,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "nand_update_bbt: Out of memory\n"); + if (!buf) return -ENOMEM; - } - - writeops = md != NULL ? 0x03 : 0x01; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chip = (int)(offs >> this->chip_shift); chipsel = chip; @@ -1257,14 +1218,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (md) md->version[chip]++; - /* Write the bad block table to the device ? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } - /* Write the mirror bad block table to the device ? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); } @@ -1273,8 +1234,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) return res; } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1286,8 +1249,7 @@ static struct nand_bbt_descr agand_flashbased = { .pattern = scan_agand_pattern }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1331,31 +1293,27 @@ static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { .pattern = mirror_pattern }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ - NAND_BBT_SCANBYTE1AND6) +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when * passed to this function. - * */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); + pr_warn("Bad block pattern already allocated; not replacing\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) { - printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); + if (!bd) return -ENOMEM; - } - bd->options = this->options & BBT_SCAN_OPTIONS; + bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; @@ -1366,22 +1324,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) /** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */ int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - /* Default for AG-AND. We must use a flash based - * bad block table as the devices have factory marked - * _good_ blocks. Erasing those blocks leads to loss - * of the good / bad information, so we _must_ store - * this information in a good / bad table during - * startup + /* + * Default for AG-AND. We must use a flash based bad block table as the + * devices have factory marked _good_ blocks. Erasing those blocks + * leads to loss of the good / bad information, so we _must_ store this + * information in a good / bad table during startup. */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ @@ -1389,15 +1345,15 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; return nand_scan_bbt(mtd, &agand_flashbased); } - /* Is a flash based bad block table requested ? */ - if (this->options & NAND_USE_FLASH_BBT) { + /* Is a flash based bad block table requested? */ + if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { + if (this->bbt_options & NAND_BBT_NO_OOB) { this->bbt_td = &bbt_main_no_bbt_descr; this->bbt_md = &bbt_mirror_no_bbt_descr; } else { @@ -1411,18 +1367,17 @@ int nand_default_bbt(struct mtd_info *mtd) } if (!this->badblock_pattern) - nand_create_default_bbt_descr(this); + nand_create_badblock_pattern(this); return nand_scan_bbt(mtd, this->badblock_pattern); } /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; @@ -1433,8 +1388,9 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int)(offs >> (this->bbt_erase_shift - 1)); res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); + pr_debug("nand_isbad_bbt(): bbt info for offs 0x%08x: " + "(block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); switch ((int)res) { case 0x00: diff --git a/drivers/mtd/nand/nand_bch.c b/drivers/mtd/nand/nand_bch.c index 0f931e75711..3803e0bba23 100644 --- a/drivers/mtd/nand/nand_bch.c +++ b/drivers/mtd/nand/nand_bch.c @@ -93,8 +93,8 @@ int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); /* else error in ecc, no action needed */ - DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n", - __func__, errloc[i]); + pr_debug("%s: corrected bitflip %u\n", __func__, + errloc[i]); } } else if (count < 0) { printk(KERN_ERR "ecc unrecoverable error\n"); diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index 271b8e735e8..b7cfe0d3712 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c @@ -110,7 +110,7 @@ static const char bitsperbyte[256] = { /* * addressbits is a lookup table to filter out the bits from the xor-ed - * ecc data that identify the faulty location. + * ECC data that identify the faulty location. * this is only used for repairing parity * see the comments in nand_correct_data for more details */ @@ -153,7 +153,7 @@ static const char addressbits[256] = { * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte * block * @buf: input buffer with raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * @code: output buffer with ECC */ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, @@ -348,7 +348,7 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize, rp17 = (par ^ rp16) & 0xff; /* - * Finally calculate the ecc bits. + * Finally calculate the ECC bits. * Again here it might seem that there are performance optimisations * possible, but benchmarks showed that on the system this is developed * the code below is the fastest @@ -436,7 +436,7 @@ EXPORT_SYMBOL(nand_calculate_ecc); * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data - * @eccsize: data bytes per ecc step (256 or 512) + * @eccsize: data bytes per ECC step (256 or 512) * * Detect and correct a 1 bit error for eccsize byte block */ @@ -505,7 +505,7 @@ int __nand_correct_data(unsigned char *buf, } /* count nr of bits; use table lookup, faster than calculating it */ if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) - return 1; /* error in ecc data; no action needed */ + return 1; /* error in ECC data; no action needed */ printk(KERN_ERR "uncorrectable error : "); return -1; diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 357e8c5252a..34c03be7730 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2273,9 +2273,9 @@ static int __init ns_init_module(void) switch (bbt) { case 2: - chip->options |= NAND_USE_FLASH_BBT_NO_OOB; + chip->bbt_options |= NAND_BBT_NO_OOB; case 1: - chip->options |= NAND_USE_FLASH_BBT; + chip->bbt_options |= NAND_BBT_USE_FLASH; case 0: break; default: diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index ea2dea8a9c8..f8aacf48ecd 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -42,7 +42,6 @@ struct ndfc_controller { struct nand_chip chip; int chip_select; struct nand_hw_control ndfc_control; - struct mtd_partition *parts; }; static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; @@ -159,13 +158,9 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) static int ndfc_chip_init(struct ndfc_controller *ndfc, struct device_node *node) { -#ifdef CONFIG_MTD_CMDLINE_PARTS - static const char *part_types[] = { "cmdlinepart", NULL }; -#else - static const char *part_types[] = { NULL }; -#endif struct device_node *flash_np; struct nand_chip *chip = &ndfc->chip; + struct mtd_part_parser_data ppdata; int ret; chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; @@ -193,6 +188,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (!flash_np) return -ENODEV; + ppdata.of_node = flash_np; ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", dev_name(&ndfc->ofdev->dev), flash_np->name); if (!ndfc->mtd.name) { @@ -204,18 +200,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, if (ret) goto err; - ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); - if (ret < 0) - goto err; - - if (ret == 0) { - ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, - &ndfc->parts); - if (ret < 0) - goto err; - } - - ret = mtd_device_register(&ndfc->mtd, ndfc->parts, ret); + ret = mtd_device_parse_register(&ndfc->mtd, NULL, &ppdata, NULL, 0); err: of_node_put(flash_np); @@ -288,6 +273,7 @@ static int __devexit ndfc_remove(struct platform_device *ofdev) struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); nand_release(&ndfc->mtd); + kfree(ndfc->mtd.name); return 0; } diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index b6a5c86ab31..b463ecfb4c1 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -187,6 +187,7 @@ static int nomadik_nand_remove(struct platform_device *pdev) pdata->exit(); if (host) { + nand_release(&host->mtd); iounmap(host->cmd_va); iounmap(host->data_va); iounmap(host->addr_va); diff --git a/drivers/mtd/nand/nuc900_nand.c b/drivers/mtd/nand/nuc900_nand.c index 9c30a0b0317..fa8faedfad6 100644 --- a/drivers/mtd/nand/nuc900_nand.c +++ b/drivers/mtd/nand/nuc900_nand.c @@ -339,6 +339,7 @@ static int __devexit nuc900_nand_remove(struct platform_device *pdev) struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); struct resource *res; + nand_release(&nuc900_nand->mtd); iounmap(nuc900_nand->reg); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ec22a5aab03..f745f00f316 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -95,8 +95,6 @@ #define P4e_s(a) (TF(a & NAND_Ecc_P4e) << 0) #define P4o_s(a) (TF(a & NAND_Ecc_P4o) << 1) -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* oob info generated runtime depending on ecc algorithm and layout selected */ static struct nand_ecclayout omap_oobinfo; /* Define some generic bad / good block scan pattern which are used @@ -115,7 +113,6 @@ struct omap_nand_info { struct nand_hw_control controller; struct omap_nand_platform_data *pdata; struct mtd_info mtd; - struct mtd_partition *parts; struct nand_chip nand; struct platform_device *pdev; @@ -745,12 +742,12 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ case 1: /* Uncorrectable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + pr_debug("ECC UNCORRECTED_ERROR 1\n"); return -1; case 11: /* UN-Correctable error */ - DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n"); + pr_debug("ECC UNCORRECTED_ERROR B\n"); return -1; case 12: @@ -767,8 +764,8 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; - DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at " - "offset: %d, bit: %d\n", find_byte, find_bit); + pr_debug("Correcting single bit ECC error at offset: " + "%d, bit: %d\n", find_byte, find_bit); page_data[find_byte] ^= (1 << find_bit); @@ -780,7 +777,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */ ecc_data2[2] == 0) return 0; } - DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + pr_debug("UNCORRECTED_ERROR default\n"); return -1; } } @@ -1104,13 +1101,8 @@ static int __devinit omap_nand_probe(struct platform_device *pdev) goto out_release_mem_region; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - mtd_device_register(&info->mtd, NULL, 0); + mtd_device_parse_register(&info->mtd, NULL, 0, + pdata->parts, pdata->nr_parts); platform_set_drvdata(pdev, &info->mtd); diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 7794d0680f9..29f505adaf8 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -21,8 +21,6 @@ #include <mach/hardware.h> #include <plat/orion_nand.h> -static const char *part_probes[] = { "cmdlinepart", NULL }; - static void orion_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) { struct nand_chip *nc = mtd->priv; @@ -81,8 +79,6 @@ static int __init orion_nand_probe(struct platform_device *pdev) struct resource *res; void __iomem *io_base; int ret = 0; - struct mtd_partition *partitions = NULL; - int num_part = 0; nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL); if (!nc) { @@ -132,17 +128,9 @@ static int __init orion_nand_probe(struct platform_device *pdev) goto no_dev; } -#ifdef CONFIG_MTD_CMDLINE_PARTS mtd->name = "orion_nand"; - num_part = parse_mtd_partitions(mtd, part_probes, &partitions, 0); -#endif - /* If cmdline partitions have been passed, let them be used */ - if (num_part <= 0) { - num_part = board->nr_parts; - partitions = board->parts; - } - - ret = mtd_device_register(mtd, partitions, num_part); + ret = mtd_device_parse_register(mtd, NULL, 0, + board->parts, board->nr_parts); if (ret) { nand_release(mtd); goto no_dev; diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index b1aa41b8a4e..a97264ececd 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -155,7 +155,8 @@ static int __devinit pasemi_nand_probe(struct platform_device *ofdev) chip->ecc.mode = NAND_ECC_SOFT; /* Enable the following for a flash based bad block table */ - chip->options = NAND_USE_FLASH_BBT | NAND_NO_AUTOINCR; + chip->options = NAND_NO_AUTOINCR; + chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ if (nand_scan(pasemi_nand_mtd, 1)) { diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 633c04bf76f..ea8e1234e0e 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -21,8 +21,6 @@ struct plat_nand_data { struct nand_chip chip; struct mtd_info mtd; void __iomem *io_base; - int nr_parts; - struct mtd_partition *parts; }; /* @@ -79,6 +77,7 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) data->chip.read_buf = pdata->ctrl.read_buf; data->chip.chip_delay = pdata->chip.chip_delay; data->chip.options |= pdata->chip.options; + data->chip.bbt_options |= pdata->chip.bbt_options; data->chip.ecc.hwctl = pdata->ctrl.hwcontrol; data->chip.ecc.layout = pdata->chip.ecclayout; @@ -99,23 +98,9 @@ static int __devinit plat_nand_probe(struct platform_device *pdev) goto out; } - if (pdata->chip.part_probe_types) { - err = parse_mtd_partitions(&data->mtd, - pdata->chip.part_probe_types, - &data->parts, 0); - if (err > 0) { - mtd_device_register(&data->mtd, data->parts, err); - return 0; - } - } - if (pdata->chip.set_parts) - pdata->chip.set_parts(data->mtd.size, &pdata->chip); - if (pdata->chip.partitions) { - data->parts = pdata->chip.partitions; - err = mtd_device_register(&data->mtd, data->parts, - pdata->chip.nr_partitions); - } else - err = mtd_device_register(&data->mtd, NULL, 0); + err = mtd_device_parse_register(&data->mtd, + pdata->chip.part_probe_types, 0, + pdata->chip.partitions, pdata->chip.nr_partitions); if (!err) return err; @@ -145,8 +130,6 @@ static int __devexit plat_nand_remove(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nand_release(&data->mtd); - if (data->parts && data->parts != pdata->chip.partitions) - kfree(data->parts); if (pdata->ctrl.remove) pdata->ctrl.remove(pdev); iounmap(data->io_base); diff --git a/drivers/mtd/nand/ppchameleonevb.c b/drivers/mtd/nand/ppchameleonevb.c index 3bbb796b451..7e52af51a19 100644 --- a/drivers/mtd/nand/ppchameleonevb.c +++ b/drivers/mtd/nand/ppchameleonevb.c @@ -99,8 +99,6 @@ static struct mtd_partition partition_info_evb[] = { #define NUM_PARTITIONS 1 -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, const char *mtd_id); - /* * hardware specific access to control-lines */ @@ -187,18 +185,12 @@ static int ppchameleonevb_device_ready(struct mtd_info *minfo) } #endif -const char *part_probes[] = { "cmdlinepart", NULL }; -const char *part_probes_evb[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ static int __init ppchameleonevb_init(void) { struct nand_chip *this; - const char *part_type = 0; - int mtd_parts_nb = 0; - struct mtd_partition *mtd_parts = 0; void __iomem *ppchameleon_fio_base; void __iomem *ppchameleonevb_fio_base; @@ -281,24 +273,13 @@ static int __init ppchameleonevb_init(void) #endif ppchameleon_mtd->name = "ppchameleon-nand"; - mtd_parts_nb = parse_mtd_partitions(ppchameleon_mtd, part_probes, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - if (ppchameleon_mtd->size == NAND_SMALL_SIZE) - mtd_parts = partition_info_me; - else - mtd_parts = partition_info_hi; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleon_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleon_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); nand_evb_init: /**************************** @@ -382,21 +363,13 @@ static int __init ppchameleonevb_init(void) } ppchameleonevb_mtd->name = NAND_EVB_MTD_NAME; - mtd_parts_nb = parse_mtd_partitions(ppchameleonevb_mtd, part_probes_evb, &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - - if (mtd_parts_nb == 0) { - mtd_parts = partition_info_evb; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; - } /* Register the partitions */ - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - mtd_device_register(ppchameleonevb_mtd, mtd_parts, mtd_parts_nb); + mtd_device_parse_register(ppchameleonevb_mtd, NULL, 0, + ppchameleon_mtd->size == NAND_SMALL_SIZE ? + partition_info_me : + partition_info_hi, + NUM_PARTITIONS); /* Return happy */ return 0; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 1fb3b3a8058..9eb7f879969 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -110,6 +110,7 @@ enum { enum { STATE_IDLE = 0, + STATE_PREPARED, STATE_CMD_HANDLE, STATE_DMA_READING, STATE_DMA_WRITING, @@ -120,21 +121,40 @@ enum { STATE_READY, }; -struct pxa3xx_nand_info { - struct nand_chip nand_chip; +struct pxa3xx_nand_host { + struct nand_chip chip; + struct pxa3xx_nand_cmdset *cmdset; + struct mtd_info *mtd; + void *info_data; + + /* page size of attached chip */ + unsigned int page_size; + int use_ecc; + int cs; + /* calculated from pxa3xx_nand_flash data */ + unsigned int col_addr_cycles; + unsigned int row_addr_cycles; + size_t read_id_bytes; + + /* cached register value */ + uint32_t reg_ndcr; + uint32_t ndtr0cs0; + uint32_t ndtr1cs0; +}; + +struct pxa3xx_nand_info { struct nand_hw_control controller; struct platform_device *pdev; - struct pxa3xx_nand_cmdset *cmdset; struct clk *clk; void __iomem *mmio_base; unsigned long mmio_phys; + struct completion cmd_complete; unsigned int buf_start; unsigned int buf_count; - struct mtd_info *mtd; /* DMA information */ int drcmr_dat; int drcmr_cmd; @@ -142,44 +162,27 @@ struct pxa3xx_nand_info { unsigned char *data_buff; unsigned char *oob_buff; dma_addr_t data_buff_phys; - size_t data_buff_size; int data_dma_ch; struct pxa_dma_desc *data_desc; dma_addr_t data_desc_addr; - uint32_t reg_ndcr; - - /* saved column/page_addr during CMD_SEQIN */ - int seqin_column; - int seqin_page_addr; - - /* relate to the command */ + struct pxa3xx_nand_host *host[NUM_CHIP_SELECT]; unsigned int state; + int cs; int use_ecc; /* use HW ECC ? */ int use_dma; /* use DMA ? */ int is_ready; unsigned int page_size; /* page size of attached chip */ unsigned int data_size; /* data size in FIFO */ + unsigned int oob_size; int retcode; - struct completion cmd_complete; /* generated NDCBx register values */ uint32_t ndcb0; uint32_t ndcb1; uint32_t ndcb2; - - /* timing calcuted from setting */ - uint32_t ndtr0cs0; - uint32_t ndtr1cs0; - - /* calculated from pxa3xx_nand_flash data */ - size_t oob_size; - size_t read_id_bytes; - - unsigned int col_addr_cycles; - unsigned int row_addr_cycles; }; static int use_dma = 1; @@ -225,7 +228,7 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = { /* Define a default flash type setting serve as flash detecting only */ #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0]) -const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; +const char *mtd_names[] = {"pxa3xx_nand-0", "pxa3xx_nand-1", NULL}; #define NDTR0_tCH(c) (min((c), 7) << 19) #define NDTR0_tCS(c) (min((c), 7) << 16) @@ -241,9 +244,10 @@ const char *mtd_names[] = {"pxa3xx_nand-0", NULL}; /* convert nano-seconds to nand flash controller clock cycles */ #define ns2cycle(ns, clk) (int)((ns) * (clk / 1000000) / 1000) -static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, +static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host, const struct pxa3xx_nand_timing *t) { + struct pxa3xx_nand_info *info = host->info_data; unsigned long nand_clk = clk_get_rate(info->clk); uint32_t ndtr0, ndtr1; @@ -258,23 +262,24 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_info *info, NDTR1_tWHR(ns2cycle(t->tWHR, nand_clk)) | NDTR1_tAR(ns2cycle(t->tAR, nand_clk)); - info->ndtr0cs0 = ndtr0; - info->ndtr1cs0 = ndtr1; + host->ndtr0cs0 = ndtr0; + host->ndtr1cs0 = ndtr1; nand_writel(info, NDTR0CS0, ndtr0); nand_writel(info, NDTR1CS0, ndtr1); } static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) { - int oob_enable = info->reg_ndcr & NDCR_SPARE_EN; + struct pxa3xx_nand_host *host = info->host[info->cs]; + int oob_enable = host->reg_ndcr & NDCR_SPARE_EN; - info->data_size = info->page_size; + info->data_size = host->page_size; if (!oob_enable) { info->oob_size = 0; return; } - switch (info->page_size) { + switch (host->page_size) { case 2048: info->oob_size = (info->use_ecc) ? 40 : 64; break; @@ -292,9 +297,10 @@ static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info) */ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info) { + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr; - ndcr = info->reg_ndcr; + ndcr = host->reg_ndcr; ndcr |= info->use_ecc ? NDCR_ECC_EN : 0; ndcr |= info->use_dma ? NDCR_DMA_EN : 0; ndcr |= NDCR_ND_RUN; @@ -359,7 +365,7 @@ static void handle_data_pio(struct pxa3xx_nand_info *info) DIV_ROUND_UP(info->oob_size, 4)); break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -385,7 +391,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info) desc->dcmd |= DCMD_INCTRGADDR | DCMD_FLOWSRC; break; default: - printk(KERN_ERR "%s: invalid state %d\n", __func__, + dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__, info->state); BUG(); } @@ -416,6 +422,15 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; unsigned int status, is_completed = 0; + unsigned int ready, cmd_done; + + if (info->cs == 0) { + ready = NDSR_FLASH_RDY; + cmd_done = NDSR_CS0_CMDD; + } else { + ready = NDSR_RDY; + cmd_done = NDSR_CS1_CMDD; + } status = nand_readl(info, NDSR); @@ -437,11 +452,11 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) handle_data_pio(info); } } - if (status & NDSR_CS0_CMDD) { + if (status & cmd_done) { info->state = STATE_CMD_DONE; is_completed = 1; } - if (status & NDSR_FLASH_RDY) { + if (status & ready) { info->is_ready = 1; info->state = STATE_READY; } @@ -463,12 +478,6 @@ NORMAL_IRQ_EXIT: return IRQ_HANDLED; } -static int pxa3xx_nand_dev_ready(struct mtd_info *mtd) -{ - struct pxa3xx_nand_info *info = mtd->priv; - return (nand_readl(info, NDSR) & NDSR_RDY) ? 1 : 0; -} - static inline int is_buf_blank(uint8_t *buf, size_t len) { for (; len > 0; len--) @@ -481,10 +490,12 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, uint16_t column, int page_addr) { uint16_t cmd; - int addr_cycle, exec_cmd, ndcb0; - struct mtd_info *mtd = info->mtd; + int addr_cycle, exec_cmd; + struct pxa3xx_nand_host *host; + struct mtd_info *mtd; - ndcb0 = 0; + host = info->host[info->cs]; + mtd = host->mtd; addr_cycle = 0; exec_cmd = 1; @@ -495,6 +506,10 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->use_ecc = 0; info->is_ready = 0; info->retcode = ERR_NONE; + if (info->cs != 0) + info->ndcb0 = NDCB0_CSEL; + else + info->ndcb0 = 0; switch (command) { case NAND_CMD_READ0: @@ -512,20 +527,19 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - info->ndcb0 = ndcb0; - addr_cycle = NDCB0_ADDR_CYC(info->row_addr_cycles - + info->col_addr_cycles); + addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles + + host->col_addr_cycles); switch (command) { case NAND_CMD_READOOB: case NAND_CMD_READ0: - cmd = info->cmdset->read1; + cmd = host->cmdset->read1; if (command == NAND_CMD_READOOB) info->buf_start = mtd->writesize + column; else info->buf_start = column; - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) info->ndcb0 |= NDCB0_CMD_TYPE(0) | addr_cycle | (cmd & NDCB0_CMD1_MASK); @@ -537,7 +551,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, case NAND_CMD_SEQIN: /* small page addr setting */ - if (unlikely(info->page_size < PAGE_CHUNK_SIZE)) { + if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) { info->ndcb1 = ((page_addr & 0xFFFFFF) << 8) | (column & 0xFF); @@ -564,7 +578,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; } - cmd = info->cmdset->program; + cmd = host->cmdset->program; info->ndcb0 |= NDCB0_CMD_TYPE(0x1) | NDCB0_AUTO_RS | NDCB0_ST_ROW_EN @@ -574,8 +588,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_READID: - cmd = info->cmdset->read_id; - info->buf_count = info->read_id_bytes; + cmd = host->cmdset->read_id; + info->buf_count = host->read_id_bytes; info->ndcb0 |= NDCB0_CMD_TYPE(3) | NDCB0_ADDR_CYC(1) | cmd; @@ -583,7 +597,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, info->data_size = 8; break; case NAND_CMD_STATUS: - cmd = info->cmdset->read_status; + cmd = host->cmdset->read_status; info->buf_count = 1; info->ndcb0 |= NDCB0_CMD_TYPE(4) | NDCB0_ADDR_CYC(1) @@ -593,7 +607,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_ERASE1: - cmd = info->cmdset->erase; + cmd = host->cmdset->erase; info->ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS | NDCB0_ADDR_CYC(3) @@ -604,7 +618,7 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, break; case NAND_CMD_RESET: - cmd = info->cmdset->reset; + cmd = host->cmdset->reset; info->ndcb0 |= NDCB0_CMD_TYPE(5) | cmd; @@ -616,8 +630,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, default: exec_cmd = 0; - printk(KERN_ERR "pxa3xx-nand: non-supported" - " command %x\n", command); + dev_err(&info->pdev->dev, "non-supported command %x\n", + command); break; } @@ -627,7 +641,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command, static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, int column, int page_addr) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int ret, exec_cmd; /* @@ -635,9 +650,21 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, * "byte" address into a "word" address appropriate * for indexing a word-oriented device */ - if (info->reg_ndcr & NDCR_DWIDTH_M) + if (host->reg_ndcr & NDCR_DWIDTH_M) column /= 2; + /* + * There may be different NAND chip hooked to + * different chip select, so check whether + * chip select has been changed, if yes, reset the timing + */ + if (info->cs != host->cs) { + info->cs = host->cs; + nand_writel(info, NDTR0CS0, host->ndtr0cs0); + nand_writel(info, NDTR1CS0, host->ndtr1cs0); + } + + info->state = STATE_PREPARED; exec_cmd = prepare_command_pool(info, command, column, page_addr); if (exec_cmd) { init_completion(&info->cmd_complete); @@ -646,12 +673,12 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command, ret = wait_for_completion_timeout(&info->cmd_complete, CHIP_DELAY_TIMEOUT); if (!ret) { - printk(KERN_ERR "Wait time out!!!\n"); + dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); } - info->state = STATE_IDLE; } + info->state = STATE_IDLE; } static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, @@ -664,7 +691,8 @@ static void pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd, static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, int page) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; chip->read_buf(mtd, buf, mtd->writesize); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -685,6 +713,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, * OOB, ignore such double bit errors */ if (is_buf_blank(buf, mtd->writesize)) + info->retcode = ERR_NONE; + else mtd->ecc_stats.failed++; } @@ -693,7 +723,8 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd, static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; char retval = 0xFF; if (info->buf_start < info->buf_count) @@ -705,7 +736,8 @@ static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd) static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; u16 retval = 0xFFFF; if (!(info->buf_start & 0x01) && info->buf_start < info->buf_count) { @@ -717,7 +749,8 @@ static u16 pxa3xx_nand_read_word(struct mtd_info *mtd) static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(buf, info->data_buff + info->buf_start, real_len); @@ -727,7 +760,8 @@ static void pxa3xx_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) static void pxa3xx_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; int real_len = min_t(size_t, len, info->buf_count - info->buf_start); memcpy(info->data_buff + info->buf_start, buf, real_len); @@ -747,7 +781,8 @@ static void pxa3xx_nand_select_chip(struct mtd_info *mtd, int chip) static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; /* pxa3xx_nand_send_command has waited for command complete */ if (this->state == FL_WRITING || this->state == FL_ERASING) { @@ -770,54 +805,70 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info, { struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; + struct pxa3xx_nand_host *host = info->host[info->cs]; uint32_t ndcr = 0x0; /* enable all interrupts */ - if (f->page_size != 2048 && f->page_size != 512) + if (f->page_size != 2048 && f->page_size != 512) { + dev_err(&pdev->dev, "Current only support 2048 and 512 size\n"); return -EINVAL; + } - if (f->flash_width != 16 && f->flash_width != 8) + if (f->flash_width != 16 && f->flash_width != 8) { + dev_err(&pdev->dev, "Only support 8bit and 16 bit!\n"); return -EINVAL; + } /* calculate flash information */ - info->cmdset = &default_cmdset; - info->page_size = f->page_size; - info->read_id_bytes = (f->page_size == 2048) ? 4 : 2; + host->cmdset = &default_cmdset; + host->page_size = f->page_size; + host->read_id_bytes = (f->page_size == 2048) ? 4 : 2; /* calculate addressing information */ - info->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; + host->col_addr_cycles = (f->page_size == 2048) ? 2 : 1; if (f->num_blocks * f->page_per_block > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; + host->row_addr_cycles = 2; ndcr |= (pdata->enable_arbiter) ? NDCR_ND_ARB_EN : 0; - ndcr |= (info->col_addr_cycles == 2) ? NDCR_RA_START : 0; + ndcr |= (host->col_addr_cycles == 2) ? NDCR_RA_START : 0; ndcr |= (f->page_per_block == 64) ? NDCR_PG_PER_BLK : 0; ndcr |= (f->page_size == 2048) ? NDCR_PAGE_SZ : 0; ndcr |= (f->flash_width == 16) ? NDCR_DWIDTH_M : 0; ndcr |= (f->dfc_width == 16) ? NDCR_DWIDTH_C : 0; - ndcr |= NDCR_RD_ID_CNT(info->read_id_bytes); + ndcr |= NDCR_RD_ID_CNT(host->read_id_bytes); ndcr |= NDCR_SPARE_EN; /* enable spare by default */ - info->reg_ndcr = ndcr; + host->reg_ndcr = ndcr; - pxa3xx_nand_set_timing(info, f->timing); + pxa3xx_nand_set_timing(host, f->timing); return 0; } static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info) { + /* + * We set 0 by hard coding here, for we don't support keep_config + * when there is more than one chip attached to the controller + */ + struct pxa3xx_nand_host *host = info->host[0]; uint32_t ndcr = nand_readl(info, NDCR); - info->page_size = ndcr & NDCR_PAGE_SZ ? 2048 : 512; - /* set info fields needed to read id */ - info->read_id_bytes = (info->page_size == 2048) ? 4 : 2; - info->reg_ndcr = ndcr; - info->cmdset = &default_cmdset; - info->ndtr0cs0 = nand_readl(info, NDTR0CS0); - info->ndtr1cs0 = nand_readl(info, NDTR1CS0); + if (ndcr & NDCR_PAGE_SZ) { + host->page_size = 2048; + host->read_id_bytes = 4; + } else { + host->page_size = 512; + host->read_id_bytes = 2; + } + + host->reg_ndcr = ndcr & ~NDCR_INT_MASK; + host->cmdset = &default_cmdset; + + host->ndtr0cs0 = nand_readl(info, NDTR0CS0); + host->ndtr1cs0 = nand_readl(info, NDTR1CS0); return 0; } @@ -847,7 +898,6 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) return -ENOMEM; } - info->data_buff_size = MAX_BUFF_SIZE; info->data_desc = (void *)info->data_buff + data_desc_offset; info->data_desc_addr = info->data_buff_phys + data_desc_offset; @@ -855,7 +905,7 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) pxa3xx_nand_data_dma_irq, info); if (info->data_dma_ch < 0) { dev_err(&pdev->dev, "failed to request data dma\n"); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); return info->data_dma_ch; } @@ -865,24 +915,28 @@ static int pxa3xx_nand_init_buff(struct pxa3xx_nand_info *info) static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info) { - struct mtd_info *mtd = info->mtd; - struct nand_chip *chip = mtd->priv; - + struct mtd_info *mtd; + int ret; + mtd = info->host[info->cs]->mtd; /* use the common timing to make a try */ - pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); - chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0); + ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]); + if (ret) + return ret; + + pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0); if (info->is_ready) - return 1; - else return 0; + + return -ENODEV; } static int pxa3xx_nand_scan(struct mtd_info *mtd) { - struct pxa3xx_nand_info *info = mtd->priv; + struct pxa3xx_nand_host *host = mtd->priv; + struct pxa3xx_nand_info *info = host->info_data; struct platform_device *pdev = info->pdev; struct pxa3xx_nand_platform_data *pdata = pdev->dev.platform_data; - struct nand_flash_dev pxa3xx_flash_ids[2] = { {NULL,}, {NULL,} }; + struct nand_flash_dev pxa3xx_flash_ids[2], *def = NULL; const struct pxa3xx_nand_flash *f = NULL; struct nand_chip *chip = mtd->priv; uint32_t id = -1; @@ -893,22 +947,20 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) goto KEEP_CONFIG; ret = pxa3xx_nand_sensing(info); - if (!ret) { - kfree(mtd); - info->mtd = NULL; - printk(KERN_INFO "There is no nand chip on cs 0!\n"); + if (ret) { + dev_info(&info->pdev->dev, "There is no chip on cs %d!\n", + info->cs); - return -EINVAL; + return ret; } chip->cmdfunc(mtd, NAND_CMD_READID, 0, 0); id = *((uint16_t *)(info->data_buff)); if (id != 0) - printk(KERN_INFO "Detect a flash id %x\n", id); + dev_info(&info->pdev->dev, "Detect a flash id %x\n", id); else { - kfree(mtd); - info->mtd = NULL; - printk(KERN_WARNING "Read out ID 0, potential timing set wrong!!\n"); + dev_warn(&info->pdev->dev, + "Read out ID 0, potential timing set wrong!!\n"); return -EINVAL; } @@ -926,14 +978,17 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) } if (i >= (ARRAY_SIZE(builtin_flash_types) + pdata->num_flash - 1)) { - kfree(mtd); - info->mtd = NULL; - printk(KERN_ERR "ERROR!! flash not defined!!!\n"); + dev_err(&info->pdev->dev, "ERROR!! flash not defined!!!\n"); return -EINVAL; } - pxa3xx_nand_config_flash(info, f); + ret = pxa3xx_nand_config_flash(info, f); + if (ret) { + dev_err(&info->pdev->dev, "ERROR! Configure failed\n"); + return ret; + } + pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; @@ -942,62 +997,78 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) pxa3xx_flash_ids[0].erasesize = f->page_size * f->page_per_block; if (f->flash_width == 16) pxa3xx_flash_ids[0].options = NAND_BUSWIDTH_16; + pxa3xx_flash_ids[1].name = NULL; + def = pxa3xx_flash_ids; KEEP_CONFIG: - if (nand_scan_ident(mtd, 1, pxa3xx_flash_ids)) + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = host->page_size; + + chip->options = NAND_NO_AUTOINCR; + chip->options |= NAND_NO_READRDY; + if (host->reg_ndcr & NDCR_DWIDTH_M) + chip->options |= NAND_BUSWIDTH_16; + + if (nand_scan_ident(mtd, 1, def)) return -ENODEV; /* calculate addressing information */ - info->col_addr_cycles = (mtd->writesize >= 2048) ? 2 : 1; + if (mtd->writesize >= 2048) + host->col_addr_cycles = 2; + else + host->col_addr_cycles = 1; + info->oob_buff = info->data_buff + mtd->writesize; if ((mtd->size >> chip->page_shift) > 65536) - info->row_addr_cycles = 3; + host->row_addr_cycles = 3; else - info->row_addr_cycles = 2; - mtd->name = mtd_names[0]; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = f->page_size; - - chip->options = (f->flash_width == 16) ? NAND_BUSWIDTH_16 : 0; - chip->options |= NAND_NO_AUTOINCR; - chip->options |= NAND_NO_READRDY; + host->row_addr_cycles = 2; + mtd->name = mtd_names[0]; return nand_scan_tail(mtd); } -static -struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) +static int alloc_nand_resource(struct platform_device *pdev) { + struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + struct pxa3xx_nand_host *host; struct nand_chip *chip; struct mtd_info *mtd; struct resource *r; - int ret, irq; + int ret, irq, cs; - mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct pxa3xx_nand_info), - GFP_KERNEL); - if (!mtd) { + pdata = pdev->dev.platform_data; + info = kzalloc(sizeof(*info) + (sizeof(*mtd) + + sizeof(*host)) * pdata->num_cs, GFP_KERNEL); + if (!info) { dev_err(&pdev->dev, "failed to allocate memory\n"); - return NULL; + return -ENOMEM; } - info = (struct pxa3xx_nand_info *)(&mtd[1]); - chip = (struct nand_chip *)(&mtd[1]); info->pdev = pdev; - info->mtd = mtd; - mtd->priv = info; - mtd->owner = THIS_MODULE; - - chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; - chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; - chip->controller = &info->controller; - chip->waitfunc = pxa3xx_nand_waitfunc; - chip->select_chip = pxa3xx_nand_select_chip; - chip->dev_ready = pxa3xx_nand_dev_ready; - chip->cmdfunc = pxa3xx_nand_cmdfunc; - chip->read_word = pxa3xx_nand_read_word; - chip->read_byte = pxa3xx_nand_read_byte; - chip->read_buf = pxa3xx_nand_read_buf; - chip->write_buf = pxa3xx_nand_write_buf; - chip->verify_buf = pxa3xx_nand_verify_buf; + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = (struct mtd_info *)((unsigned int)&info[1] + + (sizeof(*mtd) + sizeof(*host)) * cs); + chip = (struct nand_chip *)(&mtd[1]); + host = (struct pxa3xx_nand_host *)chip; + info->host[cs] = host; + host->mtd = mtd; + host->cs = cs; + host->info_data = info; + mtd->priv = host; + mtd->owner = THIS_MODULE; + + chip->ecc.read_page = pxa3xx_nand_read_page_hwecc; + chip->ecc.write_page = pxa3xx_nand_write_page_hwecc; + chip->controller = &info->controller; + chip->waitfunc = pxa3xx_nand_waitfunc; + chip->select_chip = pxa3xx_nand_select_chip; + chip->cmdfunc = pxa3xx_nand_cmdfunc; + chip->read_word = pxa3xx_nand_read_word; + chip->read_byte = pxa3xx_nand_read_byte; + chip->read_buf = pxa3xx_nand_read_buf; + chip->write_buf = pxa3xx_nand_write_buf; + chip->verify_buf = pxa3xx_nand_verify_buf; + } spin_lock_init(&chip->controller->lock); init_waitqueue_head(&chip->controller->wq); @@ -1070,13 +1141,13 @@ struct pxa3xx_nand_info *alloc_nand_resource(struct platform_device *pdev) platform_set_drvdata(pdev, info); - return info; + return 0; fail_free_buf: free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_coherent(&pdev->dev, info->data_buff_size, + dma_free_coherent(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1088,17 +1159,21 @@ fail_put_clk: clk_disable(info->clk); clk_put(info->clk); fail_free_mtd: - kfree(mtd); - return NULL; + kfree(info); + return ret; } static int pxa3xx_nand_remove(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; struct resource *r; - int irq; + int irq, cs; + if (!info) + return 0; + + pdata = pdev->dev.platform_data; platform_set_drvdata(pdev, NULL); irq = platform_get_irq(pdev, 0); @@ -1106,7 +1181,7 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) free_irq(irq, info); if (use_dma) { pxa_free_dma(info->data_dma_ch); - dma_free_writecombine(&pdev->dev, info->data_buff_size, + dma_free_writecombine(&pdev->dev, MAX_BUFF_SIZE, info->data_buff, info->data_buff_phys); } else kfree(info->data_buff); @@ -1118,10 +1193,9 @@ static int pxa3xx_nand_remove(struct platform_device *pdev) clk_disable(info->clk); clk_put(info->clk); - if (mtd) { - mtd_device_unregister(mtd); - kfree(mtd); - } + for (cs = 0; cs < pdata->num_cs; cs++) + nand_release(info->host[cs]->mtd); + kfree(info); return 0; } @@ -1129,6 +1203,7 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) { struct pxa3xx_nand_platform_data *pdata; struct pxa3xx_nand_info *info; + int ret, cs, probe_success; pdata = pdev->dev.platform_data; if (!pdata) { @@ -1136,52 +1211,88 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) return -ENODEV; } - info = alloc_nand_resource(pdev); - if (info == NULL) - return -ENOMEM; - - if (pxa3xx_nand_scan(info->mtd)) { - dev_err(&pdev->dev, "failed to scan nand\n"); - pxa3xx_nand_remove(pdev); - return -ENODEV; + ret = alloc_nand_resource(pdev); + if (ret) { + dev_err(&pdev->dev, "alloc nand resource failed\n"); + return ret; } - if (mtd_has_cmdlinepart()) { - const char *probes[] = { "cmdlinepart", NULL }; - struct mtd_partition *parts; - int nr_parts; + info = platform_get_drvdata(pdev); + probe_success = 0; + for (cs = 0; cs < pdata->num_cs; cs++) { + info->cs = cs; + ret = pxa3xx_nand_scan(info->host[cs]->mtd); + if (ret) { + dev_warn(&pdev->dev, "failed to scan nand at cs %d\n", + cs); + continue; + } - nr_parts = parse_mtd_partitions(info->mtd, probes, &parts, 0); + ret = mtd_device_parse_register(info->host[cs]->mtd, NULL, 0, + pdata->parts[cs], pdata->nr_parts[cs]); + if (!ret) + probe_success = 1; + } - if (nr_parts) - return mtd_device_register(info->mtd, parts, nr_parts); + if (!probe_success) { + pxa3xx_nand_remove(pdev); + return -ENODEV; } - return mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); + return 0; } #ifdef CONFIG_PM static int pxa3xx_nand_suspend(struct platform_device *pdev, pm_message_t state) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; + pdata = pdev->dev.platform_data; if (info->state) { dev_err(&pdev->dev, "driver busy, state = %d\n", info->state); return -EAGAIN; } + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->suspend(mtd); + } + return 0; } static int pxa3xx_nand_resume(struct platform_device *pdev) { struct pxa3xx_nand_info *info = platform_get_drvdata(pdev); - struct mtd_info *mtd = info->mtd; + struct pxa3xx_nand_platform_data *pdata; + struct mtd_info *mtd; + int cs; - nand_writel(info, NDTR0CS0, info->ndtr0cs0); - nand_writel(info, NDTR1CS0, info->ndtr1cs0); - clk_enable(info->clk); + pdata = pdev->dev.platform_data; + /* We don't want to handle interrupt without calling mtd routine */ + disable_int(info, NDCR_INT_MASK); + + /* + * Directly set the chip select to a invalid value, + * then the driver would reset the timing according + * to current chip select at the beginning of cmdfunc + */ + info->cs = 0xff; + + /* + * As the spec says, the NDSR would be updated to 0x1800 when + * doing the nand_clk disable/enable. + * To prevent it damaging state machine of the driver, clear + * all status before resume + */ + nand_writel(info, NDSR, NDSR_MASK); + for (cs = 0; cs < pdata->num_cs; cs++) { + mtd = info->host[cs]->mtd; + mtd->resume(mtd); + } return 0; } diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index cae2e013c98..f20f393bfda 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -1027,7 +1027,7 @@ void r852_shutdown(struct pci_dev *pci_dev) } #ifdef CONFIG_PM -int r852_suspend(struct device *device) +static int r852_suspend(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1048,7 +1048,7 @@ int r852_suspend(struct device *device) return 0; } -int r852_resume(struct device *device) +static int r852_resume(struct device *device) { struct r852_device *dev = pci_get_drvdata(to_pci_dev(device)); @@ -1092,7 +1092,7 @@ static const struct pci_device_id r852_pci_id_tbl[] = { MODULE_DEVICE_TABLE(pci, r852_pci_id_tbl); -SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); +static SIMPLE_DEV_PM_OPS(r852_pm_ops, r852_suspend, r852_resume); static struct pci_driver r852_pci_driver = { .name = DRV_NAME, diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c index c9f9127ff77..f309addc2fa 100644 --- a/drivers/mtd/nand/rtc_from4.c +++ b/drivers/mtd/nand/rtc_from4.c @@ -351,7 +351,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha return 0; } - /* Read the syndrom pattern from the FPGA and correct the bitorder */ + /* Read the syndrome pattern from the FPGA and correct the bitorder */ rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC); for (i = 0; i < 8; i++) { ecc[i] = bitrev8(*rs_ecc); @@ -380,7 +380,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha /* Let the library code do its magic. */ res = decode_rs8(rs_decoder, (uint8_t *) buf, par, 512, syn, 0, NULL, 0xff, NULL); if (res > 0) { - DEBUG(MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); + pr_debug("rtc_from4_correct_data: " "ECC corrected %d errors on read\n", res); } return res; } @@ -444,7 +444,6 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, len = mtd->writesize; buf = kmalloc(len, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n"); er_stat = 1; goto out; } diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 4405468f196..868685db671 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -723,7 +723,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) /* free the common resources */ - if (info->clk != NULL && !IS_ERR(info->clk)) { + if (!IS_ERR(info->clk)) { s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); clk_put(info->clk); } @@ -744,26 +744,15 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) return 0; } -const char *part_probes[] = { "cmdlinepart", NULL }; static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *mtd, struct s3c2410_nand_set *set) { - struct mtd_partition *part_info; - int nr_part = 0; + if (set) + mtd->mtd.name = set->name; - if (set == NULL) - return mtd_device_register(&mtd->mtd, NULL, 0); - - mtd->mtd.name = set->name; - nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); - - if (nr_part <= 0 && set->nr_partitions > 0) { - nr_part = set->nr_partitions; - part_info = set->partitions; - } - - return mtd_device_register(&mtd->mtd, part_info, nr_part); + return mtd_device_parse_register(&mtd->mtd, NULL, 0, + set->partitions, set->nr_partitions); } /** @@ -880,8 +869,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, /* If you use u-boot BBT creation code, specifying this flag will * let the kernel fish out the BBT from the NAND, and also skip the * full NAND scan that can take 1/2s or so. Little things... */ - if (set->flash_bbt) - chip->options |= NAND_USE_FLASH_BBT | NAND_SKIP_BBTSCAN; + if (set->flash_bbt) { + chip->bbt_options |= NAND_BBT_USE_FLASH; + chip->options |= NAND_SKIP_BBTSCAN; + } } /** diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c index 19e24ed089e..619d2a50478 100644 --- a/drivers/mtd/nand/sharpsl.c +++ b/drivers/mtd/nand/sharpsl.c @@ -103,16 +103,12 @@ static int sharpsl_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, return readb(sharpsl->io + ECCCNTR) != 0; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Main initialization routine */ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) { struct nand_chip *this; - struct mtd_partition *sharpsl_partition_info; - int nr_partitions; struct resource *r; int err = 0; struct sharpsl_nand *sharpsl; @@ -184,14 +180,9 @@ static int __devinit sharpsl_nand_probe(struct platform_device *pdev) /* Register the partitions */ sharpsl->mtd.name = "sharpsl-nand"; - nr_partitions = parse_mtd_partitions(&sharpsl->mtd, part_probes, &sharpsl_partition_info, 0); - if (nr_partitions <= 0) { - nr_partitions = data->nr_partitions; - sharpsl_partition_info = data->partitions; - } - err = mtd_device_register(&sharpsl->mtd, sharpsl_partition_info, - nr_partitions); + err = mtd_device_parse_register(&sharpsl->mtd, NULL, 0, + data->partitions, data->nr_partitions); if (err) goto err_add; diff --git a/drivers/mtd/nand/sm_common.c b/drivers/mtd/nand/sm_common.c index 43469715b3f..32ae5af7444 100644 --- a/drivers/mtd/nand/sm_common.c +++ b/drivers/mtd/nand/sm_common.c @@ -48,7 +48,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) /* As long as this function is called on erase block boundaries it will work correctly for 256 byte nand */ - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.oobbuf = (void *)&oob; diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index ca2d0555729..0fb24f9c232 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -155,8 +155,6 @@ static int socrates_nand_device_ready(struct mtd_info *mtd) return 1; } -static const char *part_probes[] = { "cmdlinepart", NULL }; - /* * Probe for the NAND device. */ @@ -166,8 +164,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) struct mtd_info *mtd; struct nand_chip *nand_chip; int res; - struct mtd_partition *partitions = NULL; - int num_partitions = 0; + struct mtd_part_parser_data ppdata; /* Allocate memory for the device structure (and zero it) */ host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); @@ -193,6 +190,7 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) mtd->name = "socrates_nand"; mtd->owner = THIS_MODULE; mtd->dev.parent = &ofdev->dev; + ppdata.of_node = ofdev->dev.of_node; /*should never be accessed directly */ nand_chip->IO_ADDR_R = (void *)0xdeadbeef; @@ -225,30 +223,10 @@ static int __devinit socrates_nand_probe(struct platform_device *ofdev) goto out; } -#ifdef CONFIG_MTD_CMDLINE_PARTS - num_partitions = parse_mtd_partitions(mtd, part_probes, - &partitions, 0); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } -#endif - - if (num_partitions == 0) { - num_partitions = of_mtd_parse_partitions(&ofdev->dev, - ofdev->dev.of_node, - &partitions); - if (num_partitions < 0) { - res = num_partitions; - goto release; - } - } - - res = mtd_device_register(mtd, partitions, num_partitions); + res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (!res) return res; -release: nand_release(mtd); out: diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 11e8371b568..beebd95f769 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -121,9 +121,6 @@ struct tmio_nand { #define mtd_to_tmio(m) container_of(m, struct tmio_nand, mtd) -#ifdef CONFIG_MTD_CMDLINE_PARTS -static const char *part_probes[] = { "cmdlinepart", NULL }; -#endif /*--------------------------------------------------------------------------*/ @@ -381,8 +378,6 @@ static int tmio_probe(struct platform_device *dev) struct tmio_nand *tmio; struct mtd_info *mtd; struct nand_chip *nand_chip; - struct mtd_partition *parts; - int nbparts = 0; int retval; if (data == NULL) @@ -461,15 +456,9 @@ static int tmio_probe(struct platform_device *dev) goto err_scan; } /* Register the partitions */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0); -#endif - if (nbparts <= 0 && data) { - parts = data->partition; - nbparts = data->num_partitions; - } - - retval = mtd_device_register(mtd, parts, nbparts); + retval = mtd_device_parse_register(mtd, NULL, 0, + data ? data->partition : NULL, + data ? data->num_partitions : 0); if (!retval) return retval; diff --git a/drivers/mtd/nand/txx9ndfmc.c b/drivers/mtd/nand/txx9ndfmc.c index bfba4e39a6c..ace46fdaef5 100644 --- a/drivers/mtd/nand/txx9ndfmc.c +++ b/drivers/mtd/nand/txx9ndfmc.c @@ -74,7 +74,6 @@ struct txx9ndfmc_drvdata { unsigned char hold; /* in gbusclock */ unsigned char spw; /* in gbusclock */ struct nand_hw_control hw_control; - struct mtd_partition *parts[MAX_TXX9NDFMC_DEV]; }; static struct platform_device *mtd_to_platdev(struct mtd_info *mtd) @@ -287,7 +286,6 @@ static int txx9ndfmc_nand_scan(struct mtd_info *mtd) static int __init txx9ndfmc_probe(struct platform_device *dev) { struct txx9ndfmc_platform_data *plat = dev->dev.platform_data; - static const char *probes[] = { "cmdlinepart", NULL }; int hold, spw; int i; struct txx9ndfmc_drvdata *drvdata; @@ -333,7 +331,6 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) struct txx9ndfmc_priv *txx9_priv; struct nand_chip *chip; struct mtd_info *mtd; - int nr_parts; if (!(plat->ch_mask & (1 << i))) continue; @@ -393,9 +390,7 @@ static int __init txx9ndfmc_probe(struct platform_device *dev) } mtd->name = txx9_priv->mtdname; - nr_parts = parse_mtd_partitions(mtd, probes, - &drvdata->parts[i], 0); - mtd_device_register(mtd, drvdata->parts[i], nr_parts); + mtd_device_parse_register(mtd, NULL, 0, NULL, 0); drvdata->mtds[i] = mtd; } @@ -421,7 +416,6 @@ static int __exit txx9ndfmc_remove(struct platform_device *dev) txx9_priv = chip->priv; nand_release(mtd); - kfree(drvdata->parts[i]); kfree(txx9_priv->mtdname); kfree(txx9_priv); } diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index b155666acfb..cda77b562ad 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -63,14 +63,12 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; } - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); + pr_debug("NFTL: add_mtd for %s\n", mtd->name); nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - if (!nftl) { - printk(KERN_WARNING "NFTL: out of memory for data structures\n"); + if (!nftl) return; - } nftl->mbd.mtd = mtd; nftl->mbd.devnum = -1; @@ -132,7 +130,7 @@ static void nftl_remove_dev(struct mtd_blktrans_dev *dev) { struct NFTLrecord *nftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); + pr_debug("NFTL: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(nftl->ReplUnitTable); @@ -149,7 +147,7 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -170,7 +168,7 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = len; ops.oobbuf = buf; @@ -193,7 +191,7 @@ static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len, struct mtd_oob_ops ops; int res; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = offs & mask; ops.ooblen = mtd->oobsize; ops.oobbuf = oob; @@ -220,7 +218,7 @@ static u16 NFTL_findfreeblock(struct NFTLrecord *nftl, int desperate ) /* Normally, we force a fold to happen before we run out of free blocks completely */ if (!desperate && nftl->numfreeEUNs < 2) { - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_findfreeblock: there are too few free EUNs\n"); + pr_debug("NFTL_findfreeblock: there are too few free EUNs\n"); return BLOCK_NIL; } @@ -291,8 +289,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (block == 2) { foldmark = oob.u.c.FoldMark | oob.u.c.FoldMark1; if (foldmark == FOLD_MARK_IN_PROGRESS) { - DEBUG(MTD_DEBUG_LEVEL1, - "Write Inhibited on EUN %d\n", thisEUN); + pr_debug("Write Inhibited on EUN %d\n", thisEUN); inplace = 0; } else { /* There's no other reason not to do inplace, @@ -357,7 +354,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p if (BlockLastState[block] != SECTOR_FREE && BlockMap[block] != BLOCK_NIL && BlockMap[block] != targetEUN) { - DEBUG(MTD_DEBUG_LEVEL1, "Setting inplace to 0. VUC %d, " + pr_debug("Setting inplace to 0. VUC %d, " "block %d was %x lastEUN, " "and is in EUN %d (%s) %d\n", thisVUC, block, BlockLastState[block], @@ -373,14 +370,14 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p pendingblock < ((thisVUC + 1)* (nftl->EraseSize / 512)) && BlockLastState[pendingblock - (thisVUC * (nftl->EraseSize / 512))] != SECTOR_FREE) { - DEBUG(MTD_DEBUG_LEVEL1, "Pending write not free in EUN %d. " + pr_debug("Pending write not free in EUN %d. " "Folding out of place.\n", targetEUN); inplace = 0; } } if (!inplace) { - DEBUG(MTD_DEBUG_LEVEL1, "Cannot fold Virtual Unit Chain %d in place. " + pr_debug("Cannot fold Virtual Unit Chain %d in place. " "Trying out-of-place\n", thisVUC); /* We need to find a targetEUN to fold into. */ targetEUN = NFTL_findfreeblock(nftl, 1); @@ -410,7 +407,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p and the Erase Unit into which we are supposed to be copying. Go for it. */ - DEBUG(MTD_DEBUG_LEVEL1,"Folding chain %d into unit %d\n", thisVUC, targetEUN); + pr_debug("Folding chain %d into unit %d\n", thisVUC, targetEUN); for (block = 0; block < nftl->EraseSize / 512 ; block++) { unsigned char movebuf[512]; int ret; @@ -428,7 +425,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); - if (ret < 0 && ret != -EUCLEAN) { + if (ret < 0 && !mtd_is_bitflip(ret)) { ret = mtd->read(mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, movebuf); @@ -457,7 +454,7 @@ static u16 NFTL_foldchain (struct NFTLrecord *nftl, unsigned thisVUC, unsigned p has duplicate chains, we need to free one of the chains because it's not necessary any more. */ thisEUN = nftl->EUNtable[thisVUC]; - DEBUG(MTD_DEBUG_LEVEL1,"Want to erase\n"); + pr_debug("Want to erase\n"); /* For each block in the old chain (except the targetEUN of course), free it and make it available for future use */ @@ -570,7 +567,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); - DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", + pr_debug("Status of block %d in EUN %d is %x\n", block , writeEUN, le16_to_cpu(bci.Status)); status = bci.Status | bci.Status1; @@ -623,7 +620,7 @@ static inline u16 NFTL_findwriteunit(struct NFTLrecord *nftl, unsigned block) but they are reserved for when we're desperate. Well, now we're desperate. */ - DEBUG(MTD_DEBUG_LEVEL1, "Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); + pr_debug("Using desperate==1 to find free EUN to accommodate write to VUC %d\n", thisVUC); writeEUN = NFTL_findfreeblock(nftl, 1); } if (writeEUN == BLOCK_NIL) { @@ -776,7 +773,7 @@ static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, size_t retlen; int res = mtd->read(mtd, ptr, 512, &retlen, buffer); - if (res < 0 && res != -EUCLEAN) + if (res < 0 && !mtd_is_bitflip(res)) return -EIO; } return 0; diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c index e3cd1ffad2f..ac4092591ae 100644 --- a/drivers/mtd/nftlmount.c +++ b/drivers/mtd/nftlmount.c @@ -32,7 +32,7 @@ /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update - * the ReplUnitTable[] table accroding to the Bad Unit Table. ReplUnitTable[] + * the ReplUnitTable[] table according to the Bad Unit Table. ReplUnitTable[] * is used for management of Erase Unit in other routines in nftl.c and nftlmount.c */ static int find_boot_record(struct NFTLrecord *nftl) @@ -297,7 +297,7 @@ static int check_free_sectors(struct NFTLrecord *nftl, unsigned int address, int * * Return: 0 when succeed, -1 on error. * - * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * ToDo: 1. Is it necessary to check_free_sector after erasing ?? */ int NFTL_formatblock(struct NFTLrecord *nftl, int block) { @@ -337,7 +337,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block) nb_erases = le32_to_cpu(uci.WearInfo); nb_erases++; - /* wrap (almost impossible with current flashs) or free block */ + /* wrap (almost impossible with current flash) or free block */ if (nb_erases == 0) nb_erases = 1; @@ -363,10 +363,10 @@ fail: * Mark as 'IGNORE' each incorrect sector. This check is only done if the chain * was being folded when NFTL was interrupted. * - * The check_free_sectors in this function is neceressary. There is a possible + * The check_free_sectors in this function is necessary. There is a possible * situation that after writing the Data area, the Block Control Information is * not updated according (due to power failure or something) which leaves the block - * in an umconsistent state. So we have to check if a block is really FREE in this + * in an inconsistent state. So we have to check if a block is really FREE in this * case. */ static void check_sectors_in_chain(struct NFTLrecord *nftl, unsigned int first_block) { @@ -428,7 +428,7 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) for (;;) { length++; - /* avoid infinite loops, although this is guaranted not to + /* avoid infinite loops, although this is guaranteed not to happen because of the previous checks */ if (length >= nftl->nb_blocks) { printk("nftl: length too long %d !\n", length); @@ -447,11 +447,11 @@ static int calc_chain_length(struct NFTLrecord *nftl, unsigned int first_block) /* format_chain: Format an invalid Virtual Unit chain. It frees all the Erase Units in a * Virtual Unit Chain, i.e. all the units are disconnected. * - * It is not stricly correct to begin from the first block of the chain because + * It is not strictly correct to begin from the first block of the chain because * if we stop the code, we may see again a valid chain if there was a first_block * flag in a block inside it. But is it really a problem ? * - * FixMe: Figure out what the last statesment means. What if power failure when we are + * FixMe: Figure out what the last statement means. What if power failure when we are * in the for (;;) loop formatting blocks ?? */ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) @@ -485,7 +485,7 @@ static void format_chain(struct NFTLrecord *nftl, unsigned int first_block) * totally free (only 0xff). * * Definition: Free Erase Unit -- A properly erased/formatted Free Erase Unit should have meet the - * following critia: + * following criteria: * 1. */ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) { @@ -502,7 +502,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) erase_mark = le16_to_cpu ((h1.EraseMark | h1.EraseMark1)); if (erase_mark != ERASE_MARK) { /* if no erase mark, the block must be totally free. This is - possible in two cases : empty filsystem or interrupted erase (very unlikely) */ + possible in two cases : empty filesystem or interrupted erase (very unlikely) */ if (check_free_sectors (nftl, block * nftl->EraseSize, nftl->EraseSize, 1) != 0) return -1; @@ -544,7 +544,7 @@ static int check_and_mark_free_block(struct NFTLrecord *nftl, int block) /* get_fold_mark: Read fold mark from Unit Control Information #2, we use FOLD_MARK_IN_PROGRESS * to indicate that we are in the progression of a Virtual Unit Chain folding. If the UCI #2 * is FOLD_MARK_IN_PROGRESS when mounting the NFTL, the (previous) folding process is interrupted - * for some reason. A clean up/check of the VUC is neceressary in this case. + * for some reason. A clean up/check of the VUC is necessary in this case. * * WARNING: return 0 if read error */ @@ -657,7 +657,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrect logical block: %d expected: %d\n", block, logical_block, first_logical_block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } if (is_first_block) { @@ -669,7 +669,7 @@ int NFTL_mount(struct NFTLrecord *s) printk("Block %d: incorrectly marked as first block in chain\n", block); /* the chain is incorrect : we must format it, - but we need to read it completly */ + but we need to read it completely */ do_format_chain = 1; } else { printk("Block %d: folding in progress - ignoring first block flag\n", diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index a996718fa6b..64be8f0848b 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -20,14 +20,23 @@ #include <linux/slab.h> #include <linux/mtd/partitions.h> -int __devinit of_mtd_parse_partitions(struct device *dev, - struct device_node *node, - struct mtd_partition **pparts) +static int parse_ofpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { + struct device_node *node; const char *partname; struct device_node *pp; int nr_parts, i; + + if (!data) + return 0; + + node = data->of_node; + if (!node) + return 0; + /* First count the subnodes */ pp = NULL; nr_parts = 0; @@ -69,7 +78,7 @@ int __devinit of_mtd_parse_partitions(struct device *dev, if (!i) { of_node_put(pp); - dev_err(dev, "No valid partition found on %s\n", node->full_name); + pr_err("No valid partition found on %s\n", node->full_name); kfree(*pparts); *pparts = NULL; return -EINVAL; @@ -77,6 +86,99 @@ int __devinit of_mtd_parse_partitions(struct device *dev, return nr_parts; } -EXPORT_SYMBOL(of_mtd_parse_partitions); + +static struct mtd_part_parser ofpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofpart_partitions, + .name = "ofpart", +}; + +static int parse_ofoldpart_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) +{ + struct device_node *dp; + int i, plen, nr_parts; + const struct { + __be32 offset, len; + } *part; + const char *names; + + if (!data) + return 0; + + dp = data->of_node; + if (!dp) + return 0; + + part = of_get_property(dp, "partitions", &plen); + if (!part) + return 0; /* No partitions found */ + + pr_warning("Device tree uses obsolete partition map binding: %s\n", + dp->full_name); + + nr_parts = plen / sizeof(part[0]); + + *pparts = kzalloc(nr_parts * sizeof(*(*pparts)), GFP_KERNEL); + if (!pparts) + return -ENOMEM; + + names = of_get_property(dp, "partition-names", &plen); + + for (i = 0; i < nr_parts; i++) { + (*pparts)[i].offset = be32_to_cpu(part->offset); + (*pparts)[i].size = be32_to_cpu(part->len) & ~1; + /* bit 0 set signifies read only partition */ + if (be32_to_cpu(part->len) & 1) + (*pparts)[i].mask_flags = MTD_WRITEABLE; + + if (names && (plen > 0)) { + int len = strlen(names) + 1; + + (*pparts)[i].name = (char *)names; + plen -= len; + names += len; + } else { + (*pparts)[i].name = "unnamed"; + } + + part++; + } + + return nr_parts; +} + +static struct mtd_part_parser ofoldpart_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_ofoldpart_partitions, + .name = "ofoldpart", +}; + +static int __init ofpart_parser_init(void) +{ + int rc; + rc = register_mtd_parser(&ofpart_parser); + if (rc) + goto out; + + rc = register_mtd_parser(&ofoldpart_parser); + if (!rc) + return 0; + + deregister_mtd_parser(&ofoldpart_parser); +out: + return rc; +} + +module_init(ofpart_parser_init); MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Parser for MTD partitioning information in device tree"); +MODULE_AUTHOR("Vitaly Wool, David Gibson"); +/* + * When MTD core cannot find the requested parser, it tries to load the module + * with the same name. Since we provide the ofoldpart parser, we should have + * the corresponding alias. + */ +MODULE_ALIAS("ofoldpart"); diff --git a/drivers/mtd/onenand/generic.c b/drivers/mtd/onenand/generic.c index 2d70d354d84..7813095264a 100644 --- a/drivers/mtd/onenand/generic.c +++ b/drivers/mtd/onenand/generic.c @@ -30,11 +30,8 @@ */ #define DRIVER_NAME "onenand-flash" -static const char *part_probes[] = { "cmdlinepart", NULL, }; - struct onenand_info { struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; }; @@ -73,13 +70,9 @@ static int __devinit generic_onenand_probe(struct platform_device *pdev) goto out_iounmap; } - err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); - if (err > 0) - mtd_device_register(&info->mtd, info->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(&info->mtd, NULL, 0); + err = mtd_device_parse_register(&info->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, info); @@ -104,7 +97,6 @@ static int __devexit generic_onenand_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); if (info) { - mtd_device_unregister(&info->mtd); onenand_release(&info->mtd); release_mem_region(res->start, size); iounmap(info->onenand.base); diff --git a/drivers/mtd/onenand/omap2.c b/drivers/mtd/onenand/omap2.c index 6a1d6d9a2df..7e9ea6852b6 100644 --- a/drivers/mtd/onenand/omap2.c +++ b/drivers/mtd/onenand/omap2.c @@ -57,7 +57,6 @@ struct omap2_onenand { unsigned long phys_base; int gpio_irq; struct mtd_info mtd; - struct mtd_partition *parts; struct onenand_chip onenand; struct completion irq_done; struct completion dma_done; @@ -67,8 +66,6 @@ struct omap2_onenand { struct regulator *regulator; }; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static void omap2_onenand_dma_cb(int lch, u16 ch_status, void *data) { struct omap2_onenand *c = data; @@ -741,6 +738,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) c->regulator = regulator_get(&pdev->dev, "vonenand"); if (IS_ERR(c->regulator)) { dev_err(&pdev->dev, "Failed to get regulator\n"); + r = PTR_ERR(c->regulator); goto err_release_dma; } c->onenand.enable = omap2_onenand_enable; @@ -753,13 +751,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev) if ((r = onenand_scan(&c->mtd, 1)) < 0) goto err_release_regulator; - r = parse_mtd_partitions(&c->mtd, part_probes, &c->parts, 0); - if (r > 0) - r = mtd_device_register(&c->mtd, c->parts, r); - else if (pdata->parts != NULL) - r = mtd_device_register(&c->mtd, pdata->parts, pdata->nr_parts); - else - r = mtd_device_register(&c->mtd, NULL, 0); + r = mtd_device_parse_register(&c->mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); if (r) goto err_release_onenand; @@ -786,7 +780,6 @@ err_release_mem_region: err_free_cs: gpmc_cs_free(c->gpmc_cs); err_kfree: - kfree(c->parts); kfree(c); return r; @@ -809,7 +802,6 @@ static int __devexit omap2_onenand_remove(struct platform_device *pdev) iounmap(c->onenand.base); release_mem_region(c->phys_base, ONENAND_IO_SIZE); gpmc_cs_free(c->gpmc_cs); - kfree(c->parts); kfree(c); return 0; diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index ac9e959802a..a8394730b4b 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1015,7 +1015,7 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from @@ -1079,7 +1079,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status) return status; /* check if we failed due to uncorrectable error */ - if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) + if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR) return status; /* check if address lies in MLC region */ @@ -1122,10 +1122,10 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1159,7 +1159,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; if (ret) break; @@ -1170,7 +1170,7 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1226,10 +1226,10 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, int ret = 0, boundary = 0; int writesize = this->writesize; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1255,7 +1255,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, this->command(mtd, ONENAND_CMD_READ, from, writesize); ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } } @@ -1291,7 +1291,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -1315,7 +1315,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* Now wait for load */ ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } @@ -1351,19 +1351,19 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, struct mtd_ecc_stats stats; int read = 0, thislen, column, oobsize; size_t len = ops->ooblen; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; u_char *buf = ops->oobbuf; int ret = 0, readcmd; from += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n", - __func__, (unsigned int) from, (int) len); + pr_debug("%s: from = 0x%08x, len = %i\n", __func__, (unsigned int)from, + (int)len); /* Initialize return length value */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1403,13 +1403,13 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); - if (ret && ret != -EBADMSG) { + if (ret && !mtd_is_eccerr(ret)) { printk(KERN_ERR "%s: read failed = 0x%x\n", __func__, ret); break; } - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, buf, column, thislen); else this->read_bufferram(mtd, ONENAND_SPARERAM, buf, column, thislen); @@ -1487,10 +1487,10 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -1576,8 +1576,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from, size_t len = ops->ooblen; u_char *buf = ops->oobbuf; - DEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %zi\n", - __func__, (unsigned int) from, len); + pr_debug("%s: from = 0x%08x, len = %zi\n", __func__, (unsigned int)from, + len); /* Initialize return value */ ops->oobretlen = 0; @@ -1750,8 +1750,8 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, /* Wait for any existing operation to clear */ onenand_panic_wait(mtd); - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ *retlen = 0; @@ -1821,7 +1821,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, } /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address @@ -1883,8 +1883,8 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; int ret = 0, cmd; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->retlen = 0; @@ -1908,7 +1908,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, if (!len) return 0; - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1945,7 +1945,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -2055,7 +2055,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -2074,17 +2074,17 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; size_t len = ops->ooblen; const u_char *buf = ops->oobbuf; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; to += ops->ooboffs; - DEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", - __func__, (unsigned int) to, (int) len); + pr_debug("%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, + (int)len); /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -2128,7 +2128,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else memcpy(oobbuf + column, buf, thislen); @@ -2217,10 +2217,10 @@ static int onenand_write_oob(struct mtd_info *mtd, loff_t to, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -2281,7 +2281,7 @@ static int onenand_multiblock_erase_verify(struct mtd_info *mtd, } /** - * onenand_multiblock_erase - [Internal] erase block(s) using multiblock erase + * onenand_multiblock_erase - [INTERN] erase block(s) using multiblock erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2397,7 +2397,7 @@ static int onenand_multiblock_erase(struct mtd_info *mtd, /** - * onenand_block_by_block_erase - [Internal] erase block(s) using regular erase + * onenand_block_by_block_erase - [INTERN] erase block(s) using regular erase * @param mtd MTD device structure * @param instr erase instruction * @param region erase region @@ -2489,8 +2489,9 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) struct mtd_erase_region_info *region = NULL; loff_t region_offset = 0; - DEBUG(MTD_DEBUG_LEVEL3, "%s: start=0x%012llx, len=%llu\n", __func__, - (unsigned long long) instr->addr, (unsigned long long) instr->len); + pr_debug("%s: start=0x%012llx, len=%llu\n", __func__, + (unsigned long long)instr->addr, + (unsigned long long)instr->len); /* Do not allow erase past end of device */ if (unlikely((len + addr) > mtd->size)) { @@ -2558,7 +2559,7 @@ static int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) */ static void onenand_sync(struct mtd_info *mtd) { - DEBUG(MTD_DEBUG_LEVEL3, "%s: called\n", __func__); + pr_debug("%s: called\n", __func__); /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_SYNCING); @@ -2602,7 +2603,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooblen = 2, .oobbuf = buf, .ooboffs = 0, @@ -2922,7 +2923,7 @@ static int onenand_otp_command(struct mtd_info *mtd, int cmd, loff_t addr, } /** - * onenand_otp_write_oob_nolock - [Internal] OneNAND write out-of-band, specific to OTP + * onenand_otp_write_oob_nolock - [INTERN] OneNAND write out-of-band, specific to OTP * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -3170,7 +3171,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len, this->command(mtd, ONENAND_CMD_RESET, 0, 0); this->wait(mtd, FL_RESETING); } else { - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = len; ops.oobbuf = buf; ops.ooboffs = 0; @@ -3429,6 +3430,19 @@ static void onenand_check_features(struct mtd_info *mtd) else if (numbufs == 1) { this->options |= ONENAND_HAS_4KB_PAGE; this->options |= ONENAND_HAS_CACHE_PROGRAM; + /* + * There are two different 4KiB pagesize chips + * and no way to detect it by H/W config values. + * + * To detect the correct NOP for each chips, + * It should check the version ID as workaround. + * + * Now it has as following + * KFM4G16Q4M has NOP 4 with version ID 0x0131 + * KFM4G16Q5M has NOP 1 with versoin ID 0x013e + */ + if ((this->version_id & 0xf) == 0xe) + this->options |= ONENAND_HAS_NOP_1; } case ONENAND_DEVICE_DENSITY_2Gb: @@ -3663,7 +3677,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int int i, ret; int block; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooboffs = 0, .ooblen = mtd->oobsize, .datbuf = NULL, @@ -4054,6 +4068,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips) this->ecclayout = &onenand_oob_128; mtd->subpage_sft = 2; } + if (ONENAND_IS_NOP_1(this)) + mtd->subpage_sft = 0; break; case 64: this->ecclayout = &onenand_oob_64; diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index b2d7fc5ea25..66fe3b7e785 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -81,7 +81,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr startblock = 0; from = 0; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = readlen; ops.oobbuf = buf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -154,7 +154,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) block = (int) (onenand_block(this, offs) << 1); res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03; - DEBUG(MTD_DEBUG_LEVEL2, "onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", + pr_debug("onenand_isbad_bbt: bbt info for offs 0x%08x: (block %d) 0x%02x\n", (unsigned int) offs, block >> 1, res); switch ((int) res) { @@ -189,10 +189,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len = this->chipsize >> (this->erase_shift + 2); /* Allocate memory (2bit per block) and clear the memory bad block table */ bbm->bbt = kzalloc(len, GFP_KERNEL); - if (!bbm->bbt) { - printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); + if (!bbm->bbt) return -ENOMEM; - } /* Set the bad block position */ bbm->badblockpos = ONENAND_BADBLOCK_POS; diff --git a/drivers/mtd/onenand/samsung.c b/drivers/mtd/onenand/samsung.c index 3306b5b3c73..5474547eafc 100644 --- a/drivers/mtd/onenand/samsung.c +++ b/drivers/mtd/onenand/samsung.c @@ -147,7 +147,6 @@ struct s3c_onenand { struct resource *dma_res; unsigned long phys_base; struct completion complete; - struct mtd_partition *parts; }; #define CMD_MAP_00(dev, addr) (dev->cmd_map(MAP_00, ((addr) << 1))) @@ -157,8 +156,6 @@ struct s3c_onenand { static struct s3c_onenand *onenand; -static const char *part_probes[] = { "cmdlinepart", NULL, }; - static inline int s3c_read_reg(int offset) { return readl(onenand->base + offset); @@ -1017,13 +1014,9 @@ static int s3c_onenand_probe(struct platform_device *pdev) if (s3c_read_reg(MEM_CFG_OFFSET) & ONENAND_SYS_CFG1_SYNC_READ) dev_info(&onenand->pdev->dev, "OneNAND Sync. Burst Read enabled\n"); - err = parse_mtd_partitions(mtd, part_probes, &onenand->parts, 0); - if (err > 0) - mtd_device_register(mtd, onenand->parts, err); - else if (err <= 0 && pdata && pdata->parts) - mtd_device_register(mtd, pdata->parts, pdata->nr_parts); - else - err = mtd_device_register(mtd, NULL, 0); + err = mtd_device_parse_register(mtd, NULL, 0, + pdata ? pdata->parts : NULL, + pdata ? pdata->nr_parts : 0); platform_set_drvdata(pdev, mtd); diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c index 84b4dda023f..e366b1d84ea 100644 --- a/drivers/mtd/redboot.c +++ b/drivers/mtd/redboot.c @@ -57,8 +57,8 @@ static inline int redboot_checksum(struct fis_image_desc *img) } static int parse_redboot_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - unsigned long fis_origin) + struct mtd_partition **pparts, + struct mtd_part_parser_data *data) { int nrparts = 0; struct fis_image_desc *buf; @@ -198,11 +198,10 @@ static int parse_redboot_partitions(struct mtd_info *master, goto out; } new_fl->img = &buf[i]; - if (fis_origin) { - buf[i].flash_base -= fis_origin; - } else { - buf[i].flash_base &= master->size-1; - } + if (data && data->origin) + buf[i].flash_base -= data->origin; + else + buf[i].flash_base &= master->size-1; /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ @@ -298,6 +297,9 @@ static struct mtd_part_parser redboot_parser = { .name = "RedBoot", }; +/* mtd parsers will request the module by parser name */ +MODULE_ALIAS("RedBoot"); + static int __init redboot_parser_init(void) { return register_mtd_parser(&redboot_parser); diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c index ed3d6cd2c6d..fddb714e323 100644 --- a/drivers/mtd/sm_ftl.c +++ b/drivers/mtd/sm_ftl.c @@ -34,7 +34,7 @@ module_param(debug, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug level (0-2)"); -/* ------------------- sysfs attributtes ---------------------------------- */ +/* ------------------- sysfs attributes ---------------------------------- */ struct sm_sysfs_attribute { struct device_attribute dev_attr; char *data; @@ -138,7 +138,7 @@ static int sm_get_lba(uint8_t *lba) if ((lba[0] & 0xF8) != 0x10) return -2; - /* check parity - endianess doesn't matter */ + /* check parity - endianness doesn't matter */ if (hweight16(*(uint16_t *)lba) & 1) return -2; @@ -147,7 +147,7 @@ static int sm_get_lba(uint8_t *lba) /* - * Read LBA asscociated with block + * Read LBA associated with block * returns -1, if block is erased * returns -2 if error happens */ @@ -252,11 +252,11 @@ static int sm_read_sector(struct sm_ftl *ftl, return 0; } - /* User might not need the oob, but we do for data vertification */ + /* User might not need the oob, but we do for data verification */ if (!oob) oob = &tmp_oob; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = SM_OOB_SIZE; ops.oobbuf = (void *)oob; @@ -276,12 +276,12 @@ again: return ret; } - /* Unfortunelly, oob read will _always_ succeed, + /* Unfortunately, oob read will _always_ succeed, despite card removal..... */ ret = mtd->read_oob(mtd, sm_mkoffset(ftl, zone, block, boffset), &ops); /* Test for unknown errors */ - if (ret != 0 && ret != -EUCLEAN && ret != -EBADMSG) { + if (ret != 0 && !mtd_is_bitflip_or_eccerr(ret)) { dbg("read of block %d at zone %d, failed due to error (%d)", block, zone, ret); goto again; @@ -306,7 +306,7 @@ again: } /* Test ECC*/ - if (ret == -EBADMSG || + if (mtd_is_eccerr(ret) || (ftl->smallpagenand && sm_correct_sector(buffer, oob))) { dbg("read of block %d at zone %d, failed due to ECC error", @@ -336,7 +336,7 @@ static int sm_write_sector(struct sm_ftl *ftl, if (ftl->unstable) return -EIO; - ops.mode = ftl->smallpagenand ? MTD_OOB_RAW : MTD_OOB_PLACE; + ops.mode = ftl->smallpagenand ? MTD_OPS_RAW : MTD_OPS_PLACE_OOB; ops.len = SM_SECTOR_SIZE; ops.datbuf = buffer; ops.ooboffs = 0; @@ -447,14 +447,14 @@ static void sm_mark_block_bad(struct sm_ftl *ftl, int zone, int block) /* We aren't checking the return value, because we don't care */ /* This also fails on fake xD cards, but I guess these won't expose - any bad blocks till fail completly */ + any bad blocks till fail completely */ for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) sm_write_sector(ftl, zone, block, boffset, NULL, &oob); } /* * Erase a block within a zone - * If erase succedes, it updates free block fifo, otherwise marks block as bad + * If erase succeeds, it updates free block fifo, otherwise marks block as bad */ static int sm_erase_block(struct sm_ftl *ftl, int zone_num, uint16_t block, int put_free) @@ -510,7 +510,7 @@ static void sm_erase_callback(struct erase_info *self) complete(&ftl->erase_completion); } -/* Throughtly test that block is valid. */ +/* Thoroughly test that block is valid. */ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) { int boffset; @@ -526,7 +526,7 @@ static int sm_check_block(struct sm_ftl *ftl, int zone, int block) for (boffset = 0; boffset < ftl->block_size; boffset += SM_SECTOR_SIZE) { - /* This shoudn't happen anyway */ + /* This shouldn't happen anyway */ if (sm_read_sector(ftl, zone, block, boffset, NULL, &oob)) return -2; diff --git a/drivers/mtd/ssfdc.c b/drivers/mtd/ssfdc.c index 5cd18979333..976e3d28b96 100644 --- a/drivers/mtd/ssfdc.c +++ b/drivers/mtd/ssfdc.c @@ -135,8 +135,7 @@ static int get_valid_cis_sector(struct mtd_info *mtd) /* Found */ cis_sector = (int)(offset >> SECTOR_SHIFT); } else { - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: CIS/IDI sector not found" + pr_debug("SSFDC_RO: CIS/IDI sector not found" " on %s (mtd%d)\n", mtd->name, mtd->index); } @@ -170,7 +169,7 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf) struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooboffs = 0; ops.ooblen = OOB_SIZE; ops.oobbuf = buf; @@ -221,8 +220,7 @@ static int get_logical_address(uint8_t *oob_buf) block_address >>= 1; if (get_parity(block_address, 10) != parity) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: logical address field%d" + pr_debug("SSFDC_RO: logical address field%d" "parity error(0x%04X)\n", j+1, block_address); } else { @@ -235,7 +233,7 @@ static int get_logical_address(uint8_t *oob_buf) if (!ok) block_address = -2; - DEBUG(MTD_DEBUG_LEVEL3, "SSFDC_RO: get_logical_address() %d\n", + pr_debug("SSFDC_RO: get_logical_address() %d\n", block_address); return block_address; @@ -249,7 +247,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) int ret, block_address, phys_block; struct mtd_info *mtd = ssfdc->mbd.mtd; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: build_block_map() nblks=%d (%luK)\n", + pr_debug("SSFDC_RO: build_block_map() nblks=%d (%luK)\n", ssfdc->map_len, (unsigned long)ssfdc->map_len * ssfdc->erase_size / 1024); @@ -262,8 +260,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ret = read_raw_oob(mtd, offset, oob_buf); if (ret < 0) { - DEBUG(MTD_DEBUG_LEVEL0, - "SSFDC_RO: mtd read_oob() failed at %lu\n", + pr_debug("SSFDC_RO: mtd read_oob() failed at %lu\n", offset); return -1; } @@ -279,8 +276,7 @@ static int build_logical_block_map(struct ssfdcr_record *ssfdc) ssfdc->logic_block_map[block_address] = (unsigned short)phys_block; - DEBUG(MTD_DEBUG_LEVEL2, - "SSFDC_RO: build_block_map() phys_block=%d," + pr_debug("SSFDC_RO: build_block_map() phys_block=%d," "logic_block_addr=%d, zone=%d\n", phys_block, block_address, zone_index); } @@ -304,11 +300,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) return; ssfdc = kzalloc(sizeof(struct ssfdcr_record), GFP_KERNEL); - if (!ssfdc) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc) return; - } ssfdc->mbd.mtd = mtd; ssfdc->mbd.devnum = -1; @@ -319,8 +312,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->erase_size = mtd->erasesize; ssfdc->map_len = (u32)mtd->size / mtd->erasesize; - DEBUG(MTD_DEBUG_LEVEL1, - "SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", + pr_debug("SSFDC_RO: cis_block=%d,erase_size=%d,map_len=%d,n_zones=%d\n", ssfdc->cis_block, ssfdc->erase_size, ssfdc->map_len, DIV_ROUND_UP(ssfdc->map_len, MAX_PHYS_BLK_PER_ZONE)); @@ -331,7 +323,7 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) ssfdc->cylinders = (unsigned short)(((u32)mtd->size >> SECTOR_SHIFT) / ((long)ssfdc->sectors * (long)ssfdc->heads)); - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", + pr_debug("SSFDC_RO: using C:%d H:%d S:%d == %ld sects\n", ssfdc->cylinders, ssfdc->heads , ssfdc->sectors, (long)ssfdc->cylinders * (long)ssfdc->heads * (long)ssfdc->sectors); @@ -342,11 +334,8 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) /* Allocate logical block map */ ssfdc->logic_block_map = kmalloc(sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len, GFP_KERNEL); - if (!ssfdc->logic_block_map) { - printk(KERN_WARNING - "SSFDC_RO: out of memory for data structures\n"); + if (!ssfdc->logic_block_map) goto out_err; - } memset(ssfdc->logic_block_map, 0xff, sizeof(ssfdc->logic_block_map[0]) * ssfdc->map_len); @@ -371,7 +360,7 @@ static void ssfdcr_remove_dev(struct mtd_blktrans_dev *dev) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); + pr_debug("SSFDC_RO: remove_dev (i=%d)\n", dev->devnum); del_mtd_blktrans_dev(dev); kfree(ssfdc->logic_block_map); @@ -387,8 +376,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, offset = (int)(logic_sect_no % sectors_per_block); block_address = (int)(logic_sect_no / sectors_per_block); - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," + pr_debug("SSFDC_RO: ssfdcr_readsect(%lu) sec_per_blk=%d, ofst=%d," " block_addr=%d\n", logic_sect_no, sectors_per_block, offset, block_address); @@ -397,8 +385,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, block_address = ssfdc->logic_block_map[block_address]; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_block_addr=%d\n", block_address); if (block_address < 0xffff) { @@ -407,8 +394,7 @@ static int ssfdcr_readsect(struct mtd_blktrans_dev *dev, sect_no = (unsigned long)block_address * sectors_per_block + offset; - DEBUG(MTD_DEBUG_LEVEL3, - "SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", + pr_debug("SSFDC_RO: ssfdcr_readsect() phys_sect_no=%lu\n", sect_no); if (read_physical_sector(ssfdc->mbd.mtd, buf, sect_no) < 0) @@ -424,7 +410,7 @@ static int ssfdcr_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) { struct ssfdcr_record *ssfdc = (struct ssfdcr_record *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", + pr_debug("SSFDC_RO: ssfdcr_getgeo() C=%d, H=%d, S=%d\n", ssfdc->cylinders, ssfdc->heads, ssfdc->sectors); geo->heads = ssfdc->heads; diff --git a/drivers/mtd/tests/mtd_oobtest.c b/drivers/mtd/tests/mtd_oobtest.c index dec92ae6111..933f7e5f32d 100644 --- a/drivers/mtd/tests/mtd_oobtest.c +++ b/drivers/mtd/tests/mtd_oobtest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_oobtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -131,7 +131,7 @@ static int write_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -184,7 +184,7 @@ static int verify_eraseblock(int ebnum) for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { set_random_data(writebuf, use_len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = use_len; @@ -211,7 +211,7 @@ static int verify_eraseblock(int ebnum) if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { int k; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -276,7 +276,7 @@ static int verify_eraseblock_in_one_go(int ebnum) size_t len = mtd->ecclayout->oobavail * pgcnt; set_random_data(writebuf, len); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = len; @@ -366,6 +366,13 @@ static int __init mtd_oobtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); @@ -507,7 +514,7 @@ static int __init mtd_oobtest_init(void) addr0 += mtd->erasesize; /* Attempt to write off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -527,7 +534,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of OOB */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = 1; @@ -551,7 +558,7 @@ static int __init mtd_oobtest_init(void) "block is bad\n"); else { /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -571,7 +578,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail + 1; @@ -595,7 +602,7 @@ static int __init mtd_oobtest_init(void) goto out; /* Attempt to write off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -615,7 +622,7 @@ static int __init mtd_oobtest_init(void) } /* Attempt to read off end of device */ - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail; @@ -655,7 +662,7 @@ static int __init mtd_oobtest_init(void) addr = (i + 1) * mtd->erasesize - mtd->writesize; for (pg = 0; pg < cnt; ++pg) { set_random_data(writebuf, sz); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = sz; @@ -683,7 +690,7 @@ static int __init mtd_oobtest_init(void) continue; set_random_data(writebuf, mtd->ecclayout->oobavail * 2); addr = (i + 1) * mtd->erasesize - mtd->writesize; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->ecclayout->oobavail * 2; diff --git a/drivers/mtd/tests/mtd_pagetest.c b/drivers/mtd/tests/mtd_pagetest.c index 00b937e38c1..afafb6935fd 100644 --- a/drivers/mtd/tests/mtd_pagetest.c +++ b/drivers/mtd/tests/mtd_pagetest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_pagetest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -128,7 +128,7 @@ static int verify_eraseblock(int ebnum) for (j = 0; j < pgcnt - 1; ++j, addr += pgsize) { /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -136,7 +136,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -146,7 +146,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -164,7 +164,7 @@ static int verify_eraseblock(int ebnum) unsigned long oldnext = next; /* Do a read to set the internal dataRAMs to different data */ err = mtd->read(mtd, addr0, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -172,7 +172,7 @@ static int verify_eraseblock(int ebnum) return err; } err = mtd->read(mtd, addrn - bufsize, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -182,7 +182,7 @@ static int verify_eraseblock(int ebnum) memset(twopages, 0, bufsize); read = 0; err = mtd->read(mtd, addr, bufsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != bufsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -231,7 +231,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -244,7 +244,7 @@ static int crosstest(void) read = 0; addr = addrn - pgsize - pgsize - pgsize; err = mtd->read(mtd, addr, pgsize, &read, pp1); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -258,7 +258,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp2); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -272,7 +272,7 @@ static int crosstest(void) addr = addrn - pgsize; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp3); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -286,7 +286,7 @@ static int crosstest(void) addr = addr0; printk(PRINT_PREF "reading page at %#llx\n", (long long)addr); err = mtd->read(mtd, addr, pgsize, &read, pp4); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -345,7 +345,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -383,7 +383,7 @@ static int erasecrosstest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); memset(readbuf, 0, pgsize); err = mtd->read(mtd, addr0, pgsize, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -439,7 +439,7 @@ static int erasetest(void) printk(PRINT_PREF "reading 1st page of block %d\n", ebnum); err = mtd->read(mtd, addr0, pgsize, &read, twopages); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -504,6 +504,13 @@ static int __init mtd_pagetest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_readtest.c b/drivers/mtd/tests/mtd_readtest.c index afe71aa15c4..550fe51225a 100644 --- a/drivers/mtd/tests/mtd_readtest.c +++ b/drivers/mtd/tests/mtd_readtest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_readtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -66,7 +66,7 @@ static int read_eraseblock_by_page(int ebnum) if (mtd->oobsize) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.len = 0; ops.retlen = 0; ops.ooblen = mtd->oobsize; @@ -75,7 +75,8 @@ static int read_eraseblock_by_page(int ebnum) ops.datbuf = NULL; ops.oobbuf = oobbuf; ret = mtd->read_oob(mtd, addr, &ops); - if (ret || ops.oobretlen != mtd->oobsize) { + if ((ret && !mtd_is_bitflip(ret)) || + ops.oobretlen != mtd->oobsize) { printk(PRINT_PREF "error: read oob failed at " "%#llx\n", (long long)addr); if (!err) @@ -169,6 +170,12 @@ static int __init mtd_readtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_speedtest.c b/drivers/mtd/tests/mtd_speedtest.c index 627d4e2466a..493b367bdd3 100644 --- a/drivers/mtd/tests/mtd_speedtest.c +++ b/drivers/mtd/tests/mtd_speedtest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_speedtest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -216,7 +216,7 @@ static int read_eraseblock(int ebnum) err = mtd->read(mtd, addr, mtd->erasesize, &read, iobuf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != mtd->erasesize) { printk(PRINT_PREF "error: read failed at %#llx\n", addr); @@ -237,7 +237,7 @@ static int read_eraseblock_by_page(int ebnum) for (i = 0; i < pgcnt; i++) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -263,7 +263,7 @@ static int read_eraseblock_by_2pages(int ebnum) for (i = 0; i < n; i++) { err = mtd->read(mtd, addr, sz, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != sz) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -278,7 +278,7 @@ static int read_eraseblock_by_2pages(int ebnum) if (pgcnt % 2) { err = mtd->read(mtd, addr, pgsize, &read, buf); /* Ignore corrected ECC errors */ - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (err || read != pgsize) { printk(PRINT_PREF "error: read failed at %#llx\n", @@ -361,6 +361,13 @@ static int __init mtd_speedtest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + if (count) printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count); else diff --git a/drivers/mtd/tests/mtd_stresstest.c b/drivers/mtd/tests/mtd_stresstest.c index 531625fc925..52ffd9120e0 100644 --- a/drivers/mtd/tests/mtd_stresstest.c +++ b/drivers/mtd/tests/mtd_stresstest.c @@ -30,7 +30,7 @@ #define PRINT_PREF KERN_INFO "mtd_stresstest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -154,7 +154,7 @@ static int do_read(void) } addr = eb * mtd->erasesize + offs; err = mtd->read(mtd, addr, len, &read, readbuf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) err = 0; if (unlikely(err || read != len)) { printk(PRINT_PREF "error: read failed at 0x%llx\n", @@ -250,6 +250,13 @@ static int __init mtd_stresstest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_subpagetest.c b/drivers/mtd/tests/mtd_subpagetest.c index 334eae53a3d..1a05bfac4ee 100644 --- a/drivers/mtd/tests/mtd_subpagetest.c +++ b/drivers/mtd/tests/mtd_subpagetest.c @@ -29,7 +29,7 @@ #define PRINT_PREF KERN_INFO "mtd_subpagetest: " -static int dev; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -198,7 +198,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -226,7 +226,7 @@ static int verify_eraseblock(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -264,7 +264,7 @@ static int verify_eraseblock2(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize * k, &read, readbuf); if (unlikely(err || read != subpgsize * k)) { - if (err == -EUCLEAN && read == subpgsize * k) { + if (mtd_is_bitflip(err) && read == subpgsize * k) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -298,7 +298,7 @@ static int verify_eraseblock_ff(int ebnum) read = 0; err = mtd->read(mtd, addr, subpgsize, &read, readbuf); if (unlikely(err || read != subpgsize)) { - if (err == -EUCLEAN && read == subpgsize) { + if (mtd_is_bitflip(err) && read == subpgsize) { printk(PRINT_PREF "ECC correction at %#llx\n", (long long)addr); err = 0; @@ -379,6 +379,13 @@ static int __init mtd_subpagetest_init(void) printk(KERN_INFO "\n"); printk(KERN_INFO "=================================================\n"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + printk(PRINT_PREF "MTD device: %d\n", dev); mtd = get_mtd_device(NULL, dev); diff --git a/drivers/mtd/tests/mtd_torturetest.c b/drivers/mtd/tests/mtd_torturetest.c index 5c6c3d24890..03ab649a696 100644 --- a/drivers/mtd/tests/mtd_torturetest.c +++ b/drivers/mtd/tests/mtd_torturetest.c @@ -46,7 +46,7 @@ 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; +static int dev = -EINVAL; module_param(dev, int, S_IRUGO); MODULE_PARM_DESC(dev, "MTD device number to use"); @@ -138,7 +138,7 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) retry: err = mtd->read(mtd, addr, len, &read, check_buf); - if (err == -EUCLEAN) + if (mtd_is_bitflip(err)) printk(PRINT_PREF "single bit flip occurred at EB %d " "MTD reported that it was fixed.\n", ebnum); else if (err) { @@ -213,6 +213,13 @@ static int __init tort_init(void) 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"); + + if (dev < 0) { + printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); + printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); + return -EINVAL; + } + 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); diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index 4be67181501..fb7f19b62d9 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -443,7 +443,7 @@ retry: if (err == UBI_IO_BITFLIPS) { scrub = 1; err = 0; - } else if (err == -EBADMSG) { + } else if (mtd_is_eccerr(err)) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 6ba55c23587..f20b6f22f24 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -172,9 +172,9 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, retry: err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); if (err) { - const char *errstr = (err == -EBADMSG) ? " (ECC error)" : ""; + const char *errstr = mtd_is_eccerr(err) ? " (ECC error)" : ""; - if (err == -EUCLEAN) { + if (mtd_is_bitflip(err)) { /* * -EUCLEAN is reported if there was a bit-flip which * was corrected, so this is harmless. @@ -205,7 +205,7 @@ retry: * all the requested data. But some buggy drivers might do * this, so we change it to -EIO. */ - if (read != len && err == -EBADMSG) { + if (read != len && mtd_is_eccerr(err)) { ubi_assert(0); err = -EIO; } @@ -469,7 +469,7 @@ static int torture_peb(struct ubi_device *ubi, int pnum) out: mutex_unlock(&ubi->buf_mutex); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * If a bit-flip or data integrity error was detected, the test * has not passed because it happened on a freshly erased @@ -760,7 +760,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, read_err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); if (read_err) { - if (read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; /* @@ -776,7 +776,7 @@ int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, magic = be32_to_cpu(ec_hdr->magic); if (magic != UBI_EC_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; /* @@ -1032,12 +1032,12 @@ int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, p = (char *)vid_hdr - ubi->vid_hdr_shift; read_err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (read_err && read_err != UBI_IO_BITFLIPS && read_err != -EBADMSG) + if (read_err && read_err != UBI_IO_BITFLIPS && !mtd_is_eccerr(read_err)) return read_err; magic = be32_to_cpu(vid_hdr->magic); if (magic != UBI_VID_HDR_MAGIC) { - if (read_err == -EBADMSG) + if (mtd_is_eccerr(read_err)) return UBI_IO_BAD_HDR_EBADMSG; if (ubi_check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { @@ -1219,7 +1219,7 @@ static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) return -ENOMEM; err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1306,7 +1306,7 @@ static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) p = (char *)vid_hdr - ubi->vid_hdr_shift; err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, ubi->vid_hdr_alsize); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto exit; crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); @@ -1358,7 +1358,7 @@ int ubi_dbg_check_write(struct ubi_device *ubi, const void *buf, int pnum, } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf1); - if (err && err != -EUCLEAN) + if (err && !mtd_is_bitflip(err)) goto out_free; for (i = 0; i < len; i++) { @@ -1422,7 +1422,7 @@ int ubi_dbg_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len) } err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); - if (err && err != -EUCLEAN) { + if (err && !mtd_is_bitflip(err)) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); goto error; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d39716e5b20..1a35fc5e3b4 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -410,7 +410,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, return 0; err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { + if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { ubi_warn("mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index ff2a65c37f6..f6a7d7ac4b9 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -81,7 +81,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); if (err) { - if (err == -EBADMSG) + if (mtd_is_eccerr(err)) err = 1; break; } diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c index a3a198f9b98..0cb17d936b5 100644 --- a/drivers/mtd/ubi/scan.c +++ b/drivers/mtd/ubi/scan.c @@ -395,7 +395,7 @@ static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, } err = ubi_io_read_data(ubi, buf, pnum, 0, len); - if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err)) goto out_free_buf; data_crc = be32_to_cpu(vid_hdr->data_crc); @@ -793,7 +793,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, err = ubi_io_read(ubi, ubi->peb_buf1, pnum, ubi->leb_start, ubi->leb_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) { /* * Bit-flips or integrity errors while reading the data area. * It is difficult to say for sure what type of corruption is diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 4b50a3029b8..9ad18da1891 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -423,7 +423,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) /* * Scrub the PEB later. Note, -EBADMSG indicates an * uncorrectable ECC error, but we have our own CRC and diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 583f66cd5bb..654a5e94e0e 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -245,6 +245,8 @@ source "drivers/net/ethernet/Kconfig" source "drivers/net/fddi/Kconfig" +source "drivers/net/hippi/Kconfig" + config NET_SB1000 tristate "General Instruments Surfboard 1000" depends on PNP diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig index a73d9dc80ff..84fb6349a59 100644 --- a/drivers/net/arcnet/Kconfig +++ b/drivers/net/arcnet/Kconfig @@ -4,7 +4,7 @@ menuconfig ARCNET depends on NETDEVICES && (ISA || PCI || PCMCIA) - bool "ARCnet support" + tristate "ARCnet support" ---help--- If you have a network card of this type, say Y and check out the (arguably) beautiful poetry in diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b2b9109b671..7f8756825b8 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -560,8 +560,8 @@ static int bond_update_speed_duplex(struct slave *slave) u32 slave_speed; int res; - slave->speed = -1; - slave->duplex = -1; + slave->speed = SPEED_UNKNOWN; + slave->duplex = DUPLEX_UNKNOWN; res = __ethtool_get_settings(slave_dev, &ecmd); if (res < 0) @@ -2553,30 +2553,6 @@ re_arm: } } -static __be32 bond_glean_dev_ip(struct net_device *dev) -{ - struct in_device *idev; - struct in_ifaddr *ifa; - __be32 addr = 0; - - if (!dev) - return 0; - - rcu_read_lock(); - idev = __in_dev_get_rcu(dev); - if (!idev) - goto out; - - ifa = idev->ifa_list; - if (!ifa) - goto out; - - addr = ifa->ifa_local; -out: - rcu_read_unlock(); - return addr; -} - static int bond_has_this_ip(struct bonding *bond, __be32 ip) { struct vlan_entry *vlan; @@ -3322,6 +3298,10 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, struct bonding *bond; struct vlan_entry *vlan; + /* we only care about primary address */ + if(ifa->ifa_flags & IFA_F_SECONDARY) + return NOTIFY_DONE; + list_for_each_entry(bond, &bn->dev_list, bond_list) { if (bond->dev == event_dev) { switch (event) { @@ -3329,7 +3309,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, bond->master_ip = ifa->ifa_local; return NOTIFY_OK; case NETDEV_DOWN: - bond->master_ip = bond_glean_dev_ip(bond->dev); + bond->master_ip = 0; return NOTIFY_OK; default: return NOTIFY_DONE; @@ -3345,8 +3325,7 @@ static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, vlan->vlan_ip = ifa->ifa_local; return NOTIFY_OK; case NETDEV_DOWN: - vlan->vlan_ip = - bond_glean_dev_ip(vlan_dev); + vlan->vlan_ip = 0; return NOTIFY_OK; default: return NOTIFY_DONE; diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 2acf0b08016..ad284baafe8 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -158,12 +158,12 @@ static void bond_info_show_slave(struct seq_file *seq, seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); - if (slave->speed == -1) + if (slave->speed == SPEED_UNKNOWN) seq_printf(seq, "Speed: %s\n", "Unknown"); else seq_printf(seq, "Speed: %d Mbps\n", slave->speed); - if (slave->duplex == -1) + if (slave->duplex == DUPLEX_UNKNOWN) seq_printf(seq, "Duplex: %s\n", "Unknown"); else seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half"); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 5a20804fdec..4ef7e2fd9fe 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -319,6 +319,13 @@ static ssize_t bonding_store_mode(struct device *d, goto out; } + if (bond->slave_cnt > 0) { + pr_err("unable to update mode of %s because it has slaves.\n", + bond->dev->name); + ret = -EPERM; + goto out; + } + new_value = bond_parse_parm(buf, bond_mode_tbl); if (new_value < 0) { pr_err("%s: Ignoring invalid mode value %.*s.\n", diff --git a/drivers/net/can/sja1000/peak_pci.c b/drivers/net/can/sja1000/peak_pci.c index 905bce0b3a4..2c7f5036f57 100644 --- a/drivers/net/can/sja1000/peak_pci.c +++ b/drivers/net/can/sja1000/peak_pci.c @@ -20,7 +20,6 @@ */ #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include <linux/interrupt.h> #include <linux/netdevice.h> diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 4cf835dbc12..3fb66d09ece 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -608,7 +608,7 @@ static void b44_tx(struct b44 *bp) skb->len, DMA_TO_DEVICE); rp->skb = NULL; - dev_kfree_skb(skb); + dev_kfree_skb_irq(skb); } bp->tx_cons = cons; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index bce203fa4b9..882f48f0a03 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -10327,6 +10327,43 @@ static int bnx2x_54618se_config_init(struct bnx2x_phy *phy, return 0; } + +static void bnx2x_5461x_set_link_led(struct bnx2x_phy *phy, + struct link_params *params, u8 mode) +{ + struct bnx2x *bp = params->bp; + u16 temp; + + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_LED_SEL1); + bnx2x_cl22_read(bp, phy, + MDIO_REG_GPHY_SHADOW, + &temp); + temp &= 0xff00; + + DP(NETIF_MSG_LINK, "54618x set link led (mode=%x)\n", mode); + switch (mode) { + case LED_MODE_FRONT_PANEL_OFF: + case LED_MODE_OFF: + temp |= 0x00ee; + break; + case LED_MODE_OPER: + temp |= 0x0001; + break; + case LED_MODE_ON: + temp |= 0x00ff; + break; + default: + break; + } + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_WR_ENA | temp); + return; +} + + static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy, struct link_params *params) { @@ -11103,7 +11140,7 @@ static struct bnx2x_phy phy_54618se = { .config_loopback = (config_loopback_t)bnx2x_54618se_config_loopback, .format_fw_ver = (format_fw_ver_t)NULL, .hw_reset = (hw_reset_t)NULL, - .set_link_led = (set_link_led_t)NULL, + .set_link_led = (set_link_led_t)bnx2x_5461x_set_link_led, .phy_specific_func = (phy_specific_func_t)NULL }; /*****************************************************************/ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 6486ab8c8fc..2f6361e949f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -10548,33 +10548,38 @@ do { \ int bnx2x_init_firmware(struct bnx2x *bp) { - const char *fw_file_name; struct bnx2x_fw_file_hdr *fw_hdr; int rc; - if (CHIP_IS_E1(bp)) - fw_file_name = FW_FILE_NAME_E1; - else if (CHIP_IS_E1H(bp)) - fw_file_name = FW_FILE_NAME_E1H; - else if (!CHIP_IS_E1x(bp)) - fw_file_name = FW_FILE_NAME_E2; - else { - BNX2X_ERR("Unsupported chip revision\n"); - return -EINVAL; - } - BNX2X_DEV_INFO("Loading %s\n", fw_file_name); + if (!bp->firmware) { + const char *fw_file_name; - rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev); - if (rc) { - BNX2X_ERR("Can't load firmware file %s\n", fw_file_name); - goto request_firmware_exit; - } + if (CHIP_IS_E1(bp)) + fw_file_name = FW_FILE_NAME_E1; + else if (CHIP_IS_E1H(bp)) + fw_file_name = FW_FILE_NAME_E1H; + else if (!CHIP_IS_E1x(bp)) + fw_file_name = FW_FILE_NAME_E2; + else { + BNX2X_ERR("Unsupported chip revision\n"); + return -EINVAL; + } + BNX2X_DEV_INFO("Loading %s\n", fw_file_name); - rc = bnx2x_check_firmware(bp); - if (rc) { - BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name); - goto request_firmware_exit; + rc = request_firmware(&bp->firmware, fw_file_name, + &bp->pdev->dev); + if (rc) { + BNX2X_ERR("Can't load firmware file %s\n", + fw_file_name); + goto request_firmware_exit; + } + + rc = bnx2x_check_firmware(bp); + if (rc) { + BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } } fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; @@ -10630,6 +10635,7 @@ static void bnx2x_release_firmware(struct bnx2x *bp) kfree(bp->init_ops); kfree(bp->init_data); release_firmware(bp->firmware); + bp->firmware = NULL; } @@ -10925,6 +10931,8 @@ static void __devexit bnx2x_remove_one(struct pci_dev *pdev) if (bp->doorbells) iounmap(bp->doorbells); + bnx2x_release_firmware(bp); + bnx2x_free_mem_bp(bp); free_netdev(dev); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index fc7bd0f23c0..e58073ef33b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -6990,6 +6990,7 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_REG_INTR_MASK 0x1b #define MDIO_REG_INTR_MASK_LINK_STATUS (0x1 << 1) #define MDIO_REG_GPHY_SHADOW 0x1c +#define MDIO_REG_GPHY_SHADOW_LED_SEL1 (0x0d << 10) #define MDIO_REG_GPHY_SHADOW_LED_SEL2 (0x0e << 10) #define MDIO_REG_GPHY_SHADOW_WR_ENA (0x1 << 15) #define MDIO_REG_GPHY_SHADOW_AUTO_DET_MED (0x1e << 10) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 0440425c83d..14517691f8d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -5380,7 +5380,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp, rc = drv->init_fw(bp); if (rc) { BNX2X_ERR("Error loading firmware\n"); - goto fw_init_err; + goto init_err; } /* Handle the beginning of COMMON_XXX pases separatelly... */ @@ -5388,25 +5388,25 @@ static int bnx2x_func_hw_init(struct bnx2x *bp, case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: rc = bnx2x_func_init_cmn_chip(bp, drv); if (rc) - goto init_hw_err; + goto init_err; break; case FW_MSG_CODE_DRV_LOAD_COMMON: rc = bnx2x_func_init_cmn(bp, drv); if (rc) - goto init_hw_err; + goto init_err; break; case FW_MSG_CODE_DRV_LOAD_PORT: rc = bnx2x_func_init_port(bp, drv); if (rc) - goto init_hw_err; + goto init_err; break; case FW_MSG_CODE_DRV_LOAD_FUNCTION: rc = bnx2x_func_init_func(bp, drv); if (rc) - goto init_hw_err; + goto init_err; break; default: @@ -5414,10 +5414,7 @@ static int bnx2x_func_hw_init(struct bnx2x *bp, rc = -EINVAL; } -init_hw_err: - drv->release_fw(bp); - -fw_init_err: +init_err: drv->gunzip_end(bp); /* In case of success, complete the comand immediatelly: no ramrods diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 161cbbb4814..bf4074167d6 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -89,10 +89,10 @@ static inline void _tg3_flag_clear(enum TG3_FLAGS flag, unsigned long *bits) #define DRV_MODULE_NAME "tg3" #define TG3_MAJ_NUM 3 -#define TG3_MIN_NUM 120 +#define TG3_MIN_NUM 121 #define DRV_MODULE_VERSION \ __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM) -#define DRV_MODULE_RELDATE "August 18, 2011" +#define DRV_MODULE_RELDATE "November 2, 2011" #define RESET_KIND_SHUTDOWN 0 #define RESET_KIND_INIT 1 @@ -628,19 +628,23 @@ static void tg3_ape_lock_init(struct tg3 *tp) regbase = TG3_APE_PER_LOCK_GRANT; /* Make sure the driver hasn't any stale locks. */ - for (i = 0; i < 8; i++) { - if (i == TG3_APE_LOCK_GPIO) - continue; - tg3_ape_write32(tp, regbase + 4 * i, APE_LOCK_GRANT_DRIVER); + for (i = TG3_APE_LOCK_PHY0; i <= TG3_APE_LOCK_GPIO; i++) { + switch (i) { + case TG3_APE_LOCK_PHY0: + case TG3_APE_LOCK_PHY1: + case TG3_APE_LOCK_PHY2: + case TG3_APE_LOCK_PHY3: + bit = APE_LOCK_GRANT_DRIVER; + break; + default: + if (!tp->pci_fn) + bit = APE_LOCK_GRANT_DRIVER; + else + bit = 1 << tp->pci_fn; + } + tg3_ape_write32(tp, regbase + 4 * i, bit); } - /* Clear the correct bit of the GPIO lock too. */ - if (!tp->pci_fn) - bit = APE_LOCK_GRANT_DRIVER; - else - bit = 1 << tp->pci_fn; - - tg3_ape_write32(tp, regbase + 4 * TG3_APE_LOCK_GPIO, bit); } static int tg3_ape_lock(struct tg3 *tp, int locknum) @@ -658,6 +662,10 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) return 0; case TG3_APE_LOCK_GRC: case TG3_APE_LOCK_MEM: + if (!tp->pci_fn) + bit = APE_LOCK_REQ_DRIVER; + else + bit = 1 << tp->pci_fn; break; default: return -EINVAL; @@ -673,11 +681,6 @@ static int tg3_ape_lock(struct tg3 *tp, int locknum) off = 4 * locknum; - if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn) - bit = APE_LOCK_REQ_DRIVER; - else - bit = 1 << tp->pci_fn; - tg3_ape_write32(tp, req + off, bit); /* Wait for up to 1 millisecond to acquire lock. */ @@ -710,6 +713,10 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) return; case TG3_APE_LOCK_GRC: case TG3_APE_LOCK_MEM: + if (!tp->pci_fn) + bit = APE_LOCK_GRANT_DRIVER; + else + bit = 1 << tp->pci_fn; break; default: return; @@ -720,11 +727,6 @@ static void tg3_ape_unlock(struct tg3 *tp, int locknum) else gnt = TG3_APE_PER_LOCK_GRANT; - if (locknum != TG3_APE_LOCK_GPIO || !tp->pci_fn) - bit = APE_LOCK_GRANT_DRIVER; - else - bit = 1 << tp->pci_fn; - tg3_ape_write32(tp, gnt + 4 * locknum, bit); } @@ -5927,6 +5929,18 @@ static int tg3_poll_work(struct tg3_napi *tnapi, int work_done, int budget) return work_done; } +static inline void tg3_reset_task_schedule(struct tg3 *tp) +{ + if (!test_and_set_bit(TG3_FLAG_RESET_TASK_PENDING, tp->tg3_flags)) + schedule_work(&tp->reset_task); +} + +static inline void tg3_reset_task_cancel(struct tg3 *tp) +{ + cancel_work_sync(&tp->reset_task); + tg3_flag_clear(tp, RESET_TASK_PENDING); +} + static int tg3_poll_msix(struct napi_struct *napi, int budget) { struct tg3_napi *tnapi = container_of(napi, struct tg3_napi, napi); @@ -5967,7 +5981,7 @@ static int tg3_poll_msix(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ napi_complete(napi); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); return work_done; } @@ -6002,7 +6016,7 @@ static void tg3_process_error(struct tg3 *tp) tg3_dump_state(tp); tg3_flag_set(tp, ERROR_PROCESSED); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); } static int tg3_poll(struct napi_struct *napi, int budget) @@ -6049,7 +6063,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ napi_complete(napi); - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); return work_done; } @@ -6338,11 +6352,11 @@ static void tg3_reset_task(struct work_struct *work) { struct tg3 *tp = container_of(work, struct tg3, reset_task); int err; - unsigned int restart_timer; tg3_full_lock(tp, 0); if (!netif_running(tp->dev)) { + tg3_flag_clear(tp, RESET_TASK_PENDING); tg3_full_unlock(tp); return; } @@ -6355,9 +6369,6 @@ static void tg3_reset_task(struct work_struct *work) tg3_full_lock(tp, 1); - restart_timer = tg3_flag(tp, RESTART_TIMER); - tg3_flag_clear(tp, RESTART_TIMER); - if (tg3_flag(tp, TX_RECOVERY_PENDING)) { tp->write32_tx_mbox = tg3_write32_tx_mbox; tp->write32_rx_mbox = tg3_write_flush_reg32; @@ -6372,14 +6383,13 @@ static void tg3_reset_task(struct work_struct *work) tg3_netif_start(tp); - if (restart_timer) - mod_timer(&tp->timer, jiffies + 1); - out: tg3_full_unlock(tp); if (!err) tg3_phy_start(tp); + + tg3_flag_clear(tp, RESET_TASK_PENDING); } static void tg3_tx_timeout(struct net_device *dev) @@ -6391,7 +6401,7 @@ static void tg3_tx_timeout(struct net_device *dev) tg3_dump_state(tp); } - schedule_work(&tp->reset_task); + tg3_reset_task_schedule(tp); } /* Test for DMA buffers crossing any 4GB boundaries: 4G, 8G, etc */ @@ -6442,31 +6452,26 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, hwbug = 1; if (tg3_flag(tp, 4K_FIFO_LIMIT)) { + u32 prvidx = *entry; u32 tmp_flag = flags & ~TXD_FLAG_END; - while (len > TG3_TX_BD_DMA_MAX) { + while (len > TG3_TX_BD_DMA_MAX && *budget) { u32 frag_len = TG3_TX_BD_DMA_MAX; len -= TG3_TX_BD_DMA_MAX; - if (len) { - tnapi->tx_buffers[*entry].fragmented = true; - /* Avoid the 8byte DMA problem */ - if (len <= 8) { - len += TG3_TX_BD_DMA_MAX / 2; - frag_len = TG3_TX_BD_DMA_MAX / 2; - } - } else - tmp_flag = flags; - - if (*budget) { - tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, - frag_len, tmp_flag, mss, vlan); - (*budget)--; - *entry = NEXT_TX(*entry); - } else { - hwbug = 1; - break; + /* Avoid the 8byte DMA problem */ + if (len <= 8) { + len += TG3_TX_BD_DMA_MAX / 2; + frag_len = TG3_TX_BD_DMA_MAX / 2; } + tnapi->tx_buffers[*entry].fragmented = true; + + tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, + frag_len, tmp_flag, mss, vlan); + *budget -= 1; + prvidx = *entry; + *entry = NEXT_TX(*entry); + map += frag_len; } @@ -6474,10 +6479,11 @@ static bool tg3_tx_frag_set(struct tg3_napi *tnapi, u32 *entry, u32 *budget, if (*budget) { tg3_tx_set_bd(&tnapi->tx_ring[*entry], map, len, flags, mss, vlan); - (*budget)--; + *budget -= 1; *entry = NEXT_TX(*entry); } else { hwbug = 1; + tnapi->tx_buffers[prvidx].fragmented = false; } } } else { @@ -6509,7 +6515,7 @@ static void tg3_tx_skb_unmap(struct tg3_napi *tnapi, u32 entry, int last) txb = &tnapi->tx_buffers[entry]; } - for (i = 0; i < last; i++) { + for (i = 0; i <= last; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; entry = NEXT_TX(entry); @@ -6559,6 +6565,8 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, dev_kfree_skb(new_skb); ret = -1; } else { + u32 save_entry = *entry; + base_flags |= TXD_FLAG_END; tnapi->tx_buffers[*entry].skb = new_skb; @@ -6568,7 +6576,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, if (tg3_tx_frag_set(tnapi, entry, budget, new_addr, new_skb->len, base_flags, mss, vlan)) { - tg3_tx_skb_unmap(tnapi, *entry, 0); + tg3_tx_skb_unmap(tnapi, save_entry, -1); dev_kfree_skb(new_skb); ret = -1; } @@ -6758,11 +6766,10 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags | ((skb_shinfo(skb)->nr_frags == 0) ? TXD_FLAG_END : 0), - mss, vlan)) + mss, vlan)) { would_hit_hwbug = 1; - /* Now loop through additional data fragments, and queue them. */ - if (skb_shinfo(skb)->nr_frags > 0) { + } else if (skb_shinfo(skb)->nr_frags > 0) { u32 tmp_mss = mss; if (!tg3_flag(tp, HW_TSO_1) && @@ -6784,11 +6791,14 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (dma_mapping_error(&tp->pdev->dev, mapping)) goto dma_error; - if (tg3_tx_frag_set(tnapi, &entry, &budget, mapping, + if (!budget || + tg3_tx_frag_set(tnapi, &entry, &budget, mapping, len, base_flags | ((i == last) ? TXD_FLAG_END : 0), - tmp_mss, vlan)) + tmp_mss, vlan)) { would_hit_hwbug = 1; + break; + } } } @@ -6828,7 +6838,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; dma_error: - tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, i); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; drop: dev_kfree_skb(skb); @@ -7281,7 +7291,8 @@ static void tg3_free_rings(struct tg3 *tp) if (!skb) continue; - tg3_tx_skb_unmap(tnapi, i, skb_shinfo(skb)->nr_frags); + tg3_tx_skb_unmap(tnapi, i, + skb_shinfo(skb)->nr_frags - 1); dev_kfree_skb_any(skb); } @@ -9200,7 +9211,7 @@ static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; - if (tp->irq_sync) + if (tp->irq_sync || tg3_flag(tp, RESET_TASK_PENDING)) goto restart_timer; spin_lock(&tp->lock); @@ -9223,10 +9234,9 @@ static void tg3_timer(unsigned long __opaque) } if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) { - tg3_flag_set(tp, RESTART_TIMER); spin_unlock(&tp->lock); - schedule_work(&tp->reset_task); - return; + tg3_reset_task_schedule(tp); + goto restart_timer; } } @@ -9674,15 +9684,14 @@ static int tg3_open(struct net_device *dev) struct tg3_napi *tnapi = &tp->napi[i]; err = tg3_request_irq(tp, i); if (err) { - for (i--; i >= 0; i--) + for (i--; i >= 0; i--) { + tnapi = &tp->napi[i]; free_irq(tnapi->irq_vec, tnapi); - break; + } + goto err_out2; } } - if (err) - goto err_out2; - tg3_full_lock(tp, 0); err = tg3_init_hw(tp, 1); @@ -9783,7 +9792,7 @@ static int tg3_close(struct net_device *dev) struct tg3 *tp = netdev_priv(dev); tg3_napi_disable(tp); - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); netif_tx_stop_all_queues(dev); @@ -11520,7 +11529,7 @@ static int tg3_run_loopback(struct tg3 *tp, u32 pktsz, bool tso_loopback) break; } - tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, 0); + tg3_tx_skb_unmap(tnapi, tnapi->tx_prod - 1, -1); dev_kfree_skb(skb); if (tx_idx != tnapi->tx_prod) @@ -14228,12 +14237,30 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) val = tr32(MEMARB_MODE); tw32(MEMARB_MODE, val | MEMARB_MODE_ENABLE); - if (tg3_flag(tp, PCIX_MODE)) { - pci_read_config_dword(tp->pdev, - tp->pcix_cap + PCI_X_STATUS, &val); - tp->pci_fn = val & 0x7; - } else { - tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3; + tp->pci_fn = PCI_FUNC(tp->pdev->devfn) & 3; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + tg3_flag(tp, 5780_CLASS)) { + if (tg3_flag(tp, PCIX_MODE)) { + pci_read_config_dword(tp->pdev, + tp->pcix_cap + PCI_X_STATUS, + &val); + tp->pci_fn = val & 0x7; + } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5717) { + tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val); + if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) == + NIC_SRAM_CPMUSTAT_SIG) { + tp->pci_fn = val & TG3_CPMU_STATUS_FMSK_5717; + tp->pci_fn = tp->pci_fn ? 1 : 0; + } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5719 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5720) { + tg3_read_mem(tp, NIC_SRAM_CPMU_STATUS, &val); + if ((val & NIC_SRAM_CPMUSTAT_SIG_MSK) == + NIC_SRAM_CPMUSTAT_SIG) { + tp->pci_fn = (val & TG3_CPMU_STATUS_FMSK_5719) >> + TG3_CPMU_STATUS_FSHFT_5719; + } } /* Get eeprom hw config before calling tg3_set_power_state(). @@ -15665,7 +15692,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev) if (tp->fw) release_firmware(tp->fw); - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); if (tg3_flag(tp, USE_PHYLIB)) { tg3_phy_fini(tp); @@ -15699,7 +15726,7 @@ static int tg3_suspend(struct device *device) if (!netif_running(dev)) return 0; - flush_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); tg3_phy_stop(tp); tg3_netif_stop(tp); @@ -15812,12 +15839,10 @@ static pci_ers_result_t tg3_io_error_detected(struct pci_dev *pdev, tg3_netif_stop(tp); del_timer_sync(&tp->timer); - tg3_flag_clear(tp, RESTART_TIMER); /* Want to make sure that the reset task doesn't run */ - cancel_work_sync(&tp->reset_task); + tg3_reset_task_cancel(tp); tg3_flag_clear(tp, TX_RECOVERY_PENDING); - tg3_flag_clear(tp, RESTART_TIMER); netif_device_detach(netdev); diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index f32f288134c..94b4bd049a3 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -1095,6 +1095,11 @@ #define TG3_CPMU_CLCK_ORIDE 0x00003624 #define CPMU_CLCK_ORIDE_MAC_ORIDE_EN 0x80000000 +#define TG3_CPMU_STATUS 0x0000362c +#define TG3_CPMU_STATUS_FMSK_5717 0x20000000 +#define TG3_CPMU_STATUS_FMSK_5719 0xc0000000 +#define TG3_CPMU_STATUS_FSHFT_5719 30 + #define TG3_CPMU_CLCK_STAT 0x00003630 #define CPMU_CLCK_STAT_MAC_CLCK_MASK 0x001f0000 #define CPMU_CLCK_STAT_MAC_CLCK_62_5 0x00000000 @@ -2128,6 +2133,10 @@ #define NIC_SRAM_RGMII_EXT_IBND_RX_EN 0x00000008 #define NIC_SRAM_RGMII_EXT_IBND_TX_EN 0x00000010 +#define NIC_SRAM_CPMU_STATUS 0x00000e00 +#define NIC_SRAM_CPMUSTAT_SIG 0x0000362c +#define NIC_SRAM_CPMUSTAT_SIG_MSK 0x0000ffff + #define NIC_SRAM_RX_MINI_BUFFER_DESC 0x00001000 #define NIC_SRAM_DMA_DESC_POOL_BASE 0x00002000 @@ -2344,9 +2353,13 @@ #define APE_PER_LOCK_GRANT_DRIVER 0x00001000 /* APE convenience enumerations. */ -#define TG3_APE_LOCK_GRC 1 -#define TG3_APE_LOCK_MEM 4 -#define TG3_APE_LOCK_GPIO 7 +#define TG3_APE_LOCK_PHY0 0 +#define TG3_APE_LOCK_GRC 1 +#define TG3_APE_LOCK_PHY1 2 +#define TG3_APE_LOCK_PHY2 3 +#define TG3_APE_LOCK_MEM 4 +#define TG3_APE_LOCK_PHY3 5 +#define TG3_APE_LOCK_GPIO 7 #define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 @@ -2866,7 +2879,6 @@ enum TG3_FLAGS { TG3_FLAG_JUMBO_CAPABLE, TG3_FLAG_CHIP_RESETTING, TG3_FLAG_INIT_COMPLETE, - TG3_FLAG_RESTART_TIMER, TG3_FLAG_TSO_BUG, TG3_FLAG_IS_5788, TG3_FLAG_MAX_RXPEND_64, @@ -2909,6 +2921,7 @@ enum TG3_FLAGS { TG3_FLAG_APE_HAS_NCSI, TG3_FLAG_5717_PLUS, TG3_FLAG_4K_FIFO_LIMIT, + TG3_FLAG_RESET_TASK_PENDING, /* Add new flags before this comment and TG3_FLAG_NUMBER_OF_FLAGS */ TG3_FLAG_NUMBER_OF_FLAGS, /* Last entry in enum TG3_FLAGS */ diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 98849a1fc74..b48378a41e4 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -7,6 +7,7 @@ config HAVE_NET_MACB config NET_ATMEL bool "Atmel devices" + default y depends on HAVE_NET_MACB || (ARM && ARCH_AT91RM9200) ---help--- If you have a network (Ethernet) card belonging to this class, say Y. diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index 438f4580bf6..2a22f525635 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -613,7 +613,7 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) if (!dm->wake_state) irq_set_irq_wake(dm->irq_wake, 1); - else if (dm->wake_state & !opts) + else if (dm->wake_state && !opts) irq_set_irq_wake(dm->irq_wake, 0); } diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 1cf671643d1..9de37642f09 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -7,8 +7,7 @@ config NET_VENDOR_FREESCALE default y depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || \ - (PPC_MPC52xx && PPC_BESTCOMM) + ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -24,7 +23,8 @@ if NET_VENDOR_FREESCALE config FEC bool "FEC ethernet controller (of ColdFire and some i.MX CPUs)" depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS) + ARCH_MXC || SOC_IMX28) + default ARCH_MXC || SOC_IMX28 if ARM select PHYLIB ---help--- Say Y here if you want to use the built-in 10/100 Fast ethernet diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 1124ce0a159..c136230d50b 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c @@ -232,6 +232,7 @@ struct fec_enet_private { struct platform_device *pdev; int opened; + int dev_id; /* Phylib and MDIO interface */ struct mii_bus *mii_bus; @@ -837,7 +838,7 @@ static void __inline__ fec_get_mac(struct net_device *ndev) /* Adjust MAC if using macaddr */ if (iap == macaddr) - ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->pdev->id; + ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id; } /* ------------------------------------------------------------------------- */ @@ -953,7 +954,7 @@ static int fec_enet_mii_probe(struct net_device *ndev) char mdio_bus_id[MII_BUS_ID_SIZE]; char phy_name[MII_BUS_ID_SIZE + 3]; int phy_id; - int dev_id = fep->pdev->id; + int dev_id = fep->dev_id; fep->phy_dev = NULL; @@ -1031,7 +1032,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) * mdio interface in board design, and need to be configured by * fec0 mii_bus. */ - if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && pdev->id > 0) { + if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { /* fec1 uses fec0 mii_bus */ fep->mii_bus = fec0_mii_bus; return 0; @@ -1063,7 +1064,7 @@ static int fec_enet_mii_init(struct platform_device *pdev) fep->mii_bus->read = fec_enet_mdio_read; fep->mii_bus->write = fec_enet_mdio_write; fep->mii_bus->reset = fec_enet_mdio_reset; - snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id + 1); + snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1); fep->mii_bus->priv = fep; fep->mii_bus->parent = &pdev->dev; @@ -1521,6 +1522,7 @@ fec_probe(struct platform_device *pdev) int i, irq, ret = 0; struct resource *r; const struct of_device_id *of_id; + static int dev_id; of_id = of_match_device(fec_dt_ids, &pdev->dev); if (of_id) @@ -1548,6 +1550,7 @@ fec_probe(struct platform_device *pdev) fep->hwp = ioremap(r->start, resource_size(r)); fep->pdev = pdev; + fep->dev_id = dev_id++; if (!fep->hwp) { ret = -ENOMEM; diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c index 52f4e8ad48e..4d9f84b8ab9 100644 --- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c +++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c @@ -183,28 +183,10 @@ void fsl_pq_mdio_bus_name(char *name, struct device_node *np) } EXPORT_SYMBOL_GPL(fsl_pq_mdio_bus_name); -/* Scan the bus in reverse, looking for an empty spot */ -static int fsl_pq_mdio_find_free(struct mii_bus *new_bus) -{ - int i; - - for (i = PHY_MAX_ADDR; i > 0; i--) { - u32 phy_id; - - if (get_phy_id(new_bus, i, &phy_id)) - return -1; - - if (phy_id == 0xffffffff) - break; - } - - return i; -} - -#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct device_node *np) { +#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) struct gfar __iomem *enet_regs; /* @@ -220,15 +202,15 @@ static u32 __iomem *get_gfar_tbipa(struct fsl_pq_mdio __iomem *regs, struct devi } else if (of_device_is_compatible(np, "fsl,etsec2-mdio") || of_device_is_compatible(np, "fsl,etsec2-tbi")) { return of_iomap(np, 1); - } else - return NULL; -} + } #endif + return NULL; +} -#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) { +#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) struct device_node *np = NULL; int err = 0; @@ -261,9 +243,10 @@ static int get_ucc_id_for_range(u64 start, u64 end, u32 *ucc_id) return err; else return -EINVAL; -} +#else + return -ENODEV; #endif - +} static int fsl_pq_mdio_probe(struct platform_device *ofdev) { @@ -339,19 +322,13 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev) of_device_is_compatible(np, "fsl,etsec2-mdio") || of_device_is_compatible(np, "fsl,etsec2-tbi") || of_device_is_compatible(np, "gianfar")) { -#if defined(CONFIG_GIANFAR) || defined(CONFIG_GIANFAR_MODULE) tbipa = get_gfar_tbipa(regs, np); if (!tbipa) { err = -EINVAL; goto err_free_irqs; } -#else - err = -ENODEV; - goto err_free_irqs; -#endif } else if (of_device_is_compatible(np, "fsl,ucc-mdio") || of_device_is_compatible(np, "ucc_geth_phy")) { -#if defined(CONFIG_UCC_GETH) || defined(CONFIG_UCC_GETH_MODULE) u32 id; static u32 mii_mng_master; @@ -364,10 +341,6 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev) mii_mng_master = id; ucc_set_qe_mux_mii_mng(id - 1); } -#else - err = -ENODEV; - goto err_free_irqs; -#endif } else { err = -ENODEV; goto err_free_irqs; @@ -386,16 +359,6 @@ static int fsl_pq_mdio_probe(struct platform_device *ofdev) } if (tbiaddr == -1) { - out_be32(tbipa, 0); - - tbiaddr = fsl_pq_mdio_find_free(new_bus); - } - - /* - * We define TBIPA at 0 to be illegal, opting to fail for boards that - * have PHYs at 1-31, rather than change tbipa and rescan. - */ - if (tbiaddr == 0) { err = -EBUSY; goto err_free_irqs; diff --git a/drivers/net/ethernet/ibm/ehea/ehea.h b/drivers/net/ethernet/ibm/ehea/ehea.h index 410d6a1984e..6650068c996 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea.h +++ b/drivers/net/ethernet/ibm/ehea/ehea.h @@ -61,9 +61,9 @@ #ifdef EHEA_SMALL_QUEUES #define EHEA_MAX_CQE_COUNT 1023 #define EHEA_DEF_ENTRIES_SQ 1023 -#define EHEA_DEF_ENTRIES_RQ1 4095 +#define EHEA_DEF_ENTRIES_RQ1 1023 #define EHEA_DEF_ENTRIES_RQ2 1023 -#define EHEA_DEF_ENTRIES_RQ3 1023 +#define EHEA_DEF_ENTRIES_RQ3 511 #else #define EHEA_MAX_CQE_COUNT 4080 #define EHEA_DEF_ENTRIES_SQ 4080 diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c index 37b70f7052b..bfeccbfde23 100644 --- a/drivers/net/ethernet/ibm/ehea/ehea_main.c +++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c @@ -371,7 +371,8 @@ static void ehea_update_stats(struct work_struct *work) out_herr: free_page((unsigned long)cb2); resched: - schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000)); + schedule_delayed_work(&port->stats_work, + round_jiffies_relative(msecs_to_jiffies(1000))); } static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes) @@ -2434,7 +2435,8 @@ static int ehea_open(struct net_device *dev) } mutex_unlock(&port->port_lock); - schedule_delayed_work(&port->stats_work, msecs_to_jiffies(1000)); + schedule_delayed_work(&port->stats_work, + round_jiffies_relative(msecs_to_jiffies(1000))); return ret; } diff --git a/drivers/net/ethernet/ibm/iseries_veth.c b/drivers/net/ethernet/ibm/iseries_veth.c index 4326681df38..acc31af6594 100644 --- a/drivers/net/ethernet/ibm/iseries_veth.c +++ b/drivers/net/ethernet/ibm/iseries_veth.c @@ -1421,7 +1421,7 @@ static void veth_receive(struct veth_lpar_connection *cnx, /* FIXME: do we need this? */ memset(local_list, 0, sizeof(local_list)); - memset(remote_list, 0, sizeof(VETH_MAX_FRAMES_PER_MSG)); + memset(remote_list, 0, sizeof(remote_list)); /* a 0 address marks the end of the valid entries */ if (senddata->addr[startchunk] == 0) diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 61029dc7fa6..76213162fbe 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -5,7 +5,11 @@ config NET_VENDOR_INTEL bool "Intel devices" default y - depends on PCI || PCI_MSI + depends on PCI || PCI_MSI || ISA || ISA_DMA_API || ARM || \ + ARCH_ACORN || MCA || MCA_LEGACY || SNI_RM || SUN3 || \ + GSC || BVME6000 || MVME16x || ARCH_ENP2611 || \ + (ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR) || \ + EXPERIMENTAL ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index db95731863d..00fcd39ad66 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -442,12 +442,14 @@ static int ixgbe_set_vf_macvlan(struct ixgbe_adapter *adapter, int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter) { +#ifdef CONFIG_PCI_IOV int i; for (i = 0; i < adapter->num_vfs; i++) { if (adapter->vfinfo[i].vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) return true; } +#endif return false; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 4a5d8897faa..df04f1a3857 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -42,11 +42,11 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting); int ixgbe_ndo_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi); void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter); -#ifdef CONFIG_PCI_IOV void ixgbe_disable_sriov(struct ixgbe_adapter *adapter); +int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); +#ifdef CONFIG_PCI_IOV void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, const struct ixgbe_info *ii); -int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); #endif diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 7becff1f387..76b84573566 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -1745,6 +1745,112 @@ jme_phy_off(struct jme_adapter *jme) } static int +jme_phy_specreg_read(struct jme_adapter *jme, u32 specreg) +{ + u32 phy_addr; + + phy_addr = JM_PHY_SPEC_REG_READ | specreg; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG, + phy_addr); + return jme_mdio_read(jme->dev, jme->mii_if.phy_id, + JM_PHY_SPEC_DATA_REG); +} + +static void +jme_phy_specreg_write(struct jme_adapter *jme, u32 ext_reg, u32 phy_data) +{ + u32 phy_addr; + + phy_addr = JM_PHY_SPEC_REG_WRITE | ext_reg; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_DATA_REG, + phy_data); + jme_mdio_write(jme->dev, jme->mii_if.phy_id, JM_PHY_SPEC_ADDR_REG, + phy_addr); +} + +static int +jme_phy_calibration(struct jme_adapter *jme) +{ + u32 ctrl1000, phy_data; + + jme_phy_off(jme); + jme_phy_on(jme); + /* Enabel PHY test mode 1 */ + ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); + ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK; + ctrl1000 |= PHY_GAD_TEST_MODE_1; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000); + + phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG); + phy_data &= ~JM_PHY_EXT_COMM_2_CALI_MODE_0; + phy_data |= JM_PHY_EXT_COMM_2_CALI_LATCH | + JM_PHY_EXT_COMM_2_CALI_ENABLE; + jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data); + msleep(20); + phy_data = jme_phy_specreg_read(jme, JM_PHY_EXT_COMM_2_REG); + phy_data &= ~(JM_PHY_EXT_COMM_2_CALI_ENABLE | + JM_PHY_EXT_COMM_2_CALI_MODE_0 | + JM_PHY_EXT_COMM_2_CALI_LATCH); + jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_2_REG, phy_data); + + /* Disable PHY test mode */ + ctrl1000 = jme_mdio_read(jme->dev, jme->mii_if.phy_id, MII_CTRL1000); + ctrl1000 &= ~PHY_GAD_TEST_MODE_MSK; + jme_mdio_write(jme->dev, jme->mii_if.phy_id, MII_CTRL1000, ctrl1000); + return 0; +} + +static int +jme_phy_setEA(struct jme_adapter *jme) +{ + u32 phy_comm0 = 0, phy_comm1 = 0; + u8 nic_ctrl; + + pci_read_config_byte(jme->pdev, PCI_PRIV_SHARE_NICCTRL, &nic_ctrl); + if ((nic_ctrl & 0x3) == JME_FLAG_PHYEA_ENABLE) + return 0; + + switch (jme->pdev->device) { + case PCI_DEVICE_ID_JMICRON_JMC250: + if (((jme->chip_main_rev == 5) && + ((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) || + (jme->chip_sub_rev == 3))) || + (jme->chip_main_rev >= 6)) { + phy_comm0 = 0x008A; + phy_comm1 = 0x4109; + } + if ((jme->chip_main_rev == 3) && + ((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2))) + phy_comm0 = 0xE088; + break; + case PCI_DEVICE_ID_JMICRON_JMC260: + if (((jme->chip_main_rev == 5) && + ((jme->chip_sub_rev == 0) || (jme->chip_sub_rev == 1) || + (jme->chip_sub_rev == 3))) || + (jme->chip_main_rev >= 6)) { + phy_comm0 = 0x008A; + phy_comm1 = 0x4109; + } + if ((jme->chip_main_rev == 3) && + ((jme->chip_sub_rev == 1) || (jme->chip_sub_rev == 2))) + phy_comm0 = 0xE088; + if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 0)) + phy_comm0 = 0x608A; + if ((jme->chip_main_rev == 2) && (jme->chip_sub_rev == 2)) + phy_comm0 = 0x408A; + break; + default: + return -ENODEV; + } + if (phy_comm0) + jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_0_REG, phy_comm0); + if (phy_comm1) + jme_phy_specreg_write(jme, JM_PHY_EXT_COMM_1_REG, phy_comm1); + + return 0; +} + +static int jme_open(struct net_device *netdev) { struct jme_adapter *jme = netdev_priv(netdev); @@ -1769,7 +1875,8 @@ jme_open(struct net_device *netdev) jme_set_settings(netdev, &jme->old_ecmd); else jme_reset_phy_processor(jme); - + jme_phy_calibration(jme); + jme_phy_setEA(jme); jme_reset_link(jme); return 0; @@ -3184,7 +3291,8 @@ jme_resume(struct device *dev) jme_set_settings(netdev, &jme->old_ecmd); else jme_reset_phy_processor(jme); - + jme_phy_calibration(jme); + jme_phy_setEA(jme); jme_start_irq(jme); netif_device_attach(netdev); @@ -3239,4 +3347,3 @@ MODULE_DESCRIPTION("JMicron JMC2x0 PCI Express Ethernet driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); MODULE_DEVICE_TABLE(pci, jme_pci_tbl); - diff --git a/drivers/net/ethernet/jme.h b/drivers/net/ethernet/jme.h index 02ea27c1dcb..4304072bd3c 100644 --- a/drivers/net/ethernet/jme.h +++ b/drivers/net/ethernet/jme.h @@ -760,6 +760,25 @@ enum jme_rxmcs_bits { RXMCS_CHECKSUM, }; +/* Extern PHY common register 2 */ + +#define PHY_GAD_TEST_MODE_1 0x00002000 +#define PHY_GAD_TEST_MODE_MSK 0x0000E000 +#define JM_PHY_SPEC_REG_READ 0x00004000 +#define JM_PHY_SPEC_REG_WRITE 0x00008000 +#define PHY_CALIBRATION_DELAY 20 +#define JM_PHY_SPEC_ADDR_REG 0x1E +#define JM_PHY_SPEC_DATA_REG 0x1F + +#define JM_PHY_EXT_COMM_0_REG 0x30 +#define JM_PHY_EXT_COMM_1_REG 0x31 +#define JM_PHY_EXT_COMM_2_REG 0x32 +#define JM_PHY_EXT_COMM_2_CALI_ENABLE 0x01 +#define JM_PHY_EXT_COMM_2_CALI_MODE_0 0x02 +#define JM_PHY_EXT_COMM_2_CALI_LATCH 0x10 +#define PCI_PRIV_SHARE_NICCTRL 0xF5 +#define JME_FLAG_PHYEA_ENABLE 0x2 + /* * Wakeup Frame setup interface registers */ diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 6bb2b9506ca..0b3567ab812 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -34,6 +34,8 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/io.h> +#include <linux/dma-mapping.h> +#include <linux/module.h> #include <asm/checksum.h> diff --git a/drivers/net/ethernet/marvell/skge.c b/drivers/net/ethernet/marvell/skge.c index c7b60839ac9..dea0cb4400e 100644 --- a/drivers/net/ethernet/marvell/skge.c +++ b/drivers/net/ethernet/marvell/skge.c @@ -2606,6 +2606,9 @@ static int skge_up(struct net_device *dev) spin_unlock_irq(&hw->hw_lock); napi_enable(&skge->napi); + + skge_set_multicast(dev); + return 0; free_tx_ring: diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index cbd026f3bc5..7803efa46eb 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -50,7 +50,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "1.29" +#define DRV_VERSION "1.30" /* * The Yukon II chipset takes 64 bit command blocks (called list elements) @@ -68,7 +68,7 @@ #define MAX_SKB_TX_LE (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1)) #define TX_MIN_PENDING (MAX_SKB_TX_LE+1) #define TX_MAX_PENDING 1024 -#define TX_DEF_PENDING 127 +#define TX_DEF_PENDING 63 #define TX_WATCHDOG (5 * HZ) #define NAPI_WEIGHT 64 @@ -366,17 +366,6 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) gm_phy_write(hw, port, PHY_MARV_FE_SPEC_2, spec); } } else { - if (hw->chip_id >= CHIP_ID_YUKON_OPT) { - u16 ctrl2 = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL_2); - - /* enable PHY Reverse Auto-Negotiation */ - ctrl2 |= 1u << 13; - - /* Write PHY changes (SW-reset must follow) */ - gm_phy_write(hw, port, PHY_MARV_EXT_CTRL_2, ctrl2); - } - - /* disable energy detect */ ctrl &= ~PHY_M_PC_EN_DET_MSK; @@ -880,6 +869,7 @@ static void sky2_wol_init(struct sky2_port *sky2) /* block receiver */ sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); + sky2_read32(hw, B0_CTST); } static void sky2_set_tx_stfwd(struct sky2_hw *hw, unsigned port) @@ -1285,6 +1275,14 @@ static void rx_set_checksum(struct sky2_port *sky2) ? BMU_ENA_RX_CHKSUM : BMU_DIS_RX_CHKSUM); } +/* + * Fixed initial key as seed to RSS. + */ +static const uint32_t rss_init_key[10] = { + 0x7c3351da, 0x51c5cf4e, 0x44adbdd1, 0xe8d38d18, 0x48897c43, + 0xb1d60e7e, 0x6a3dd760, 0x01a2e453, 0x16f46f13, 0x1a0e7b30 +}; + /* Enable/disable receive hash calculation (RSS) */ static void rx_set_rss(struct net_device *dev, u32 features) { @@ -1300,12 +1298,9 @@ static void rx_set_rss(struct net_device *dev, u32 features) /* Program RSS initial values */ if (features & NETIF_F_RXHASH) { - u32 key[nkeys]; - - get_random_bytes(key, nkeys * sizeof(u32)); for (i = 0; i < nkeys; i++) sky2_write32(hw, SK_REG(sky2->port, RSS_KEY + i * 4), - key[i]); + rss_init_key[i]); /* Need to turn on (undocumented) flag to make hashing work */ sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), @@ -1728,6 +1723,8 @@ static int sky2_setup_irq(struct sky2_hw *hw, const char *name) if (err) dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq); else { + hw->flags |= SKY2_HW_IRQ_SETUP; + napi_enable(&hw->napi); sky2_write32(hw, B0_IMSK, Y2_IS_BASE); sky2_read32(hw, B0_IMSK); @@ -1738,7 +1735,7 @@ static int sky2_setup_irq(struct sky2_hw *hw, const char *name) /* Bring up network interface. */ -static int sky2_up(struct net_device *dev) +static int sky2_open(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -1758,6 +1755,11 @@ static int sky2_up(struct net_device *dev) sky2_hw_up(sky2); + if (hw->chip_id == CHIP_ID_YUKON_OPT || + hw->chip_id == CHIP_ID_YUKON_PRM || + hw->chip_id == CHIP_ID_YUKON_OP_2) + imask |= Y2_IS_PHY_QLNK; /* enable PHY Quick Link */ + /* Enable interrupts from phy/mac for port */ imask = sky2_read32(hw, B0_IMSK); imask |= portirq_msk[port]; @@ -2051,6 +2053,8 @@ static void sky2_tx_reset(struct sky2_hw *hw, unsigned port) sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), RB_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); + + sky2_read32(hw, B0_CTST); } static void sky2_hw_down(struct sky2_port *sky2) @@ -2101,7 +2105,7 @@ static void sky2_hw_down(struct sky2_port *sky2) } /* Network shutdown */ -static int sky2_down(struct net_device *dev) +static int sky2_close(struct net_device *dev) { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; @@ -2112,15 +2116,22 @@ static int sky2_down(struct net_device *dev) netif_info(sky2, ifdown, dev, "disabling interface\n"); - /* Disable port IRQ */ - sky2_write32(hw, B0_IMSK, - sky2_read32(hw, B0_IMSK) & ~portirq_msk[sky2->port]); - sky2_read32(hw, B0_IMSK); - if (hw->ports == 1) { + sky2_write32(hw, B0_IMSK, 0); + sky2_read32(hw, B0_IMSK); + napi_disable(&hw->napi); free_irq(hw->pdev->irq, hw); + hw->flags &= ~SKY2_HW_IRQ_SETUP; } else { + u32 imask; + + /* Disable port IRQ */ + imask = sky2_read32(hw, B0_IMSK); + imask &= ~portirq_msk[sky2->port]; + sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); + synchronize_irq(hw->pdev->irq); napi_synchronize(&hw->napi); } @@ -2598,7 +2609,7 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last) if (netif_running(dev)) { sky2_tx_complete(sky2, last); - /* Wake unless it's detached, and called e.g. from sky2_down() */ + /* Wake unless it's detached, and called e.g. from sky2_close() */ if (tx_avail(sky2) > MAX_SKB_TX_LE + 4) netif_wake_queue(dev); } @@ -3269,7 +3280,6 @@ static void sky2_reset(struct sky2_hw *hw) hw->chip_id == CHIP_ID_YUKON_PRM || hw->chip_id == CHIP_ID_YUKON_OP_2) { u16 reg; - u32 msk; if (hw->chip_id == CHIP_ID_YUKON_OPT && hw->chip_rev == 0) { /* disable PCI-E PHY power down (set PHY reg 0x80, bit 7 */ @@ -3292,11 +3302,6 @@ static void sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); sky2_pci_write16(hw, PSM_CONFIG_REG4, reg); - /* enable PHY Quick Link */ - msk = sky2_read32(hw, B0_IMSK); - msk |= Y2_IS_PHY_QLNK; - sky2_write32(hw, B0_IMSK, msk); - /* check if PSMv2 was running before */ reg = sky2_pci_read16(hw, PSM_CONFIG_REG3); if (reg & PCI_EXP_LNKCTL_ASPMC) @@ -3394,7 +3399,7 @@ static void sky2_detach(struct net_device *dev) netif_tx_lock(dev); netif_device_detach(dev); /* stop txq */ netif_tx_unlock(dev); - sky2_down(dev); + sky2_close(dev); } } @@ -3404,7 +3409,7 @@ static int sky2_reattach(struct net_device *dev) int err = 0; if (netif_running(dev)) { - err = sky2_up(dev); + err = sky2_open(dev); if (err) { netdev_info(dev, "could not restart %d\n", err); dev_close(dev); @@ -3421,10 +3426,13 @@ static void sky2_all_down(struct sky2_hw *hw) { int i; - sky2_read32(hw, B0_IMSK); - sky2_write32(hw, B0_IMSK, 0); - synchronize_irq(hw->pdev->irq); - napi_disable(&hw->napi); + if (hw->flags & SKY2_HW_IRQ_SETUP) { + sky2_read32(hw, B0_IMSK); + sky2_write32(hw, B0_IMSK, 0); + + synchronize_irq(hw->pdev->irq); + napi_disable(&hw->napi); + } for (i = 0; i < hw->ports; i++) { struct net_device *dev = hw->dev[i]; @@ -3457,11 +3465,12 @@ static void sky2_all_up(struct sky2_hw *hw) netif_wake_queue(dev); } - sky2_write32(hw, B0_IMSK, imask); - sky2_read32(hw, B0_IMSK); - - sky2_read32(hw, B0_Y2_SP_LISR); - napi_enable(&hw->napi); + if (hw->flags & SKY2_HW_IRQ_SETUP) { + sky2_write32(hw, B0_IMSK, imask); + sky2_read32(hw, B0_IMSK); + sky2_read32(hw, B0_Y2_SP_LISR); + napi_enable(&hw->napi); + } } static void sky2_restart(struct work_struct *work) @@ -4082,6 +4091,16 @@ static int sky2_set_coalesce(struct net_device *dev, return 0; } +/* + * Hardware is limited to min of 128 and max of 2048 for ring size + * and rounded up to next power of two + * to avoid division in modulus calclation + */ +static unsigned long roundup_ring_size(unsigned long pending) +{ + return max(128ul, roundup_pow_of_two(pending+1)); +} + static void sky2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { @@ -4109,7 +4128,7 @@ static int sky2_set_ringparam(struct net_device *dev, sky2->rx_pending = ering->rx_pending; sky2->tx_pending = ering->tx_pending; - sky2->tx_ring_size = roundup_pow_of_two(sky2->tx_pending+1); + sky2->tx_ring_size = roundup_ring_size(sky2->tx_pending); return sky2_reattach(dev); } @@ -4567,7 +4586,7 @@ static int sky2_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct sky2_port *sky2 = netdev_priv(dev); - if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug) + if (dev->netdev_ops->ndo_open != sky2_open || !sky2_debug) return NOTIFY_DONE; switch (event) { @@ -4632,8 +4651,8 @@ static __exit void sky2_debug_cleanup(void) not allowing netpoll on second port */ static const struct net_device_ops sky2_netdev_ops[2] = { { - .ndo_open = sky2_up, - .ndo_stop = sky2_down, + .ndo_open = sky2_open, + .ndo_stop = sky2_close, .ndo_start_xmit = sky2_xmit_frame, .ndo_do_ioctl = sky2_ioctl, .ndo_validate_addr = eth_validate_addr, @@ -4649,8 +4668,8 @@ static const struct net_device_ops sky2_netdev_ops[2] = { #endif }, { - .ndo_open = sky2_up, - .ndo_stop = sky2_down, + .ndo_open = sky2_open, + .ndo_stop = sky2_close, .ndo_start_xmit = sky2_xmit_frame, .ndo_do_ioctl = sky2_ioctl, .ndo_validate_addr = eth_validate_addr, @@ -4703,7 +4722,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; - sky2->tx_ring_size = roundup_pow_of_two(TX_DEF_PENDING+1); + sky2->tx_ring_size = roundup_ring_size(TX_DEF_PENDING); sky2->rx_pending = RX_DEF_PENDING; hw->dev[port] = dev; diff --git a/drivers/net/ethernet/marvell/sky2.h b/drivers/net/ethernet/marvell/sky2.h index 0af31b8b5f1..ff6f58bf822 100644 --- a/drivers/net/ethernet/marvell/sky2.h +++ b/drivers/net/ethernet/marvell/sky2.h @@ -2287,6 +2287,7 @@ struct sky2_hw { #define SKY2_HW_RSS_BROKEN 0x00000100 #define SKY2_HW_VLAN_BROKEN 0x00000200 #define SKY2_HW_RSS_CHKSUM 0x00000400 /* RSS requires chksum */ +#define SKY2_HW_IRQ_SETUP 0x00000800 u8 chip_id; u8 chip_rev; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 227997d775e..5829e0b47e7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -147,6 +147,7 @@ void mlx4_en_destroy_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); if (priv->mdev->dev->caps.comp_pool && cq->vector) mlx4_release_eq(priv->mdev->dev, cq->vector); + cq->vector = 0; cq->buf_size = 0; cq->buf = NULL; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index b89c36dbf5b..c2df6c35860 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -581,6 +581,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud * Packet is OK - process it. */ length = be32_to_cpu(cqe->byte_cnt); + length -= ring->fcs_del; ring->bytes += length; ring->packets++; @@ -813,8 +814,11 @@ static int mlx4_en_config_rss_qp(struct mlx4_en_priv *priv, int qpn, context->db_rec_addr = cpu_to_be64(ring->wqres.db.dma); /* Cancel FCS removal if FW allows */ - if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) + if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) { context->param3 |= cpu_to_be32(1 << 29); + ring->fcs_del = ETH_FCS_LEN; + } else + ring->fcs_del = 0; err = mlx4_qp_to_ready(mdev->dev, &ring->wqres.mtt, context, qp, state); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 8fda331c65d..207b5add3ca 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -272,6 +272,7 @@ struct mlx4_en_rx_ring { u32 prod; u32 cons; u32 buf_size; + u8 fcs_del; void *buf; void *rx_info; unsigned long bytes; diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig index 4a6b9fd073b..eb836f770f5 100644 --- a/drivers/net/ethernet/natsemi/Kconfig +++ b/drivers/net/ethernet/natsemi/Kconfig @@ -5,7 +5,10 @@ config NET_VENDOR_NATSEMI bool "National Semi-conductor devices" default y - depends on MCA || MAC || MACH_JAZZ || PCI || XTENSA_PLATFORM_XT2000 + depends on AMIGA_PCMCIA || ARM || EISA || EXPERIMENTAL || H8300 || \ + ISA || M32R || MAC || MACH_JAZZ || MACH_TX49XX || MCA || \ + MCA_LEGACY || MIPS || PCI || PCMCIA || SUPERH || \ + XTENSA_PLATFORM_XT2000 || ZORRO ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 1e37eb98c4e..1c61d36e657 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -609,7 +609,7 @@ struct nv_ethtool_str { }; static const struct nv_ethtool_str nv_estats_str[] = { - { "tx_bytes" }, + { "tx_bytes" }, /* includes Ethernet FCS CRC */ { "tx_zero_rexmt" }, { "tx_one_rexmt" }, { "tx_many_rexmt" }, @@ -637,7 +637,7 @@ static const struct nv_ethtool_str nv_estats_str[] = { /* version 2 stats */ { "tx_deferral" }, { "tx_packets" }, - { "rx_bytes" }, + { "rx_bytes" }, /* includes Ethernet FCS CRC */ { "tx_pause" }, { "rx_pause" }, { "rx_drop_frame" }, @@ -649,7 +649,7 @@ static const struct nv_ethtool_str nv_estats_str[] = { }; struct nv_ethtool_stats { - u64 tx_bytes; + u64 tx_bytes; /* should be ifconfig->tx_bytes + 4*tx_packets */ u64 tx_zero_rexmt; u64 tx_one_rexmt; u64 tx_many_rexmt; @@ -670,14 +670,14 @@ struct nv_ethtool_stats { u64 rx_unicast; u64 rx_multicast; u64 rx_broadcast; - u64 rx_packets; + u64 rx_packets; /* should be ifconfig->rx_packets */ u64 rx_errors_total; u64 tx_errors_total; /* version 2 stats */ u64 tx_deferral; - u64 tx_packets; - u64 rx_bytes; + u64 tx_packets; /* should be ifconfig->tx_packets */ + u64 rx_bytes; /* should be ifconfig->rx_bytes + 4*rx_packets */ u64 tx_pause; u64 rx_pause; u64 rx_drop_frame; @@ -1682,6 +1682,7 @@ static void nv_get_hw_stats(struct net_device *dev) np->estats.tx_pause += readl(base + NvRegTxPause); np->estats.rx_pause += readl(base + NvRegRxPause); np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame); + np->estats.rx_errors_total += np->estats.rx_drop_frame; } if (np->driver_data & DEV_HAS_STATISTICS_V3) { @@ -1705,12 +1706,22 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev) if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_STATISTICS_V3)) { nv_get_hw_stats(dev); + /* + * Note: because HW stats are not always available and + * for consistency reasons, the following ifconfig + * stats are managed by software: rx_bytes, tx_bytes, + * rx_packets and tx_packets. The related hardware + * stats reported by ethtool should be equivalent to + * these ifconfig stats, with 4 additional bytes per + * packet (Ethernet FCS CRC). + */ + /* copy to net_device stats */ - dev->stats.tx_bytes = np->estats.tx_bytes; dev->stats.tx_fifo_errors = np->estats.tx_fifo_errors; dev->stats.tx_carrier_errors = np->estats.tx_carrier_errors; dev->stats.rx_crc_errors = np->estats.rx_crc_errors; dev->stats.rx_over_errors = np->estats.rx_over_errors; + dev->stats.rx_fifo_errors = np->estats.rx_drop_frame; dev->stats.rx_errors = np->estats.rx_errors_total; dev->stats.tx_errors = np->estats.tx_errors_total; } @@ -2099,10 +2110,10 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2141,13 +2152,13 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) /* setup the fragments */ for (i = 0; i < fragments; i++) { const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2159,12 +2170,12 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev) put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.orig)) put_tx = np->first_tx.orig; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2213,10 +2224,10 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* add fragments to entries count */ for (i = 0; i < fragments; i++) { - u32 size = skb_frag_size(&skb_shinfo(skb)->frags[i]); + u32 frag_size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - entries += (size >> NV_TX2_TSO_MAX_SHIFT) + - ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + entries += (frag_size >> NV_TX2_TSO_MAX_SHIFT) + + ((frag_size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); } spin_lock_irqsave(&np->lock, flags); @@ -2257,13 +2268,13 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, /* setup the fragments */ for (i = 0; i < fragments; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - u32 size = skb_frag_size(frag); + u32 frag_size = skb_frag_size(frag); offset = 0; do { prev_tx = put_tx; prev_tx_ctx = np->put_tx_ctx; - bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size; np->put_tx_ctx->dma = skb_frag_dma_map( &np->pci_dev->dev, frag, offset, @@ -2276,12 +2287,12 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb, put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); offset += bcnt; - size -= bcnt; + frag_size -= bcnt; if (unlikely(put_tx++ == np->last_tx.ex)) put_tx = np->first_tx.ex; if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx)) np->put_tx_ctx = np->first_tx_ctx; - } while (size); + } while (frag_size); } /* set last fragment flag */ @@ -2374,13 +2385,8 @@ static int nv_tx_done(struct net_device *dev, int limit) if (np->desc_ver == DESC_VER_1) { if (flags & NV_TX_LASTPACKET) { if (flags & NV_TX_ERROR) { - if (flags & NV_TX_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX_RETRYERROR) && !(flags & NV_TX_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; } else { dev->stats.tx_packets++; dev->stats.tx_bytes += np->get_tx_ctx->skb->len; @@ -2392,13 +2398,8 @@ static int nv_tx_done(struct net_device *dev, int limit) } else { if (flags & NV_TX2_LASTPACKET) { if (flags & NV_TX2_ERROR) { - if (flags & NV_TX2_UNDERFLOW) - dev->stats.tx_fifo_errors++; - if (flags & NV_TX2_CARRIERLOST) - dev->stats.tx_carrier_errors++; if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) nv_legacybackoff_reseed(dev); - dev->stats.tx_errors++; } else { dev->stats.tx_packets++; dev->stats.tx_bytes += np->get_tx_ctx->skb->len; @@ -2434,15 +2435,16 @@ static int nv_tx_done_optimized(struct net_device *dev, int limit) nv_unmap_txskb(np, np->get_tx_ctx); if (flags & NV_TX2_LASTPACKET) { - if (!(flags & NV_TX2_ERROR)) - dev->stats.tx_packets++; - else { + if (flags & NV_TX2_ERROR) { if ((flags & NV_TX2_RETRYERROR) && !(flags & NV_TX2_RETRYCOUNT_MASK)) { if (np->driver_data & DEV_HAS_GEAR_MODE) nv_gear_backoff_reseed(dev); else nv_legacybackoff_reseed(dev); } + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += np->get_tx_ctx->skb->len; } dev_kfree_skb_any(np->get_tx_ctx->skb); @@ -2636,7 +2638,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX_ERROR_MASK) == NV_RX_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2650,11 +2651,6 @@ static int nv_rx_process(struct net_device *dev, int limit) else { if (flags & NV_RX_MISSEDFRAME) dev->stats.rx_missed_errors++; - if (flags & NV_RX_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2670,7 +2666,6 @@ static int nv_rx_process(struct net_device *dev, int limit) if ((flags & NV_RX2_ERROR_MASK) == NV_RX2_ERROR4) { len = nv_getlen(dev, skb->data, len); if (len < 0) { - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2682,11 +2677,6 @@ static int nv_rx_process(struct net_device *dev, int limit) } /* the rest are hard errors */ else { - if (flags & NV_RX2_CRCERR) - dev->stats.rx_crc_errors++; - if (flags & NV_RX2_OVERFLOW) - dev->stats.rx_over_errors++; - dev->stats.rx_errors++; dev_kfree_skb(skb); goto next_pkt; } @@ -2787,7 +2777,6 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) __vlan_hwaccel_put_tag(skb, vid); } napi_gro_receive(&np->napi, skb); - dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { @@ -2962,11 +2951,11 @@ static void nv_set_multicast(struct net_device *dev) struct netdev_hw_addr *ha; netdev_for_each_mc_addr(ha, dev) { - unsigned char *addr = ha->addr; + unsigned char *hw_addr = ha->addr; u32 a, b; - a = le32_to_cpu(*(__le32 *) addr); - b = le16_to_cpu(*(__le16 *) (&addr[4])); + a = le32_to_cpu(*(__le32 *) hw_addr); + b = le16_to_cpu(*(__le16 *) (&hw_addr[4])); alwaysOn[0] &= a; alwaysOff[0] &= ~a; alwaysOn[1] &= b; @@ -3398,7 +3387,8 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; - writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "tx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3509,7 +3499,8 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; - writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "rx irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3553,7 +3544,8 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data) for (i = 0;; i++) { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; - writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); + writel(events, base + NvRegMSIXIrqStatus); + netdev_dbg(dev, "irq events: %08x\n", events); if (!(events & np->irqmask)) break; @@ -3617,10 +3609,10 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data) if (!(np->msi_flags & NV_MSI_X_ENABLED)) { events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegIrqStatus); } else { events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); + writel(events & NVREG_IRQ_TIMER, base + NvRegMSIXIrqStatus); } pci_push(base); if (!(events & NVREG_IRQ_TIMER)) @@ -4566,7 +4558,7 @@ static void nv_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *e struct fe_priv *np = netdev_priv(dev); /* update stats */ - nv_do_stats_poll((unsigned long)dev); + nv_get_hw_stats(dev); memcpy(buffer, &np->estats, nv_get_sset_count(dev, ETH_SS_STATS)*sizeof(u64)); } diff --git a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c index 9c075ea2682..9cb5f912e48 100644 --- a/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c +++ b/drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_param.c @@ -18,8 +18,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */ -#include <linux/module.h> /* for __MODULE_STRING */ #include "pch_gbe.h" +#include <linux/module.h> /* for __MODULE_STRING */ #define OPTION_UNSET -1 #define OPTION_DISABLED 0 diff --git a/drivers/net/ethernet/pasemi/Makefile b/drivers/net/ethernet/pasemi/Makefile index 05db5434baf..90497ffb1ac 100644 --- a/drivers/net/ethernet/pasemi/Makefile +++ b/drivers/net/ethernet/pasemi/Makefile @@ -2,4 +2,5 @@ # Makefile for the A Semi network device drivers. # -obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o pasemi_mac_ethtool.o +obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o +pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o diff --git a/drivers/net/ethernet/qlogic/qlge/qlge.h b/drivers/net/ethernet/qlogic/qlge/qlge.h index 8731f79c9ef..b8478aab050 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge.h +++ b/drivers/net/ethernet/qlogic/qlge/qlge.h @@ -58,10 +58,8 @@ #define TX_DESC_PER_IOCB 8 -/* The maximum number of frags we handle is based - * on PAGE_SIZE... - */ -#if (PAGE_SHIFT == 12) || (PAGE_SHIFT == 13) /* 4k & 8k pages */ + +#if ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2) > 0 #define TX_DESC_PER_OAL ((MAX_SKB_FRAGS - TX_DESC_PER_IOCB) + 2) #else /* all other page sizes */ #define TX_DESC_PER_OAL 0 @@ -1353,7 +1351,7 @@ struct tx_ring_desc { struct ob_mac_iocb_req *queue_entry; u32 index; struct oal oal; - struct map_list map[MAX_SKB_FRAGS + 1]; + struct map_list map[MAX_SKB_FRAGS + 2]; int map_cnt; struct tx_ring_desc *next; }; diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index 1fc01ca72b4..4bf68cfef39 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -940,7 +940,7 @@ static void r6040_multicast_list(struct net_device *dev) iowrite16(lp->mcr0, ioaddr + MCR0); /* Fill the MAC hash tables with their values */ - if (lp->mcr0 && MCR0_HASH_EN) { + if (lp->mcr0 & MCR0_HASH_EN) { iowrite16(hash_table[0], ioaddr + MAR0); iowrite16(hash_table[1], ioaddr + MAR1); iowrite16(hash_table[2], ioaddr + MAR2); diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 92b45f08858..c8f47f17186 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -477,7 +477,6 @@ enum rtl_register_content { /* Config1 register p.24 */ LEDS1 = (1 << 7), LEDS0 = (1 << 6), - MSIEnable = (1 << 5), /* Enable Message Signaled Interrupt */ Speed_down = (1 << 4), MEMMAP = (1 << 3), IOMAP = (1 << 2), @@ -485,6 +484,7 @@ enum rtl_register_content { PMEnable = (1 << 0), /* Power Management Enable */ /* Config2 register p. 25 */ + MSIEnable = (1 << 5), /* 8169 only. Reserved in the 8168. */ PCI_Clock_66MHz = 0x01, PCI_Clock_33MHz = 0x00, @@ -1183,11 +1183,13 @@ static u8 rtl8168d_efuse_read(void __iomem *ioaddr, int reg_addr) return value; } -static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr) +static void rtl8169_irq_mask_and_ack(struct rtl8169_private *tp) { - RTL_W16(IntrMask, 0x0000); + void __iomem *ioaddr = tp->mmio_addr; - RTL_W16(IntrStatus, 0xffff); + RTL_W16(IntrMask, 0x0000); + RTL_W16(IntrStatus, tp->intr_event); + RTL_R8(ChipCmd); } static unsigned int rtl8169_tbi_reset_pending(struct rtl8169_private *tp) @@ -1292,7 +1294,7 @@ static void __rtl8169_check_link_status(struct net_device *dev, netif_carrier_off(dev); netif_info(tp, ifdown, dev, "link down\n"); if (pm) - pm_schedule_suspend(&tp->pci_dev->dev, 100); + pm_schedule_suspend(&tp->pci_dev->dev, 5000); } spin_unlock_irqrestore(&tp->lock, flags); } @@ -3424,22 +3426,24 @@ static const struct rtl_cfg_info { }; /* Cfg9346_Unlock assumed. */ -static unsigned rtl_try_msi(struct pci_dev *pdev, void __iomem *ioaddr, +static unsigned rtl_try_msi(struct rtl8169_private *tp, const struct rtl_cfg_info *cfg) { + void __iomem *ioaddr = tp->mmio_addr; unsigned msi = 0; u8 cfg2; cfg2 = RTL_R8(Config2) & ~MSIEnable; if (cfg->features & RTL_FEATURE_MSI) { - if (pci_enable_msi(pdev)) { - dev_info(&pdev->dev, "no MSI. Back to INTx.\n"); + if (pci_enable_msi(tp->pci_dev)) { + netif_info(tp, hw, tp->dev, "no MSI. Back to INTx.\n"); } else { cfg2 |= MSIEnable; msi = RTL_FEATURE_MSI; } } - RTL_W8(Config2, cfg2); + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) + RTL_W8(Config2, cfg2); return msi; } @@ -3933,8 +3937,6 @@ static void rtl_hw_reset(struct rtl8169_private *tp) break; udelay(100); } - - rtl8169_init_ring_indexes(tp); } static int __devinit @@ -4077,7 +4079,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->features |= RTL_FEATURE_WOL; if ((RTL_R8(Config5) & (UWF | BWF | MWF)) != 0) tp->features |= RTL_FEATURE_WOL; - tp->features |= rtl_try_msi(pdev, ioaddr, cfg); + tp->features |= rtl_try_msi(tp, cfg); RTL_W8(Cfg9346, Cfg9346_Lock); if (rtl_tbi_enabled(tp)) { @@ -4339,7 +4341,7 @@ static void rtl8169_hw_reset(struct rtl8169_private *tp) void __iomem *ioaddr = tp->mmio_addr; /* Disable interrupts */ - rtl8169_irq_mask_and_ack(ioaddr); + rtl8169_irq_mask_and_ack(tp); rtl_rx_close(tp); @@ -4885,8 +4887,7 @@ static void rtl_hw_start_8168(struct net_device *dev) RTL_W16(IntrMitigate, 0x5151); /* Work around for RxFIFO overflow. */ - if (tp->mac_version == RTL_GIGA_MAC_VER_11 || - tp->mac_version == RTL_GIGA_MAC_VER_22) { + if (tp->mac_version == RTL_GIGA_MAC_VER_11) { tp->intr_event |= RxFIFOOver | PCSTimeout; tp->intr_event &= ~RxOverflow; } @@ -5076,6 +5077,11 @@ static void rtl_hw_start_8101(struct net_device *dev) void __iomem *ioaddr = tp->mmio_addr; struct pci_dev *pdev = tp->pci_dev; + if (tp->mac_version >= RTL_GIGA_MAC_VER_30) { + tp->intr_event &= ~RxFIFOOver; + tp->napi_event &= ~RxFIFOOver; + } + if (tp->mac_version == RTL_GIGA_MAC_VER_13 || tp->mac_version == RTL_GIGA_MAC_VER_16) { int cap = pci_pcie_cap(pdev); @@ -5342,7 +5348,7 @@ static void rtl8169_wait_for_quiescence(struct net_device *dev) /* Wait for any pending NAPI task to complete */ napi_disable(&tp->napi); - rtl8169_irq_mask_and_ack(ioaddr); + rtl8169_irq_mask_and_ack(tp); tp->intr_mask = 0xffff; RTL_W16(IntrMask, tp->intr_event); @@ -5389,14 +5395,16 @@ static void rtl8169_reset_task(struct work_struct *work) if (!netif_running(dev)) goto out_unlock; + rtl8169_hw_reset(tp); + rtl8169_wait_for_quiescence(dev); for (i = 0; i < NUM_RX_DESC; i++) rtl8169_mark_to_asic(tp->RxDescArray + i, rx_buf_sz); rtl8169_tx_clear(tp); + rtl8169_init_ring_indexes(tp); - rtl8169_hw_reset(tp); rtl_hw_start(dev); netif_wake_queue(dev); rtl8169_check_link_status(dev, tp, tp->mmio_addr); @@ -5407,11 +5415,6 @@ out_unlock: static void rtl8169_tx_timeout(struct net_device *dev) { - struct rtl8169_private *tp = netdev_priv(dev); - - rtl8169_hw_reset(tp); - - /* Let's wait a bit while any (async) irq lands on */ rtl8169_schedule_work(dev, rtl8169_reset_task); } @@ -5804,6 +5807,10 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) */ status = RTL_R16(IntrStatus); while (status && status != 0xffff) { + status &= tp->intr_event; + if (!status) + break; + handled = 1; /* Handle all of the error cases first. These will reset @@ -5818,27 +5825,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) switch (tp->mac_version) { /* Work around for rx fifo overflow */ case RTL_GIGA_MAC_VER_11: - case RTL_GIGA_MAC_VER_22: - case RTL_GIGA_MAC_VER_26: netif_stop_queue(dev); rtl8169_tx_timeout(dev); goto done; - /* Testers needed. */ - case RTL_GIGA_MAC_VER_17: - case RTL_GIGA_MAC_VER_19: - case RTL_GIGA_MAC_VER_20: - case RTL_GIGA_MAC_VER_21: - case RTL_GIGA_MAC_VER_23: - case RTL_GIGA_MAC_VER_24: - case RTL_GIGA_MAC_VER_27: - case RTL_GIGA_MAC_VER_28: - case RTL_GIGA_MAC_VER_31: - /* Experimental science. Pktgen proof. */ - case RTL_GIGA_MAC_VER_12: - case RTL_GIGA_MAC_VER_25: - if (status == RxFIFOOver) - goto done; - break; default: break; } diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index d2be42aafbe..8843071fe98 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -1937,6 +1937,7 @@ static int __devinit smsc911x_init(struct net_device *dev) { struct smsc911x_data *pdata = netdev_priv(dev); unsigned int byte_test; + unsigned int to = 100; SMSC_TRACE(pdata, probe, "Driver Parameters:"); SMSC_TRACE(pdata, probe, "LAN base: 0x%08lX", @@ -1952,6 +1953,17 @@ static int __devinit smsc911x_init(struct net_device *dev) return -ENODEV; } + /* + * poll the READY bit in PMT_CTRL. Any other access to the device is + * forbidden while this bit isn't set. Try for 100ms + */ + while (!(smsc911x_reg_read(pdata, PMT_CTRL) & PMT_CTRL_READY_) && --to) + udelay(1000); + if (to == 0) { + pr_err("Device not READY in 100ms aborting\n"); + return -ENODEV; + } + /* Check byte ordering */ byte_test = smsc911x_reg_read(pdata, BYTE_TEST); SMSC_TRACE(pdata, probe, "BYTE_TEST: 0x%08X", byte_test); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c index da66ac511c4..4d5402a1d26 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c @@ -39,10 +39,11 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, /* DMA SW reset */ value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); - limit = 15000; + limit = 10; while (limit--) { if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) break; + mdelay(10); } if (limit < 0) return -EBUSY; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c index 627f656b0f3..bc17fd08b55 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c @@ -41,10 +41,11 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, u32 dma_tx, /* DMA SW reset */ value |= DMA_BUS_MODE_SFT_RESET; writel(value, ioaddr + DMA_BUS_MODE); - limit = 15000; + limit = 10; while (limit--) { if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET)) break; + mdelay(10); } if (limit < 0) return -EBUSY; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 9bafa6cf9e8..a140a8fbf05 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -72,7 +72,6 @@ struct stmmac_priv { spinlock_t lock; spinlock_t tx_lock; int wolopts; - int wolenabled; int wol_irq; #ifdef CONFIG_STMMAC_TIMER struct stmmac_timer *tm; @@ -80,6 +79,7 @@ struct stmmac_priv { struct plat_stmmacenet_data *plat; struct stmmac_counters mmc; struct dma_features dma_cap; + int hw_cap_support; }; extern int stmmac_mdio_unregister(struct net_device *ndev); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index e8eff09bbbd..0395f9eba80 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -430,6 +430,12 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct stmmac_priv *priv = netdev_priv(dev); u32 support = WAKE_MAGIC | WAKE_UCAST; + /* By default almost all GMAC devices support the WoL via + * magic frame but we can disable it if the HW capability + * register shows no support for pmt_magic_frame. */ + if ((priv->hw_cap_support) && (!priv->dma_cap.pmt_magic_frame)) + wol->wolopts &= ~WAKE_MAGIC; + if (!device_can_wakeup(priv->device)) return -EINVAL; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 20546bbbb8d..72cd190b9c1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -321,12 +321,10 @@ static int stmmac_init_phy(struct net_device *dev) } /* Stop Advertising 1000BASE Capability if interface is not GMII */ - if ((interface) && ((interface == PHY_INTERFACE_MODE_MII) || - (interface == PHY_INTERFACE_MODE_RMII))) { - phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | - SUPPORTED_Asym_Pause); - phydev->advertising = phydev->supported; - } + if ((interface == PHY_INTERFACE_MODE_MII) || + (interface == PHY_INTERFACE_MODE_RMII)) + phydev->advertising &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); /* * Broken HW is sometimes missing the pull-up resistor on the @@ -783,10 +781,15 @@ static void stmmac_mmc_setup(struct stmmac_priv *priv) unsigned int mode = MMC_CNTRL_RESET_ON_READ | MMC_CNTRL_COUNTER_RESET | MMC_CNTRL_PRESET | MMC_CNTRL_FULL_HALF_PRESET; - /* Do not manage MMC IRQ (FIXME) */ + /* Mask MMC irq, counters are managed in SW and registers + * are cleared on each READ eventually. */ dwmac_mmc_intr_all_mask(priv->ioaddr); - dwmac_mmc_ctrl(priv->ioaddr, mode); - memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); + + if (priv->dma_cap.rmon) { + dwmac_mmc_ctrl(priv->ioaddr, mode); + memset(&priv->mmc, 0, sizeof(struct stmmac_counters)); + } else + pr_info(" No MAC Management Counters available"); } static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) @@ -807,8 +810,29 @@ static u32 stmmac_get_synopsys_id(struct stmmac_priv *priv) return 0; } -/* New GMAC chips support a new register to indicate the - * presence of the optional feature/functions. +/** + * stmmac_selec_desc_mode + * @dev : device pointer + * Description: select the Enhanced/Alternate or Normal descriptors */ +static void stmmac_selec_desc_mode(struct stmmac_priv *priv) +{ + if (priv->plat->enh_desc) { + pr_info(" Enhanced/Alternate descriptors\n"); + priv->hw->desc = &enh_desc_ops; + } else { + pr_info(" Normal descriptors\n"); + priv->hw->desc = &ndesc_ops; + } +} + +/** + * stmmac_get_hw_features + * @priv : private device pointer + * Description: + * new GMAC chip generations have a new register to indicate the + * presence of the optional feature/functions. + * This can be also used to override the value passed through the + * platform and necessary for old MAC10/100 and GMAC chips. */ static int stmmac_get_hw_features(struct stmmac_priv *priv) { @@ -829,7 +853,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) (hw_cap & DMA_HW_FEAT_RWKSEL) >> 9; priv->dma_cap.pmt_magic_frame = (hw_cap & DMA_HW_FEAT_MGKSEL) >> 10; - /*MMC*/ + /* MMC */ priv->dma_cap.rmon = (hw_cap & DMA_HW_FEAT_MMCSEL) >> 11; /* IEEE 1588-2002*/ priv->dma_cap.time_stamp = @@ -857,8 +881,7 @@ static int stmmac_get_hw_features(struct stmmac_priv *priv) priv->dma_cap.enh_desc = (hw_cap & DMA_HW_FEAT_ENHDESSEL) >> 24; - } else - pr_debug("\tNo HW DMA feature register supported"); + } return hw_cap; } @@ -913,6 +936,44 @@ static int stmmac_open(struct net_device *dev) goto open_error; } + stmmac_get_synopsys_id(priv); + + priv->hw_cap_support = stmmac_get_hw_features(priv); + + if (priv->hw_cap_support) { + pr_info(" Support DMA HW capability register"); + + /* We can override some gmac/dma configuration fields: e.g. + * enh_desc, tx_coe (e.g. that are passed through the + * platform) with the values from the HW capability + * register (if supported). + */ + priv->plat->enh_desc = priv->dma_cap.enh_desc; + priv->plat->tx_coe = priv->dma_cap.tx_coe; + priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up; + + /* By default disable wol on magic frame if not supported */ + if (!priv->dma_cap.pmt_magic_frame) + priv->wolopts &= ~WAKE_MAGIC; + + } else + pr_info(" No HW DMA feature register supported"); + + /* Select the enhnaced/normal descriptor structures */ + stmmac_selec_desc_mode(priv); + + /* PMT module is not integrated in all the MAC devices. */ + if (priv->plat->pmt) { + pr_info(" Remote wake-up capable\n"); + device_set_wakeup_capable(priv->device, 1); + } + + priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); + if (priv->rx_coe) + pr_info(" Checksum Offload Engine supported\n"); + if (priv->plat->tx_coe) + pr_info(" Checksum insertion supported\n"); + /* Create and initialize the TX/RX descriptors chains. */ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize); priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); @@ -935,15 +996,6 @@ static int stmmac_open(struct net_device *dev) /* Initialize the MAC Core */ priv->hw->mac->core_init(priv->ioaddr); - stmmac_get_synopsys_id(priv); - - stmmac_get_hw_features(priv); - - priv->rx_coe = priv->hw->mac->rx_coe(priv->ioaddr); - if (priv->rx_coe) - pr_info("stmmac: Rx Checksum Offload Engine supported\n"); - if (priv->plat->tx_coe) - pr_info("\tTX Checksum insertion supported\n"); netdev_update_features(dev); /* Request the IRQ lines */ @@ -965,8 +1017,7 @@ static int stmmac_open(struct net_device *dev) memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats)); priv->xstats.threshold = tc; - if (priv->dma_cap.rmon) - stmmac_mmc_setup(priv); + stmmac_mmc_setup(priv); /* Start the ball rolling... */ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name); @@ -1489,9 +1540,7 @@ static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) if (!priv->phydev) return -EINVAL; - spin_lock(&priv->lock); ret = phy_mii_ioctl(priv->phydev, rq, cmd); - spin_unlock(&priv->lock); return ret; } @@ -1558,7 +1607,7 @@ static int stmmac_sysfs_dma_cap_read(struct seq_file *seq, void *v) struct net_device *dev = seq->private; struct stmmac_priv *priv = netdev_priv(dev); - if (!stmmac_get_hw_features(priv)) { + if (!priv->hw_cap_support) { seq_printf(seq, "DMA HW features not supported\n"); return 0; } @@ -1766,12 +1815,6 @@ static int stmmac_mac_device_setup(struct net_device *dev) if (!device) return -ENOMEM; - if (priv->plat->enh_desc) { - device->desc = &enh_desc_ops; - pr_info("\tEnhanced descriptor structure\n"); - } else - device->desc = &ndesc_ops; - priv->hw = device; priv->hw->ring = &ring_mode_ops; @@ -1845,11 +1888,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev) priv->ioaddr = addr; - /* PMT module is not integrated in all the MAC devices. */ - if (plat_dat->pmt) { - pr_info("\tPMT module supported\n"); - device_set_wakeup_capable(&pdev->dev, 1); - } /* * On some platforms e.g. SPEAr the wake up irq differs from the mac irq * The external wake up irq can be passed through the platform code @@ -1862,7 +1900,6 @@ static int stmmac_dvr_probe(struct platform_device *pdev) if (priv->wol_irq == -ENXIO) priv->wol_irq = ndev->irq; - platform_set_drvdata(pdev, ndev); /* Set the I/O base addr */ @@ -1875,7 +1912,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev) goto out_free_ndev; } - /* MAC HW revice detection */ + /* MAC HW device detection */ ret = stmmac_mac_device_setup(ndev); if (ret < 0) goto out_plat_exit; @@ -1978,12 +2015,13 @@ static int stmmac_suspend(struct device *dev) if (!ndev || !netif_running(ndev)) return 0; + if (priv->phydev) + phy_stop(priv->phydev); + spin_lock(&priv->lock); netif_device_detach(ndev); netif_stop_queue(ndev); - if (priv->phydev) - phy_stop(priv->phydev); #ifdef CONFIG_STMMAC_TIMER priv->tm->timer_stop(); @@ -2041,12 +2079,13 @@ static int stmmac_resume(struct device *dev) #endif napi_enable(&priv->napi); - if (priv->phydev) - phy_start(priv->phydev); - netif_start_queue(ndev); spin_unlock(&priv->lock); + + if (priv->phydev) + phy_start(priv->phydev); + return 0; } diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index c517dac02ae..cf14ab9db57 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -2637,7 +2637,7 @@ static int __devinit happy_meal_sbus_probe_one(struct platform_device *op, int i sbus_dp = op->dev.parent->of_node; /* We can match PCI devices too, do not accept those here. */ - if (strcmp(sbus_dp->name, "sbus")) + if (strcmp(sbus_dp->name, "sbus") && strcmp(sbus_dp->name, "sbi")) return err; if (is_qfe) { diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c index dca9d3369cd..c97d2f59085 100644 --- a/drivers/net/ethernet/ti/davinci_cpdma.c +++ b/drivers/net/ethernet/ti/davinci_cpdma.c @@ -836,11 +836,13 @@ int cpdma_chan_stop(struct cpdma_chan *chan) chan_write(chan, cp, CPDMA_TEARDOWN_VALUE); /* handle completed packets */ + spin_unlock_irqrestore(&chan->lock, flags); do { ret = __cpdma_chan_process(chan); if (ret < 0) break; } while ((ret & CPDMA_DESC_TD_COMPLETE) == 0); + spin_lock_irqsave(&chan->lock, flags); /* remaining packets haven't been tx/rx'ed, clean them up */ while (chan->head) { diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c index 10826d8a2a2..1187a1169eb 100644 --- a/drivers/net/ethernet/tile/tilepro.c +++ b/drivers/net/ethernet/tile/tilepro.c @@ -926,7 +926,7 @@ static int tile_net_poll(struct napi_struct *napi, int budget) goto done; /* Re-enable the ingress interrupt. */ - enable_percpu_irq(priv->intr_id); + enable_percpu_irq(priv->intr_id, 0); /* HACK: Avoid the "rotting packet" problem (see above). */ if (qup->__packet_receive_read != @@ -1296,7 +1296,7 @@ static void tile_net_open_enable(void *dev_ptr) info->napi_enabled = true; /* Enable the ingress interrupt. */ - enable_percpu_irq(priv->intr_id); + enable_percpu_irq(priv->intr_id, 0); } @@ -1697,7 +1697,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, for (i = 0; i < sh->nr_frags; i++) { skb_frag_t *f = &sh->frags[i]; - unsigned long pfn = page_to_pfn(f->page); + unsigned long pfn = page_to_pfn(skb_frag_page(f)); /* FIXME: Compute "hash_for_home" properly. */ /* ISSUE: The hypervisor checks CHIP_HAS_REV1_DMA_PACKETS(). */ @@ -1706,7 +1706,7 @@ static unsigned int tile_net_tx_frags(lepp_frag_t *frags, /* FIXME: Hmmm. */ if (!hash_default) { void *va = pfn_to_kaddr(pfn) + f->page_offset; - BUG_ON(PageHighMem(f->page)); + BUG_ON(PageHighMem(skb_frag_page(f))); finv_buffer_remote(va, f->size, 0); } diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index caf3659e173..2681b53820e 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -114,6 +114,7 @@ void temac_indirect_out32(struct temac_local *lp, int reg, u32 value) return; temac_iow(lp, XTE_LSW0_OFFSET, value); temac_iow(lp, XTE_CTL0_OFFSET, CNTLREG_WRITE_ENABLE_MASK | reg); + temac_indirect_busywait(lp); } /** @@ -203,6 +204,9 @@ static void temac_dma_bd_release(struct net_device *ndev) struct temac_local *lp = netdev_priv(ndev); int i; + /* Reset Local Link (DMA) */ + lp->dma_out(lp, DMA_CONTROL_REG, DMA_CONTROL_RST); + for (i = 0; i < RX_BD_NUM; i++) { if (!lp->rx_skb[i]) break; @@ -860,6 +864,8 @@ static int temac_open(struct net_device *ndev) phy_start(lp->phy_dev); } + temac_device_reset(ndev); + rc = request_irq(lp->tx_irq, ll_temac_tx_irq, 0, ndev->name, ndev); if (rc) goto err_tx_irq; @@ -867,7 +873,6 @@ static int temac_open(struct net_device *ndev) if (rc) goto err_rx_irq; - temac_device_reset(ndev); return 0; err_rx_irq: diff --git a/drivers/net/hippi/Kconfig b/drivers/net/hippi/Kconfig index 7393eb732ee..95eb34fdbba 100644 --- a/drivers/net/hippi/Kconfig +++ b/drivers/net/hippi/Kconfig @@ -36,4 +36,4 @@ config ROADRUNNER_LARGE_RINGS kernel code or by user space programs. Say Y here only if you have the memory. -endif /* HIPPI */ +endif # HIPPI diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index a3ce3d4561e..74134970b70 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -192,6 +192,13 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) */ macvlan_broadcast(skb, port, src->dev, MACVLAN_MODE_VEPA); + else { + /* forward to original port. */ + vlan = src; + ret = macvlan_broadcast_one(skb, vlan, eth, 0); + goto out; + } + return RX_HANDLER_PASS; } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bb88e12101c..a70244306c9 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -3,7 +3,7 @@ # menuconfig PHYLIB - bool "PHY Device support and infrastructure" + tristate "PHY Device support and infrastructure" depends on !S390 depends on NETDEVICES help diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c index 89f829f5f72..f8a6853b692 100644 --- a/drivers/net/ppp/pptp.c +++ b/drivers/net/ppp/pptp.c @@ -423,10 +423,8 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr, lock_sock(sk); opt->src_addr = sp->sa_addr.pptp; - if (add_chan(po)) { - release_sock(sk); + if (add_chan(po)) error = -EBUSY; - } release_sock(sk); return error; diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index e81e22e3d1d..e95f0e60a9b 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -36,7 +36,7 @@ #include <linux/usb/usbnet.h> #include <linux/slab.h> -#define DRIVER_VERSION "26-Sep-2011" +#define DRIVER_VERSION "08-Nov-2011" #define DRIVER_NAME "asix" /* ASIX AX8817X based USB 2.0 Ethernet Devices */ @@ -163,7 +163,7 @@ #define MARVELL_CTRL_TXDELAY 0x0002 #define MARVELL_CTRL_RXDELAY 0x0080 -#define PHY_MODE_RTL8211CL 0x0004 +#define PHY_MODE_RTL8211CL 0x000C /* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ struct asix_data { @@ -652,9 +652,17 @@ static u32 asix_get_phyid(struct usbnet *dev) { int phy_reg; u32 phy_id; + int i; - phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); - if (phy_reg < 0) + /* Poll for the rare case the FW or phy isn't ready yet. */ + for (i = 0; i < 100; i++) { + phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); + if (phy_reg != 0 && phy_reg != 0xFFFF) + break; + mdelay(1); + } + + if (phy_reg <= 0 || phy_reg == 0xFFFF) return 0; phy_id = (phy_reg & 0xffff) << 16; @@ -1075,7 +1083,7 @@ static const struct net_device_ops ax88772_netdev_ops = { static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) { - int ret; + int ret, embd_phy; struct asix_data *data = (struct asix_data *)&dev->data; u8 buf[ETH_ALEN]; u32 phyid; @@ -1100,16 +1108,36 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) dev->mii.reg_num_mask = 0x1f; dev->mii.phy_id = asix_get_phy_addr(dev); - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); - dev->net->netdev_ops = &ax88772_netdev_ops; dev->net->ethtool_ops = &ax88772_ethtool_ops; - ret = ax88772_reset(dev); + embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); + + /* Reset the PHY to normal operation mode */ + ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); + if (ret < 0) { + dbg("Select PHY #1 failed: %d", ret); + return ret; + } + + ret = asix_sw_reset(dev, AX_SWRESET_IPPD | AX_SWRESET_PRL); + if (ret < 0) + return ret; + + msleep(150); + + ret = asix_sw_reset(dev, AX_SWRESET_CLEAR); if (ret < 0) return ret; + msleep(150); + + ret = asix_sw_reset(dev, embd_phy ? AX_SWRESET_IPRL : AX_SWRESET_PRTE); + + /* Read PHYID register *AFTER* the PHY was reset properly */ + phyid = asix_get_phyid(dev); + dbg("PHYID=0x%08x", phyid); + /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ if (dev->driver_info->flags & FLAG_FRAMING_AX) { /* hard_mtu is still the default - the device does not support @@ -1220,6 +1248,7 @@ static int ax88178_reset(struct usbnet *dev) __le16 eeprom; u8 status; int gpio0 = 0; + u32 phyid; asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &status); dbg("GPIO Status: 0x%04x", status); @@ -1235,12 +1264,13 @@ static int ax88178_reset(struct usbnet *dev) data->ledmode = 0; gpio0 = 1; } else { - data->phymode = le16_to_cpu(eeprom) & 7; + data->phymode = le16_to_cpu(eeprom) & 0x7F; data->ledmode = le16_to_cpu(eeprom) >> 8; gpio0 = (le16_to_cpu(eeprom) & 0x80) ? 0 : 1; } dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode); + /* Power up external GigaPHY through AX88178 GPIO pin */ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40); if ((le16_to_cpu(eeprom) >> 8) != 1) { asix_write_gpio(dev, 0x003c, 30); @@ -1252,6 +1282,13 @@ static int ax88178_reset(struct usbnet *dev) asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30); } + /* Read PHYID register *AFTER* powering up PHY */ + phyid = asix_get_phyid(dev); + dbg("PHYID=0x%08x", phyid); + + /* Set AX88178 to enable MII/GMII/RGMII interface for external PHY */ + asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, 0, 0, 0, NULL); + asix_sw_reset(dev, 0); msleep(150); @@ -1396,7 +1433,6 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) { int ret; u8 buf[ETH_ALEN]; - u32 phyid; struct asix_data *data = (struct asix_data *)&dev->data; data->eeprom_len = AX88772_EEPROM_LEN; @@ -1423,12 +1459,12 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->netdev_ops = &ax88178_netdev_ops; dev->net->ethtool_ops = &ax88178_ethtool_ops; - phyid = asix_get_phyid(dev); - dbg("PHYID=0x%08x", phyid); + /* Blink LEDS so users know driver saw dongle */ + asix_sw_reset(dev, 0); + msleep(150); - ret = ax88178_reset(dev); - if (ret < 0) - return ret; + asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD); + msleep(150); /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */ if (dev->driver_info->flags & FLAG_FRAMING_AX) { @@ -1619,6 +1655,10 @@ static const struct usb_device_id products [] = { // ASIX 88772a USB_DEVICE(0x0db0, 0xa877), .driver_info = (unsigned long) &ax88772_info, +}, { + // Asus USB Ethernet Adapter + USB_DEVICE (0x0b95, 0x7e2b), + .driver_info = (unsigned long) &ax88772_info, }, { }, // END }; diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index c924ea2bce0..99ed6eb4dfa 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -567,7 +567,7 @@ static const struct usb_device_id products [] = { { USB_DEVICE_AND_INTERFACE_INFO(0x1004, 0x61aa, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = (unsigned long)&wwan_info, + .driver_info = 0, }, /* diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index d43db32f947..9c26c6390d6 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -144,10 +144,11 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) } frame = (struct vl600_frame_hdr *) buf->data; - /* NOTE: Should check that frame->magic == 0x53544448? - * Otherwise if we receive garbage at the beginning of the frame - * we may end up allocating a huge buffer and saving all the - * future incoming data into it. */ + /* Yes, check that frame->magic == 0x53544448 (or 0x44544d48), + * otherwise we may run out of memory w/a bad packet */ + if (ntohl(frame->magic) != 0x53544448 && + ntohl(frame->magic) != 0x44544d48) + goto error; if (buf->len < sizeof(*frame) || buf->len != le32_to_cpup(&frame->len)) { @@ -296,6 +297,11 @@ encapsulate: * overwrite the remaining fields. */ packet = (struct vl600_pkt_hdr *) skb->data; + /* The VL600 wants IPv6 packets to have an IPv4 ethertype + * Since this modem only supports IPv4 and IPv6, just set all + * frames to 0x0800 (ETH_P_IP) + */ + packet->h_proto = htons(ETH_P_IP); memset(&packet->dummy, 0, sizeof(packet->dummy)); packet->len = cpu_to_le32(orig_len); @@ -308,21 +314,12 @@ encapsulate: if (skb->len < full_len) /* Pad */ skb_put(skb, full_len - skb->len); - /* The VL600 wants IPv6 packets to have an IPv4 ethertype - * Check if this is an IPv6 packet, and set the ethertype - * to 0x800 - */ - if ((skb->data[sizeof(struct vl600_pkt_hdr *) + 0x22] & 0xf0) == 0x60) { - skb->data[sizeof(struct vl600_pkt_hdr *) + 0x20] = 0x08; - skb->data[sizeof(struct vl600_pkt_hdr *) + 0x21] = 0; - } - return skb; } static const struct driver_info vl600_info = { .description = "LG VL600 modem", - .flags = FLAG_ETHER | FLAG_RX_ASSEMBLE, + .flags = FLAG_RX_ASSEMBLE | FLAG_WWAN, .bind = vl600_bind, .unbind = vl600_unbind, .status = usbnet_cdc_status, diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 22a7cf951e7..a5b9b12ef26 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -51,6 +51,7 @@ #define USB_VENDOR_ID_SMSC (0x0424) #define USB_PRODUCT_ID_LAN7500 (0x7500) #define USB_PRODUCT_ID_LAN7505 (0x7505) +#define RXW_PADDING 2 #define check_warn(ret, fmt, args...) \ ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); }) @@ -1088,13 +1089,13 @@ static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); le32_to_cpus(&rx_cmd_b); - skb_pull(skb, 4 + NET_IP_ALIGN); + skb_pull(skb, 4 + RXW_PADDING); packet = skb->data; /* get the packet length */ - size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN; - align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + size = (rx_cmd_a & RX_CMD_A_LEN) - RXW_PADDING; + align_count = (4 - ((size + RXW_PADDING) % 4)) % 4; if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { netif_dbg(dev, rx_err, dev->net, diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 7d6082160bc..fae0fbd8bc8 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1057,7 +1057,8 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb, unsigned long flags; int retval; - skb_tx_timestamp(skb); + if (skb) + skb_tx_timestamp(skb); // some devices want funky USB-level framing, for // win32 driver (usually) and/or hardware quirks diff --git a/drivers/net/wireless/ath/ath9k/ar9002_calib.c b/drivers/net/wireless/ath/ath9k/ar9002_calib.c index e0ab0657cc3..88279e325dc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_calib.c @@ -868,10 +868,6 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) /* Do PA Calibration */ ar9002_hw_pa_cal(ah, true); - /* Do NF Calibration after DC offset and other calibrations */ - ath9k_hw_loadnf(ah, chan); - ath9k_hw_start_nfcal(ah, true); - if (ah->caldata) ah->caldata->nfcal_pending = true; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 16851cb109a..12a730dcb50 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -908,12 +908,15 @@ static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) int i; bool restore; - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_RTT) || !ah->caldata) + if (!ah->caldata) return false; hist = &ah->caldata->rtt_hist; + if (!hist->num_readings) + return false; + ar9003_hw_rtt_enable(ah); - ar9003_hw_rtt_set_mask(ah, 0x10); + ar9003_hw_rtt_set_mask(ah, 0x00); for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->rxchainmask & (1 << i))) continue; @@ -1070,6 +1073,7 @@ skip_tx_iqcal: if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) { u32 *table; + hist->num_readings++; for (i = 0; i < AR9300_MAX_CHAINS; i++) { if (!(ah->rxchainmask & (1 << i))) continue; @@ -1081,9 +1085,6 @@ skip_tx_iqcal: ar9003_hw_rtt_disable(ah); } - ath9k_hw_loadnf(ah, chan); - ath9k_hw_start_nfcal(ah, true); - /* Initialize list pointers */ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; ah->supp_cals = IQ_MISMATCH_CAL; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 2f4023e6608..4114fe752c6 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -572,14 +572,14 @@ #define AR_PHY_TXGAIN_TABLE (AR_SM_BASE + 0x300) -#define AR_PHY_TX_IQCAL_CONTROL_0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3c4 : 0x444) -#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3c8 : 0x448) -#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3c4 : 0x440) -#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + AR_SREV_9485(ah) ? \ - 0x3f0 : 0x48c) +#define AR_PHY_TX_IQCAL_CONTROL_0 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3c4 : 0x444)) +#define AR_PHY_TX_IQCAL_CONTROL_1 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3c8 : 0x448)) +#define AR_PHY_TX_IQCAL_START (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3c4 : 0x440)) +#define AR_PHY_TX_IQCAL_STATUS_B0 (AR_SM_BASE + (AR_SREV_9485(ah) ? \ + 0x3f0 : 0x48c)) #define AR_PHY_TX_IQCAL_CORR_COEFF_B0(_i) (AR_SM_BASE + \ (AR_SREV_9485(ah) ? \ 0x3d0 : 0x450) + ((_i) << 2)) @@ -651,7 +651,7 @@ #define AR_SWITCH_TABLE_ALL_S (0) #define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ - (AR_SREV_9485(ah) ? 0x1628c : 0x16294)) + (AR_SREV_9462(ah) ? 0x16294 : 0x1628c)) #define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 #define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 @@ -668,12 +668,12 @@ #define AR_PHY_65NM_CH2_RXTX2 0x16904 #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ - (AR_SREV_9485(ah) ? 0x16284 : 0x16290)) + (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) #define AR_CH0_TOP2_XPABIASLVL 0xf000 #define AR_CH0_TOP2_XPABIASLVL_S 12 #define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \ - (AR_SREV_9485(ah) ? 0x16290 : 0x16298)) + (AR_SREV_9462(ah) ? 0x16298 : 0x16290)) #define AR_CH0_XTAL_CAPINDAC 0x7f000000 #define AR_CH0_XTAL_CAPINDAC_S 24 #define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000 @@ -908,8 +908,8 @@ #define AR_PHY_TPC_5_B1 (AR_SM1_BASE + 0x208) #define AR_PHY_TPC_6_B1 (AR_SM1_BASE + 0x20c) #define AR_PHY_TPC_11_B1 (AR_SM1_BASE + 0x220) -#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + (AR_SREV_AR9300(ah) ? \ - 0x240 : 0x280)) +#define AR_PHY_PDADC_TAB_1 (AR_SM1_BASE + (AR_SREV_AR9462(ah) ? \ + 0x280 : 0x240)) #define AR_PHY_TPC_19_B1 (AR_SM1_BASE + 0x240) #define AR_PHY_TPC_19_B1_ALPHA_THERM 0xff #define AR_PHY_TPC_19_B1_ALPHA_THERM_S 0 @@ -931,10 +931,10 @@ #define AR_PHY_AIC_SRAM_ADDR_B1 (AR_SM1_BASE + 0x5f0) #define AR_PHY_AIC_SRAM_DATA_B1 (AR_SM1_BASE + 0x5f4) -#define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + (i) ? \ - AR_SM1_BASE : AR_SM_BASE) -#define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + (i) ? \ - AR_SM1_BASE : AR_SM_BASE) +#define AR_PHY_RTT_TABLE_SW_INTF_B(i) (0x384 + ((i) ? \ + AR_SM1_BASE : AR_SM_BASE)) +#define AR_PHY_RTT_TABLE_SW_INTF_1_B(i) (0x388 + ((i) ? \ + AR_SM1_BASE : AR_SM_BASE)) /* * Channel 2 Register Map */ diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index 611ea6ce850..d16d029f81a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -521,7 +521,7 @@ static const u32 ar9485_1_1_radio_postamble[][2] = { {0x000160ac, 0x24611800}, {0x000160b0, 0x03284f3e}, {0x0001610c, 0x00170000}, - {0x00016140, 0x10804008}, + {0x00016140, 0x50804008}, }; static const u32 ar9485_1_1_mac_postamble[][5] = { @@ -603,7 +603,7 @@ static const u32 ar9485_1_1_radio_core[][2] = { static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10052e5e}, + {0x00018c00, 0x18052e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -776,7 +776,7 @@ static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = { static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10013e5e}, + {0x00018c00, 0x18013e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -882,7 +882,7 @@ static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10012e5e}, + {0x00018c00, 0x18012e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; @@ -1021,7 +1021,7 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = { /* Addr allmodes */ - {0x00018c00, 0x10053e5e}, + {0x00018c00, 0x18053e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 4952ad8c4e8..8873c6e6fb9 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1725,6 +1725,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_init_cal(ah, chan)) return -EIO; + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); + ENABLE_REGWRITE_BUFFER(ah); ath9k_hw_restore_chainmask(ah); @@ -1824,7 +1827,8 @@ static void ath9k_set_power_sleep(struct ath_hw *ah, int setChip) } /* Clear Bit 14 of AR_WA after putting chip into Full Sleep mode. */ - REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); + if (AR_SREV_9300_20_OR_LATER(ah)) + REG_WRITE(ah, AR_WA, ah->WARegVal & ~AR_WA_D3_L1_DISABLE); } /* diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 93fbe6f4089..a9c5ae75277 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -286,7 +286,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) ath_start_ani(common); } - if (ath9k_hw_ops(ah)->antdiv_comb_conf_get && sc->ant_rx != 3) { + if ((ah->caps.hw_caps & ATH9K_HW_CAP_ANT_DIV_COMB) && sc->ant_rx != 3) { struct ath_hw_antcomb_conf div_ant_conf; u8 lna_conf; @@ -1843,6 +1843,9 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; struct ath_node *an = (struct ath_node *) sta->drv_priv; + if (!(sc->sc_flags & SC_OP_TXAGGR)) + return; + switch (cmd) { case STA_NOTIFY_SLEEP: an->sleeping = true; diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 888abc2be3a..528d5f3e868 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -1271,7 +1271,9 @@ static void ath_rc_init(struct ath_softc *sc, ath_rc_priv->max_valid_rate = k; ath_rc_sort_validrates(rate_table, ath_rc_priv); - ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + ath_rc_priv->rate_max_phy = (k > 4) ? + ath_rc_priv->valid_rate_index[k-4] : + ath_rc_priv->valid_rate_index[k-1]; ath_rc_priv->rate_table = rate_table; ath_dbg(common, ATH_DBG_CONFIG, diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index d20946939cd..59472e1605c 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -296,7 +296,8 @@ static void carl9170_tx_release(struct kref *ref) super = (void *)skb->data; txinfo->status.ampdu_len = super->s.rix; txinfo->status.ampdu_ack_len = super->s.cnt; - } else if (txinfo->flags & IEEE80211_TX_STAT_ACK) { + } else if ((txinfo->flags & IEEE80211_TX_STAT_ACK) && + !(txinfo->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)) { /* * drop redundant tx_status reports: * @@ -308,15 +309,17 @@ static void carl9170_tx_release(struct kref *ref) * * 3. minstrel_ht is picky, it only accepts * reports of frames with the TX_STATUS_AMPDU flag. + * + * 4. mac80211 is not particularly interested in + * feedback either [CTL_REQ_TX_STATUS not set] */ dev_kfree_skb_any(skb); return; } else { /* - * Frame has failed, but we want to keep it in - * case it was lost due to a power-state - * transition. + * Either the frame transmission has failed or + * mac80211 requested tx status. */ } } diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c index 85fa9cc7350..65ecb5bab25 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -254,6 +254,8 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy, int r; sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + if (!sband) + return; /* * If no country IE has been received always enable active scan diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index fcff923b3c1..279a53eae4c 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -617,9 +617,19 @@ static bool pio_rx_frame(struct b43_pio_rxqueue *q) const char *err_msg = NULL; struct b43_rxhdr_fw4 *rxhdr = (struct b43_rxhdr_fw4 *)wl->pio_scratchspace; + size_t rxhdr_size = sizeof(*rxhdr); BUILD_BUG_ON(sizeof(wl->pio_scratchspace) < sizeof(*rxhdr)); - memset(rxhdr, 0, sizeof(*rxhdr)); + switch (dev->fw.hdr_format) { + case B43_FW_HDR_410: + case B43_FW_HDR_351: + rxhdr_size -= sizeof(rxhdr->format_598) - + sizeof(rxhdr->format_351); + break; + case B43_FW_HDR_598: + break; + } + memset(rxhdr, 0, rxhdr_size); /* Check if we have data and wait for it to get ready. */ if (q->rev >= 8) { @@ -657,11 +667,11 @@ data_ready: /* Get the preamble (RX header) */ if (q->rev >= 8) { - b43_block_read(dev, rxhdr, sizeof(*rxhdr), + b43_block_read(dev, rxhdr, rxhdr_size, q->mmio_base + B43_PIO8_RXDATA, sizeof(u32)); } else { - b43_block_read(dev, rxhdr, sizeof(*rxhdr), + b43_block_read(dev, rxhdr, rxhdr_size, q->mmio_base + B43_PIO_RXDATA, sizeof(u16)); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index c73e8600d21..5f77cbe0b6a 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -175,6 +175,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp, } } +/* TODO: verify if needed for SSLPN or LCN */ static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate) { const struct b43_phy *phy = &dev->phy; @@ -256,6 +257,9 @@ int b43_generate_txhdr(struct b43_wldev *dev, unsigned int plcp_fragment_len; u32 mac_ctl = 0; u16 phy_ctl = 0; + bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP || + phy->type == B43_PHYTYPE_N || + phy->type == B43_PHYTYPE_HT); u8 extra_ft = 0; struct ieee80211_rate *txrate; struct ieee80211_tx_rate *rates; @@ -531,7 +535,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, extra_ft |= B43_TXH_EFT_RTSFB_CCK; if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS && - phy->type == B43_PHYTYPE_N) { + fill_phy_ctl1) { txhdr->phy_ctl1_rts = cpu_to_le16( b43_generate_tx_phy_ctl1(dev, rts_rate)); txhdr->phy_ctl1_rts_fb = cpu_to_le16( @@ -552,7 +556,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, break; } - if (phy->type == B43_PHYTYPE_N) { + if (fill_phy_ctl1) { txhdr->phy_ctl1 = cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate)); txhdr->phy_ctl1_fb = @@ -736,7 +740,14 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) /* Link quality statistics */ switch (chanstat & B43_RX_CHAN_PHYTYPE) { + case B43_PHYTYPE_HT: + /* TODO: is max the right choice? */ + status.signal = max_t(__s8, + max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1), + rxhdr->phy_ht_power2); + break; case B43_PHYTYPE_N: + /* Broadcom has code for min and avg, but always uses max */ if (rxhdr->power0 == 16 || rxhdr->power0 == 32) status.signal = max(rxhdr->power1, rxhdr->power2); else @@ -827,7 +838,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) #endif return; drop: - b43dbg(dev->wl, "RX: Packet dropped\n"); dev_kfree_skb_any(skb); } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 16c514d54af..98d90747836 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -249,6 +249,12 @@ struct b43_rxhdr_fw4 { } __packed; } __packed; union { + /* HT-PHY */ + struct { + PAD_BYTES(1); + __s8 phy_ht_power0; + } __packed; + /* RSSI for N-PHYs */ struct { __s8 power2; @@ -257,7 +263,15 @@ struct b43_rxhdr_fw4 { __le16 phy_status2; /* PHY RX Status 2 */ } __packed; - __le16 phy_status3; /* PHY RX Status 3 */ + union { + /* HT-PHY */ + struct { + __s8 phy_ht_power1; + __s8 phy_ht_power2; + } __packed; + + __le16 phy_status3; /* PHY RX Status 3 */ + } __packed; union { /* Tested with 598.314, 644.1001 and 666.2 */ struct { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index b56a30297c2..6ebec8f4284 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -358,13 +358,14 @@ static uint nrxdactive(struct dma_info *di, uint h, uint t) static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags) { - uint dmactrlflags = di->dma.dmactrlflags; + uint dmactrlflags; if (di == NULL) { - DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name)); + DMA_ERROR(("_dma_ctrlflags: NULL dma handle\n")); return 0; } + dmactrlflags = di->dma.dmactrlflags; dmactrlflags &= ~mask; dmactrlflags |= flags; diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index e12b48c2cff..dd008b0e641 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -191,6 +191,7 @@ static struct iwl_base_params iwl1000_base_params = { .chain_noise_scale = 1000, .wd_timeout = IWL_DEF_WD_TIMEOUT, .max_event_log_size = 128, + .wd_disable = true, }; static struct iwl_ht_params iwl1000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index c511c98a89a..f55fb2d1af5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -364,6 +364,7 @@ static struct iwl_base_params iwl5000_base_params = { .wd_timeout = IWL_LONG_WD_TIMEOUT, .max_event_log_size = 512, .no_idle_support = true, + .wd_disable = true, }; static struct iwl_ht_params iwl5000_ht_params = { .ht_greenfield_support = true, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 58a381c01c8..5c7c17c7166 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -528,6 +528,24 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx) return 0; } +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx) +{ + if (conf_is_ht40_minus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_BELOW; + ctx->ht.is_40mhz = true; + } else if (conf_is_ht40_plus(conf)) { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + ctx->ht.is_40mhz = true; + } else { + ctx->ht.extension_chan_offset = + IEEE80211_HT_PARAM_CHA_SEC_NONE; + ctx->ht.is_40mhz = false; + } +} + int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; @@ -586,19 +604,11 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) ctx->ht.enabled = conf_is_ht(conf); if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } + /* if HT40 is used, it should not change + * after associated except channel switch */ + if (!ctx->ht.is_40mhz || + !iwl_is_associated_ctx(ctx)) + iwlagn_config_ht40(conf, ctx); } else ctx->ht.is_40mhz = false; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c index ed628362393..4b2aa1da095 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-sta.c @@ -1268,9 +1268,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_TKIP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - if (sta) addr = sta->addr; else /* station mode case only */ @@ -1283,8 +1280,6 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, seq.tkip.iv32, p1k, CMD_SYNC); break; case WLAN_CIPHER_SUITE_CCMP: - keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; - /* fall through */ case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: ret = iwlagn_send_sta_key(priv, keyconf, sta_id, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 35a6b71f358..df1540ca610 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -91,7 +91,10 @@ static void iwlagn_tx_cmd_build_basic(struct iwl_priv *priv, tx_cmd->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } else { - tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; + else + tx_flags &= ~TX_CMD_FLG_SEQ_CTL_MSK; } iwlagn_tx_cmd_protection(priv, info, fc, &tx_flags); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index ccba69b7f8a..e0e9a3dfbc0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -2316,6 +2316,17 @@ static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + /* fall through */ + case WLAN_CIPHER_SUITE_CCMP: + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + break; + default: + break; + } + /* * We could program these keys into the hardware as well, but we * don't expect much multicast traffic in IBSS and having keys @@ -2599,21 +2610,9 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, /* Configure HT40 channels */ ctx->ht.enabled = conf_is_ht(conf); - if (ctx->ht.enabled) { - if (conf_is_ht40_minus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_BELOW; - ctx->ht.is_40mhz = true; - } else if (conf_is_ht40_plus(conf)) { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_ABOVE; - ctx->ht.is_40mhz = true; - } else { - ctx->ht.extension_chan_offset = - IEEE80211_HT_PARAM_CHA_SEC_NONE; - ctx->ht.is_40mhz = false; - } - } else + if (ctx->ht.enabled) + iwlagn_config_ht40(conf, ctx); + else ctx->ht.is_40mhz = false; if ((le16_to_cpu(ctx->staging.channel) != ch)) @@ -2851,6 +2850,9 @@ static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw, int ret; u8 sta_id; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return 0; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -2899,6 +2901,9 @@ static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw, struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv; struct iwl_rxon_context *ctx = vif_priv->ctx; + if (ctx->ctxid != IWL_RXON_CTX_PAN) + return; + IWL_DEBUG_MAC80211(priv, "enter\n"); mutex_lock(&priv->shrd->mutex); @@ -3499,9 +3504,10 @@ MODULE_PARM_DESC(plcp_check, "Check plcp health (default: 1 [enabled])"); module_param_named(ack_check, iwlagn_mod_params.ack_check, bool, S_IRUGO); MODULE_PARM_DESC(ack_check, "Check ack health (default: 0 [disabled])"); -module_param_named(wd_disable, iwlagn_mod_params.wd_disable, bool, S_IRUGO); +module_param_named(wd_disable, iwlagn_mod_params.wd_disable, int, S_IRUGO); MODULE_PARM_DESC(wd_disable, - "Disable stuck queue watchdog timer (default: 0 [enabled])"); + "Disable stuck queue watchdog timer 0=system default, " + "1=disable, 2=enable (default: 0)"); /* * set bt_coex_active to true, uCode will do kill/defer diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 5b936ec1a54..3856abaea50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h @@ -86,6 +86,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes); +void iwlagn_config_ht40(struct ieee80211_conf *conf, + struct iwl_rxon_context *ctx); /* uCode */ int iwlagn_rx_calib_result(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index b247a56d513..fcf54160e4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -1755,16 +1755,6 @@ static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq) { if (iwl_trans_check_stuck_queue(trans(priv), txq)) { int ret; - if (txq == priv->shrd->cmd_queue) { - /* - * validate command queue still working - * by sending "ECHO" command - */ - if (!iwl_cmd_echo_test(priv)) - return 0; - else - IWL_DEBUG_HC(priv, "echo testing fail\n"); - } ret = iwl_force_reset(priv, IWL_FW_RESET, false); return (ret == -EAGAIN) ? 0 : 1; } @@ -1820,11 +1810,23 @@ void iwl_setup_watchdog(struct iwl_priv *priv) { unsigned int timeout = priv->cfg->base_params->wd_timeout; - if (timeout && !iwlagn_mod_params.wd_disable) - mod_timer(&priv->watchdog, - jiffies + msecs_to_jiffies(IWL_WD_TICK(timeout))); - else - del_timer(&priv->watchdog); + if (!iwlagn_mod_params.wd_disable) { + /* use system default */ + if (timeout && !priv->cfg->base_params->wd_disable) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } else { + /* module parameter overwrite default configuration */ + if (timeout && iwlagn_mod_params.wd_disable == 2) + mod_timer(&priv->watchdog, + jiffies + + msecs_to_jiffies(IWL_WD_TICK(timeout))); + else + del_timer(&priv->watchdog); + } } /** diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 137da338070..f2fc288f3dd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -113,6 +113,7 @@ struct iwl_lib_ops { * @shadow_reg_enable: HW shadhow register bit * @no_idle_support: do not support idle mode * @hd_v2: v2 of enhanced sensitivity value, used for 2000 series and up + * wd_disable: disable watchdog timer */ struct iwl_base_params { int eeprom_size; @@ -134,6 +135,7 @@ struct iwl_base_params { const bool shadow_reg_enable; const bool no_idle_support; const bool hd_v2; + const bool wd_disable; }; /* * @advanced_bt_coexist: support advanced bt coexist diff --git a/drivers/net/wireless/iwlwifi/iwl-pci.c b/drivers/net/wireless/iwlwifi/iwl-pci.c index f0c623ade3f..1800029911a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-pci.c +++ b/drivers/net/wireless/iwlwifi/iwl-pci.c @@ -446,10 +446,9 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); err = pci_enable_msi(pdev); - if (err) { - dev_printk(KERN_ERR, &pdev->dev, "pci_enable_msi failed"); - goto out_iounmap; - } + if (err) + dev_printk(KERN_ERR, &pdev->dev, + "pci_enable_msi failed(0X%x)", err); /* TODO: Move this away, not needed if not MSI */ /* enable rfkill interrupt: hw bug w/a */ @@ -470,7 +469,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) out_disable_msi: pci_disable_msi(pdev); -out_iounmap: pci_iounmap(pdev, pci_bus->hw_base); out_pci_release_regions: pci_set_drvdata(pdev, NULL); diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h index 1f7a93c67c4..14eaf37ce3b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-shared.h +++ b/drivers/net/wireless/iwlwifi/iwl-shared.h @@ -120,7 +120,7 @@ extern struct iwl_mod_params iwlagn_mod_params; * @restart_fw: restart firmware, default = 1 * @plcp_check: enable plcp health check, default = true * @ack_check: disable ack health check, default = false - * @wd_disable: enable stuck queue check, default = false + * @wd_disable: enable stuck queue check, default = 0 * @bt_coex_active: enable bt coex, default = true * @led_mode: system default, default = 0 * @no_sleep_autoadjust: disable autoadjust, default = true @@ -141,7 +141,7 @@ struct iwl_mod_params { int restart_fw; bool plcp_check; bool ack_check; - bool wd_disable; + int wd_disable; bool bt_coex_active; int led_mode; bool no_sleep_autoadjust; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c index 8e8c75c997e..5f17ab8e76b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c @@ -407,6 +407,7 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) struct iwl_queue *q = &txq->q; enum dma_data_direction dma_dir; unsigned long flags; + spinlock_t *lock; if (!q->n_bd) return; @@ -414,19 +415,22 @@ static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id) /* In the command queue, all the TBs are mapped as BIDI * so unmap them as such. */ - if (txq_id == trans->shrd->cmd_queue) + if (txq_id == trans->shrd->cmd_queue) { dma_dir = DMA_BIDIRECTIONAL; - else + lock = &trans->hcmd_lock; + } else { dma_dir = DMA_TO_DEVICE; + lock = &trans->shrd->sta_lock; + } - spin_lock_irqsave(&trans->shrd->sta_lock, flags); + spin_lock_irqsave(lock, flags); while (q->write_ptr != q->read_ptr) { /* The read_ptr needs to bound by q->n_window */ iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr), dma_dir); q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); } - spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); + spin_unlock_irqrestore(lock, flags); } /** @@ -986,29 +990,16 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) return 0; } -static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans) +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) { unsigned long flags; - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(trans); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + /* tell the device to stop sending interrupts */ spin_lock_irqsave(&trans->shrd->lock, flags); iwl_disable_interrupts(trans); spin_unlock_irqrestore(&trans->shrd->lock, flags); - /* wait to make sure we flush pending tasklet*/ - synchronize_irq(bus(trans)->irq); - tasklet_kill(&trans_pcie->irq_tasklet); -} - -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) -{ - /* stop and reset the on-board processor */ - iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); - - /* tell the device to stop sending interrupts */ - iwl_trans_pcie_disable_sync_irq(trans); - /* device going down, Stop using ICT table */ iwl_disable_ict(trans); @@ -1035,6 +1026,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Stop the device, and put it in low power state */ iwl_apm_stop(priv(trans)); + + /* Upon stop, the APM issues an interrupt if HW RF kill is set. + * Clean again the interrupt here + */ + spin_lock_irqsave(&trans->shrd->lock, flags); + iwl_disable_interrupts(trans); + spin_unlock_irqrestore(&trans->shrd->lock, flags); + + /* wait to make sure we flush pending tasklet*/ + synchronize_irq(bus(trans)->irq); + tasklet_kill(&trans_pcie->irq_tasklet); + + /* stop and reset the on-board processor */ + iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); } static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, @@ -1192,9 +1197,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len); /* Set up entry for this TFD in Tx byte-count array */ - if (is_agg) - iwl_trans_txq_update_byte_cnt_tbl(trans, txq, - le16_to_cpu(tx_cmd->len)); + iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len)); dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen, DMA_BIDIRECTIONAL); diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index ff6378276ff..a7f1ab28940 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -634,7 +634,7 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy, if (channel && !(channel->flags & IEEE80211_CHAN_DISABLED)) cfg80211_inform_bss(wiphy, channel, - bssid, le64_to_cpu(*(__le64 *)tsfdesc), + bssid, get_unaligned_le64(tsfdesc), capa, intvl, ie, ielen, LBS_SCAN_RSSI_TO_MBM(rssi), GFP_KERNEL); @@ -728,15 +728,9 @@ static void lbs_scan_worker(struct work_struct *work) le16_to_cpu(scan_cmd->hdr.size), lbs_ret_scan, 0); - if (priv->scan_channel >= priv->scan_req->n_channels) { + if (priv->scan_channel >= priv->scan_req->n_channels) /* Mark scan done */ - if (priv->internal_scan) - kfree(priv->scan_req); - else - cfg80211_scan_done(priv->scan_req, false); - - priv->scan_req = NULL; - } + lbs_scan_done(priv); /* Restart network */ if (carrier) @@ -774,6 +768,21 @@ static void _internal_start_scan(struct lbs_private *priv, bool internal, lbs_deb_leave(LBS_DEB_CFG80211); } +/* + * Clean up priv->scan_req. Should be used to handle the allocation details. + */ +void lbs_scan_done(struct lbs_private *priv) +{ + WARN_ON(!priv->scan_req); + + if (priv->internal_scan) + kfree(priv->scan_req); + else + cfg80211_scan_done(priv->scan_req, false); + + priv->scan_req = NULL; +} + static int lbs_cfg_scan(struct wiphy *wiphy, struct net_device *dev, struct cfg80211_scan_request *request) diff --git a/drivers/net/wireless/libertas/cfg.h b/drivers/net/wireless/libertas/cfg.h index a02ee151710..558168ce634 100644 --- a/drivers/net/wireless/libertas/cfg.h +++ b/drivers/net/wireless/libertas/cfg.h @@ -16,6 +16,7 @@ int lbs_reg_notifier(struct wiphy *wiphy, void lbs_send_disconnect_notification(struct lbs_private *priv); void lbs_send_mic_failureevent(struct lbs_private *priv, u32 event); +void lbs_scan_done(struct lbs_private *priv); void lbs_scan_deinit(struct lbs_private *priv); int lbs_disconnect(struct lbs_private *priv, u16 reason); diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c index 11b69b300dc..728baa44525 100644 --- a/drivers/net/wireless/libertas/if_spi.c +++ b/drivers/net/wireless/libertas/if_spi.c @@ -995,6 +995,7 @@ static int if_spi_host_to_card(struct lbs_private *priv, spin_unlock_irqrestore(&card->buffer_lock, flags); break; default: + kfree(packet); netdev_err(priv->dev, "can't transfer buffer of type %d\n", type); err = -EINVAL; diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 4ae99a40dbf..957681dede1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -255,10 +255,8 @@ static int lbs_eth_stop(struct net_device *dev) lbs_update_mcast(priv); cancel_delayed_work_sync(&priv->scan_work); - if (priv->scan_req) { - cfg80211_scan_done(priv->scan_req, false); - priv->scan_req = NULL; - } + if (priv->scan_req) + lbs_scan_done(priv); netif_carrier_off(priv->dev); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index ac278156d39..6e0a3eaecf7 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -939,7 +939,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) { struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL; unsigned long cmd_flags; - unsigned long cmd_pending_q_flags; unsigned long scan_pending_q_flags; uint16_t cancel_scan_cmd = false; @@ -949,12 +948,9 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) cmd_node = adapter->curr_cmd; cmd_node->wait_q_enabled = false; cmd_node->cmd_flag |= CMD_F_CANCELED; - spin_lock_irqsave(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); - list_del(&cmd_node->list); - spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, - cmd_pending_q_flags); mwifiex_insert_cmd_to_free_q(adapter, cmd_node); + mwifiex_complete_cmd(adapter, adapter->curr_cmd); + adapter->curr_cmd = NULL; spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } @@ -981,7 +977,6 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter) spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags); } adapter->cmd_wait_q.status = -1; - mwifiex_complete_cmd(adapter, adapter->curr_cmd); } /* diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index dae8dbb24a0..8d3ab378662 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -819,8 +819,10 @@ mwifiex_scan_setup_scan_config(struct mwifiex_private *priv, wildcard_ssid_tlv->header.len = cpu_to_le16( (u16) (ssid_len + sizeof(wildcard_ssid_tlv-> max_ssid_length))); - wildcard_ssid_tlv->max_ssid_length = - user_scan_in->ssid_list[ssid_idx].max_len; + + /* max_ssid_length = 0 tells firmware to perform + specific scan for the SSID filled */ + wildcard_ssid_tlv->max_ssid_length = 0; memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[ssid_idx].ssid, @@ -1469,7 +1471,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, s32 rssi, const u8 *ie_buf, size_t ie_len, u16 beacon_period, u16 cap_info_bitmap, u8 band) { - struct mwifiex_bssdescriptor *bss_desc = NULL; + struct mwifiex_bssdescriptor *bss_desc; int ret; unsigned long flags; u8 *beacon_ie; @@ -1484,6 +1486,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid, beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL); if (!beacon_ie) { + kfree(bss_desc); dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n"); return -ENOMEM; } diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index ea4a29b7e33..1679c2593b7 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -55,9 +55,14 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) { bool cancel_flag = false; int status = adapter->cmd_wait_q.status; - struct cmd_ctrl_node *cmd_queued = adapter->cmd_queued; + struct cmd_ctrl_node *cmd_queued; + if (!adapter->cmd_queued) + return 0; + + cmd_queued = adapter->cmd_queued; adapter->cmd_queued = NULL; + dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); diff --git a/drivers/net/wireless/p54/p54spi.c b/drivers/net/wireless/p54/p54spi.c index f18df82eeb9..78d0d698855 100644 --- a/drivers/net/wireless/p54/p54spi.c +++ b/drivers/net/wireless/p54/p54spi.c @@ -588,8 +588,6 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) WARN_ON(priv->fw_state != FW_STATE_READY); - cancel_work_sync(&priv->work); - p54spi_power_off(priv); spin_lock_irqsave(&priv->tx_lock, flags); INIT_LIST_HEAD(&priv->tx_pending); @@ -597,6 +595,8 @@ static void p54spi_op_stop(struct ieee80211_hw *dev) priv->fw_state = FW_STATE_OFF; mutex_unlock(&priv->mutex); + + cancel_work_sync(&priv->work); } static int __devinit p54spi_probe(struct spi_device *spi) @@ -656,6 +656,7 @@ static int __devinit p54spi_probe(struct spi_device *spi) init_completion(&priv->fw_comp); INIT_LIST_HEAD(&priv->tx_pending); mutex_init(&priv->mutex); + spin_lock_init(&priv->tx_lock); SET_IEEE80211_DEV(hw, &spi->dev); priv->common.open = p54spi_op_start; priv->common.stop = p54spi_op_stop; diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index d97a2caf582..bc2ba80c47b 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -778,7 +778,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, dwrq->flags = 0; dwrq->length = 0; } - essid->octets[essid->length] = '\0'; + essid->octets[dwrq->length] = '\0'; memcpy(extra, essid->octets, dwrq->length); kfree(essid); diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 3f183a15186..1ba079dffb1 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -3771,7 +3771,7 @@ static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) /* Apparently the data is read from end to start */ rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); /* The returned value is in CPU order, but eeprom is le */ - rt2x00dev->eeprom[i] = cpu_to_le32(reg); + *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index f1565792f27..377876315b8 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -919,6 +919,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x050d, 0x935b) }, /* Buffalo */ { USB_DEVICE(0x0411, 0x00e8) }, + { USB_DEVICE(0x0411, 0x0158) }, { USB_DEVICE(0x0411, 0x016f) }, { USB_DEVICE(0x0411, 0x01a2) }, /* Corega */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 2ec5c00235e..99ff12d0c29 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -943,6 +943,7 @@ struct rt2x00_dev { * Powersaving work */ struct delayed_work autowakeup_work; + struct work_struct sleep_work; /* * Data queue arrays for RX, TX, Beacon and ATIM. diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index e1fb2a8569b..edd317fa7c0 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -465,6 +465,23 @@ static u8 *rt2x00lib_find_ie(u8 *data, unsigned int len, u8 ie) return NULL; } +static void rt2x00lib_sleep(struct work_struct *work) +{ + struct rt2x00_dev *rt2x00dev = + container_of(work, struct rt2x00_dev, sleep_work); + + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return; + + /* + * Check again is powersaving is enabled, to prevent races from delayed + * work execution. + */ + if (!test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) + rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, + IEEE80211_CONF_CHANGE_PS); +} + static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, struct sk_buff *skb, struct rxdone_entry_desc *rxdesc) @@ -512,8 +529,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, cam |= (tim_ie->bitmap_ctrl & 0x01); if (!cam && !test_bit(CONFIG_POWERSAVING, &rt2x00dev->flags)) - rt2x00lib_config(rt2x00dev, &rt2x00dev->hw->conf, - IEEE80211_CONF_CHANGE_PS); + queue_work(rt2x00dev->workqueue, &rt2x00dev->sleep_work); } static int rt2x00lib_rxdone_read_signal(struct rt2x00_dev *rt2x00dev, @@ -1141,6 +1157,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) INIT_WORK(&rt2x00dev->intf_work, rt2x00lib_intf_scheduled); INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); + INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); /* * Let the driver probe the device to detect the capabilities. @@ -1197,6 +1214,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) */ cancel_work_sync(&rt2x00dev->intf_work); cancel_delayed_work_sync(&rt2x00dev->autowakeup_work); + cancel_work_sync(&rt2x00dev->sleep_work); if (rt2x00_is_usb(rt2x00dev)) { del_timer_sync(&rt2x00dev->txstatus_timer); cancel_work_sync(&rt2x00dev->rxdone_work); diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index db526284454..55c8e50f45f 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -395,7 +395,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) if (mac->link_state != MAC80211_LINKED) return; - spin_lock(&rtlpriv->locks.lps_lock); + spin_lock_irq(&rtlpriv->locks.lps_lock); /* Idle for a while if we connect to AP a while ago. */ if (mac->cnt_after_linked >= 2) { @@ -407,7 +407,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw) } } - spin_unlock(&rtlpriv->locks.lps_lock); + spin_unlock_irq(&rtlpriv->locks.lps_lock); } /*Leave the leisure power save mode.*/ @@ -416,8 +416,9 @@ void rtl_lps_leave(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); + unsigned long flags; - spin_lock(&rtlpriv->locks.lps_lock); + spin_lock_irqsave(&rtlpriv->locks.lps_lock, flags); if (ppsc->fwctrl_lps) { if (ppsc->dot11_psmode != EACTIVE) { @@ -438,7 +439,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw) rtl_lps_set_psmode(hw, EACTIVE); } } - spin_unlock(&rtlpriv->locks.lps_lock); + spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flags); } /* For sw LPS*/ @@ -539,9 +540,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw) RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM); } - spin_lock(&rtlpriv->locks.lps_lock); + spin_lock_irq(&rtlpriv->locks.lps_lock); rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS); - spin_unlock(&rtlpriv->locks.lps_lock); + spin_unlock_irq(&rtlpriv->locks.lps_lock); } void rtl_swlps_rfon_wq_callback(void *data) @@ -574,9 +575,9 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw) if (rtlpriv->link_info.busytraffic) return; - spin_lock(&rtlpriv->locks.lps_lock); + spin_lock_irq(&rtlpriv->locks.lps_lock); rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS); - spin_unlock(&rtlpriv->locks.lps_lock); + spin_unlock_irq(&rtlpriv->locks.lps_lock); if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM && !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c index 592a10ac592..3b585aadabf 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c @@ -569,7 +569,7 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP:{ if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ring = &pcipriv->dev.tx_ring[queue_id]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c index 72852900df8..e49cf2244c7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/phy.c @@ -548,7 +548,7 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw, break; case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { ring = &pcipriv->dev.tx_ring[queue_id]; diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 3ac7af1c550..0883349e1c8 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3374,7 +3374,7 @@ bool rtl92d_phy_set_rf_power_state(struct ieee80211_hw *hw, break; case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index f27171af979..f10ac1ad908 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -602,7 +602,7 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw, } case ERFSLEEP: if (ppsc->rfpwr_state == ERFOFF) - break; + return false; for (queue_id = 0, i = 0; queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) { diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c index 128ccb79318..fc29c671cf3 100644 --- a/drivers/net/wireless/wl12xx/scan.c +++ b/drivers/net/wireless/wl12xx/scan.c @@ -559,7 +559,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, break; } /* Fail if SSID isn't present in the filters */ - if (j == req->n_ssids) { + if (j == cmd->n_ssids) { ret = -EINVAL; goto out_free; } diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 0cb594c8609..15e332d08c8 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1021,7 +1021,7 @@ static int xen_netbk_tx_check_gop(struct xen_netbk *netbk, pending_idx = *((u16 *)skb->data); xen_netbk_idx_release(netbk, pending_idx); for (j = start; j < i; j++) { - pending_idx = frag_get_pending_idx(&shinfo->frags[i]); + pending_idx = frag_get_pending_idx(&shinfo->frags[j]); xen_netbk_idx_release(netbk, pending_idx); } @@ -1668,7 +1668,7 @@ static int __init netback_init(void) "netback/%u", group); if (IS_ERR(netbk->task)) { - printk(KERN_ALERT "kthread_run() fails at netback\n"); + printk(KERN_ALERT "kthread_create() fails at netback\n"); del_timer(&netbk->net_timer); rc = PTR_ERR(netbk->task); goto failed_init; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 6d3dd3988d0..0f0cfa3bca3 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -26,11 +26,6 @@ #include <linux/string.h> #include <linux/slab.h> -/* For archs that don't support NO_IRQ (such as x86), provide a dummy value */ -#ifndef NO_IRQ -#define NO_IRQ 0 -#endif - /** * irq_of_parse_and_map - Parse and map an interrupt into linux virq space * @device: Device node of the device whose interrupt is to be mapped @@ -44,7 +39,7 @@ unsigned int irq_of_parse_and_map(struct device_node *dev, int index) struct of_irq oirq; if (of_irq_map_one(dev, index, &oirq)) - return NO_IRQ; + return 0; return irq_create_of_mapping(oirq.controller, oirq.specifier, oirq.size); @@ -60,27 +55,27 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map); */ struct device_node *of_irq_find_parent(struct device_node *child) { - struct device_node *p, *c = child; + struct device_node *p; const __be32 *parp; - if (!of_node_get(c)) + if (!of_node_get(child)) return NULL; do { - parp = of_get_property(c, "interrupt-parent", NULL); + parp = of_get_property(child, "interrupt-parent", NULL); if (parp == NULL) - p = of_get_parent(c); + p = of_get_parent(child); else { if (of_irq_workarounds & OF_IMAP_NO_PHANDLE) p = of_node_get(of_irq_dflt_pic); else p = of_find_node_by_phandle(be32_to_cpup(parp)); } - of_node_put(c); - c = p; + of_node_put(child); + child = p; } while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL); - return (p == child) ? NULL : p; + return p; } /** @@ -345,7 +340,7 @@ int of_irq_to_resource(struct device_node *dev, int index, struct resource *r) /* Only dereference the resource if both the * resource and the irq are valid. */ - if (r && irq != NO_IRQ) { + if (r && irq) { r->start = r->end = irq; r->flags = IORESOURCE_IRQ; r->name = dev->full_name; @@ -363,7 +358,7 @@ int of_irq_count(struct device_node *dev) { int nr = 0; - while (of_irq_to_resource(dev, nr, NULL) != NO_IRQ) + while (of_irq_to_resource(dev, nr, NULL)) nr++; return nr; @@ -383,7 +378,7 @@ int of_irq_to_resource_table(struct device_node *dev, struct resource *res, int i; for (i = 0; i < nr_irqs; i++, res++) - if (of_irq_to_resource(dev, i, res) == NO_IRQ) + if (!of_irq_to_resource(dev, i, res)) break; return i; @@ -424,6 +419,8 @@ void __init of_irq_init(const struct of_device_id *matches) desc->dev = np; desc->interrupt_parent = of_irq_find_parent(np); + if (desc->interrupt_parent == np) + desc->interrupt_parent = NULL; list_add_tail(&desc->list, &intc_desc_list); } diff --git a/drivers/of/platform.c b/drivers/of/platform.c index cbd5d701c7e..63b3ec48c20 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -314,7 +314,7 @@ static const struct of_dev_auxdata *of_dev_lookup(const struct of_dev_auxdata *l if (!lookup) return NULL; - for(; lookup->name != NULL; lookup++) { + for(; lookup->compatible != NULL; lookup++) { if (!of_device_is_compatible(np, lookup->compatible)) continue; if (of_address_to_resource(np, 0, &res)) diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index dccd8636095..f8c752e408a 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c @@ -239,26 +239,45 @@ int oprofile_set_ulong(unsigned long *addr, unsigned long val) return err; } +static int timer_mode; + static int __init oprofile_init(void) { int err; + /* always init architecture to setup backtrace support */ err = oprofile_arch_init(&oprofile_ops); - if (err < 0 || timer) { - printk(KERN_INFO "oprofile: using timer interrupt.\n"); + + timer_mode = err || timer; /* fall back to timer mode on errors */ + if (timer_mode) { + if (!err) + oprofile_arch_exit(); err = oprofile_timer_init(&oprofile_ops); if (err) return err; } - return oprofilefs_register(); + + err = oprofilefs_register(); + if (!err) + return 0; + + /* failed */ + if (timer_mode) + oprofile_timer_exit(); + else + oprofile_arch_exit(); + + return err; } static void __exit oprofile_exit(void) { - oprofile_timer_exit(); oprofilefs_unregister(); - oprofile_arch_exit(); + if (timer_mode) + oprofile_timer_exit(); + else + oprofile_arch_exit(); } diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c index 89f63456646..84a208dbed9 100644 --- a/drivers/oprofile/oprofile_files.c +++ b/drivers/oprofile/oprofile_files.c @@ -45,7 +45,7 @@ static ssize_t timeout_write(struct file *file, char const __user *buf, return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_timeout(val); @@ -84,7 +84,7 @@ static ssize_t depth_write(struct file *file, char const __user *buf, size_t cou return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(&oprofile_backtrace_depth, val); @@ -141,9 +141,10 @@ static ssize_t enable_write(struct file *file, char const __user *buf, size_t co return -EINVAL; retval = oprofilefs_ulong_from_user(&val, buf, count); - if (retval) + if (retval <= 0) return retval; + retval = 0; if (val) retval = oprofile_start(); else diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index d0de6cc2d7a..2f0aa0f700e 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -60,6 +60,13 @@ ssize_t oprofilefs_ulong_to_user(unsigned long val, char __user *buf, size_t cou } +/* + * Note: If oprofilefs_ulong_from_user() returns 0, then *val remains + * unchanged and might be uninitialized. This follows write syscall + * implementation when count is zero: "If count is zero ... [and if] + * no errors are detected, 0 will be returned without causing any + * other effect." (man 2 write) + */ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_t count) { char tmpbuf[TMPBUFSIZE]; @@ -79,7 +86,7 @@ int oprofilefs_ulong_from_user(unsigned long *val, char const __user *buf, size_ raw_spin_lock_irqsave(&oprofilefs_lock, flags); *val = simple_strtoul(tmpbuf, NULL, 0); raw_spin_unlock_irqrestore(&oprofilefs_lock, flags); - return 0; + return count; } @@ -99,7 +106,7 @@ static ssize_t ulong_write_file(struct file *file, char const __user *buf, size_ return -EINVAL; retval = oprofilefs_ulong_from_user(&value, buf, count); - if (retval) + if (retval <= 0) return retval; retval = oprofile_set_ulong(file->private_data, value); diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 3ef44624f51..878fba12658 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c @@ -110,6 +110,7 @@ int oprofile_timer_init(struct oprofile_operations *ops) ops->start = oprofile_hrtimer_start; ops->stop = oprofile_hrtimer_stop; ops->cpu_type = "timer"; + printk(KERN_INFO "oprofile: using timer interrupt.\n"); return 0; } diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index b6f9749b4fa..f02b5235056 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -76,6 +76,7 @@ config PCI_IOV config PCI_PRI bool "PCI PRI support" + depends on PCI select PCI_ATS help PRI is the PCI Page Request Interface. It allows PCI devices that are diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c index 7ec56fb0bd7..b0dd08e6a9d 100644 --- a/drivers/pci/ats.c +++ b/drivers/pci/ats.c @@ -13,6 +13,7 @@ #include <linux/export.h> #include <linux/pci-ats.h> #include <linux/pci.h> +#include <linux/slab.h> #include "pci.h" diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 596172b4ae9..9ddf69e3bbe 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -132,6 +132,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) if (!acpi_pci_check_ejectable(pbus, handle) && !is_dock_device(handle)) return AE_OK; + pdev = pbus->self; + if (pdev && pci_is_pcie(pdev)) { + tmp = acpi_find_root_bridge_handle(pdev); + if (tmp) { + struct acpi_pci_root *root = acpi_pci_find_root(tmp); + + if (root && (root->osc_control_set & + OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) + return AE_OK; + } + } + acpi_evaluate_integer(handle, "_ADR", NULL, &adr); device = (adr >> 16) & 0xffff; function = adr & 0xffff; @@ -213,7 +225,6 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv) pdev = pci_get_slot(pbus, PCI_DEVFN(device, function)); if (pdev) { - pdev->current_state = PCI_D0; slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); pci_dev_put(pdev); } @@ -1378,11 +1389,13 @@ find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) { int *count = (int *)context; - if (acpi_is_root_bridge(handle)) { - acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, NULL); - (*count)++; - } + if (!acpi_is_root_bridge(handle)) + return AE_OK; + + (*count)++; + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, NULL); + return AE_OK ; } diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 1e9c9aacc3a..085dbb5fc16 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -213,9 +213,6 @@ static int board_added(struct slot *p_slot) goto err_exit; } - /* Wait for 1 second after checking link training status */ - msleep(1000); - /* Check for a power fault */ if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) { ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot)); diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index 96dc4734e4a..7b1414810ae 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -280,6 +280,14 @@ int pciehp_check_link_status(struct controller *ctrl) else msleep(1000); + /* + * Need to wait for 1000 ms after Data Link Layer Link Active + * (DLLLA) bit reads 1b before sending configuration request. + * We need it before checking Link Training (LT) bit becuase + * LT is still set even after DLLLA bit is set on some platform. + */ + msleep(1000); + retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); if (retval) { ctrl_err(ctrl, "Cannot read LNKSTATUS register\n"); @@ -294,6 +302,16 @@ int pciehp_check_link_status(struct controller *ctrl) return retval; } + /* + * If the port supports Link speeds greater than 5.0 GT/s, we + * must wait for 100 ms after Link training completes before + * sending configuration request. + */ + if (ctrl->pcie->port->subordinate->max_bus_speed > PCIE_SPEED_5_0GT) + msleep(100); + + pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); + return retval; } @@ -484,7 +502,6 @@ int pciehp_power_on_slot(struct slot * slot) u16 slot_cmd; u16 cmd_mask; u16 slot_status; - u16 lnk_status; int retval = 0; /* Clear sticky power-fault bit from previous power failures */ @@ -516,14 +533,6 @@ int pciehp_power_on_slot(struct slot * slot) ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__, pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_cmd); - retval = pciehp_readw(ctrl, PCI_EXP_LNKSTA, &lnk_status); - if (retval) { - ctrl_err(ctrl, "%s: Cannot read LNKSTA register\n", - __func__); - return retval; - } - pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status); - return retval; } diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c index aca972bbfb4..dd7e0c51a33 100644 --- a/drivers/pci/hotplug/shpchp_core.c +++ b/drivers/pci/hotplug/shpchp_core.c @@ -278,8 +278,8 @@ static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) static int is_shpc_capable(struct pci_dev *dev) { - if ((dev->vendor == PCI_VENDOR_ID_AMD) || (dev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) + if (dev->vendor == PCI_VENDOR_ID_AMD && + dev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) return 1; if (!pci_find_capability(dev, PCI_CAP_ID_SHPC)) return 0; diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c index 36547f0ce30..75ba2311b54 100644 --- a/drivers/pci/hotplug/shpchp_hpc.c +++ b/drivers/pci/hotplug/shpchp_hpc.c @@ -944,8 +944,8 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev) ctrl->pci_dev = pdev; /* pci_dev of the P2P bridge */ ctrl_dbg(ctrl, "Hotplug Controller:\n"); - if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device == - PCI_DEVICE_ID_AMD_GOLAM_7450)) { + if (pdev->vendor == PCI_VENDOR_ID_AMD && + pdev->device == PCI_DEVICE_ID_AMD_GOLAM_7450) { /* amd shpc driver doesn't use Base Offset; assume 0 */ ctrl->mmio_base = pci_resource_start(pdev, 0); ctrl->mmio_size = pci_resource_len(pdev, 0); diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index b82c155d7b3..1969a3ee305 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -283,6 +283,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) struct resource *res; struct pci_dev *pdev; struct pci_sriov *iov = dev->sriov; + int bars = 0; if (!nr_virtfn) return 0; @@ -307,6 +308,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + bars |= (1 << (i + PCI_IOV_RESOURCES)); res = dev->resource + PCI_IOV_RESOURCES + i; if (res->parent) nres++; @@ -324,6 +326,11 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) return -ENOMEM; } + if (pci_enable_resources(dev, bars)) { + dev_err(&dev->dev, "SR-IOV: IOV BARS not allocated\n"); + return -ENOMEM; + } + if (iov->link != dev->devfn) { pdev = pci_get_slot(dev->bus, iov->link); if (!pdev) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 6f45a73c6e9..6d4a5319148 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -664,6 +664,9 @@ static int pci_platform_power_transition(struct pci_dev *dev, pci_power_t state) error = platform_pci_set_power_state(dev, state); if (!error) pci_update_current_state(dev, state); + /* Fall back to PCI_D0 if native PM is not supported */ + if (!dev->pm_cap) + dev->current_state = PCI_D0; } else { error = -ENODEV; /* Fall back to PCI_D0 if native PM is not supported */ @@ -1126,7 +1129,11 @@ static int __pci_enable_device_flags(struct pci_dev *dev, if (atomic_add_return(1, &dev->enable_cnt) > 1) return 0; /* already enabled */ - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) + /* only skip sriov related */ + for (i = 0; i <= PCI_ROM_RESOURCE; i++) + if (dev->resource[i].flags & flags) + bars |= (1 << i); + for (i = PCI_BRIDGE_RESOURCES; i < DEVICE_COUNT_RESOURCE; i++) if (dev->resource[i].flags & flags) bars |= (1 << i); diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index ef566443f94..e17e2f8001d 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -2,23 +2,17 @@ # PINCTRL infrastructure and drivers # -menuconfig PINCTRL - bool "PINCTRL Support" +config PINCTRL + bool depends on EXPERIMENTAL - help - This enables the PINCTRL subsystem for controlling pins - on chip packages, for example multiplexing pins on primarily - PGA and BGA packages for systems on chip. - - If unsure, say N. if PINCTRL +menu "Pin controllers" + depends on PINCTRL + config PINMUX bool "Support pinmux controllers" - help - Say Y here if you want the pincontrol subsystem to handle pin - multiplexing drivers. config DEBUG_PINCTRL bool "Debug PINCTRL calls" @@ -30,14 +24,12 @@ config PINMUX_SIRF bool "CSR SiRFprimaII pinmux driver" depends on ARCH_PRIMA2 select PINMUX - help - Say Y here to enable the SiRFprimaII pinmux driver config PINMUX_U300 bool "U300 pinmux driver" depends on ARCH_U300 select PINMUX - help - Say Y here to enable the U300 pinmux driver + +endmenu endif diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index f4e3d82379d..7f43cf86d77 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -83,8 +83,10 @@ config DELL_LAPTOP depends on EXPERIMENTAL depends on BACKLIGHT_CLASS_DEVICE depends on RFKILL || RFKILL = n - depends on POWER_SUPPLY depends on SERIO_I8042 + select POWER_SUPPLY + select LEDS_CLASS + select NEW_LEDS default n ---help--- This driver adds support for rfkill and backlight control to Dell diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index a43cfd906c6..d93e962f261 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -589,14 +589,14 @@ static const struct backlight_ops dell_ops = { .update_status = dell_send_intensity, }; -static void touchpad_led_on() +static void touchpad_led_on(void) { int command = 0x97; char data = 1; i8042_command(&data, command | 1 << 12); } -static void touchpad_led_off() +static void touchpad_led_off(void) { int command = 0x97; char data = 2; diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 13ef8c37471..dcdc1f4a462 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -121,6 +121,7 @@ struct toshiba_acpi_dev { int illumination_supported:1; int video_supported:1; int fan_supported:1; + int system_event_supported:1; struct mutex mutex; }; @@ -724,7 +725,7 @@ static int keys_proc_show(struct seq_file *m, void *v) u32 hci_result; u32 value; - if (!dev->key_event_valid) { + if (!dev->key_event_valid && dev->system_event_supported) { hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); if (hci_result == HCI_SUCCESS) { dev->key_event_valid = 1; @@ -964,6 +965,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev) /* enable event fifo */ hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); + if (hci_result == HCI_SUCCESS) + dev->system_event_supported = 1; props.type = BACKLIGHT_PLATFORM; props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; @@ -1032,12 +1035,15 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) { struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); u32 hci_result, value; + int retries = 3; - if (event != 0x80) + if (!dev->system_event_supported || event != 0x80) return; + do { hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); - if (hci_result == HCI_SUCCESS) { + switch (hci_result) { + case HCI_SUCCESS: if (value == 0x100) continue; /* act on key press; ignore key release */ @@ -1049,14 +1055,19 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) pr_info("Unknown key %x\n", value); } - } else if (hci_result == HCI_NOT_SUPPORTED) { + break; + case HCI_NOT_SUPPORTED: /* This is a workaround for an unresolved issue on * some machines where system events sporadically * become disabled. */ hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); pr_notice("Re-enabled hotkeys\n"); + /* fall through */ + default: + retries--; + break; } - } while (hci_result != HCI_EMPTY); + } while (retries && hci_result != HCI_EMPTY); } diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index bbf3edd85be..5be4a392a3a 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -509,15 +509,12 @@ static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev, struct acpi_resource_dma *p) { int i; - unsigned char map = 0, flags = 0; - - if (p->channel_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char map = 0, flags; for (i = 0; i < p->channel_count; i++) map |= 1 << p->channels[i]; - flags |= dma_flags(dev, p->type, p->bus_master, p->transfer); + flags = dma_flags(dev, p->type, p->bus_master, p->transfer); pnp_register_dma_resource(dev, option_flags, map, flags); } @@ -527,17 +524,14 @@ static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) if (p->interrupts[i]) __set_bit(p->interrupts[i], map.bits); - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -547,10 +541,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, { int i; pnp_irq_mask_t map; - unsigned char flags = 0; - - if (p->interrupt_count == 0) - flags |= IORESOURCE_DISABLED; + unsigned char flags; bitmap_zero(map.bits, PNP_IRQ_NR); for (i = 0; i < p->interrupt_count; i++) { @@ -564,7 +555,7 @@ static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev, } } - flags |= irq_flags(p->triggering, p->polarity, p->sharable); + flags = irq_flags(p->triggering, p->polarity, p->sharable); pnp_register_irq_resource(dev, option_flags, &map, flags); } @@ -574,11 +565,8 @@ static __init void pnpacpi_parse_port_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (io->io_decode == ACPI_DECODE_16) - flags |= IORESOURCE_IO_16BIT_ADDR; + flags = IORESOURCE_IO_16BIT_ADDR; pnp_register_port_resource(dev, option_flags, io->minimum, io->maximum, io->alignment, io->address_length, flags); } @@ -587,13 +575,8 @@ static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev, unsigned int option_flags, struct acpi_resource_fixed_io *io) { - unsigned char flags = 0; - - if (io->address_length == 0) - flags |= IORESOURCE_DISABLED; - pnp_register_port_resource(dev, option_flags, io->address, io->address, - 0, io->address_length, flags | IORESOURCE_IO_FIXED); + 0, io->address_length, IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, @@ -602,11 +585,8 @@ static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -617,11 +597,8 @@ static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->maximum, p->alignment, p->address_length, flags); } @@ -632,11 +609,8 @@ static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev, { unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->address, p->address, 0, p->address_length, flags); } @@ -656,19 +630,16 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev, return; } - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, @@ -678,19 +649,16 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev, struct acpi_resource_extended_address64 *p = &r->data.ext_address64; unsigned char flags = 0; - if (p->address_length == 0) - flags |= IORESOURCE_DISABLED; - if (p->resource_type == ACPI_MEMORY_RANGE) { if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY) - flags |= IORESOURCE_MEM_WRITEABLE; + flags = IORESOURCE_MEM_WRITEABLE; pnp_register_mem_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, flags); } else if (p->resource_type == ACPI_IO_RANGE) pnp_register_port_resource(dev, option_flags, p->minimum, p->minimum, 0, p->address_length, - flags | IORESOURCE_IO_FIXED); + IORESOURCE_IO_FIXED); } struct acpipnp_parse_option_s { diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index cffcb7c00b0..01fa671ec97 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c @@ -61,7 +61,8 @@ MODULE_PARM_DESC(debug, "Flag to enable PMIC Battery debug messages."); #define PMIC_BATT_CHR_SBATDET_MASK (1 << 5) #define PMIC_BATT_CHR_SDCLMT_MASK (1 << 6) #define PMIC_BATT_CHR_SUSBOVP_MASK (1 << 7) -#define PMIC_BATT_CHR_EXCPT_MASK 0xC6 +#define PMIC_BATT_CHR_EXCPT_MASK 0x86 + #define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31) #define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF @@ -304,11 +305,6 @@ static void pmic_battery_read_status(struct pmic_power_module_info *pbi) pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; pmic_battery_log_event(BATT_EVENT_BATOVP_EXCPT); batt_exception = 1; - } else if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) { - pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT); - batt_exception = 1; } else if (r8 & PMIC_BATT_CHR_STEMP_MASK) { pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT; pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; @@ -316,6 +312,10 @@ static void pmic_battery_read_status(struct pmic_power_module_info *pbi) batt_exception = 1; } else { pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; + if (r8 & PMIC_BATT_CHR_SDCLMT_MASK) { + /* PMIC will change charging current automatically */ + pmic_battery_log_event(BATT_EVENT_DCLMT_EXCPT); + } } } diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c index d9fb729535a..fb7300837fe 100644 --- a/drivers/ps3/ps3-vuart.c +++ b/drivers/ps3/ps3-vuart.c @@ -952,7 +952,7 @@ static int ps3_vuart_bus_interrupt_get(void) } result = request_irq(vuart_bus_priv.virq, ps3_vuart_irq_handler, - IRQF_DISABLED, "vuart", &vuart_bus_priv); + 0, "vuart", &vuart_bus_priv); if (result) { pr_debug("%s:%d: request_irq failed (%d)\n", diff --git a/drivers/ps3/ps3stor_lib.c b/drivers/ps3/ps3stor_lib.c index cc328dec946..8c3f5adf1bc 100644 --- a/drivers/ps3/ps3stor_lib.c +++ b/drivers/ps3/ps3stor_lib.c @@ -167,7 +167,7 @@ int ps3stor_setup(struct ps3_storage_device *dev, irq_handler_t handler) goto fail_close_device; } - error = request_irq(dev->irq, handler, IRQF_DISABLED, + error = request_irq(dev->irq, handler, 0, dev->sbd.core.driver->name, dev); if (error) { dev_err(&dev->sbd.core, "%s:%u: request_irq failed %d\n", diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index cf3f9997546..10451a15e82 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c @@ -101,7 +101,9 @@ static s32 scaled_ppm_to_ppb(long ppm) static int ptp_clock_getres(struct posix_clock *pc, struct timespec *tp) { - return 1; /* always round timer functions to one nanosecond */ + tp->tv_sec = 0; + tp->tv_nsec = 1; + return 0; } static int ptp_clock_settime(struct posix_clock *pc, const struct timespec *tp) diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c index 5225930a10c..691b1ab1a3d 100644 --- a/drivers/rapidio/devices/tsi721.c +++ b/drivers/rapidio/devices/tsi721.c @@ -851,14 +851,12 @@ static int tsi721_doorbell_init(struct tsi721_device *priv) INIT_WORK(&priv->idb_work, tsi721_db_dpc); /* Allocate buffer for inbound doorbells queue */ - priv->idb_base = dma_alloc_coherent(&priv->pdev->dev, + priv->idb_base = dma_zalloc_coherent(&priv->pdev->dev, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE, &priv->idb_dma, GFP_KERNEL); if (!priv->idb_base) return -ENOMEM; - memset(priv->idb_base, 0, IDB_QSIZE * TSI721_IDB_ENTRY_SIZE); - dev_dbg(&priv->pdev->dev, "Allocated IDB buffer @ %p (phys = %llx)\n", priv->idb_base, (unsigned long long)priv->idb_dma); @@ -904,7 +902,7 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) */ /* Allocate space for DMA descriptors */ - bd_ptr = dma_alloc_coherent(&priv->pdev->dev, + bd_ptr = dma_zalloc_coherent(&priv->pdev->dev, bd_num * sizeof(struct tsi721_dma_desc), &bd_phys, GFP_KERNEL); if (!bd_ptr) @@ -913,8 +911,6 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) priv->bdma[chnum].bd_phys = bd_phys; priv->bdma[chnum].bd_base = bd_ptr; - memset(bd_ptr, 0, bd_num * sizeof(struct tsi721_dma_desc)); - dev_dbg(&priv->pdev->dev, "DMA descriptors @ %p (phys = %llx)\n", bd_ptr, (unsigned long long)bd_phys); @@ -922,7 +918,7 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) sts_size = (bd_num >= TSI721_DMA_MINSTSSZ) ? bd_num : TSI721_DMA_MINSTSSZ; sts_size = roundup_pow_of_two(sts_size); - sts_ptr = dma_alloc_coherent(&priv->pdev->dev, + sts_ptr = dma_zalloc_coherent(&priv->pdev->dev, sts_size * sizeof(struct tsi721_dma_sts), &sts_phys, GFP_KERNEL); if (!sts_ptr) { @@ -938,8 +934,6 @@ static int tsi721_bdma_ch_init(struct tsi721_device *priv, int chnum) priv->bdma[chnum].sts_base = sts_ptr; priv->bdma[chnum].sts_size = sts_size; - memset(sts_ptr, 0, sts_size); - dev_dbg(&priv->pdev->dev, "desc status FIFO @ %p (phys = %llx) size=0x%x\n", sts_ptr, (unsigned long long)sts_phys, sts_size); @@ -1400,7 +1394,7 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, /* Outbound message descriptor status FIFO allocation */ priv->omsg_ring[mbox].sts_size = roundup_pow_of_two(entries + 1); - priv->omsg_ring[mbox].sts_base = dma_alloc_coherent(&priv->pdev->dev, + priv->omsg_ring[mbox].sts_base = dma_zalloc_coherent(&priv->pdev->dev, priv->omsg_ring[mbox].sts_size * sizeof(struct tsi721_dma_sts), &priv->omsg_ring[mbox].sts_phys, GFP_KERNEL); @@ -1412,9 +1406,6 @@ static int tsi721_open_outb_mbox(struct rio_mport *mport, void *dev_id, goto out_desc; } - memset(priv->omsg_ring[mbox].sts_base, 0, - entries * sizeof(struct tsi721_dma_sts)); - /* * Configure Outbound Messaging Engine */ @@ -2116,8 +2107,8 @@ static int __devinit tsi721_setup_mport(struct tsi721_device *priv) INIT_LIST_HEAD(&mport->dbells); rio_init_dbell_res(&mport->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); - rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 0); - rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); + rio_init_mbox_res(&mport->riores[RIO_INB_MBOX_RESOURCE], 0, 3); + rio_init_mbox_res(&mport->riores[RIO_OUTB_MBOX_RESOURCE], 0, 3); strcpy(mport->name, "Tsi721 mport"); /* Hook up interrupt handler */ @@ -2163,7 +2154,7 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct tsi721_device *priv; - int i; + int i, cap; int err; u32 regval; @@ -2271,10 +2262,20 @@ static int __devinit tsi721_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Unable to set consistent DMA mask\n"); } - /* Clear "no snoop" and "relaxed ordering" bits. */ - pci_read_config_dword(pdev, 0x40 + PCI_EXP_DEVCTL, ®val); - regval &= ~(PCI_EXP_DEVCTL_RELAX_EN | PCI_EXP_DEVCTL_NOSNOOP_EN); - pci_write_config_dword(pdev, 0x40 + PCI_EXP_DEVCTL, regval); + cap = pci_pcie_cap(pdev); + BUG_ON(cap == 0); + + /* Clear "no snoop" and "relaxed ordering" bits, use default MRRS. */ + pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL, ®val); + regval &= ~(PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_RELAX_EN | + PCI_EXP_DEVCTL_NOSNOOP_EN); + regval |= 0x2 << MAX_READ_REQUEST_SZ_SHIFT; + pci_write_config_dword(pdev, cap + PCI_EXP_DEVCTL, regval); + + /* Adjust PCIe completion timeout. */ + pci_read_config_dword(pdev, cap + PCI_EXP_DEVCTL2, ®val); + regval &= ~(0x0f); + pci_write_config_dword(pdev, cap + PCI_EXP_DEVCTL2, regval | 0x2); /* * FIXUP: correct offsets of MSI-X tables in the MSI-X Capability Block diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index 58be4deb140..822e54c394d 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h @@ -72,6 +72,8 @@ #define TSI721_MSIXPBA_OFFSET 0x2a000 #define TSI721_PCIECFG_EPCTL 0x400 +#define MAX_READ_REQUEST_SZ_SHIFT 12 + /* * Event Management Registers */ diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 5abeb3ac3e8..298c6c6a279 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -160,7 +160,7 @@ static struct aat2870_regulator *aat2870_get_regulator(int id) break; } - if (!ri) + if (i == ARRAY_SIZE(aat2870_regulators)) return NULL; ri->enable_addr = AAT2870_LDO_EN; diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 669d0216022..938398f3e86 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2799,8 +2799,8 @@ void regulator_unregister(struct regulator_dev *rdev) list_del(&rdev->list); if (rdev->supply) regulator_put(rdev->supply); - device_unregister(&rdev->dev); kfree(rdev->constraints); + device_unregister(&rdev->dev); mutex_unlock(®ulator_list_mutex); } EXPORT_SYMBOL_GPL(regulator_unregister); diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 66d2d60b436..b552aae55b4 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -664,10 +664,10 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, switch (id) { case TPS65910_REG_VDD1: - dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; + dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; if (dcdc_mult == 1) dcdc_mult--; - vsel = (selector % VDD1_2_NUM_VOLTS) + 3; + vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; tps65910_modify_bits(pmic, TPS65910_VDD1, (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), @@ -675,10 +675,10 @@ static int tps65910_set_voltage_dcdc(struct regulator_dev *dev, tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: - dcdc_mult = (selector / VDD1_2_NUM_VOLTS) + 1; + dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; if (dcdc_mult == 1) dcdc_mult--; - vsel = (selector % VDD1_2_NUM_VOLTS) + 3; + vsel = (selector % VDD1_2_NUM_VOLT_FINE) + 3; tps65910_modify_bits(pmic, TPS65910_VDD2, (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), @@ -756,9 +756,9 @@ static int tps65910_list_voltage_dcdc(struct regulator_dev *dev, switch (id) { case TPS65910_REG_VDD1: case TPS65910_REG_VDD2: - mult = (selector / VDD1_2_NUM_VOLTS) + 1; + mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; volt = VDD1_2_MIN_VOLT + - (selector % VDD1_2_NUM_VOLTS) * VDD1_2_OFFSET; + (selector % VDD1_2_NUM_VOLT_FINE) * VDD1_2_OFFSET; break; case TPS65911_REG_VDDCTRL: volt = VDDCTRL_MIN_VOLT + (selector * VDDCTRL_OFFSET); @@ -947,6 +947,8 @@ static __devinit int tps65910_probe(struct platform_device *pdev) if (i == TPS65910_REG_VDD1 || i == TPS65910_REG_VDD2) { pmic->desc[i].ops = &tps65910_ops_dcdc; + pmic->desc[i].n_voltages = VDD1_2_NUM_VOLT_FINE * + VDD1_2_NUM_VOLT_COARSE; } else if (i == TPS65910_REG_VDD3) { if (tps65910_chip_id(tps65910) == TPS65910) pmic->desc[i].ops = &tps65910_ops_vdd3; diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c index ee8747f4fa0..11cc308d66e 100644 --- a/drivers/regulator/twl-regulator.c +++ b/drivers/regulator/twl-regulator.c @@ -71,6 +71,7 @@ struct twlreg_info { #define VREG_TYPE 1 #define VREG_REMAP 2 #define VREG_DEDICATED 3 /* LDO control */ +#define VREG_VOLTAGE_SMPS_4030 9 /* TWL6030 register offsets */ #define VREG_TRANS 1 #define VREG_STATE 2 @@ -514,6 +515,32 @@ static struct regulator_ops twl4030ldo_ops = { .get_status = twl4030reg_get_status, }; +static int +twl4030smps_set_voltage(struct regulator_dev *rdev, int min_uV, int max_uV, + unsigned *selector) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + int vsel = DIV_ROUND_UP(min_uV - 600000, 12500); + + twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE_SMPS_4030, + vsel); + return 0; +} + +static int twl4030smps_get_voltage(struct regulator_dev *rdev) +{ + struct twlreg_info *info = rdev_get_drvdata(rdev); + int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, + VREG_VOLTAGE_SMPS_4030); + + return vsel * 12500 + 600000; +} + +static struct regulator_ops twl4030smps_ops = { + .set_voltage = twl4030smps_set_voltage, + .get_voltage = twl4030smps_get_voltage, +}; + static int twl6030ldo_list_voltage(struct regulator_dev *rdev, unsigned index) { struct twlreg_info *info = rdev_get_drvdata(rdev); @@ -856,6 +883,21 @@ static struct regulator_ops twlsmps_ops = { }, \ } +#define TWL4030_ADJUSTABLE_SMPS(label, offset, num, turnon_delay, remap_conf) \ + { \ + .base = offset, \ + .id = num, \ + .delay = turnon_delay, \ + .remap = remap_conf, \ + .desc = { \ + .name = #label, \ + .id = TWL4030_REG_##label, \ + .ops = &twl4030smps_ops, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + }, \ + } + #define TWL6030_ADJUSTABLE_LDO(label, offset, min_mVolts, max_mVolts) { \ .base = offset, \ .min_mV = min_mVolts, \ @@ -947,8 +989,8 @@ static struct twlreg_info twl_regs[] = { TWL4030_ADJUSTABLE_LDO(VINTANA2, 0x43, 12, 100, 0x08), TWL4030_FIXED_LDO(VINTDIG, 0x47, 1500, 13, 100, 0x08), TWL4030_ADJUSTABLE_LDO(VIO, 0x4b, 14, 1000, 0x08), - TWL4030_ADJUSTABLE_LDO(VDD1, 0x55, 15, 1000, 0x08), - TWL4030_ADJUSTABLE_LDO(VDD2, 0x63, 16, 1000, 0x08), + TWL4030_ADJUSTABLE_SMPS(VDD1, 0x55, 15, 1000, 0x08), + TWL4030_ADJUSTABLE_SMPS(VDD2, 0x63, 16, 1000, 0x08), TWL4030_FIXED_LDO(VUSB1V5, 0x71, 1500, 17, 100, 0x08), TWL4030_FIXED_LDO(VUSB1V8, 0x74, 1800, 18, 100, 0x08), TWL4030_FIXED_LDO(VUSB3V1, 0x77, 3100, 19, 150, 0x08), diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index e8326f26fa2..dc4c2748bbc 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -63,7 +63,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg) */ delta = timespec_sub(old_system, old_rtc); delta_delta = timespec_sub(delta, old_delta); - if (abs(delta_delta.tv_sec) >= 2) { + if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) { /* * if delta_delta is too large, assume time correction * has occured and set old_delta to the current delta. @@ -97,9 +97,8 @@ static int rtc_resume(struct device *dev) rtc_tm_to_time(&tm, &new_rtc.tv_sec); new_rtc.tv_nsec = 0; - if (new_rtc.tv_sec <= old_rtc.tv_sec) { - if (new_rtc.tv_sec < old_rtc.tv_sec) - pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); + if (new_rtc.tv_sec < old_rtc.tv_sec) { + pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); return 0; } @@ -116,7 +115,8 @@ static int rtc_resume(struct device *dev) sleep_time = timespec_sub(sleep_time, timespec_sub(new_system, old_system)); - timekeeping_inject_sleeptime(&sleep_time); + if (sleep_time.tv_sec >= 0) + timekeeping_inject_sleeptime(&sleep_time); return 0; } diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index eda128fc1d3..64aedd8cc09 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -357,10 +357,19 @@ static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) static struct rtc_class_ops m41t80_rtc_ops = { .read_time = m41t80_rtc_read_time, .set_time = m41t80_rtc_set_time, + /* + * XXX - m41t80 alarm functionality is reported broken. + * until it is fixed, don't register alarm functions. + * .read_alarm = m41t80_rtc_read_alarm, .set_alarm = m41t80_rtc_set_alarm, + */ .proc = m41t80_rtc_proc, + /* + * See above comment on broken alarm + * .alarm_irq_enable = m41t80_rtc_alarm_irq_enable, + */ }; #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index d33544802a2..bb21f443fb7 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -76,12 +76,15 @@ static inline unsigned char vrtc_is_updating(void) /* * rtc_time's year contains the increment over 1900, but vRTC's YEAR * register can't be programmed to value larger than 0x64, so vRTC - * driver chose to use 1960 (1970 is UNIX time start point) as the base, + * driver chose to use 1972 (1970 is UNIX time start point) as the base, * and does the translation at read/write time. * - * Why not just use 1970 as the offset? it's because using 1960 will + * Why not just use 1970 as the offset? it's because using 1972 will * make it consistent in leap year setting for both vrtc and low-level - * physical rtc devices. + * physical rtc devices. Then why not use 1960 as the offset? If we use + * 1960, for a device's first use, its YEAR register is 0 and the system + * year will be parsed as 1960 which is not a valid UNIX time and will + * cause many applications to fail mysteriously. */ static int mrst_read_time(struct device *dev, struct rtc_time *time) { @@ -99,10 +102,10 @@ static int mrst_read_time(struct device *dev, struct rtc_time *time) time->tm_year = vrtc_cmos_read(RTC_YEAR); spin_unlock_irqrestore(&rtc_lock, flags); - /* Adjust for the 1960/1900 */ - time->tm_year += 60; + /* Adjust for the 1972/1900 */ + time->tm_year += 72; time->tm_mon--; - return RTC_24H; + return rtc_valid_tm(time); } static int mrst_set_time(struct device *dev, struct rtc_time *time) @@ -119,9 +122,9 @@ static int mrst_set_time(struct device *dev, struct rtc_time *time) min = time->tm_min; sec = time->tm_sec; - if (yrs < 70 || yrs > 138) + if (yrs < 72 || yrs > 138) return -EINVAL; - yrs -= 60; + yrs -= 72; spin_lock_irqsave(&rtc_lock, flags); diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index b3eba3cddd4..e4b6880aabd 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -220,7 +220,7 @@ static void puv3_rtc_enable(struct platform_device *pdev, int en) } } -static int puv3_rtc_remove(struct platform_device *dev) +static int __devexit puv3_rtc_remove(struct platform_device *dev) { struct rtc_device *rtc = platform_get_drvdata(dev); @@ -236,7 +236,7 @@ static int puv3_rtc_remove(struct platform_device *dev) return 0; } -static int puv3_rtc_probe(struct platform_device *pdev) +static int __devinit puv3_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7639ab906f0..5b979d9cc33 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -202,7 +202,6 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = s3c_rtc_base; int year = tm->tm_year - 100; - clk_enable(rtc_clk); pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n", 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -214,6 +213,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) return -EINVAL; } + clk_enable(rtc_clk); writeb(bin2bcd(tm->tm_sec), base + S3C2410_RTCSEC); writeb(bin2bcd(tm->tm_min), base + S3C2410_RTCMIN); writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 43068fbd0ba..1b6d9247fdc 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -641,6 +641,8 @@ static int __init zcore_init(void) if (ipl_info.type != IPL_TYPE_FCP_DUMP) return -ENODATA; + if (OLDMEM_BASE) + return -ENODATA; zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long)); debug_register_view(zcore_dbf, &debug_sprintf_view); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 75c3f1f8fd4..a84631a7391 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -529,10 +529,7 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) int chsc_chp_vary(struct chp_id chpid, int on) { struct channel_path *chp = chpid_to_chp(chpid); - struct chp_link link; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); /* @@ -542,10 +539,10 @@ int chsc_chp_vary(struct chp_id chpid, int on) /* Try to update the channel path descritor. */ chsc_determine_base_channel_path_desc(chpid, &chp->desc); for_each_subchannel_staged(s390_subchannel_vary_chpid_on, - __s390_vary_chpid_on, &link); + __s390_vary_chpid_on, &chpid); } else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, - NULL, &link); + NULL, &chpid); return 0; } diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 155a82bcb9e..4a1ff5c2eb8 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -68,8 +68,13 @@ struct schib { __u8 mda[4]; /* model dependent area */ } __attribute__ ((packed,aligned(4))); +/* + * When rescheduled, todo's with higher values will overwrite those + * with lower values. + */ enum sch_todo { SCH_TODO_NOTHING, + SCH_TODO_EVAL, SCH_TODO_UNREG, }; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 92d7324acb1..21908e67bf6 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -195,51 +195,6 @@ void css_sch_device_unregister(struct subchannel *sch) } EXPORT_SYMBOL_GPL(css_sch_device_unregister); -static void css_sch_todo(struct work_struct *work) -{ - struct subchannel *sch; - enum sch_todo todo; - - sch = container_of(work, struct subchannel, todo_work); - /* Find out todo. */ - spin_lock_irq(sch->lock); - todo = sch->todo; - CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid, - sch->schid.sch_no, todo); - sch->todo = SCH_TODO_NOTHING; - spin_unlock_irq(sch->lock); - /* Perform todo. */ - if (todo == SCH_TODO_UNREG) - css_sch_device_unregister(sch); - /* Release workqueue ref. */ - put_device(&sch->dev); -} - -/** - * css_sched_sch_todo - schedule a subchannel operation - * @sch: subchannel - * @todo: todo - * - * Schedule the operation identified by @todo to be performed on the slow path - * workqueue. Do nothing if another operation with higher priority is already - * scheduled. Needs to be called with subchannel lock held. - */ -void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo) -{ - CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n", - sch->schid.ssid, sch->schid.sch_no, todo); - if (sch->todo >= todo) - return; - /* Get workqueue ref. */ - if (!get_device(&sch->dev)) - return; - sch->todo = todo; - if (!queue_work(cio_work_q, &sch->todo_work)) { - /* Already queued, release workqueue ref. */ - put_device(&sch->dev); - } -} - static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) { int i; @@ -466,6 +421,65 @@ static void css_evaluate_subchannel(struct subchannel_id schid, int slow) css_schedule_eval(schid); } +/** + * css_sched_sch_todo - schedule a subchannel operation + * @sch: subchannel + * @todo: todo + * + * Schedule the operation identified by @todo to be performed on the slow path + * workqueue. Do nothing if another operation with higher priority is already + * scheduled. Needs to be called with subchannel lock held. + */ +void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo) +{ + CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d\n", + sch->schid.ssid, sch->schid.sch_no, todo); + if (sch->todo >= todo) + return; + /* Get workqueue ref. */ + if (!get_device(&sch->dev)) + return; + sch->todo = todo; + if (!queue_work(cio_work_q, &sch->todo_work)) { + /* Already queued, release workqueue ref. */ + put_device(&sch->dev); + } +} + +static void css_sch_todo(struct work_struct *work) +{ + struct subchannel *sch; + enum sch_todo todo; + int ret; + + sch = container_of(work, struct subchannel, todo_work); + /* Find out todo. */ + spin_lock_irq(sch->lock); + todo = sch->todo; + CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d\n", sch->schid.ssid, + sch->schid.sch_no, todo); + sch->todo = SCH_TODO_NOTHING; + spin_unlock_irq(sch->lock); + /* Perform todo. */ + switch (todo) { + case SCH_TODO_NOTHING: + break; + case SCH_TODO_EVAL: + ret = css_evaluate_known_subchannel(sch, 1); + if (ret == -EAGAIN) { + spin_lock_irq(sch->lock); + css_sched_sch_todo(sch, todo); + spin_unlock_irq(sch->lock); + } + break; + case SCH_TODO_UNREG: + css_sch_device_unregister(sch); + break; + } + /* Release workqueue ref. */ + put_device(&sch->dev); +} + static struct idset *slow_subchannel_set; static spinlock_t slow_subchannel_lock; static wait_queue_head_t css_eval_wq; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index d734f4a0eca..47269858ecb 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -1868,9 +1868,9 @@ static void __ccw_device_pm_restore(struct ccw_device *cdev) */ cdev->private->flags.resuming = 1; cdev->private->path_new_mask = LPM_ANYPATH; - css_schedule_eval(sch->schid); + css_sched_sch_todo(sch, SCH_TODO_EVAL); spin_unlock_irq(sch->lock); - css_complete_work(); + css_wait_for_slow_path(); /* cdev may have been moved to a different subchannel. */ sch = to_subchannel(cdev->dev.parent); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 52c233fa2b1..1b853513c89 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -496,8 +496,26 @@ static void ccw_device_reset_path_events(struct ccw_device *cdev) cdev->private->pgid_reset_mask = 0; } -void -ccw_device_verify_done(struct ccw_device *cdev, int err) +static void create_fake_irb(struct irb *irb, int type) +{ + memset(irb, 0, sizeof(*irb)); + if (type == FAKE_CMD_IRB) { + struct cmd_scsw *scsw = &irb->scsw.cmd; + scsw->cc = 1; + scsw->fctl = SCSW_FCTL_START_FUNC; + scsw->actl = SCSW_ACTL_START_PEND; + scsw->stctl = SCSW_STCTL_STATUS_PEND; + } else if (type == FAKE_TM_IRB) { + struct tm_scsw *scsw = &irb->scsw.tm; + scsw->x = 1; + scsw->cc = 1; + scsw->fctl = SCSW_FCTL_START_FUNC; + scsw->actl = SCSW_ACTL_START_PEND; + scsw->stctl = SCSW_STCTL_STATUS_PEND; + } +} + +void ccw_device_verify_done(struct ccw_device *cdev, int err) { struct subchannel *sch; @@ -520,12 +538,8 @@ callback: ccw_device_done(cdev, DEV_STATE_ONLINE); /* Deliver fake irb to device driver, if needed. */ if (cdev->private->flags.fake_irb) { - memset(&cdev->private->irb, 0, sizeof(struct irb)); - cdev->private->irb.scsw.cmd.cc = 1; - cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC; - cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND; - cdev->private->irb.scsw.cmd.stctl = - SCSW_STCTL_STATUS_PEND; + create_fake_irb(&cdev->private->irb, + cdev->private->flags.fake_irb); cdev->private->flags.fake_irb = 0; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index f98698d5735..ec7fb6d3b47 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -198,7 +198,7 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, if (cdev->private->state == DEV_STATE_VERIFY) { /* Remember to fake irb when finished. */ if (!cdev->private->flags.fake_irb) { - cdev->private->flags.fake_irb = 1; + cdev->private->flags.fake_irb = FAKE_CMD_IRB; cdev->private->intparm = intparm; return 0; } else @@ -213,9 +213,9 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, ret = cio_set_options (sch, flags); if (ret) return ret; - /* Adjust requested path mask to excluded varied off paths. */ + /* Adjust requested path mask to exclude unusable paths. */ if (lpm) { - lpm &= sch->opm; + lpm &= sch->lpm; if (lpm == 0) return -EACCES; } @@ -605,11 +605,21 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, sch = to_subchannel(cdev->dev.parent); if (!sch->schib.pmcw.ena) return -EINVAL; + if (cdev->private->state == DEV_STATE_VERIFY) { + /* Remember to fake irb when finished. */ + if (!cdev->private->flags.fake_irb) { + cdev->private->flags.fake_irb = FAKE_TM_IRB; + cdev->private->intparm = intparm; + return 0; + } else + /* There's already a fake I/O around. */ + return -EBUSY; + } if (cdev->private->state != DEV_STATE_ONLINE) return -EIO; - /* Adjust requested path mask to excluded varied off paths. */ + /* Adjust requested path mask to exclude unusable paths. */ if (lpm) { - lpm &= sch->opm; + lpm &= sch->lpm; if (lpm == 0) return -EACCES; } diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index 2ebb492a5c1..76253dfcc1b 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h @@ -111,6 +111,9 @@ enum cdev_todo { CDEV_TODO_UNREG_EVAL, }; +#define FAKE_CMD_IRB 1 +#define FAKE_TM_IRB 2 + struct ccw_device_private { struct ccw_device *cdev; struct subchannel *sch; @@ -138,7 +141,7 @@ struct ccw_device_private { unsigned int doverify:1; /* delayed path verification */ unsigned int donotify:1; /* call notify function */ unsigned int recog_done:1; /* dev. recog. complete */ - unsigned int fake_irb:1; /* deliver faked irb */ + unsigned int fake_irb:2; /* deliver faked irb */ unsigned int resuming:1; /* recognition while resume */ unsigned int pgroup:1; /* pathgroup is set up */ unsigned int mpath:1; /* multipathing is set up */ diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b77ae519d79..96bbe9d12a7 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1271,18 +1271,16 @@ ap_config_timeout(unsigned long ptr) } /** - * ap_schedule_poll_timer(): Schedule poll timer. + * __ap_schedule_poll_timer(): Schedule poll timer. * * Set up the timer to run the poll tasklet */ -static inline void ap_schedule_poll_timer(void) +static inline void __ap_schedule_poll_timer(void) { ktime_t hr_time; spin_lock_bh(&ap_poll_timer_lock); - if (ap_using_interrupts() || ap_suspend_flag) - goto out; - if (hrtimer_is_queued(&ap_poll_timer)) + if (hrtimer_is_queued(&ap_poll_timer) || ap_suspend_flag) goto out; if (ktime_to_ns(hrtimer_expires_remaining(&ap_poll_timer)) <= 0) { hr_time = ktime_set(0, poll_timeout); @@ -1294,6 +1292,18 @@ out: } /** + * ap_schedule_poll_timer(): Schedule poll timer. + * + * Set up the timer to run the poll tasklet + */ +static inline void ap_schedule_poll_timer(void) +{ + if (ap_using_interrupts()) + return; + __ap_schedule_poll_timer(); +} + +/** * ap_poll_read(): Receive pending reply messages from an AP device. * @ap_dev: pointer to the AP device * @flags: pointer to control flags, bit 2^0 is set if another poll is @@ -1374,8 +1384,9 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) *flags |= 1; *flags |= 2; break; - case AP_RESPONSE_Q_FULL: case AP_RESPONSE_RESET_IN_PROGRESS: + __ap_schedule_poll_timer(); + case AP_RESPONSE_Q_FULL: *flags |= 2; break; case AP_RESPONSE_MESSAGE_TOO_BIG: @@ -1541,6 +1552,8 @@ static void ap_reset(struct ap_device *ap_dev) rc = ap_init_queue(ap_dev->qid); if (rc == -ENODEV) ap_dev->unregistered = 1; + else + __ap_schedule_poll_timer(); } static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index fa80ba1f034..9b66d2d1809 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -4,7 +4,7 @@ menu "S/390 network device drivers" config LCS def_tristate m prompt "Lan Channel Station Interface" - depends on CCW && NETDEVICES && (NET_ETHERNET || TR || FDDI) + depends on CCW && NETDEVICES && (ETHERNET || TR || FDDI) help Select this option if you want to use LCS networking on IBM System z. This device driver supports Token Ring (IEEE 802.5), diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index c28713da1ec..863fc219715 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -50,7 +50,7 @@ #include "lcs.h" -#if !defined(CONFIG_NET_ETHERNET) && \ +#if !defined(CONFIG_ETHERNET) && \ !defined(CONFIG_TR) && !defined(CONFIG_FDDI) #error Cannot compile lcs.c without some net devices switched on. #endif @@ -1634,7 +1634,7 @@ lcs_startlan_auto(struct lcs_card *card) int rc; LCS_DBF_TEXT(2, trace, "strtauto"); -#ifdef CONFIG_NET_ETHERNET +#ifdef CONFIG_ETHERNET card->lan_type = LCS_FRAME_TYPE_ENET; rc = lcs_send_startlan(card, LCS_INITIATOR_TCPIP); if (rc == 0) @@ -2166,7 +2166,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) goto netdev_out; } switch (card->lan_type) { -#ifdef CONFIG_NET_ETHERNET +#ifdef CONFIG_ETHERNET case LCS_FRAME_TYPE_ENET: card->lan_type_trans = eth_type_trans; dev = alloc_etherdev(0); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3251333a23d..b6a6356d09b 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1994,6 +1994,8 @@ static struct net_device *netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; + if (dev_alloc_name(dev, dev->name) < 0) + goto out_netdev; privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index b77c65ed138..4abc79d3963 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -236,8 +236,7 @@ static inline int qeth_is_ipa_enabled(struct qeth_ipa_info *ipa, #define QETH_IN_BUF_COUNT_MAX 128 #define QETH_MAX_BUFFER_ELEMENTS(card) ((card)->qdio.in_buf_size >> 12) #define QETH_IN_BUF_REQUEUE_THRESHOLD(card) \ - ((card)->ssqd.qdioac1 & AC1_SIGA_INPUT_NEEDED ? 1 : \ - ((card)->qdio.in_buf_pool.buf_count / 2)) + ((card)->qdio.in_buf_pool.buf_count / 2) /* buffers we have to be behind before we get a PCI */ #define QETH_PCI_THRESHOLD_A(card) ((card)->qdio.in_buf_pool.buf_count+1) diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 81534437373..fff57de7894 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -881,7 +881,6 @@ EXPORT_SYMBOL_GPL(qeth_do_run_thread); void qeth_schedule_recovery(struct qeth_card *card) { QETH_CARD_TEXT(card, 2, "startrec"); - WARN_ON(1); if (qeth_set_thread_start_bit(card, QETH_RECOVER_THREAD) == 0) schedule_work(&card->kernel_thread_starter); } diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e4c1176ee25..4d5307ddbe5 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -2756,11 +2756,13 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) struct neighbour *n = NULL; struct dst_entry *dst; + rcu_read_lock(); dst = skb_dst(skb); if (dst) n = dst_get_neighbour(dst); if (n) { cast_type = n->type; + rcu_read_unlock(); if ((cast_type == RTN_BROADCAST) || (cast_type == RTN_MULTICAST) || (cast_type == RTN_ANYCAST)) @@ -2768,6 +2770,8 @@ int inline qeth_l3_get_cast_type(struct qeth_card *card, struct sk_buff *skb) else return RTN_UNSPEC; } + rcu_read_unlock(); + /* try something else */ if (skb->protocol == ETH_P_IPV6) return (skb_network_header(skb)[24] == 0xff) ? @@ -2847,6 +2851,8 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr); + + rcu_read_lock(); dst = skb_dst(skb); if (dst) n = dst_get_neighbour(dst); @@ -2893,6 +2899,7 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, QETH_CAST_UNICAST | QETH_HDR_PASSTHRU; } } + rcu_read_unlock(); } static inline void qeth_l3_hdr_csum(struct qeth_card *card, diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c index 0ea2fbfe0e9..d979bb26522 100644 --- a/drivers/s390/net/qeth_l3_sys.c +++ b/drivers/s390/net/qeth_l3_sys.c @@ -335,10 +335,10 @@ static ssize_t qeth_l3_dev_sniffer_store(struct device *dev, QETH_IN_BUF_COUNT_MAX) qeth_realloc_buffer_pool(card, QETH_IN_BUF_COUNT_MAX); - break; } else rc = -EPERM; - default: /* fall through */ + break; + default: rc = -EINVAL; } out: diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 11f07f88822..b79576b64f4 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -55,6 +55,10 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); + /* if previous slave_alloc returned early, there is nothing to do */ + if (!zfcp_sdev->port) + return; + zfcp_erp_lun_shutdown_wait(sdev, "scssd_1"); put_device(&zfcp_sdev->port->dev); } diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c index 5f94d22c491..54266829290 100644 --- a/drivers/sbus/char/bbc_i2c.c +++ b/drivers/sbus/char/bbc_i2c.c @@ -233,13 +233,9 @@ int bbc_i2c_write_buf(struct bbc_i2c_client *client, int ret = 0; while (len > 0) { - int err = bbc_i2c_writeb(client, *buf, off); - - if (err < 0) { - ret = err; + ret = bbc_i2c_writeb(client, *buf, off); + if (ret < 0) break; - } - len--; buf++; off++; @@ -253,11 +249,9 @@ int bbc_i2c_read_buf(struct bbc_i2c_client *client, int ret = 0; while (len > 0) { - int err = bbc_i2c_readb(client, buf, off); - if (err < 0) { - ret = err; + ret = bbc_i2c_readb(client, buf, off); + if (ret < 0) break; - } len--; buf++; off++; @@ -422,17 +416,6 @@ static struct platform_driver bbc_i2c_driver = { .remove = __devexit_p(bbc_i2c_remove), }; -static int __init bbc_i2c_init(void) -{ - return platform_driver_register(&bbc_i2c_driver); -} - -static void __exit bbc_i2c_exit(void) -{ - platform_driver_unregister(&bbc_i2c_driver); -} - -module_init(bbc_i2c_init); -module_exit(bbc_i2c_exit); +module_platform_driver(bbc_i2c_driver); MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 965a1fccd66..4b9939726c3 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -275,15 +275,4 @@ static struct platform_driver d7s_driver = { .remove = __devexit_p(d7s_remove), }; -static int __init d7s_init(void) -{ - return platform_driver_register(&d7s_driver); -} - -static void __exit d7s_exit(void) -{ - platform_driver_unregister(&d7s_driver); -} - -module_init(d7s_init); -module_exit(d7s_exit); +module_platform_driver(d7s_driver); diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index be7b4e56154..339fd6f65ed 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -1138,16 +1138,6 @@ static struct platform_driver envctrl_driver = { .remove = __devexit_p(envctrl_remove), }; -static int __init envctrl_init(void) -{ - return platform_driver_register(&envctrl_driver); -} - -static void __exit envctrl_exit(void) -{ - platform_driver_unregister(&envctrl_driver); -} +module_platform_driver(envctrl_driver); -module_init(envctrl_init); -module_exit(envctrl_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 73dd4e7afaa..826157f3869 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -216,16 +216,6 @@ static struct platform_driver flash_driver = { .remove = __devexit_p(flash_remove), }; -static int __init flash_init(void) -{ - return platform_driver_register(&flash_driver); -} - -static void __exit flash_cleanup(void) -{ - platform_driver_unregister(&flash_driver); -} +module_platform_driver(flash_driver); -module_init(flash_init); -module_exit(flash_cleanup); MODULE_LICENSE("GPL"); diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c index ebce9639a26..0b31658ccde 100644 --- a/drivers/sbus/char/uctrl.c +++ b/drivers/sbus/char/uctrl.c @@ -435,16 +435,6 @@ static struct platform_driver uctrl_driver = { }; -static int __init uctrl_init(void) -{ - return platform_driver_register(&uctrl_driver); -} - -static void __exit uctrl_exit(void) -{ - platform_driver_unregister(&uctrl_driver); -} +module_platform_driver(uctrl_driver); -module_init(uctrl_init); -module_exit(uctrl_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 4aa76d6f11d..705e13e470a 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -38,6 +38,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/slab.h> #include <linux/mutex.h> #include <linux/spinlock.h> @@ -1109,6 +1110,9 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, unique_id++; } + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | + PCIE_LINK_STATE_CLKPM); + error = pci_enable_device(pdev); if (error) goto out; diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c index dba72a4e6a1..1ad0b822556 100644 --- a/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -1906,18 +1906,19 @@ static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, spin_lock(&session->lock); task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) { + if (!task || !task->sc) { spin_unlock(&session->lock); return -EINVAL; } sc = task->sc; - spin_unlock(&session->lock); if (!blk_rq_cpu_valid(sc->request)) cpu = smp_processor_id(); else cpu = sc->request->cpu; + spin_unlock(&session->lock); + p = &per_cpu(bnx2i_percpu, cpu); spin_lock(&p->p_work_lock); if (unlikely(!p->iothread)) { diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index cefbe44bb84..8d67467dd9c 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -31,6 +31,8 @@ #include <linux/sysfs.h> #include <linux/ctype.h> #include <linux/workqueue.h> +#include <net/dcbnl.h> +#include <net/dcbevent.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> #include <scsi/scsi_transport.h> @@ -101,6 +103,8 @@ static int fcoe_ddp_done(struct fc_lport *, u16); static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, unsigned int); static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr); static bool fcoe_match(struct net_device *netdev); static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); @@ -129,6 +133,11 @@ static struct notifier_block fcoe_cpu_notifier = { .notifier_call = fcoe_cpu_callback, }; +/* notification function for DCB events */ +static struct notifier_block dcb_notifier = { + .notifier_call = fcoe_dcb_app_notification, +}; + static struct scsi_transport_template *fcoe_nport_scsi_transport; static struct scsi_transport_template *fcoe_vport_scsi_transport; @@ -1522,6 +1531,8 @@ int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) skb_reset_network_header(skb); skb->mac_len = elen; skb->protocol = htons(ETH_P_FCOE); + skb->priority = port->priority; + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && fcoe->realdev->features & NETIF_F_HW_VLAN_TX) { skb->vlan_tci = VLAN_TAG_PRESENT | @@ -1624,6 +1635,7 @@ static inline int fcoe_filter_frames(struct fc_lport *lport, stats->InvalidCRCCount++; if (stats->InvalidCRCCount < 5) printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); + put_cpu(); return -EINVAL; } @@ -1746,6 +1758,7 @@ int fcoe_percpu_receive_thread(void *arg) */ static void fcoe_dev_setup(void) { + register_dcbevent_notifier(&dcb_notifier); register_netdevice_notifier(&fcoe_notifier); } @@ -1754,9 +1767,69 @@ static void fcoe_dev_setup(void) */ static void fcoe_dev_cleanup(void) { + unregister_dcbevent_notifier(&dcb_notifier); unregister_netdevice_notifier(&fcoe_notifier); } +static struct fcoe_interface * +fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) +{ + struct fcoe_interface *fcoe; + struct net_device *real_dev; + + list_for_each_entry(fcoe, &fcoe_hostlist, list) { + if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) + real_dev = vlan_dev_real_dev(fcoe->netdev); + else + real_dev = fcoe->netdev; + + if (netdev == real_dev) + return fcoe; + } + return NULL; +} + +static int fcoe_dcb_app_notification(struct notifier_block *notifier, + ulong event, void *ptr) +{ + struct dcb_app_type *entry = ptr; + struct fcoe_interface *fcoe; + struct net_device *netdev; + struct fcoe_port *port; + int prio; + + if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) + return NOTIFY_OK; + + netdev = dev_get_by_index(&init_net, entry->ifindex); + if (!netdev) + return NOTIFY_OK; + + fcoe = fcoe_hostlist_lookup_realdev_port(netdev); + dev_put(netdev); + if (!fcoe) + return NOTIFY_OK; + + if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) + prio = ffs(entry->app.priority) - 1; + else + prio = entry->app.priority; + + if (prio < 0) + return NOTIFY_OK; + + if (entry->app.protocol == ETH_P_FIP || + entry->app.protocol == ETH_P_FCOE) + fcoe->ctlr.priority = prio; + + if (entry->app.protocol == ETH_P_FCOE) { + port = lport_priv(fcoe->ctlr.lp); + port->priority = prio; + } + + return NOTIFY_OK; +} + /** * fcoe_device_notification() - Handler for net device events * @notifier: The context of the notification @@ -1965,6 +2038,46 @@ static bool fcoe_match(struct net_device *netdev) } /** + * fcoe_dcb_create() - Initialize DCB attributes and hooks + * @netdev: The net_device object of the L2 link that should be queried + * @port: The fcoe_port to bind FCoE APP priority with + * @ + */ +static void fcoe_dcb_create(struct fcoe_interface *fcoe) +{ +#ifdef CONFIG_DCB + int dcbx; + u8 fup, up; + struct net_device *netdev = fcoe->realdev; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + struct dcb_app app = { + .priority = 0, + .protocol = ETH_P_FCOE + }; + + /* setup DCB priority attributes. */ + if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { + dcbx = netdev->dcbnl_ops->getdcbx(netdev); + + if (dcbx & DCB_CAP_DCBX_VER_IEEE) { + app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; + up = dcb_ieee_getapp_mask(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_ieee_getapp_mask(netdev, &app); + } else { + app.selector = DCB_APP_IDTYPE_ETHTYPE; + up = dcb_getapp(netdev, &app); + app.protocol = ETH_P_FIP; + fup = dcb_getapp(netdev, &app); + } + + port->priority = ffs(up) ? ffs(up) - 1 : 0; + fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority; + } +#endif +} + +/** * fcoe_create() - Create a fcoe interface * @netdev : The net_device object the Ethernet interface to create on * @fip_mode: The FIP mode for this creation @@ -2007,6 +2120,9 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) /* Make this the "master" N_Port */ fcoe->ctlr.lp = lport; + /* setup DCB priority attributes. */ + fcoe_dcb_create(fcoe); + /* add to lports list */ fcoe_hostlist_add(lport); diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c index c74c4b8e71e..e7522dcc296 100644 --- a/drivers/scsi/fcoe/fcoe_ctlr.c +++ b/drivers/scsi/fcoe/fcoe_ctlr.c @@ -320,6 +320,7 @@ static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) skb_put(skb, sizeof(*sol)); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -474,6 +475,7 @@ static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, } skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); fip->send(fip, skb); @@ -566,6 +568,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, cap->fip.fip_dl_len = htons(dlen / FIP_BPW); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); return 0; @@ -1911,6 +1914,7 @@ static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, skb_put(skb, len); skb->protocol = htons(ETH_P_FIP); + skb->priority = fip->priority; skb_reset_mac_header(skb); skb_reset_network_header(skb); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index e76107b2ade..865d452542b 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -23,6 +23,7 @@ #include <linux/interrupt.h> #include <linux/types.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/delay.h> @@ -3922,6 +3923,10 @@ static int __devinit hpsa_pci_init(struct ctlr_info *h) dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); return -ENODEV; } + + pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); + err = pci_enable_device(h->pdev); if (err) { dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 8889b1babca..d570573b796 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -2802,6 +2802,11 @@ _scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) if (ioc->is_driver_loading) return; + + fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + if (!fw_event) + return; + fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); @@ -4330,7 +4335,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* insert into event log */ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_KERNEL); + event_reply = kzalloc(sz, GFP_ATOMIC); if (!event_reply) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index ac326c41e93..6465dae5883 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1762,12 +1762,31 @@ qla2x00_get_host_port_state(struct Scsi_Host *shost) scsi_qla_host_t *vha = shost_priv(shost); struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); - if (!base_vha->flags.online) + if (!base_vha->flags.online) { fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - else if (atomic_read(&base_vha->loop_state) == LOOP_TIMEOUT) - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - else + return; + } + + switch (atomic_read(&base_vha->loop_state)) { + case LOOP_UPDATE: + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + break; + case LOOP_DOWN: + if (test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags)) + fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; + else + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_DEAD: + fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; + break; + case LOOP_READY: fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; + break; + default: + fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; + break; + } } static int diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 9df4787715c..f3cddd5800c 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -12,17 +12,17 @@ * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- * | Module Init and Probe | 0x0116 | | - * | Mailbox commands | 0x1129 | | + * | Mailbox commands | 0x112b | | * | Device Discovery | 0x2083 | | * | Queue Command and IO tracing | 0x302e | 0x3008 | * | DPC Thread | 0x401c | | * | Async Events | 0x5059 | | - * | Timer Routines | 0x600d | | + * | Timer Routines | 0x6010 | 0x600e,0x600f | * | User Space Interactions | 0x709d | | - * | Task Management | 0x8041 | | + * | Task Management | 0x8041 | 0x800b | * | AER/EEH | 0x900f | | * | Virtual Port | 0xa007 | | - * | ISP82XX Specific | 0xb051 | | + * | ISP82XX Specific | 0xb052 | | * | MultiQ | 0xc00b | | * | Misc | 0xd00b | | * ---------------------------------------------------------------------- diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index ce32d8135c9..c0c11afb685 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -578,6 +578,7 @@ extern int qla82xx_check_md_needed(scsi_qla_host_t *); extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int); extern char *qdev_state(uint32_t); +extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); /* BSG related functions */ extern int qla24xx_bsg_request(struct fc_bsg_job *); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f03e915f187..54ea68cec4c 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1509,7 +1509,8 @@ enable_82xx_npiv: &ha->fw_xcb_count, NULL, NULL, &ha->max_npiv_vports, NULL); - if (!fw_major_version && ql2xallocfwdump) + if (!fw_major_version && ql2xallocfwdump + && !IS_QLA82XX(ha)) qla2x00_alloc_fw_dump(vha); } } else { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index dbec89622a0..a4b267e60a3 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -120,11 +120,10 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) * Returns a pointer to the continuation type 1 IOCB packet. */ static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha) +qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) { cont_a64_entry_t *cont_pkt; - struct req_que *req = vha->req; /* Adjust ring index. */ req->ring_index++; if (req->ring_index == req->length) { @@ -292,7 +291,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -684,7 +683,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -2070,7 +2069,8 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, + vha->hw->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; cont_iocb_prsnt = 1; @@ -2096,6 +2096,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) int index; uint16_t tot_dsds; scsi_qla_host_t *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; struct fc_bsg_job *bsg_job = ((struct srb_ctx *)sp->ctx)->u.bsg_job; int loop_iterartion = 0; int cont_iocb_prsnt = 0; @@ -2141,7 +2142,8 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) * Five DSDs are available in the Cont. * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, + ha->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; cont_iocb_prsnt = 1; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 2516adf1aee..7b91b290ffd 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1741,7 +1741,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) resid, scsi_bufflen(cp)); cp->result = DID_ERROR << 16 | lscsi_status; - break; + goto check_scsi_status; } if (!lscsi_status && diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 3b3cec9f6ac..82a33533ed2 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -79,8 +79,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) mcp->mb[0] = MBS_LINK_DOWN_ERROR; ql_log(ql_log_warn, base_vha, 0x1004, "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); - rval = QLA_FUNCTION_FAILED; - goto premature_exit; + return QLA_FUNCTION_TIMEOUT; } /* @@ -163,6 +162,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1010, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -188,6 +188,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) HINT_MBX_INT_PENDING) { spin_unlock_irqrestore(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; ql_dbg(ql_dbg_mbx, base_vha, 0x1012, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -302,7 +303,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112a, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101c, "Mailbox cmd timeout occured. " "Scheduling ISP abort eeh_busy=0x%x.\n", @@ -318,7 +327,15 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - + if (IS_QLA82XX(ha)) { + ql_dbg(ql_dbg_mbx, vha, 0x112b, + "disabling pause transmit on port " + "0 & 1.\n"); + qla82xx_wr_32(ha, + QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0| + CRB_NIU_XG_PAUSE_CTL_P1); + } ql_log(ql_log_info, base_vha, 0x101e, "Mailbox cmd timeout occured. " "Scheduling ISP abort.\n"); diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 94bded5ddce..03554934b0a 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -3817,6 +3817,20 @@ exit: return rval; } +void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha) +{ + struct qla_hw_data *ha = vha->hw; + + if (ha->flags.mbox_busy) { + ha->flags.mbox_int = 1; + ha->flags.mbox_busy = 0; + ql_log(ql_log_warn, vha, 0x6010, + "Doing premature completion of mbx command.\n"); + if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) + complete(&ha->mbx_intr_comp); + } +} + void qla82xx_watchdog(scsi_qla_host_t *vha) { uint32_t dev_state, halt_status; @@ -3839,9 +3853,13 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) qla2xxx_wake_dpc(vha); } else { if (qla82xx_check_fw_alive(vha)) { + ql_dbg(ql_dbg_timer, vha, 0x6011, + "disabling pause transmit on port 0 & 1.\n"); + qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, + CRB_NIU_XG_PAUSE_CTL_P0|CRB_NIU_XG_PAUSE_CTL_P1); halt_status = qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS1); - ql_dbg(ql_dbg_timer, vha, 0x6005, + ql_log(ql_log_info, vha, 0x6005, "dumping hw/fw registers:.\n " " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n " " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n " @@ -3858,6 +3876,11 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) QLA82XX_CRB_PEG_NET_3 + 0x3c), qla82xx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c)); + if (LSW(MSB(halt_status)) == 0x67) + ql_log(ql_log_warn, vha, 0xb052, + "Firmware aborted with " + "error code 0x00006700. Device is " + "being reset.\n"); if (halt_status & HALT_STATUS_UNRECOVERABLE) { set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags); @@ -3869,16 +3892,8 @@ void qla82xx_watchdog(scsi_qla_host_t *vha) } qla2xxx_wake_dpc(vha); ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_log(ql_log_warn, vha, 0x6007, - "Due to FW hung, doing " - "premature completion of mbx " - "command.\n"); - if (test_bit(MBX_INTR_WAIT, - &ha->mbx_cmd_flags)) - complete(&ha->mbx_intr_comp); - } + ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n"); + qla82xx_clear_pending_mbx(vha); } } } @@ -4073,10 +4088,7 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) msleep(1000); if (qla82xx_check_fw_alive(vha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - complete(&ha->mbx_intr_comp); - } + qla82xx_clear_pending_mbx(vha); break; } } diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 57820c199bc..57a226be339 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1173,4 +1173,8 @@ struct qla82xx_md_entry_queue { static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, 0x410000B8, 0x410000BC }; + +#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 +#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 + #endif diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fd14c7bfc62..f9e5b85e84d 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -201,12 +201,12 @@ MODULE_PARM_DESC(ql2xmdcapmask, "Set the Minidump driver capture mask level. " "Default is 0x7F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); -int ql2xmdenable; +int ql2xmdenable = 1; module_param(ql2xmdenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xmdenable, "Enable/disable MiniDump. " - "0 (Default) - MiniDump disabled. " - "1 - MiniDump enabled."); + "0 - MiniDump disabled. " + "1 (Default) - MiniDump enabled."); /* * SCSI host template entry points @@ -423,6 +423,7 @@ fail2: qla25xx_delete_queues(vha); destroy_workqueue(ha->wq); ha->wq = NULL; + vha->req = ha->req_q_map[0]; fail: ha->mqenable = 0; kfree(ha->req_q_map); @@ -814,49 +815,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -/* - * qla2x00_wait_for_loop_ready - * Wait for MAX_LOOP_TIMEOUT(5 min) value for loop - * to be in LOOP_READY state. - * Input: - * ha - pointer to host adapter structure - * - * Note: - * Does context switching-Release SPIN_LOCK - * (if any) before calling this routine. - * - * - * Return: - * Success (LOOP_READY) : 0 - * Failed (LOOP_NOT_READY) : 1 - */ -static inline int -qla2x00_wait_for_loop_ready(scsi_qla_host_t *vha) -{ - int return_status = QLA_SUCCESS; - unsigned long loop_timeout ; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - /* wait for 5 min at the max for loop to be ready */ - loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); - - while ((!atomic_read(&base_vha->loop_down_timer) && - atomic_read(&base_vha->loop_state) == LOOP_DOWN) || - atomic_read(&base_vha->loop_state) != LOOP_READY) { - if (atomic_read(&base_vha->loop_state) == LOOP_DEAD) { - return_status = QLA_FUNCTION_FAILED; - break; - } - msleep(1000); - if (time_after_eq(jiffies, loop_timeout)) { - return_status = QLA_FUNCTION_FAILED; - break; - } - } - return (return_status); -} - static void sp_get(struct srb *sp) { @@ -1035,12 +993,6 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, "Wait for hba online failed for cmd=%p.\n", cmd); goto eh_reset_failed; } - err = 1; - if (qla2x00_wait_for_loop_ready(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800b, - "Wait for loop ready failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } err = 2; if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) != QLA_SUCCESS) { @@ -1137,10 +1089,9 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) goto eh_bus_reset_done; } - if (qla2x00_wait_for_loop_ready(vha) == QLA_SUCCESS) { - if (qla2x00_loop_reset(vha) == QLA_SUCCESS) - ret = SUCCESS; - } + if (qla2x00_loop_reset(vha) == QLA_SUCCESS) + ret = SUCCESS; + if (ret == FAILED) goto eh_bus_reset_done; @@ -1206,15 +1157,6 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS) goto eh_host_reset_lock; - /* - * Fixme-may be dpc thread is active and processing - * loop_resync,so wait a while for it to - * be completed and then issue big hammer.Otherwise - * it may cause I/O failure as big hammer marks the - * devices as lost kicking of the port_down_timer - * while dpc is stuck for the mailbox to complete. - */ - qla2x00_wait_for_loop_ready(vha); if (vha != base_vha) { if (qla2x00_vp_abort_isp(vha)) goto eh_host_reset_lock; @@ -1297,16 +1239,13 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) atomic_set(&vha->loop_state, LOOP_DOWN); atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); qla2x00_mark_all_devices_lost(vha, 0); - qla2x00_wait_for_loop_ready(vha); } if (ha->flags.enable_lip_reset) { ret = qla2x00_lip_reset(vha); - if (ret != QLA_SUCCESS) { + if (ret != QLA_SUCCESS) ql_dbg(ql_dbg_taskm, vha, 0x802e, "lip_reset failed (%d).\n", ret); - } else - qla2x00_wait_for_loop_ready(vha); } /* Issue marker command only when we are going to start the I/O */ @@ -4070,13 +4009,8 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) /* For ISP82XX complete any pending mailbox cmd */ if (IS_QLA82XX(ha)) { ha->flags.isp82xx_fw_hung = 1; - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ql_dbg(ql_dbg_aer, vha, 0x9001, - "Due to pci channel io frozen, doing premature " - "completion of mbx command.\n"); - complete(&ha->mbx_intr_comp); - } + ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n"); + qla82xx_clear_pending_mbx(vha); } qla2x00_free_irqs(vha); pci_disable_device(pdev); diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 13b6357c1fa..23f33a6d52d 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.03.07.07-k" +#define QLA2XXX_VERSION "8.03.07.12-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 3 diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h index ace637bf254..fd5edc6e166 100644 --- a/drivers/scsi/qla4xxx/ql4_def.h +++ b/drivers/scsi/qla4xxx/ql4_def.h @@ -147,7 +147,7 @@ #define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ #define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ -#define QL4_SESS_RECOVERY_TMO 30 /* iSCSI session */ +#define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ /* recovery timeout */ #define LSDW(x) ((u32)((u64)(x))) @@ -173,6 +173,8 @@ #define ISNS_DEREG_TOV 5 #define HBA_ONLINE_TOV 30 #define DISABLE_ACB_TOV 30 +#define IP_CONFIG_TOV 30 +#define LOGIN_TOV 12 #define MAX_RESET_HA_RETRIES 2 @@ -240,6 +242,45 @@ struct ddb_entry { uint16_t fw_ddb_index; /* DDB firmware index */ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ + uint16_t ddb_type; +#define FLASH_DDB 0x01 + + struct dev_db_entry fw_ddb_entry; + int (*unblock_sess)(struct iscsi_cls_session *cls_session); + int (*ddb_change)(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); + + /* Driver Re-login */ + unsigned long flags; /* DDB Flags */ + uint16_t default_relogin_timeout; /* Max time to wait for + * relogin to complete */ + atomic_t retry_relogin_timer; /* Min Time between relogins + * (4000 only) */ + atomic_t relogin_timer; /* Max Time to wait for + * relogin to complete */ + atomic_t relogin_retry_count; /* Num of times relogin has been + * retried */ + uint32_t default_time2wait; /* Default Min time between + * relogins (+aens) */ + +}; + +struct qla_ddb_index { + struct list_head list; + uint16_t fw_ddb_idx; + struct dev_db_entry fw_ddb; +}; + +#define DDB_IPADDR_LEN 64 + +struct ql4_tuple_ddb { + int port; + int tpgt; + char ip_addr[DDB_IPADDR_LEN]; + char iscsi_name[ISCSI_NAME_SIZE]; + uint16_t options; +#define DDB_OPT_IPV6 0x0e0e +#define DDB_OPT_IPV4 0x0f0f }; /* @@ -411,7 +452,7 @@ struct scsi_qla_host { #define AF_FW_RECOVERY 19 /* 0x00080000 */ #define AF_EEH_BUSY 20 /* 0x00100000 */ #define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ - +#define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ unsigned long dpc_flags; #define DPC_RESET_HA 1 /* 0x00000002 */ @@ -604,6 +645,7 @@ struct scsi_qla_host { uint16_t bootload_minor; uint16_t bootload_patch; uint16_t bootload_build; + uint16_t def_timeout; /* Default login timeout */ uint32_t flash_state; #define QLFLASH_WAITING 0 @@ -623,6 +665,11 @@ struct scsi_qla_host { uint16_t iscsi_pci_func_cnt; uint8_t model_name[16]; struct completion disable_acb_comp; + struct dma_pool *fw_ddb_dma_pool; +#define DDB_DMA_BLOCK_SIZE 512 + uint16_t pri_ddb_idx; + uint16_t sec_ddb_idx; + int is_reset; }; struct ql4_task_data { @@ -835,6 +882,10 @@ static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) /*---------------------------------------------------------------------------*/ /* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */ + +#define INIT_ADAPTER 0 +#define RESET_ADAPTER 1 + #define PRESERVE_DDB_LIST 0 #define REBUILD_DDB_LIST 1 diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h index cbd5a20dbbd..4ac07f88252 100644 --- a/drivers/scsi/qla4xxx/ql4_fw.h +++ b/drivers/scsi/qla4xxx/ql4_fw.h @@ -12,6 +12,7 @@ #define MAX_PRST_DEV_DB_ENTRIES 64 #define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES #define MAX_DEV_DB_ENTRIES 512 +#define MAX_DEV_DB_ENTRIES_40XX 256 /************************************************************************* * @@ -604,6 +605,13 @@ struct addr_ctrl_blk { uint8_t res14[140]; /* 274-2FF */ }; +#define IP_ADDR_COUNT 4 /* Total 4 IP address supported in one interface + * One IPv4, one IPv6 link local and 2 IPv6 + */ + +#define IP_STATE_MASK 0x0F000000 +#define IP_STATE_SHIFT 24 + struct init_fw_ctrl_blk { struct addr_ctrl_blk pri; /* struct addr_ctrl_blk sec;*/ diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h index 160db9d5ea2..d0dd4b33020 100644 --- a/drivers/scsi/qla4xxx/ql4_glbl.h +++ b/drivers/scsi/qla4xxx/ql4_glbl.h @@ -13,7 +13,7 @@ struct iscsi_cls_conn; int qla4xxx_hw_reset(struct scsi_qla_host *ha); int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha); +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset); int qla4xxx_soft_reset(struct scsi_qla_host *ha); irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); @@ -153,10 +153,13 @@ int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index, uint32_t *mbx_sts); int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index); int qla4xxx_send_passthru0(struct iscsi_task *task); +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha); int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, uint16_t stats_size, dma_addr_t stats_dma); void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry); int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, struct dev_db_entry *fw_ddb_entry, dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); @@ -169,11 +172,22 @@ int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha, uint32_t region, uint32_t field0, uint32_t field1); +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index); +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session); +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state); +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); /* BSG Functions */ int qla4xxx_bsg_request(struct bsg_job *bsg_job); int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); + extern int ql4xextended_error_logging; extern int ql4xdontresethba; extern int ql4xenablemsix; diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c index 3075fbaef55..1bdfa8120ac 100644 --- a/drivers/scsi/qla4xxx/ql4_init.c +++ b/drivers/scsi/qla4xxx/ql4_init.c @@ -773,22 +773,24 @@ int qla4xxx_start_firmware(struct scsi_qla_host *ha) * be freed so that when login happens from user space there are free DDB * indices available. **/ -static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) +void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) { int max_ddbs; int ret; uint32_t idx = 0, next_idx = 0; uint32_t state = 0, conn_err = 0; - max_ddbs = is_qla40XX(ha) ? MAX_PRST_DEV_DB_ENTRIES : + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : MAX_DEV_DB_ENTRIES; for (idx = 0; idx < max_ddbs; idx = next_idx) { ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, &next_idx, &state, &conn_err, NULL, NULL); - if (ret == QLA_ERROR) + if (ret == QLA_ERROR) { + next_idx++; continue; + } if (state == DDB_DS_NO_CONNECTION_ACTIVE || state == DDB_DS_SESSION_FAILED) { DEBUG2(ql4_printk(KERN_INFO, ha, @@ -804,7 +806,6 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) } } - /** * qla4xxx_initialize_adapter - initiailizes hba * @ha: Pointer to host adapter structure. @@ -812,7 +813,7 @@ static void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) * This routine parforms all of the steps necessary to initialize the adapter. * **/ -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) +int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) { int status = QLA_ERROR; @@ -840,7 +841,8 @@ int qla4xxx_initialize_adapter(struct scsi_qla_host *ha) if (status == QLA_ERROR) goto exit_init_hba; - qla4xxx_free_ddb_index(ha); + if (is_reset == RESET_ADAPTER) + qla4xxx_build_ddb_list(ha, is_reset); set_bit(AF_ONLINE, &ha->flags); exit_init_hba: @@ -855,38 +857,12 @@ exit_init_hba: return status; } -/** - * qla4xxx_process_ddb_changed - process ddb state change - * @ha - Pointer to host adapter structure. - * @fw_ddb_index - Firmware's device database index - * @state - Device state - * - * This routine processes a Decive Database Changed AEN Event. - **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - uint32_t state, uint32_t conn_err) +int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) { - struct ddb_entry * ddb_entry; uint32_t old_fw_ddb_device_state; int status = QLA_ERROR; - /* check for out of range index */ - if (fw_ddb_index >= MAX_DDB_ENTRIES) - goto exit_ddb_event; - - /* Get the corresponging ddb entry */ - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); - /* Device does not currently exist in our database. */ - if (ddb_entry == NULL) { - ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", - __func__, fw_ddb_index); - - if (state == DDB_DS_NO_CONNECTION_ACTIVE) - clear_bit(fw_ddb_index, ha->ddb_idx_map); - - goto exit_ddb_event; - } - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; DEBUG2(ql4_printk(KERN_INFO, ha, "%s: DDB - old state = 0x%x, new state = 0x%x for " @@ -900,9 +876,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -936,9 +910,7 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, switch (state) { case DDB_DS_SESSION_ACTIVE: case DDB_DS_DISCOVERY: - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); qla4xxx_update_session_conn_param(ha, ddb_entry); status = QLA_SUCCESS; break; @@ -954,7 +926,198 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, __func__)); break; } + return status; +} + +void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) +{ + /* + * This triggers a relogin. After the relogin_timer + * expires, the relogin gets scheduled. We must wait a + * minimum amount of time since receiving an 0x8014 AEN + * with failed device_state or a logout response before + * we can issue another relogin. + * + * Firmware pads this timeout: (time2wait +1). + * Driver retry to login should be longer than F/W. + * Otherwise F/W will fail + * set_ddb() mbx cmd with 0x4005 since it still + * counting down its time2wait. + */ + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + +} + +int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, + struct ddb_entry *ddb_entry, uint32_t state) +{ + uint32_t old_fw_ddb_device_state; + int status = QLA_ERROR; + + old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: DDB - old state = 0x%x, new state = 0x%x for " + "index [%d]\n", __func__, + ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); + + ddb_entry->fw_ddb_device_state = state; + + switch (old_fw_ddb_device_state) { + case DDB_DS_LOGIN_IN_PROCESS: + case DDB_DS_NO_CONNECTION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_ACTIVE: + switch (state) { + case DDB_DS_SESSION_FAILED: + iscsi_block_session(ddb_entry->sess); + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + case DDB_DS_SESSION_FAILED: + switch (state) { + case DDB_DS_SESSION_ACTIVE: + ddb_entry->unblock_sess(ddb_entry->sess); + qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); + status = QLA_SUCCESS; + break; + case DDB_DS_SESSION_FAILED: + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + status = QLA_SUCCESS; + break; + } + break; + default: + DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", + __func__)); + break; + } + return status; +} + +/** + * qla4xxx_process_ddb_changed - process ddb state change + * @ha - Pointer to host adapter structure. + * @fw_ddb_index - Firmware's device database index + * @state - Device state + * + * This routine processes a Decive Database Changed AEN Event. + **/ +int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, + uint32_t fw_ddb_index, + uint32_t state, uint32_t conn_err) +{ + struct ddb_entry *ddb_entry; + int status = QLA_ERROR; + + /* check for out of range index */ + if (fw_ddb_index >= MAX_DDB_ENTRIES) + goto exit_ddb_event; + + /* Get the corresponging ddb entry */ + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); + /* Device does not currently exist in our database. */ + if (ddb_entry == NULL) { + ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", + __func__, fw_ddb_index); + + if (state == DDB_DS_NO_CONNECTION_ACTIVE) + clear_bit(fw_ddb_index, ha->ddb_idx_map); + + goto exit_ddb_event; + } + + ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); exit_ddb_event: return status; } + +/** + * qla4xxx_login_flash_ddb - Login to target (DDB) + * @cls_session: Pointer to the session to login + * + * This routine logins to the target. + * Issues setddb and conn open mbx + **/ +void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + struct dev_db_entry *fw_ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + uint32_t mbx_sts = 0; + int ret; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!test_bit(AF_LINK_UP, &ha->flags)) + return; + + if (ddb_entry->ddb_type != FLASH_DDB) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Skipping login to non FLASH DB")); + goto exit_login; + } + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_login; + } + + if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { + ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) + goto exit_login; + + ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; + ha->tot_ddbs++; + } + + memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, + sizeof(struct dev_db_entry)); + ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; + + ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, + fw_ddb_dma, &mbx_sts); + if (ret == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); + goto exit_login; + } + + ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; + ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); + if (ret == QLA_ERROR) { + ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, + sess->targetname); + goto exit_login; + } + +exit_login: + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); +} + diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index 4c2b8487039..c2593782fbb 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -41,6 +41,16 @@ int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, return status; } + if (is_qla40XX(ha)) { + if (test_bit(AF_HA_REMOVAL, &ha->flags)) { + DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " + "prematurely completing mbx cmd as " + "adapter removal detected\n", + ha->host_no, __func__)); + return status; + } + } + if (is_qla8022(ha)) { if (test_bit(AF_FW_RECOVERY, &ha->flags)) { DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " @@ -413,6 +423,7 @@ qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, memcpy(ha->name_string, init_fw_cb->iscsi_name, min(sizeof(ha->name_string), sizeof(init_fw_cb->iscsi_name))); + ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout); /*memcpy(ha->alias, init_fw_cb->Alias, min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index 30f31b127f3..4169c8baa11 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -8,6 +8,7 @@ #include <linux/slab.h> #include <linux/blkdev.h> #include <linux/iscsi_boot_sysfs.h> +#include <linux/inet.h> #include <scsi/scsi_tcq.h> #include <scsi/scsicam.h> @@ -31,6 +32,13 @@ static struct kmem_cache *srb_cachep; /* * Module parameter information and variables */ +int ql4xdisablesysfsboot = 1; +module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ql4xdisablesysfsboot, + "Set to disable exporting boot targets to sysfs\n" + " 0 - Export boot targets\n" + " 1 - Do not export boot targets (Default)"); + int ql4xdontresethba = 0; module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ql4xdontresethba, @@ -63,7 +71,7 @@ static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; module_param(ql4xsess_recovery_tmo, int, S_IRUGO); MODULE_PARM_DESC(ql4xsess_recovery_tmo, "Target Session Recovery Timeout.\n" - " Default: 30 sec."); + " Default: 120 sec."); static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); /* @@ -415,7 +423,7 @@ static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) qla_ep = ep->dd_data; ha = to_qla_host(qla_ep->host); - if (adapter_up(ha)) + if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) ret = 1; return ret; @@ -975,6 +983,150 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, } +int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) +{ + uint32_t mbx_sts = 0; + uint16_t tmp_ddb_index; + int ret; + +get_ddb_index: + tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); + + if (tmp_ddb_index >= MAX_DDB_ENTRIES) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free DDB index not available\n")); + ret = QLA_ERROR; + goto exit_get_ddb_index; + } + + if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) + goto get_ddb_index; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Found a free DDB index at %d\n", tmp_ddb_index)); + ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); + if (ret == QLA_ERROR) { + if (mbx_sts == MBOX_STS_COMMAND_ERROR) { + ql4_printk(KERN_INFO, ha, + "DDB index = %d not available trying next\n", + tmp_ddb_index); + goto get_ddb_index; + } + DEBUG2(ql4_printk(KERN_INFO, ha, + "Free FW DDB not available\n")); + } + + *ddb_index = tmp_ddb_index; + +exit_get_ddb_index: + return ret; +} + +static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry, + char *existing_ipaddr, + char *user_ipaddr) +{ + uint8_t dst_ipaddr[IPv6_ADDR_LEN]; + char formatted_ipaddr[DDB_IPADDR_LEN]; + int status = QLA_SUCCESS, ret = 0; + + if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { + ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); + } else { + ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, + '\0', NULL); + if (ret == 0) { + status = QLA_ERROR; + goto out_match; + } + ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); + } + + if (strcmp(existing_ipaddr, formatted_ipaddr)) + status = QLA_ERROR; + +out_match: + return status; +} + +static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, + struct iscsi_cls_conn *cls_conn) +{ + int idx = 0, max_ddbs, rval; + struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); + struct iscsi_session *sess, *existing_sess; + struct iscsi_conn *conn, *existing_conn; + struct ddb_entry *ddb_entry; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + if (sess->targetname == NULL || + conn->persistent_address == NULL || + conn->persistent_port == 0) + return QLA_ERROR; + + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + for (idx = 0; idx < max_ddbs; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + if (ddb_entry->ddb_type != FLASH_DDB) + continue; + + existing_sess = ddb_entry->sess->dd_data; + existing_conn = ddb_entry->conn->dd_data; + + if (existing_sess->targetname == NULL || + existing_conn->persistent_address == NULL || + existing_conn->persistent_port == 0) + continue; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IQN = %s User IQN = %s\n", + existing_sess->targetname, + sess->targetname)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "IP = %s User IP = %s\n", + existing_conn->persistent_address, + conn->persistent_address)); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Port = %d User Port = %d\n", + existing_conn->persistent_port, + conn->persistent_port)); + + if (strcmp(existing_sess->targetname, sess->targetname)) + continue; + rval = qla4xxx_match_ipaddress(ha, ddb_entry, + existing_conn->persistent_address, + conn->persistent_address); + if (rval == QLA_ERROR) + continue; + if (existing_conn->persistent_port != conn->persistent_port) + continue; + break; + } + + if (idx == max_ddbs) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match found in fwdb sessions\n")); + return QLA_SUCCESS; +} + static struct iscsi_cls_session * qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, uint16_t qdepth, @@ -984,8 +1136,7 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, struct scsi_qla_host *ha; struct qla_endpoint *qla_ep; struct ddb_entry *ddb_entry; - uint32_t ddb_index; - uint32_t mbx_sts = 0; + uint16_t ddb_index; struct iscsi_session *sess; struct sockaddr *dst_addr; int ret; @@ -1000,32 +1151,9 @@ qla4xxx_session_create(struct iscsi_endpoint *ep, dst_addr = (struct sockaddr *)&qla_ep->dst_addr; ha = to_qla_host(qla_ep->host); -get_ddb_index: - ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); - - if (ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free DDB index not available\n")); - return NULL; - } - - if (test_and_set_bit(ddb_index, ha->ddb_idx_map)) - goto get_ddb_index; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Found a free DDB index at %d\n", ddb_index)); - ret = qla4xxx_req_ddb_entry(ha, ddb_index, &mbx_sts); - if (ret == QLA_ERROR) { - if (mbx_sts == MBOX_STS_COMMAND_ERROR) { - ql4_printk(KERN_INFO, ha, - "DDB index = %d not available trying next\n", - ddb_index); - goto get_ddb_index; - } - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free FW DDB not available\n")); + ret = qla4xxx_get_ddb_index(ha, &ddb_index); + if (ret == QLA_ERROR) return NULL; - } cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, cmds_max, sizeof(struct ddb_entry), @@ -1040,6 +1168,8 @@ get_ddb_index: ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; ddb_entry->ha = ha; ddb_entry->sess = cls_sess; + ddb_entry->unblock_sess = qla4xxx_unblock_ddb; + ddb_entry->ddb_change = qla4xxx_ddb_change; cls_sess->recovery_tmo = ql4xsess_recovery_tmo; ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; ha->tot_ddbs++; @@ -1077,6 +1207,9 @@ qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_idx); + if (!cls_conn) + return NULL; + sess = cls_sess->dd_data; ddb_entry = sess->dd_data; ddb_entry->conn = cls_conn; @@ -1109,7 +1242,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) struct iscsi_session *sess; struct ddb_entry *ddb_entry; struct scsi_qla_host *ha; - struct dev_db_entry *fw_ddb_entry; + struct dev_db_entry *fw_ddb_entry = NULL; dma_addr_t fw_ddb_entry_dma; uint32_t mbx_sts = 0; int ret = 0; @@ -1120,12 +1253,25 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) ddb_entry = sess->dd_data; ha = ddb_entry->ha; + /* Check if we have matching FW DDB, if yes then do not + * login to this target. This could cause target to logout previous + * connection + */ + ret = qla4xxx_match_fwdb_session(ha, cls_conn); + if (ret == QLA_SUCCESS) { + ql4_printk(KERN_INFO, ha, + "Session already exist in FW.\n"); + ret = -EEXIST; + goto exit_conn_start; + } + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), &fw_ddb_entry_dma, GFP_KERNEL); if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return -ENOMEM; + ret = -ENOMEM; + goto exit_conn_start; } ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); @@ -1138,9 +1284,7 @@ static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) if (mbx_sts) if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); + ddb_entry->unblock_sess(ddb_entry->sess); goto exit_set_param; } @@ -1167,8 +1311,9 @@ exit_set_param: ret = 0; exit_conn_start: - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); return ret; } @@ -1344,6 +1489,101 @@ static int qla4xxx_task_xmit(struct iscsi_task *task) return -ENOSYS; } +static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry, + struct iscsi_cls_session *cls_sess, + struct iscsi_cls_conn *cls_conn) +{ + int buflen = 0; + struct iscsi_session *sess; + struct iscsi_conn *conn; + char ip_addr[DDB_IPADDR_LEN]; + uint16_t options = 0; + + sess = cls_sess->dd_data; + conn = cls_conn->dd_data; + + conn->max_recv_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); + + conn->max_xmit_dlength = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); + + sess->initial_r2t_en = + (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); + + sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); + + sess->first_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); + + sess->max_burst = BYTE_UNITS * + le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); + + sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + + sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); + + conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); + + sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, + (char *)fw_ddb_entry->iscsi_name, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, + (char *)ha->name_string, buflen); + iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, + (char *)ip_addr, buflen); +} + +void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + uint32_t ddb_state; + dma_addr_t fw_ddb_entry_dma; + struct dev_db_entry *fw_ddb_entry; + + fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + &fw_ddb_entry_dma, GFP_KERNEL); + if (!fw_ddb_entry) { + ql4_printk(KERN_ERR, ha, + "%s: Unable to allocate dma buffer\n", __func__); + goto exit_session_conn_fwddb_param; + } + + if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, + fw_ddb_entry_dma, NULL, NULL, &ddb_state, + NULL, NULL, NULL) == QLA_ERROR) { + DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " + "get_ddb_entry for fw_ddb_index %d\n", + ha->host_no, __func__, + ddb_entry->fw_ddb_index)); + goto exit_session_conn_fwddb_param; + } + + cls_sess = ddb_entry->sess; + + cls_conn = ddb_entry->conn; + + /* Update params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); + +exit_session_conn_fwddb_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); +} + void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry) { @@ -1360,7 +1600,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, if (!fw_ddb_entry) { ql4_printk(KERN_ERR, ha, "%s: Unable to allocate dma buffer\n", __func__); - return; + goto exit_session_conn_param; } if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, @@ -1370,7 +1610,7 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, "get_ddb_entry for fw_ddb_index %d\n", ha->host_no, __func__, ddb_entry->fw_ddb_index)); - return; + goto exit_session_conn_param; } cls_sess = ddb_entry->sess; @@ -1379,6 +1619,12 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, cls_conn = ddb_entry->conn; conn = cls_conn->dd_data; + /* Update timers after login */ + ddb_entry->default_relogin_timeout = + le16_to_cpu(fw_ddb_entry->def_timeout); + ddb_entry->default_time2wait = + le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); + /* Update params */ conn->max_recv_dlength = BYTE_UNITS * le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); @@ -1407,6 +1653,11 @@ void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, memcpy(sess->initiatorname, ha->name_string, min(sizeof(ha->name_string), sizeof(sess->initiatorname))); + +exit_session_conn_param: + if (fw_ddb_entry) + dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), + fw_ddb_entry, fw_ddb_entry_dma); } /* @@ -1607,6 +1858,9 @@ static void qla4xxx_mem_free(struct scsi_qla_host *ha) vfree(ha->chap_list); ha->chap_list = NULL; + if (ha->fw_ddb_dma_pool) + dma_pool_destroy(ha->fw_ddb_dma_pool); + /* release io space registers */ if (is_qla8022(ha)) { if (ha->nx_pcibase) @@ -1689,6 +1943,16 @@ static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) goto mem_alloc_error_exit; } + ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, + DDB_DMA_BLOCK_SIZE, 8, 0); + + if (ha->fw_ddb_dma_pool == NULL) { + ql4_printk(KERN_WARNING, ha, + "%s: fw_ddb_dma_pool allocation failed..\n", + __func__); + goto mem_alloc_error_exit; + } + return QLA_SUCCESS; mem_alloc_error_exit: @@ -1800,6 +2064,60 @@ void qla4_8xxx_watchdog(struct scsi_qla_host *ha) } } +void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + if (atomic_read(&ddb_entry->retry_relogin_timer) != + INVALID_ENTRY) { + if (atomic_read(&ddb_entry->retry_relogin_timer) == + 0) { + atomic_set(&ddb_entry->retry_relogin_timer, + INVALID_ENTRY); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index [%d] login device\n", + __func__, ddb_entry->fw_ddb_index)); + } else + atomic_dec(&ddb_entry->retry_relogin_timer); + } + } + + /* Wait for relogin to timeout */ + if (atomic_read(&ddb_entry->relogin_timer) && + (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { + /* + * If the relogin times out and the device is + * still NOT ONLINE then try and relogin again. + */ + if (!iscsi_is_session_online(cls_sess)) { + /* Reset retry relogin timer */ + atomic_inc(&ddb_entry->relogin_retry_count); + DEBUG2(ql4_printk(KERN_INFO, ha, + "%s: index[%d] relogin timed out-retrying" + " relogin (%d), retry (%d)\n", __func__, + ddb_entry->fw_ddb_index, + atomic_read(&ddb_entry->relogin_retry_count), + ddb_entry->default_time2wait + 4)); + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + atomic_set(&ddb_entry->retry_relogin_timer, + ddb_entry->default_time2wait + 4); + } + } +} + /** * qla4xxx_timer - checks every second for work to do. * @ha: Pointer to host adapter structure. @@ -1809,6 +2127,8 @@ static void qla4xxx_timer(struct scsi_qla_host *ha) int start_dpc = 0; uint16_t w; + iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); + /* If we are in the middle of AER/EEH processing * skip any processing and reschedule the timer */ @@ -2078,7 +2398,12 @@ static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) sess = cls_session->dd_data; ddb_entry = sess->dd_data; ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); + + if (ddb_entry->ddb_type == FLASH_DDB) + iscsi_block_session(ddb_entry->sess); + else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } /** @@ -2163,7 +2488,7 @@ recover_ha_init_adapter: /* NOTE: AF_ONLINE flag set upon successful completion of * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); } /* Retry failed adapter initialization, if necessary @@ -2245,17 +2570,108 @@ static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) iscsi_unblock_session(ddb_entry->sess); } else { /* Trigger relogin */ - iscsi_session_failure(cls_session->dd_data, - ISCSI_ERR_CONN_FAILED); + if (ddb_entry->ddb_type == FLASH_DDB) { + if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) + qla4xxx_arm_relogin_timer(ddb_entry); + } else + iscsi_session_failure(cls_session->dd_data, + ISCSI_ERR_CONN_FAILED); } } } +int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + + iscsi_unblock_session(ddb_entry->sess); + + /* Start scan target */ + if (test_bit(AF_ONLINE, &ha->flags)) { + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " start scan\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); + } + return QLA_SUCCESS; +} + +int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_session->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" + " unblock user space session\n", ha->host_no, __func__, + ddb_entry->fw_ddb_index); + iscsi_conn_start(ddb_entry->conn); + iscsi_conn_login_event(ddb_entry->conn, + ISCSI_CONN_STATE_LOGGED_IN); + + return QLA_SUCCESS; +} + static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) { iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); } +static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) +{ + uint16_t relogin_timer; + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + relogin_timer = max(ddb_entry->default_relogin_timeout, + (uint16_t)RELOGIN_TOV); + atomic_set(&ddb_entry->relogin_timer, relogin_timer); + + DEBUG2(ql4_printk(KERN_INFO, ha, + "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, + ddb_entry->fw_ddb_index, relogin_timer)); + + qla4xxx_login_flash_ddb(cls_sess); +} + +static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) +{ + struct iscsi_session *sess; + struct ddb_entry *ddb_entry; + struct scsi_qla_host *ha; + + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ha = ddb_entry->ha; + + if (!(ddb_entry->ddb_type == FLASH_DDB)) + return; + + if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && + !iscsi_is_session_online(cls_sess)) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "relogin issued\n")); + qla4xxx_relogin_flash_ddb(cls_sess); + } +} + void qla4xxx_wake_dpc(struct scsi_qla_host *ha) { if (ha->dpc_thread) @@ -2356,6 +2772,12 @@ dpc_post_reset_ha: if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) qla4xxx_get_dhcp_ip_address(ha); + /* ---- relogin device? --- */ + if (adapter_up(ha) && + test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { + iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); + } + /* ---- link change? --- */ if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { if (!test_bit(AF_LINK_UP, &ha->flags)) { @@ -2368,8 +2790,12 @@ dpc_post_reset_ha: * fatal error recovery. Therefore, the driver must * manually relogin to devices when recovering from * connection failures, logouts, expired KATO, etc. */ - - qla4xxx_relogin_all_devices(ha); + if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { + qla4xxx_build_ddb_list(ha, ha->is_reset); + iscsi_host_for_each_session(ha->host, + qla4xxx_login_flash_ddb); + } else + qla4xxx_relogin_all_devices(ha); } } } @@ -2867,6 +3293,9 @@ static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) " target ID %d\n", __func__, ddb_index[0], ddb_index[1])); + ha->pri_ddb_idx = ddb_index[0]; + ha->sec_ddb_idx = ddb_index[1]; + exit_boot_info_free: dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); exit_boot_info: @@ -3034,6 +3463,9 @@ static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) return ret; } + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (ddb_index[0] == 0xffff) goto sec_target; @@ -3066,7 +3498,15 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) struct iscsi_boot_kobj *boot_kobj; if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) - return 0; + return QLA_ERROR; + + if (ql4xdisablesysfsboot) { + ql4_printk(KERN_INFO, ha, + "%s: syfsboot disabled - driver will trigger login" + "and publish session for discovery .\n", __func__); + return QLA_SUCCESS; + } + ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); if (!ha->boot_kset) @@ -3108,7 +3548,7 @@ static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) if (!boot_kobj) goto put_host; - return 0; + return QLA_SUCCESS; put_host: scsi_host_put(ha->host); @@ -3174,9 +3614,507 @@ static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) exit_chap_list: dma_free_coherent(&ha->pdev->dev, chap_size, chap_flash_data, chap_dma); - return; } +static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + struct scsi_qla_host *ha; + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_session *sess; + struct iscsi_conn *conn; + + DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); + ha = ddb_entry->ha; + cls_sess = ddb_entry->sess; + sess = cls_sess->dd_data; + cls_conn = ddb_entry->conn; + conn = cls_conn->dd_data; + + tddb->tpgt = sess->tpgt; + tddb->port = conn->persistent_port; + strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); + strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); +} + +static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, + struct ql4_tuple_ddb *tddb) +{ + uint16_t options = 0; + + tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); + memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], + min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); + + options = le16_to_cpu(fw_ddb_entry->options); + if (options & DDB_OPT_IPV6_DEVICE) + sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); + else + sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); + + tddb->port = le16_to_cpu(fw_ddb_entry->port); +} + +static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, + struct ql4_tuple_ddb *old_tddb, + struct ql4_tuple_ddb *new_tddb) +{ + if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) + return QLA_ERROR; + + if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) + return QLA_ERROR; + + if (old_tddb->port != new_tddb->port) + return QLA_ERROR; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", + old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, + old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, + new_tddb->ip_addr, new_tddb->iscsi_name)); + + return QLA_SUCCESS; +} + +static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct ddb_entry *ddb_entry; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int idx; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if (ddb_entry == NULL) + continue; + + qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, + struct list_head *list_nt, + struct dev_db_entry *fw_ddb_entry) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + struct ql4_tuple_ddb *fw_tddb = NULL; + struct ql4_tuple_ddb *tmp_tddb = NULL; + int ret = QLA_ERROR; + + fw_tddb = vzalloc(sizeof(*fw_tddb)); + if (!fw_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + tmp_tddb = vzalloc(sizeof(*tmp_tddb)); + if (!tmp_tddb) { + DEBUG2(ql4_printk(KERN_WARNING, ha, + "Memory Allocation failed.\n")); + ret = QLA_SUCCESS; + goto exit_check; + } + + qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); + + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); + if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb)) { + ret = QLA_SUCCESS; /* found */ + goto exit_check; + } + } + +exit_check: + if (fw_tddb) + vfree(fw_tddb); + if (tmp_tddb) + vfree(tmp_tddb); + return ret; +} + +static void qla4xxx_free_nt_list(struct list_head *list_nt) +{ + struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; + + /* Free up the normaltargets list */ + list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { + list_del_init(&nt_ddb_idx->list); + vfree(nt_ddb_idx); + } + +} + +static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, + struct dev_db_entry *fw_ddb_entry) +{ + struct iscsi_endpoint *ep; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + struct sockaddr *dst_addr; + char *ip; + + /* TODO: need to destroy on unload iscsi_endpoint*/ + dst_addr = vmalloc(sizeof(*dst_addr)); + if (!dst_addr) + return NULL; + + if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { + dst_addr->sa_family = AF_INET6; + addr6 = (struct sockaddr_in6 *)dst_addr; + ip = (char *)&addr6->sin6_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); + addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); + + } else { + dst_addr->sa_family = AF_INET; + addr = (struct sockaddr_in *)dst_addr; + ip = (char *)&addr->sin_addr; + memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); + addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); + } + + ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); + vfree(dst_addr); + return ep; +} + +static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) +{ + if (ql4xdisablesysfsboot) + return QLA_SUCCESS; + if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) + return QLA_ERROR; + return QLA_SUCCESS; +} + +static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, + struct ddb_entry *ddb_entry) +{ + ddb_entry->ddb_type = FLASH_DDB; + ddb_entry->fw_ddb_index = INVALID_ENTRY; + ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; + ddb_entry->ha = ha; + ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; + ddb_entry->ddb_change = qla4xxx_flash_ddb_change; + + atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); + atomic_set(&ddb_entry->relogin_timer, 0); + atomic_set(&ddb_entry->relogin_retry_count, 0); + + ddb_entry->default_relogin_timeout = + le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); + ddb_entry->default_time2wait = + le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); +} + +static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) +{ + uint32_t idx = 0; + uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ + uint32_t sts[MBOX_REG_COUNT]; + uint32_t ip_state; + unsigned long wtime; + int ret; + + wtime = jiffies + (HZ * IP_CONFIG_TOV); + do { + for (idx = 0; idx < IP_ADDR_COUNT; idx++) { + if (ip_idx[idx] == -1) + continue; + + ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); + + if (ret == QLA_ERROR) { + ip_idx[idx] = -1; + continue; + } + + ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; + + DEBUG2(ql4_printk(KERN_INFO, ha, + "Waiting for IP state for idx = %d, state = 0x%x\n", + ip_idx[idx], ip_state)); + if (ip_state == IP_ADDRSTATE_UNCONFIGURED || + ip_state == IP_ADDRSTATE_INVALID || + ip_state == IP_ADDRSTATE_PREFERRED || + ip_state == IP_ADDRSTATE_DEPRICATED || + ip_state == IP_ADDRSTATE_DISABLING) + ip_idx[idx] = -1; + + } + + /* Break if all IP states checked */ + if ((ip_idx[0] == -1) && + (ip_idx[1] == -1) && + (ip_idx[2] == -1) && + (ip_idx[3] == -1)) + break; + schedule_timeout_uninterruptible(HZ); + } while (time_after(wtime, jiffies)); +} + +void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) +{ + int max_ddbs; + int ret; + uint32_t idx = 0, next_idx = 0; + uint32_t state = 0, conn_err = 0; + uint16_t conn_id; + struct dev_db_entry *fw_ddb_entry; + struct ddb_entry *ddb_entry = NULL; + dma_addr_t fw_ddb_dma; + struct iscsi_cls_session *cls_sess; + struct iscsi_session *sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_endpoint *ep; + uint16_t cmds_max = 32, tmo = 0; + uint32_t initial_cmdsn = 0; + struct list_head list_st, list_nt; /* List of sendtargets */ + struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; + int fw_idx_size; + unsigned long wtime; + struct qla_ddb_index *nt_ddb_idx; + + if (!test_bit(AF_LINK_UP, &ha->flags)) { + set_bit(AF_BUILD_DDB_LIST, &ha->flags); + ha->is_reset = is_reset; + return; + } + max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : + MAX_DEV_DB_ENTRIES; + + fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, + &fw_ddb_dma); + if (fw_ddb_entry == NULL) { + DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); + goto exit_ddb_list; + } + + INIT_LIST_HEAD(&list_st); + INIT_LIST_HEAD(&list_nt); + fw_idx_size = sizeof(struct qla_ddb_index); + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, + fw_ddb_dma, NULL, + &next_idx, &state, &conn_err, + NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) + goto continue_next_st; + + /* Check if ST, add to the list_st */ + if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) + goto continue_next_st; + + st_ddb_idx = vzalloc(fw_idx_size); + if (!st_ddb_idx) + break; + + st_ddb_idx->fw_ddb_idx = idx; + + list_add_tail(&st_ddb_idx->list, &list_st); +continue_next_st: + if (next_idx == 0) + break; + } + + /* Before issuing conn open mbox, ensure all IPs states are configured + * Note, conn open fails if IPs are not configured + */ + qla4xxx_wait_for_ip_configuration(ha); + + /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); + } + + /* Wait to ensure all sendtargets are done for min 12 sec wait */ + tmo = ((ha->def_timeout < LOGIN_TOV) ? LOGIN_TOV : ha->def_timeout); + DEBUG2(ql4_printk(KERN_INFO, ha, + "Default time to wait for build ddb %d\n", tmo)); + + wtime = jiffies + (HZ * tmo); + do { + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, + list) { + ret = qla4xxx_get_fwddb_entry(ha, + st_ddb_idx->fw_ddb_idx, + NULL, 0, NULL, &next_idx, + &state, &conn_err, NULL, + NULL); + if (ret == QLA_ERROR) + continue; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + list_del_init(&st_ddb_idx->list); + vfree(st_ddb_idx); + } + } + schedule_timeout_uninterruptible(HZ / 10); + } while (time_after(wtime, jiffies)); + + /* Free up the sendtargets list */ + list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { + list_del_init(&st_ddb_idx->list); + vfree(st_ddb_idx); + } + + for (idx = 0; idx < max_ddbs; idx = next_idx) { + ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, + fw_ddb_dma, NULL, + &next_idx, &state, &conn_err, + NULL, &conn_id); + if (ret == QLA_ERROR) + break; + + if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) + goto continue_next_nt; + + /* Check if NT, then add to list it */ + if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) + goto continue_next_nt; + + if (state == DDB_DS_NO_CONNECTION_ACTIVE || + state == DDB_DS_SESSION_FAILED) { + DEBUG2(ql4_printk(KERN_INFO, ha, + "Adding DDB to session = 0x%x\n", + idx)); + if (is_reset == INIT_ADAPTER) { + nt_ddb_idx = vmalloc(fw_idx_size); + if (!nt_ddb_idx) + break; + + nt_ddb_idx->fw_ddb_idx = idx; + + memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + if (qla4xxx_is_flash_ddb_exists(ha, &list_nt, + fw_ddb_entry) == QLA_SUCCESS) { + vfree(nt_ddb_idx); + goto continue_next_nt; + } + list_add_tail(&nt_ddb_idx->list, &list_nt); + } else if (is_reset == RESET_ADAPTER) { + if (qla4xxx_is_session_exists(ha, + fw_ddb_entry) == QLA_SUCCESS) + goto continue_next_nt; + } + + /* Create session object, with INVALID_ENTRY, + * the targer_id would get set when we issue the login + */ + cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, + ha->host, cmds_max, + sizeof(struct ddb_entry), + sizeof(struct ql4_task_data), + initial_cmdsn, INVALID_ENTRY); + if (!cls_sess) + goto exit_ddb_list; + + /* + * iscsi_session_setup increments the driver reference + * count which wouldn't let the driver to be unloaded. + * so calling module_put function to decrement the + * reference count. + **/ + module_put(qla4xxx_iscsi_transport.owner); + sess = cls_sess->dd_data; + ddb_entry = sess->dd_data; + ddb_entry->sess = cls_sess; + + cls_sess->recovery_tmo = ql4xsess_recovery_tmo; + memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, + sizeof(struct dev_db_entry)); + + qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); + + cls_conn = iscsi_conn_setup(cls_sess, + sizeof(struct qla_conn), + conn_id); + if (!cls_conn) + goto exit_ddb_list; + + ddb_entry->conn = cls_conn; + + /* Setup ep, for displaying attributes in sysfs */ + ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); + if (ep) { + ep->conn = cls_conn; + cls_conn->ep = ep; + } else { + DEBUG2(ql4_printk(KERN_ERR, ha, + "Unable to get ep\n")); + } + + /* Update sess/conn params */ + qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, + cls_conn); + + if (is_reset == RESET_ADAPTER) { + iscsi_block_session(cls_sess); + /* Use the relogin path to discover new devices + * by short-circuting the logic of setting + * timer to relogin - instead set the flags + * to initiate login right away. + */ + set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); + set_bit(DF_RELOGIN, &ddb_entry->flags); + } + } +continue_next_nt: + if (next_idx == 0) + break; + } +exit_ddb_list: + qla4xxx_free_nt_list(&list_nt); + if (fw_ddb_entry) + dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); + + qla4xxx_free_ddb_index(ha); +} + + /** * qla4xxx_probe_adapter - callback function to probe HBA * @pdev: pointer to pci_dev structure @@ -3298,7 +4236,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, * firmware * NOTE: interrupts enabled upon successful completion */ - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); while ((!test_bit(AF_ONLINE, &ha->flags)) && init_retry_count++ < MAX_INIT_RETRIES) { @@ -3319,7 +4257,7 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) continue; - status = qla4xxx_initialize_adapter(ha); + status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); } if (!test_bit(AF_ONLINE, &ha->flags)) { @@ -3386,12 +4324,16 @@ static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, ha->host_no, ha->firmware_version[0], ha->firmware_version[1], ha->patch_number, ha->build_number); - qla4xxx_create_chap_list(ha); - if (qla4xxx_setup_boot_info(ha)) ql4_printk(KERN_ERR, ha, "%s:ISCSI boot info setup failed\n", __func__); + /* Perform the build ddb list and login to each */ + qla4xxx_build_ddb_list(ha, INIT_ADAPTER); + iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); + + qla4xxx_create_chap_list(ha); + qla4xxx_create_ifaces(ha); return 0; @@ -3449,6 +4391,38 @@ static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) } } +static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) +{ + struct ddb_entry *ddb_entry; + int options; + int idx; + + for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { + + ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); + if ((ddb_entry != NULL) && + (ddb_entry->ddb_type == FLASH_DDB)) { + + options = LOGOUT_OPTION_CLOSE_SESSION; + if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) + == QLA_ERROR) + ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", + __func__); + + qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); + /* + * we have decremented the reference count of the driver + * when we setup the session to have the driver unload + * to be seamless without actually destroying the + * session + **/ + try_module_get(qla4xxx_iscsi_transport.owner); + iscsi_destroy_endpoint(ddb_entry->conn->ep); + qla4xxx_free_ddb(ha, ddb_entry); + iscsi_session_teardown(ddb_entry->sess); + } + } +} /** * qla4xxx_remove_adapter - calback function to remove adapter. * @pci_dev: PCI device pointer @@ -3465,9 +4439,11 @@ static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) /* destroy iface from sysfs */ qla4xxx_destroy_ifaces(ha); - if (ha->boot_kset) + if ((!ql4xdisablesysfsboot) && ha->boot_kset) iscsi_boot_destroy_kset(ha->boot_kset); + qla4xxx_destroy_fw_ddb_session(ha); + scsi_remove_host(ha->host); qla4xxx_free_adapter(ha); @@ -4115,7 +5091,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) qla4_8xxx_idc_unlock(ha); clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); qla4_8xxx_idc_lock(ha); if (rval != QLA_SUCCESS) { @@ -4151,7 +5127,7 @@ static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == QLA82XX_DEV_READY)) { clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha); + rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); if (rval == QLA_SUCCESS) { ret = qla4xxx_request_irqs(ha); if (ret) { diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h index c15347d3f53..5254e57968f 100644 --- a/drivers/scsi/qla4xxx/ql4_version.h +++ b/drivers/scsi/qla4xxx/ql4_version.h @@ -5,4 +5,4 @@ * See LICENSE.qla4xxx for copyright and licensing details. */ -#define QLA4XXX_DRIVER_VERSION "5.02.00-k8" +#define QLA4XXX_DRIVER_VERSION "5.02.00-k9" diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 06bc26554a6..f85cfa6c47b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1409,6 +1409,8 @@ static void scsi_kill_request(struct request *req, struct request_queue *q) blk_start_request(req); + scmd_printk(KERN_INFO, cmd, "killing request\n"); + sdev = cmd->device; starget = scsi_target(sdev); shost = sdev->host; @@ -1490,7 +1492,6 @@ static void scsi_request_fn(struct request_queue *q) struct request *req; if (!sdev) { - printk("scsi: killing requests for dead queue\n"); while ((req = blk_peek_request(q)) != NULL) scsi_kill_request(req, q); return; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 72273a0e566..b3c6d957fbd 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -319,11 +319,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, return sdev; out_device_destroy: - scsi_device_set_state(sdev, SDEV_DEL); - transport_destroy_device(&sdev->sdev_gendev); - put_device(&sdev->sdev_dev); - scsi_free_queue(sdev->request_queue); - put_device(&sdev->sdev_gendev); + __scsi_remove_device(sdev); out: if (display_failure_msg) printk(ALLOC_FAILURE_MSG, __func__); diff --git a/drivers/sh/Makefile b/drivers/sh/Makefile index 24e6cec0ae8..67e272ab162 100644 --- a/drivers/sh/Makefile +++ b/drivers/sh/Makefile @@ -7,3 +7,11 @@ obj-$(CONFIG_HAVE_CLK) += clk/ obj-$(CONFIG_MAPLE) += maple/ obj-$(CONFIG_SUPERHYWAY) += superhyway/ obj-$(CONFIG_GENERIC_GPIO) += pfc.o + +# +# For the moment we only use this framework for ARM-based SH/R-Mobile +# platforms and generic SH. SH-based SH-Mobile platforms are still using +# an older framework that is pending up-porting, at which point this +# special casing can go away. +# +obj-$(CONFIG_SUPERH)$(CONFIG_ARCH_SHMOBILE) += pm_runtime.o diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c index dc8d022c07a..db257a35e71 100644 --- a/drivers/sh/clk/core.c +++ b/drivers/sh/clk/core.c @@ -25,7 +25,6 @@ #include <linux/seq_file.h> #include <linux/err.h> #include <linux/io.h> -#include <linux/debugfs.h> #include <linux/cpufreq.h> #include <linux/clk.h> #include <linux/sh_clk.h> @@ -173,6 +172,26 @@ long clk_rate_div_range_round(struct clk *clk, unsigned int div_min, return clk_rate_round_helper(&div_range_round); } +static long clk_rate_mult_range_iter(unsigned int pos, + struct clk_rate_round_data *rounder) +{ + return clk_get_rate(rounder->arg) * pos; +} + +long clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min, + unsigned int mult_max, unsigned long rate) +{ + struct clk_rate_round_data mult_range_round = { + .min = mult_min, + .max = mult_max, + .func = clk_rate_mult_range_iter, + .arg = clk_get_parent(clk), + .rate = rate, + }; + + return clk_rate_round_helper(&mult_range_round); +} + int clk_rate_table_find(struct clk *clk, struct cpufreq_frequency_table *freq_table, unsigned long rate) @@ -205,9 +224,6 @@ int clk_reparent(struct clk *child, struct clk *parent) list_add(&child->sibling, &parent->children); child->parent = parent; - /* now do the debugfs renaming to reattach the child - to the proper parent */ - return 0; } @@ -665,89 +681,6 @@ static int __init clk_syscore_init(void) subsys_initcall(clk_syscore_init); #endif -/* - * debugfs support to trace clock tree hierarchy and attributes - */ -static struct dentry *clk_debugfs_root; - -static int clk_debugfs_register_one(struct clk *c) -{ - int err; - struct dentry *d; - struct clk *pa = c->parent; - char s[255]; - char *p = s; - - p += sprintf(p, "%p", c); - d = debugfs_create_dir(s, pa ? pa->dentry : clk_debugfs_root); - if (!d) - return -ENOMEM; - c->dentry = d; - - d = debugfs_create_u8("usecount", S_IRUGO, c->dentry, (u8 *)&c->usecount); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_u32("rate", S_IRUGO, c->dentry, (u32 *)&c->rate); - if (!d) { - err = -ENOMEM; - goto err_out; - } - d = debugfs_create_x32("flags", S_IRUGO, c->dentry, (u32 *)&c->flags); - if (!d) { - err = -ENOMEM; - goto err_out; - } - return 0; - -err_out: - debugfs_remove_recursive(c->dentry); - return err; -} - -static int clk_debugfs_register(struct clk *c) -{ - int err; - struct clk *pa = c->parent; - - if (pa && !pa->dentry) { - err = clk_debugfs_register(pa); - if (err) - return err; - } - - if (!c->dentry) { - err = clk_debugfs_register_one(c); - if (err) - return err; - } - return 0; -} - -static int __init clk_debugfs_init(void) -{ - struct clk *c; - struct dentry *d; - int err; - - d = debugfs_create_dir("clock", NULL); - if (!d) - return -ENOMEM; - clk_debugfs_root = d; - - list_for_each_entry(c, &clock_list, node) { - err = clk_debugfs_register(c); - if (err) - goto err_out; - } - return 0; -err_out: - debugfs_remove_recursive(clk_debugfs_root); - return err; -} -late_initcall(clk_debugfs_init); - static int __init clk_late_init(void) { unsigned long flags; diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c new file mode 100644 index 00000000000..afe9282629b --- /dev/null +++ b/drivers/sh/pm_runtime.c @@ -0,0 +1,65 @@ +/* + * Runtime PM support code + * + * Copyright (C) 2009-2010 Magnus Damm + * + * 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/init.h> +#include <linux/kernel.h> +#include <linux/io.h> +#include <linux/pm_runtime.h> +#include <linux/pm_domain.h> +#include <linux/pm_clock.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/sh_clk.h> +#include <linux/bitmap.h> +#include <linux/slab.h> + +#ifdef CONFIG_PM_RUNTIME + +static int default_platform_runtime_idle(struct device *dev) +{ + /* suspend synchronously to disable clocks immediately */ + return pm_runtime_suspend(dev); +} + +static struct dev_pm_domain default_pm_domain = { + .ops = { + .runtime_suspend = pm_clk_suspend, + .runtime_resume = pm_clk_resume, + .runtime_idle = default_platform_runtime_idle, + USE_PLATFORM_PM_SLEEP_OPS + }, +}; + +#define DEFAULT_PM_DOMAIN_PTR (&default_pm_domain) + +#else + +#define DEFAULT_PM_DOMAIN_PTR NULL + +#endif /* CONFIG_PM_RUNTIME */ + +static struct pm_clk_notifier_block platform_bus_notifier = { + .pm_domain = DEFAULT_PM_DOMAIN_PTR, + .con_ids = { NULL, }, +}; + +static int __init sh_pm_runtime_init(void) +{ + pm_clk_add_notifier(&platform_bus_type, &platform_bus_notifier); + return 0; +} +core_initcall(sh_pm_runtime_init); + +static int __init sh_pm_runtime_late_init(void) +{ + pm_genpd_poweroff_unused(); + return 0; +} +late_initcall(sh_pm_runtime_late_init); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index a1fd73df541..8ba4510a951 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -199,7 +199,7 @@ config SPI_FSL_LIB depends on FSL_SOC config SPI_FSL_SPI - tristate "Freescale SPI controller" + bool "Freescale SPI controller" depends on FSL_SOC select SPI_FSL_LIB help @@ -208,7 +208,7 @@ config SPI_FSL_SPI MPC8569 uses the controller in QE mode, MPC8610 in cpu mode. config SPI_FSL_ESPI - tristate "Freescale eSPI controller" + bool "Freescale eSPI controller" depends on FSL_SOC select SPI_FSL_LIB help diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 024b48aed5c..acc88b4d286 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -13,6 +13,7 @@ */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/spinlock.h> diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 79665e2e6ec..16d6a839c7f 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -907,7 +907,7 @@ static void atmel_spi_cleanup(struct spi_device *spi) /*-------------------------------------------------------------------------*/ -static int __init atmel_spi_probe(struct platform_device *pdev) +static int __devinit atmel_spi_probe(struct platform_device *pdev) { struct resource *regs; int irq; @@ -1003,7 +1003,7 @@ out_free: return ret; } -static int __exit atmel_spi_remove(struct platform_device *pdev) +static int __devexit atmel_spi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); @@ -1072,6 +1072,7 @@ static struct platform_driver atmel_spi_driver = { }, .suspend = atmel_spi_suspend, .resume = atmel_spi_resume, + .probe = atmel_spi_probe, .remove = __exit_p(atmel_spi_remove), }; module_platform_driver(atmel_spi_driver); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index e093d3ec41b..0094c645ff0 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -256,7 +256,7 @@ static void spi_gpio_cleanup(struct spi_device *spi) spi_bitbang_cleanup(spi); } -static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in) +static int __devinit spi_gpio_alloc(unsigned pin, const char *label, bool is_in) { int value; @@ -270,7 +270,7 @@ static int __init spi_gpio_alloc(unsigned pin, const char *label, bool is_in) return value; } -static int __init +static int __devinit spi_gpio_request(struct spi_gpio_platform_data *pdata, const char *label, u16 *res_flags) { diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index e763254741c..182e9c87382 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -8,6 +8,7 @@ * */ +#include <linux/module.h> #include <linux/init.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -426,7 +427,7 @@ static int __devinit nuc900_spi_probe(struct platform_device *pdev) goto err_clk; } - mfp_set_groupg(&pdev->dev); + mfp_set_groupg(&pdev->dev, NULL); nuc900_init_spi(hw); err = spi_bitbang_start(&hw->bitbang); diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index f103e470cb6..5559b229919 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2184,6 +2184,12 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_clk_prep; } + status = clk_enable(pl022->clk); + if (status) { + dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); + goto err_no_clk_en; + } + /* Disable SSP */ writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); @@ -2237,6 +2243,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id) free_irq(adev->irq[0], pl022); err_no_irq: + clk_disable(pl022->clk); + err_no_clk_en: clk_unprepare(pl022->clk); err_clk_prep: clk_put(pl022->clk); diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c index 84c934c0a54..520e8286db2 100644 --- a/drivers/ssb/driver_pcicore.c +++ b/drivers/ssb/driver_pcicore.c @@ -517,10 +517,14 @@ static void ssb_pcicore_pcie_setup_workarounds(struct ssb_pcicore *pc) static void __devinit ssb_pcicore_init_clientmode(struct ssb_pcicore *pc) { - ssb_pcicore_fix_sprom_core_index(pc); + struct ssb_device *pdev = pc->dev; + struct ssb_bus *bus = pdev->bus; + + if (bus->bustype == SSB_BUSTYPE_PCI) + ssb_pcicore_fix_sprom_core_index(pc); /* Disable PCI interrupts. */ - ssb_write32(pc->dev, SSB_INTVEC, 0); + ssb_write32(pdev, SSB_INTVEC, 0); /* Additional PCIe always once-executed workarounds */ if (pc->dev->id.coreid == SSB_DEV_PCIE) { diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index 21d8c1c16cd..5e78c77d5a0 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -671,7 +671,7 @@ static int do_insnlist_ioctl(struct comedi_device *dev, } insns = - kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL); + kcalloc(insnlist.n_insns, sizeof(struct comedi_insn), GFP_KERNEL); if (!insns) { DPRINTK("kmalloc failed\n"); ret = -ENOMEM; @@ -1432,7 +1432,21 @@ static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return ret; } -static void comedi_unmap(struct vm_area_struct *area) + +static void comedi_vm_open(struct vm_area_struct *area) +{ + struct comedi_async *async; + struct comedi_device *dev; + + async = area->vm_private_data; + dev = async->subdevice->device; + + mutex_lock(&dev->mutex); + async->mmap_count++; + mutex_unlock(&dev->mutex); +} + +static void comedi_vm_close(struct vm_area_struct *area) { struct comedi_async *async; struct comedi_device *dev; @@ -1446,15 +1460,13 @@ static void comedi_unmap(struct vm_area_struct *area) } static struct vm_operations_struct comedi_vm_ops = { - .close = comedi_unmap, + .open = comedi_vm_open, + .close = comedi_vm_close, }; static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_async *async = NULL; unsigned long start = vma->vm_start; unsigned long size; @@ -1462,6 +1474,15 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) int i; int retval; struct comedi_subdevice *s; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + + dev_file_info = comedi_get_device_file_info(minor); + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1528,11 +1549,17 @@ static unsigned int comedi_poll(struct file *file, poll_table * wait) { unsigned int mask = 0; const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_subdevice *read_subdev; struct comedi_subdevice *write_subdev; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); if (!dev->attached) { @@ -1578,9 +1605,15 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1640,11 +1673,11 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) break; if (s->busy != file) { @@ -1683,9 +1716,15 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; if (!dev->attached) { DPRINTK("no driver configured on comedi%i\n", dev->minor); @@ -1741,11 +1780,11 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) { retval = 0; break; @@ -1885,11 +1924,17 @@ ok: static int comedi_close(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; struct comedi_subdevice *s = NULL; int i; + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); + + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; mutex_lock(&dev->mutex); @@ -1923,10 +1968,15 @@ static int comedi_close(struct inode *inode, struct file *file) static int comedi_fasync(int fd, struct file *file, int on) { const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); + struct comedi_device_file_info *dev_file_info; + struct comedi_device *dev; + dev_file_info = comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + if (dev_file_info == NULL) + return -ENODEV; + dev = dev_file_info->device; + if (dev == NULL) + return -ENODEV; return fasync_helper(fd, file, on, &dev->async_queue); } diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index a8fea9a9173..6144afb8cba 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -1,4 +1,4 @@ -#define DRIVER_VERSION "v0.5" +#define DRIVER_VERSION "v0.6" #define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com" #define DRIVER_DESC "Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com" /* @@ -25,7 +25,7 @@ Driver: usbduxsigma Description: University of Stirling USB DAQ & INCITE Technology Limited Devices: [ITL] USB-DUX (usbduxsigma.o) Author: Bernd Porr <BerndPorr@f2s.com> -Updated: 21 Jul 2011 +Updated: 8 Nov 2011 Status: testing */ /* @@ -44,6 +44,7 @@ Status: testing * 0.3: proper vendor ID and driver name * 0.4: fixed D/A voltage range * 0.5: various bug fixes, health check at startup + * 0.6: corrected wrong input range */ /* generates loads of debug info */ @@ -175,7 +176,7 @@ Status: testing /* comedi constants */ static const struct comedi_lrange range_usbdux_ai_range = { 1, { BIP_RANGE - (2.65) + (2.65/2.0) } }; diff --git a/drivers/staging/et131x/Kconfig b/drivers/staging/et131x/Kconfig index 9e1864c6dfd..8190f2aaf53 100644 --- a/drivers/staging/et131x/Kconfig +++ b/drivers/staging/et131x/Kconfig @@ -1,6 +1,7 @@ config ET131X tristate "Agere ET-1310 Gigabit Ethernet support" - depends on PCI + depends on PCI && NET && NETDEVICES + select PHYLIB default n ---help--- This driver supports Agere ET-1310 ethernet adapters. diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index f5f44a02456..0c1c6ca8c37 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -4469,6 +4469,12 @@ static int et131x_resume(struct device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(et131x_pm_ops, et131x_suspend, et131x_resume); +#define ET131X_PM_OPS (&et131x_pm_ops) +#else +#define ET131X_PM_OPS NULL +#endif + /* ISR functions */ /** @@ -5470,12 +5476,6 @@ err_out: return result; } -static SIMPLE_DEV_PM_OPS(et131x_pm_ops, et131x_suspend, et131x_resume); -#define ET131X_PM_OPS (&et131x_pm_ops) -#else -#define ET131X_PM_OPS NULL -#endif - static DEFINE_PCI_DEVICE_TABLE(et131x_pci_table) = { { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_GIG), 0UL}, { PCI_VDEVICE(ATT, ET131X_PCI_DEVICE_ID_FAST), 0UL}, diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c index 326e967d54e..aec9311b108 100644 --- a/drivers/staging/iio/industrialio-core.c +++ b/drivers/staging/iio/industrialio-core.c @@ -242,19 +242,26 @@ static const struct file_operations iio_event_chrdev_fileops = { static int iio_event_getfd(struct iio_dev *indio_dev) { - if (indio_dev->event_interface == NULL) + struct iio_event_interface *ev_int = indio_dev->event_interface; + int fd; + + if (ev_int == NULL) return -ENODEV; - mutex_lock(&indio_dev->event_interface->event_list_lock); - if (test_and_set_bit(IIO_BUSY_BIT_POS, - &indio_dev->event_interface->flags)) { - mutex_unlock(&indio_dev->event_interface->event_list_lock); + mutex_lock(&ev_int->event_list_lock); + if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) { + mutex_unlock(&ev_int->event_list_lock); return -EBUSY; } - mutex_unlock(&indio_dev->event_interface->event_list_lock); - return anon_inode_getfd("iio:event", - &iio_event_chrdev_fileops, - indio_dev->event_interface, O_RDONLY); + mutex_unlock(&ev_int->event_list_lock); + fd = anon_inode_getfd("iio:event", + &iio_event_chrdev_fileops, ev_int, O_RDONLY); + if (fd < 0) { + mutex_lock(&ev_int->event_list_lock); + clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags); + mutex_unlock(&ev_int->event_list_lock); + } + return fd; } static int __init iio_init(void) diff --git a/drivers/staging/media/as102/as102_drv.c b/drivers/staging/media/as102/as102_drv.c index d335c7d6fa0..828526d4c28 100644 --- a/drivers/staging/media/as102/as102_drv.c +++ b/drivers/staging/media/as102/as102_drv.c @@ -32,8 +32,8 @@ #include "as102_fw.h" #include "dvbdev.h" -int debug; -module_param_named(debug, debug, int, 0644); +int as102_debug; +module_param_named(debug, as102_debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default: off)"); int dual_tuner; diff --git a/drivers/staging/media/as102/as102_drv.h b/drivers/staging/media/as102/as102_drv.h index bcda635b5a9..fd33f5a12dc 100644 --- a/drivers/staging/media/as102/as102_drv.h +++ b/drivers/staging/media/as102/as102_drv.h @@ -37,7 +37,8 @@ extern struct spi_driver as102_spi_driver; #define DRIVER_FULL_NAME "Abilis Systems as10x usb driver" #define DRIVER_NAME "as10x_usb" -extern int debug; +extern int as102_debug; +#define debug as102_debug #define dprintk(debug, args...) \ do { if (debug) { \ diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index b445cd63f90..2542c374390 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -275,7 +275,7 @@ int cvm_oct_xmit(struct sk_buff *skb, struct net_device *dev) CVM_OCT_SKB_CB(skb)[0] = hw_buffer.u64; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *fs = skb_shinfo(skb)->frags + i; - hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page) + fs->page_offset)); + hw_buffer.s.addr = XKPHYS_TO_PHYS((u64)(page_address(fs->page.p) + fs->page_offset)); hw_buffer.s.size = fs->size; CVM_OCT_SKB_CB(skb)[i + 1] = hw_buffer.u64; } diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index fb2e89c3056..5385da2e9cd 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -89,6 +89,7 @@ static struct usb_device_id rtl871x_usb_id_tbl[] = { {USB_DEVICE(0x0DF6, 0x0045)}, {USB_DEVICE(0x0DF6, 0x0059)}, /* 11n mode disable */ {USB_DEVICE(0x0DF6, 0x004B)}, + {USB_DEVICE(0x0DF6, 0x005D)}, {USB_DEVICE(0x0DF6, 0x0063)}, /* Sweex */ {USB_DEVICE(0x177F, 0x0154)}, diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c index 480b0ed2e4d..115635f9502 100644 --- a/drivers/staging/rts_pstor/rtsx.c +++ b/drivers/staging/rts_pstor/rtsx.c @@ -1021,6 +1021,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, th = kthread_create(rtsx_scan_thread, dev, "rtsx-scan"); if (IS_ERR(th)) { printk(KERN_ERR "Unable to start the device-scanning thread\n"); + complete(&dev->scanning_done); quiesce_and_remove_host(dev); err = PTR_ERR(th); goto errout; diff --git a/drivers/staging/slicoss/Kconfig b/drivers/staging/slicoss/Kconfig index 5cde96b2e6e..5c2a15b42df 100644 --- a/drivers/staging/slicoss/Kconfig +++ b/drivers/staging/slicoss/Kconfig @@ -1,6 +1,6 @@ config SLICOSS tristate "Alacritech Gigabit IS-NIC support" - depends on PCI && X86 + depends on PCI && X86 && NET default n help This driver supports Alacritech's IS-NIC gigabit ethernet cards. diff --git a/drivers/staging/spectra/lld_mtd.c b/drivers/staging/spectra/lld_mtd.c index 2bd34662beb..a9c309a167c 100644 --- a/drivers/staging/spectra/lld_mtd.c +++ b/drivers/staging/spectra/lld_mtd.c @@ -340,7 +340,7 @@ u16 mtd_Read_Page_Main_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = read_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = read_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -400,7 +400,7 @@ u16 mtd_Write_Page_Main_Spare(u8 *write_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = write_data; ops.len = DeviceInfo.wPageDataSize; ops.oobbuf = write_data + DeviceInfo.wPageDataSize + BTSIG_OFFSET; @@ -473,7 +473,7 @@ u16 mtd_Read_Page_Spare(u8 *read_data, u32 Block, struct mtd_oob_ops ops; int ret; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.datbuf = NULL; ops.len = 0; ops.oobbuf = read_data; diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c index 3d1279c424a..7eb56178fb6 100644 --- a/drivers/staging/tidspbridge/core/dsp-clock.c +++ b/drivers/staging/tidspbridge/core/dsp-clock.c @@ -54,6 +54,7 @@ /* Bridge GPT id (1 - 4), DM Timer id (5 - 8) */ #define DMT_ID(id) ((id) + 4) +#define DM_TIMER_CLOCKS 4 /* Bridge MCBSP id (6 - 10), OMAP Mcbsp id (0 - 4) */ #define MCBSP_ID(id) ((id) - 6) @@ -114,8 +115,13 @@ static s8 get_clk_type(u8 id) */ void dsp_clk_exit(void) { + int i; + dsp_clock_disable_all(dsp_clocks); + for (i = 0; i < DM_TIMER_CLOCKS; i++) + omap_dm_timer_free(timer[i]); + clk_put(iva2_clk); clk_put(ssi.sst_fck); clk_put(ssi.ssr_fck); @@ -130,9 +136,13 @@ void dsp_clk_exit(void) void dsp_clk_init(void) { static struct platform_device dspbridge_device; + int i, id; dspbridge_device.dev.bus = &platform_bus_type; + for (i = 0, id = 5; i < DM_TIMER_CLOCKS; i++, id++) + timer[i] = omap_dm_timer_request_specific(id); + iva2_clk = clk_get(&dspbridge_device.dev, "iva2_ck"); if (IS_ERR(iva2_clk)) dev_err(bridge, "failed to get iva2 clock %p\n", iva2_clk); @@ -204,8 +214,7 @@ int dsp_clk_enable(enum dsp_clk_id clk_id) clk_enable(iva2_clk); break; case GPT_CLK: - timer[clk_id - 1] = - omap_dm_timer_request_specific(DMT_ID(clk_id)); + status = omap_dm_timer_start(timer[clk_id - 1]); break; #ifdef CONFIG_OMAP_MCBSP case MCBSP_CLK: @@ -281,7 +290,7 @@ int dsp_clk_disable(enum dsp_clk_id clk_id) clk_disable(iva2_clk); break; case GPT_CLK: - omap_dm_timer_free(timer[clk_id - 1]); + status = omap_dm_timer_stop(timer[clk_id - 1]); break; #ifdef CONFIG_OMAP_MCBSP case MCBSP_CLK: diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c index c43c7e3421c..76cfc6edecd 100644 --- a/drivers/staging/tidspbridge/rmgr/drv_interface.c +++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c @@ -24,11 +24,7 @@ #include <linux/types.h> #include <linux/platform_device.h> #include <linux/pm.h> - -#ifdef MODULE #include <linux/module.h> -#endif - #include <linux/device.h> #include <linux/init.h> #include <linux/moduleparam.h> diff --git a/drivers/staging/usbip/vhci_rx.c b/drivers/staging/usbip/vhci_rx.c index 09c44abb89e..3872b8cccdc 100644 --- a/drivers/staging/usbip/vhci_rx.c +++ b/drivers/staging/usbip/vhci_rx.c @@ -68,6 +68,7 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, { struct usbip_device *ud = &vdev->ud; struct urb *urb; + unsigned long flags; spin_lock(&vdev->priv_lock); urb = pickup_urb_and_free_priv(vdev, pdu->base.seqnum); @@ -101,9 +102,9 @@ static void vhci_recv_ret_submit(struct vhci_device *vdev, usbip_dbg_vhci_rx("now giveback urb %p\n", urb); - spin_lock(&the_controller->lock); + spin_lock_irqsave(&the_controller->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock(&the_controller->lock); + spin_unlock_irqrestore(&the_controller->lock, flags); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); @@ -141,6 +142,7 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, { struct vhci_unlink *unlink; struct urb *urb; + unsigned long flags; usbip_dump_header(pdu); @@ -170,9 +172,9 @@ static void vhci_recv_ret_unlink(struct vhci_device *vdev, urb->status = pdu->u.ret_unlink.status; pr_info("urb->status %d\n", urb->status); - spin_lock(&the_controller->lock); + spin_lock_irqsave(&the_controller->lock, flags); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); - spin_unlock(&the_controller->lock); + spin_unlock_irqrestore(&the_controller->lock, flags); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 0fd96c10271..8599545cdf9 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -614,13 +614,12 @@ int iscsit_add_reject( hdr = (struct iscsi_reject *) cmd->pdu; hdr->reason = reason; - cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); + cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); if (!cmd->buf_ptr) { pr_err("Unable to allocate memory for cmd->buf_ptr\n"); iscsit_release_cmd(cmd); return -1; } - memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN); spin_lock_bh(&conn->cmd_lock); list_add_tail(&cmd->i_list, &conn->conn_cmd_list); @@ -661,13 +660,12 @@ int iscsit_add_reject_from_cmd( hdr = (struct iscsi_reject *) cmd->pdu; hdr->reason = reason; - cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); + cmd->buf_ptr = kmemdup(buf, ISCSI_HDR_LEN, GFP_KERNEL); if (!cmd->buf_ptr) { pr_err("Unable to allocate memory for cmd->buf_ptr\n"); iscsit_release_cmd(cmd); return -1; } - memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN); if (add_to_conn) { spin_lock_bh(&conn->cmd_lock); @@ -1017,11 +1015,6 @@ done: " non-existent or non-exported iSCSI LUN:" " 0x%016Lx\n", get_unaligned_le64(&hdr->lun)); } - if (ret == PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - send_check_condition = 1; goto attach_cmd; } @@ -1044,6 +1037,8 @@ done: */ send_check_condition = 1; } else { + cmd->data_length = cmd->se_cmd.data_length; + if (iscsit_decide_list_to_build(cmd, payload_length) < 0) return iscsit_add_reject_from_cmd( ISCSI_REASON_BOOKMARK_NO_RESOURCES, @@ -1123,7 +1118,7 @@ attach_cmd: * the backend memory allocation. */ ret = transport_generic_new_cmd(&cmd->se_cmd); - if ((ret < 0) || (cmd->se_cmd.se_cmd_flags & SCF_SE_CMD_FAILED)) { + if (ret < 0) { immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; dump_immediate_data = 1; goto after_immediate_data; @@ -1341,7 +1336,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) spin_lock_irqsave(&se_cmd->t_state_lock, flags); if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) || - (se_cmd->se_cmd_flags & SCF_SE_CMD_FAILED)) + (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION)) dump_unsolicited_data = 1; spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); @@ -2513,10 +2508,10 @@ static int iscsit_send_data_in( if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); + hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); + hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); } } hton24(hdr->dlength, datain.length); @@ -3018,10 +3013,10 @@ static int iscsit_send_status( hdr->flags |= ISCSI_FLAG_CMD_FINAL; if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); + hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); + hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); } hdr->response = cmd->iscsi_response; hdr->cmd_status = cmd->se_cmd.scsi_status; @@ -3133,6 +3128,7 @@ static int iscsit_send_task_mgt_rsp( hdr = (struct iscsi_tm_rsp *) cmd->pdu; memset(hdr, 0, ISCSI_HDR_LEN); hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; + hdr->flags = ISCSI_FLAG_CMD_FINAL; hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr); hdr->itt = cpu_to_be32(cmd->init_task_tag); cmd->stat_sn = conn->stat_sn++; diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index beb39469e7f..1cd6ce373b8 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -30,9 +30,11 @@ static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) { - int j = DIV_ROUND_UP(len, 2); + int j = DIV_ROUND_UP(len, 2), rc; - hex2bin(dst, src, j); + rc = hex2bin(dst, src, j); + if (rc < 0) + pr_debug("CHAP string contains non hex digit symbols\n"); dst[j] = '\0'; return j; diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 3723d90d5ae..f1a02dad05a 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h @@ -398,7 +398,6 @@ struct iscsi_cmd { u32 pdu_send_order; /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */ u32 pdu_start; - u32 residual_count; /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */ u32 seq_send_order; /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */ @@ -535,7 +534,6 @@ struct iscsi_conn { atomic_t connection_exit; atomic_t connection_recovery; atomic_t connection_reinstatement; - atomic_t connection_wait; atomic_t connection_wait_rcfr; atomic_t sleep_on_conn_wait_comp; atomic_t transport_failed; @@ -643,7 +641,6 @@ struct iscsi_session { atomic_t session_reinstatement; atomic_t session_stop_active; atomic_t sleep_on_sess_wait_comp; - atomic_t transport_wait_cmds; /* connection list */ struct list_head sess_conn_list; struct list_head cr_active_list; diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index c4c68da3e50..101b1beb3bc 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -938,8 +938,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) * handle the SCF_SCSI_RESERVATION_CONFLICT case here as well. */ if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { - if (se_cmd->se_cmd_flags & - SCF_SCSI_RESERVATION_CONFLICT) { + if (se_cmd->scsi_sense_reason == TCM_RESERVATION_CONFLICT) { cmd->i_state = ISTATE_SEND_STATUS; spin_unlock_bh(&cmd->istate_lock); iscsit_add_cmd_to_response_queue(cmd, cmd->conn, diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index daad362a93c..d734bdec24f 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -224,7 +224,7 @@ static int iscsi_login_zero_tsih_s1( iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); pr_err("Could not allocate memory for session\n"); - return -1; + return -ENOMEM; } iscsi_login_set_conn_values(sess, conn, pdu->cid); @@ -250,7 +250,8 @@ static int iscsi_login_zero_tsih_s1( pr_err("idr_pre_get() for sess_idr failed\n"); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; + kfree(sess); + return -ENOMEM; } spin_lock(&sess_idr_lock); idr_get_new(&sess_idr, NULL, &sess->session_index); @@ -270,14 +271,16 @@ static int iscsi_login_zero_tsih_s1( ISCSI_LOGIN_STATUS_NO_RESOURCES); pr_err("Unable to allocate memory for" " struct iscsi_sess_ops.\n"); - return -1; + kfree(sess); + return -ENOMEM; } sess->se_sess = transport_init_session(); - if (!sess->se_sess) { + if (IS_ERR(sess->se_sess)) { iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; + kfree(sess); + return -ENOMEM; } return 0; diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 426cd4bf6a9..98936cb7c29 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -981,14 +981,13 @@ struct iscsi_login *iscsi_target_init_negotiation( return NULL; } - login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); + login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL); if (!login->req) { pr_err("Unable to allocate memory for Login Request.\n"); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_NO_RESOURCES); goto out; } - memcpy(login->req, login_pdu, ISCSI_HDR_LEN); login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); if (!login->req_buf) { diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 3df1c9b8ae6..81d5832fbbd 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -113,11 +113,9 @@ static struct se_cmd *tcm_loop_allocate_core_cmd( scsi_bufflen(sc), sc->sc_data_direction, sam_task_attr, &tl_cmd->tl_sense_buf[0]); - /* - * Signal BIDI usage with T_TASK(cmd)->t_tasks_bidi - */ if (scsi_bidi_cmnd(sc)) - se_cmd->t_tasks_bidi = 1; + se_cmd->se_cmd_flags |= SCF_BIDI; + /* * Locate the struct se_lun pointer and attach it to struct se_cmd */ @@ -148,27 +146,13 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) * Allocate the necessary tasks to complete the received CDB+data */ ret = transport_generic_allocate_tasks(se_cmd, sc->cmnd); - if (ret == -ENOMEM) { - /* Out of Resources */ - return PYX_TRANSPORT_LU_COMM_FAILURE; - } else if (ret == -EINVAL) { - /* - * Handle case for SAM_STAT_RESERVATION_CONFLICT - */ - if (se_cmd->se_cmd_flags & SCF_SCSI_RESERVATION_CONFLICT) - return PYX_TRANSPORT_RESERVATION_CONFLICT; - /* - * Otherwise, return SAM_STAT_CHECK_CONDITION and return - * sense data. - */ - return PYX_TRANSPORT_USE_SENSE_REASON; - } - + if (ret != 0) + return ret; /* * For BIDI commands, pass in the extra READ buffer * to transport_generic_map_mem_to_cmd() below.. */ - if (se_cmd->t_tasks_bidi) { + if (se_cmd->se_cmd_flags & SCF_BIDI) { struct scsi_data_buffer *sdb = scsi_in(sc); sgl_bidi = sdb->table.sgl; @@ -194,12 +178,8 @@ static int tcm_loop_new_cmd_map(struct se_cmd *se_cmd) } /* Tell the core about our preallocated memory */ - ret = transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), + return transport_generic_map_mem_to_cmd(se_cmd, scsi_sglist(sc), scsi_sg_count(sc), sgl_bidi, sgl_bidi_count); - if (ret < 0) - return PYX_TRANSPORT_LU_COMM_FAILURE; - - return 0; } /* @@ -1360,17 +1340,16 @@ void tcm_loop_drop_scsi_hba( { struct tcm_loop_hba *tl_hba = container_of(wwn, struct tcm_loop_hba, tl_hba_wwn); - int host_no = tl_hba->sh->host_no; + + pr_debug("TCM_Loop_ConfigFS: Deallocating emulated Target" + " SAS Address: %s at Linux/SCSI Host ID: %d\n", + tl_hba->tl_wwn_address, tl_hba->sh->host_no); /* * Call device_unregister() on the original tl_hba->dev. * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will * release *tl_hba; */ device_unregister(&tl_hba->dev); - - pr_debug("TCM_Loop_ConfigFS: Deallocated emulated Target" - " SAS Address: %s at Linux/SCSI Host ID: %d\n", - config_item_name(&wwn->wwn_group.cg_item), host_no); } /* Start items for tcm_loop_cit */ diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 88f2ad43ec8..1dcbef499d6 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -191,9 +191,10 @@ int target_emulate_set_target_port_groups(struct se_task *task) int alua_access_state, primary = 0, rc; u16 tg_pt_id, rtpi; - if (!l_port) - return PYX_TRANSPORT_LU_COMM_FAILURE; - + if (!l_port) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; + } buf = transport_kmap_first_data_page(cmd); /* @@ -203,7 +204,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) l_tg_pt_gp_mem = l_port->sep_alua_tg_pt_gp_mem; if (!l_tg_pt_gp_mem) { pr_err("Unable to access l_port->sep_alua_tg_pt_gp_mem\n"); - rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + rc = -EINVAL; goto out; } spin_lock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); @@ -211,7 +213,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) if (!l_tg_pt_gp) { spin_unlock(&l_tg_pt_gp_mem->tg_pt_gp_mem_lock); pr_err("Unable to access *l_tg_pt_gp_mem->tg_pt_gp\n"); - rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + rc = -EINVAL; goto out; } rc = (l_tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICT_ALUA); @@ -220,7 +223,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) if (!rc) { pr_debug("Unable to process SET_TARGET_PORT_GROUPS" " while TPGS_EXPLICT_ALUA is disabled\n"); - rc = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + rc = -EINVAL; goto out; } @@ -245,7 +249,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) * REQUEST, and the additional sense code set to INVALID * FIELD IN PARAMETER LIST. */ - rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + rc = -EINVAL; goto out; } rc = -1; @@ -298,7 +303,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) * throw an exception with ASCQ: INVALID_PARAMETER_LIST */ if (rc != 0) { - rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + rc = -EINVAL; goto out; } } else { @@ -335,7 +341,8 @@ int target_emulate_set_target_port_groups(struct se_task *task) * INVALID_PARAMETER_LIST */ if (rc != 0) { - rc = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + rc = -EINVAL; goto out; } } @@ -1184,7 +1191,6 @@ void core_alua_free_lu_gp(struct t10_alua_lu_gp *lu_gp) * struct t10_alua_lu_gp. */ spin_lock(&lu_gps_lock); - atomic_set(&lu_gp->lu_gp_shutdown, 1); list_del(&lu_gp->lu_gp_node); alua_lu_gps_count--; spin_unlock(&lu_gps_lock); @@ -1438,7 +1444,6 @@ struct t10_alua_tg_pt_gp_member *core_alua_allocate_tg_pt_gp_mem( tg_pt_gp_mem->tg_pt = port; port->sep_alua_tg_pt_gp_mem = tg_pt_gp_mem; - atomic_set(&port->sep_tg_pt_gp_active, 1); return tg_pt_gp_mem; } diff --git a/drivers/target/target_core_cdb.c b/drivers/target/target_core_cdb.c index 683ba02b824..831468b3163 100644 --- a/drivers/target/target_core_cdb.c +++ b/drivers/target/target_core_cdb.c @@ -478,7 +478,7 @@ target_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf) if (cmd->data_length < 60) return 0; - buf[2] = 0x3c; + buf[3] = 0x3c; /* Set HEADSUP, ORDSUP, SIMPSUP */ buf[5] = 0x07; @@ -703,6 +703,7 @@ int target_emulate_inquiry(struct se_task *task) if (cmd->data_length < 4) { pr_err("SCSI Inquiry payload length: %u" " too small for EVPD=1\n", cmd->data_length); + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; return -EINVAL; } @@ -719,6 +720,7 @@ int target_emulate_inquiry(struct se_task *task) } pr_err("Unknown VPD Code: 0x%02x\n", cdb[2]); + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; ret = -EINVAL; out_unmap: @@ -969,7 +971,8 @@ int target_emulate_modesense(struct se_task *task) default: pr_err("MODE SENSE: unimplemented page/subpage: 0x%02x/0x%02x\n", cdb[2] & 0x3f, cdb[3]); - return PYX_TRANSPORT_UNKNOWN_MODE_PAGE; + cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; + return -EINVAL; } offset += length; @@ -1027,7 +1030,8 @@ int target_emulate_request_sense(struct se_task *task) if (cdb[1] & 0x01) { pr_err("REQUEST_SENSE description emulation not" " supported\n"); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -ENOSYS; } buf = transport_kmap_first_data_page(cmd); @@ -1100,7 +1104,8 @@ int target_emulate_unmap(struct se_task *task) if (!dev->transport->do_discard) { pr_err("UNMAP emulation not supported for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; } /* First UNMAP block descriptor starts at 8 byte offset */ @@ -1157,7 +1162,8 @@ int target_emulate_write_same(struct se_task *task) if (!dev->transport->do_discard) { pr_err("WRITE_SAME emulation not supported" " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; } if (cmd->t_task_cdb[0] == WRITE_SAME) @@ -1193,11 +1199,13 @@ int target_emulate_write_same(struct se_task *task) int target_emulate_synchronize_cache(struct se_task *task) { struct se_device *dev = task->task_se_cmd->se_dev; + struct se_cmd *cmd = task->task_se_cmd; if (!dev->transport->do_sync_cache) { pr_err("SYNCHRONIZE_CACHE emulation not supported" " for: %s\n", dev->transport->name); - return PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + return -ENOSYS; } dev->transport->do_sync_cache(task); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index e0c1e8a8dd4..93d4f6a1b79 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -67,9 +67,6 @@ static struct config_group target_core_hbagroup; static struct config_group alua_group; static struct config_group alua_lu_gps_group; -static DEFINE_SPINLOCK(se_device_lock); -static LIST_HEAD(se_dev_list); - static inline struct se_hba * item_to_hba(struct config_item *item) { @@ -2741,7 +2738,6 @@ static struct config_group *target_core_make_subdev( " struct se_subsystem_dev\n"); goto unlock; } - INIT_LIST_HEAD(&se_dev->se_dev_node); INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); @@ -2777,9 +2773,6 @@ static struct config_group *target_core_make_subdev( " from allocate_virtdevice()\n"); goto out; } - spin_lock(&se_device_lock); - list_add_tail(&se_dev->se_dev_node, &se_dev_list); - spin_unlock(&se_device_lock); config_group_init_type_name(&se_dev->se_dev_group, name, &target_core_dev_cit); @@ -2874,10 +2867,6 @@ static void target_core_drop_subdev( mutex_lock(&hba->hba_access_mutex); t = hba->transport; - spin_lock(&se_device_lock); - list_del(&se_dev->se_dev_node); - spin_unlock(&se_device_lock); - dev_stat_grp = &se_dev->dev_stat_grps.stat_group; for (i = 0; dev_stat_grp->default_groups[i]; i++) { df_item = &dev_stat_grp->default_groups[i]->cg_item; diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index ba5edec2c5f..9b863942547 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -104,7 +104,6 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) se_cmd->se_lun = deve->se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; - se_cmd->se_orig_obj_ptr = se_cmd->se_lun->lun_se_dev; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; } spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); @@ -137,7 +136,6 @@ int transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) se_lun = &se_sess->se_tpg->tpg_virt_lun0; se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; se_cmd->orig_fe_lun = 0; - se_cmd->se_orig_obj_ptr = se_cmd->se_lun->lun_se_dev; se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; } /* @@ -200,7 +198,6 @@ int transport_lookup_tmr_lun(struct se_cmd *se_cmd, u32 unpacked_lun) se_lun = deve->se_lun; se_cmd->pr_res_key = deve->pr_res_key; se_cmd->orig_fe_lun = unpacked_lun; - se_cmd->se_orig_obj_ptr = se_cmd->se_dev; } spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); @@ -708,7 +705,7 @@ done: se_task->task_scsi_status = GOOD; transport_complete_task(se_task, 1); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } /* se_release_device_for_hba(): @@ -957,8 +954,12 @@ int se_dev_set_emulate_dpo(struct se_device *dev, int flag) return -EINVAL; } - pr_err("dpo_emulated not supported\n"); - return -EINVAL; + if (flag) { + pr_err("dpo_emulated not supported\n"); + return -EINVAL; + } + + return 0; } int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) @@ -968,7 +969,7 @@ int se_dev_set_emulate_fua_write(struct se_device *dev, int flag) return -EINVAL; } - if (dev->transport->fua_write_emulated == 0) { + if (flag && dev->transport->fua_write_emulated == 0) { pr_err("fua_write_emulated not supported\n"); return -EINVAL; } @@ -985,8 +986,12 @@ int se_dev_set_emulate_fua_read(struct se_device *dev, int flag) return -EINVAL; } - pr_err("ua read emulated not supported\n"); - return -EINVAL; + if (flag) { + pr_err("ua read emulated not supported\n"); + return -EINVAL; + } + + return 0; } int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) @@ -995,7 +1000,7 @@ int se_dev_set_emulate_write_cache(struct se_device *dev, int flag) pr_err("Illegal value %d\n", flag); return -EINVAL; } - if (dev->transport->write_cache_emulated == 0) { + if (flag && dev->transport->write_cache_emulated == 0) { pr_err("write_cache_emulated not supported\n"); return -EINVAL; } @@ -1056,7 +1061,7 @@ int se_dev_set_emulate_tpu(struct se_device *dev, int flag) * We expect this value to be non-zero when generic Block Layer * Discard supported is detected iblock_create_virtdevice(). */ - if (!dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { pr_err("Generic Block Discard not supported\n"); return -ENOSYS; } @@ -1077,7 +1082,7 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag) * We expect this value to be non-zero when generic Block Layer * Discard supported is detected iblock_create_virtdevice(). */ - if (!dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { + if (flag && !dev->se_sub_dev->se_dev_attrib.max_unmap_block_desc_count) { pr_err("Generic Block Discard not supported\n"); return -ENOSYS; } @@ -1587,7 +1592,6 @@ int core_dev_setup_virtual_lun0(void) ret = -ENOMEM; goto out; } - INIT_LIST_HEAD(&se_dev->se_dev_node); INIT_LIST_HEAD(&se_dev->t10_wwn.t10_vpd_list); spin_lock_init(&se_dev->t10_wwn.t10_vpd_lock); INIT_LIST_HEAD(&se_dev->t10_pr.registration_list); diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 67cd6fe05bf..b4864fba4ef 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -289,9 +289,9 @@ static int fd_do_readv(struct se_task *task) return -ENOMEM; } - for (i = 0; i < task->task_sg_nents; i++) { - iov[i].iov_len = sg[i].length; - iov[i].iov_base = sg_virt(&sg[i]); + for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { + iov[i].iov_len = sg->length; + iov[i].iov_base = sg_virt(sg); } old_fs = get_fs(); @@ -342,9 +342,9 @@ static int fd_do_writev(struct se_task *task) return -ENOMEM; } - for (i = 0; i < task->task_sg_nents; i++) { - iov[i].iov_len = sg[i].length; - iov[i].iov_base = sg_virt(&sg[i]); + for_each_sg(task->task_sg, sg, task->task_sg_nents, i) { + iov[i].iov_len = sg->length; + iov[i].iov_base = sg_virt(sg); } old_fs = get_fs(); @@ -438,7 +438,7 @@ static int fd_do_task(struct se_task *task) if (ret > 0 && dev->se_sub_dev->se_dev_attrib.emulate_write_cache > 0 && dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && - cmd->t_tasks_fua) { + (cmd->se_cmd_flags & SCF_FUA)) { /* * We might need to be a bit smarter here * and return some sense data to let the initiator @@ -449,13 +449,15 @@ static int fd_do_task(struct se_task *task) } - if (ret < 0) + if (ret < 0) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return ret; + } if (ret) { task->task_scsi_status = GOOD; transport_complete_task(task, 1); } - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } /* fd_free_task(): (Part of se_subsystem_api_t template) diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 7698efe2926..4aa99220443 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -531,7 +531,7 @@ static int iblock_do_task(struct se_task *task) */ if (dev->se_sub_dev->se_dev_attrib.emulate_write_cache == 0 || (dev->se_sub_dev->se_dev_attrib.emulate_fua_write > 0 && - task->task_se_cmd->t_tasks_fua)) + (cmd->se_cmd_flags & SCF_FUA))) rw = WRITE_FUA; else rw = WRITE; @@ -554,12 +554,15 @@ static int iblock_do_task(struct se_task *task) else { pr_err("Unsupported SCSI -> BLOCK LBA conversion:" " %u\n", dev->se_sub_dev->se_dev_attrib.block_size); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOSYS; } bio = iblock_get_bio(task, block_lba, sg_num); - if (!bio) - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + if (!bio) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; + } bio_list_init(&list); bio_list_add(&list, bio); @@ -588,12 +591,13 @@ static int iblock_do_task(struct se_task *task) submit_bio(rw, bio); blk_finish_plug(&plug); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; fail: while ((bio = bio_list_pop(&list))) bio_put(bio); - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; } static u32 iblock_get_device_rev(struct se_device *dev) diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 5a4ebfc3a54..95dee7074ae 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -191,7 +191,7 @@ static int target_check_scsi2_reservation_conflict(struct se_cmd *cmd, int *ret) pr_err("Received legacy SPC-2 RESERVE/RELEASE" " while active SPC-3 registrations exist," " returning RESERVATION_CONFLICT\n"); - *ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; return true; } @@ -252,7 +252,8 @@ int target_scsi2_reservation_reserve(struct se_task *task) (cmd->t_task_cdb[1] & 0x02)) { pr_err("LongIO and Obselete Bits set, returning" " ILLEGAL_REQUEST\n"); - ret = PYX_TRANSPORT_ILLEGAL_REQUEST; + cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; + ret = -EINVAL; goto out; } /* @@ -277,7 +278,8 @@ int target_scsi2_reservation_reserve(struct se_task *task) " from %s \n", cmd->se_lun->unpacked_lun, cmd->se_deve->mapped_lun, sess->se_node_acl->initiatorname); - ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + ret = -EINVAL; goto out_unlock; } @@ -1510,7 +1512,8 @@ static int core_scsi3_decode_spec_i_port( tidh_new = kzalloc(sizeof(struct pr_transport_id_holder), GFP_KERNEL); if (!tidh_new) { pr_err("Unable to allocate tidh_new\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } INIT_LIST_HEAD(&tidh_new->dest_list); tidh_new->dest_tpg = tpg; @@ -1522,7 +1525,8 @@ static int core_scsi3_decode_spec_i_port( sa_res_key, all_tg_pt, aptpl); if (!local_pr_reg) { kfree(tidh_new); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; } tidh_new->dest_pr_reg = local_pr_reg; /* @@ -1548,7 +1552,8 @@ static int core_scsi3_decode_spec_i_port( pr_err("SPC-3 PR: Illegal tpdl: %u + 28 byte header" " does not equal CDB data_length: %u\n", tpdl, cmd->data_length); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } /* @@ -1598,7 +1603,9 @@ static int core_scsi3_decode_spec_i_port( " for tmp_tpg\n"); atomic_dec(&tmp_tpg->tpg_pr_ref_count); smp_mb__after_atomic_dec(); - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -EINVAL; goto out; } /* @@ -1628,7 +1635,9 @@ static int core_scsi3_decode_spec_i_port( atomic_dec(&dest_node_acl->acl_pr_ref_count); smp_mb__after_atomic_dec(); core_scsi3_tpg_undepend_item(tmp_tpg); - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -EINVAL; goto out; } @@ -1646,7 +1655,8 @@ static int core_scsi3_decode_spec_i_port( if (!dest_tpg) { pr_err("SPC-3 PR SPEC_I_PT: Unable to locate" " dest_tpg\n"); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } #if 0 @@ -1660,7 +1670,8 @@ static int core_scsi3_decode_spec_i_port( " %u for Transport ID: %s\n", tid_len, ptr); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } /* @@ -1678,7 +1689,8 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } @@ -1690,7 +1702,9 @@ static int core_scsi3_decode_spec_i_port( smp_mb__after_atomic_dec(); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -EINVAL; goto out; } #if 0 @@ -1727,7 +1741,9 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_lunacl_undepend_item(dest_se_deve); core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -ENOMEM; goto out; } INIT_LIST_HEAD(&tidh_new->dest_list); @@ -1759,7 +1775,8 @@ static int core_scsi3_decode_spec_i_port( core_scsi3_nodeacl_undepend_item(dest_node_acl); core_scsi3_tpg_undepend_item(dest_tpg); kfree(tidh_new); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } tidh_new->dest_pr_reg = dest_pr_reg; @@ -2098,7 +2115,8 @@ static int core_scsi3_emulate_pro_register( if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } se_tpg = se_sess->se_tpg; se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; @@ -2117,13 +2135,14 @@ static int core_scsi3_emulate_pro_register( if (res_key) { pr_warn("SPC-3 PR: Reservation Key non-zero" " for SA REGISTER, returning CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * Do nothing but return GOOD status. */ if (!sa_res_key) - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; if (!spec_i_pt) { /* @@ -2138,7 +2157,8 @@ static int core_scsi3_emulate_pro_register( if (ret != 0) { pr_err("Unable to allocate" " struct t10_pr_registration\n"); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } } else { /* @@ -2197,14 +2217,16 @@ static int core_scsi3_emulate_pro_register( " 0x%016Lx\n", res_key, pr_reg->pr_res_key); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } } if (spec_i_pt) { pr_err("SPC-3 PR UNREGISTER: SPEC_I_PT" " set while sa_res_key=0\n"); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } /* * An existing ALL_TG_PT=1 registration being released @@ -2215,7 +2237,8 @@ static int core_scsi3_emulate_pro_register( " registration exists, but ALL_TG_PT=1 bit not" " present in received PROUT\n"); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } /* * Allocate APTPL metadata buffer used for UNREGISTER ops @@ -2227,7 +2250,9 @@ static int core_scsi3_emulate_pro_register( pr_err("Unable to allocate" " pr_aptpl_buf\n"); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } } /* @@ -2241,7 +2266,8 @@ static int core_scsi3_emulate_pro_register( if (pr_holder < 0) { kfree(pr_aptpl_buf); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } spin_lock(&pr_tmpl->registration_lock); @@ -2405,7 +2431,8 @@ static int core_scsi3_pro_reserve( if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } se_tpg = se_sess->se_tpg; se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; @@ -2417,7 +2444,8 @@ static int core_scsi3_pro_reserve( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for RESERVE\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2433,7 +2461,8 @@ static int core_scsi3_pro_reserve( " does not match existing SA REGISTER res_key:" " 0x%016Lx\n", res_key, pr_reg->pr_res_key); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2448,7 +2477,8 @@ static int core_scsi3_pro_reserve( if (scope != PR_SCOPE_LU_SCOPE) { pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } /* * See if we have an existing PR reservation holder pointer at @@ -2480,7 +2510,8 @@ static int core_scsi3_pro_reserve( spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2503,7 +2534,8 @@ static int core_scsi3_pro_reserve( spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * From spc4r17 Section 5.7.9: Reserving: @@ -2517,7 +2549,7 @@ static int core_scsi3_pro_reserve( */ spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } /* * Otherwise, our *pr_reg becomes the PR reservation holder for said @@ -2574,7 +2606,8 @@ static int core_scsi3_emulate_pro_reserve( default: pr_err("SPC-3 PR: Unknown Service Action RESERVE Type:" " 0x%02x\n", type); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } return ret; @@ -2630,7 +2663,8 @@ static int core_scsi3_emulate_pro_release( if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } /* * Locate the existing *pr_reg via struct se_node_acl pointers @@ -2639,7 +2673,8 @@ static int core_scsi3_emulate_pro_release( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for RELEASE\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } /* * From spc4r17 Section 5.7.11.2 Releasing: @@ -2661,7 +2696,7 @@ static int core_scsi3_emulate_pro_release( */ spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } if ((pr_res_holder->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG) || (pr_res_holder->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)) @@ -2675,7 +2710,7 @@ static int core_scsi3_emulate_pro_release( */ spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } /* * From spc4r17 Section 5.7.11.2 Releasing: @@ -2697,7 +2732,8 @@ static int core_scsi3_emulate_pro_release( " 0x%016Lx\n", res_key, pr_reg->pr_res_key); spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * From spc4r17 Section 5.7.11.2 Releasing and above: @@ -2719,7 +2755,8 @@ static int core_scsi3_emulate_pro_release( spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * In response to a persistent reservation release request from the @@ -2802,7 +2839,8 @@ static int core_scsi3_emulate_pro_clear( if (!pr_reg_n) { pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for CLEAR\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } /* * From spc4r17 section 5.7.11.6, Clearing: @@ -2821,7 +2859,8 @@ static int core_scsi3_emulate_pro_clear( " existing SA REGISTER res_key:" " 0x%016Lx\n", res_key, pr_reg_n->pr_res_key); core_scsi3_put_pr_reg(pr_reg_n); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * a) Release the persistent reservation, if any; @@ -2979,8 +3018,10 @@ static int core_scsi3_pro_preempt( int all_reg = 0, calling_it_nexus = 0, released_regs = 0; int prh_type = 0, prh_scope = 0, ret; - if (!se_sess) - return PYX_TRANSPORT_LU_COMM_FAILURE; + if (!se_sess) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; + } se_deve = &se_sess->se_node_acl->device_list[cmd->orig_fe_lun]; pr_reg_n = core_scsi3_locate_pr_reg(cmd->se_dev, se_sess->se_node_acl, @@ -2989,16 +3030,19 @@ static int core_scsi3_pro_preempt( pr_err("SPC-3 PR: Unable to locate" " PR_REGISTERED *pr_reg for PREEMPT%s\n", (abort) ? "_AND_ABORT" : ""); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } if (pr_reg_n->pr_res_key != res_key) { core_scsi3_put_pr_reg(pr_reg_n); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } if (scope != PR_SCOPE_LU_SCOPE) { pr_err("SPC-3 PR: Illegal SCOPE: 0x%02x\n", scope); core_scsi3_put_pr_reg(pr_reg_n); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } INIT_LIST_HEAD(&preempt_and_abort_list); @@ -3012,7 +3056,8 @@ static int core_scsi3_pro_preempt( if (!all_reg && !sa_res_key) { spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg_n); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } /* * From spc4r17, section 5.7.11.4.4 Removing Registrations: @@ -3106,7 +3151,8 @@ static int core_scsi3_pro_preempt( if (!released_regs) { spin_unlock(&dev->dev_reservation_lock); core_scsi3_put_pr_reg(pr_reg_n); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * For an existing all registrants type reservation @@ -3297,7 +3343,8 @@ static int core_scsi3_emulate_pro_preempt( default: pr_err("SPC-3 PR: Unknown Service Action PREEMPT%s" " Type: 0x%02x\n", (abort) ? "_AND_ABORT" : "", type); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } return ret; @@ -3331,7 +3378,8 @@ static int core_scsi3_emulate_pro_register_and_move( if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } memset(dest_iport, 0, 64); memset(i_buf, 0, PR_REG_ISID_ID_LEN); @@ -3349,7 +3397,8 @@ static int core_scsi3_emulate_pro_register_and_move( if (!pr_reg) { pr_err("SPC-3 PR: Unable to locate PR_REGISTERED" " *pr_reg for REGISTER_AND_MOVE\n"); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } /* * The provided reservation key much match the existing reservation key @@ -3360,7 +3409,8 @@ static int core_scsi3_emulate_pro_register_and_move( " res_key: 0x%016Lx does not match existing SA REGISTER" " res_key: 0x%016Lx\n", res_key, pr_reg->pr_res_key); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } /* * The service active reservation key needs to be non zero @@ -3369,7 +3419,8 @@ static int core_scsi3_emulate_pro_register_and_move( pr_warn("SPC-3 PR REGISTER_AND_MOVE: Received zero" " sa_res_key\n"); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } /* @@ -3392,7 +3443,8 @@ static int core_scsi3_emulate_pro_register_and_move( " does not equal CDB data_length: %u\n", tid_len, cmd->data_length); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } spin_lock(&dev->se_port_lock); @@ -3417,7 +3469,8 @@ static int core_scsi3_emulate_pro_register_and_move( atomic_dec(&dest_se_tpg->tpg_pr_ref_count); smp_mb__after_atomic_dec(); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; } spin_lock(&dev->se_port_lock); @@ -3430,7 +3483,8 @@ static int core_scsi3_emulate_pro_register_and_move( " fabric ops from Relative Target Port Identifier:" " %hu\n", rtpi); core_scsi3_put_pr_reg(pr_reg); - return PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + return -EINVAL; } buf = transport_kmap_first_data_page(cmd); @@ -3445,14 +3499,16 @@ static int core_scsi3_emulate_pro_register_and_move( " from fabric: %s\n", proto_ident, dest_tf_ops->get_fabric_proto_ident(dest_se_tpg), dest_tf_ops->get_fabric_name()); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } if (dest_tf_ops->tpg_parse_pr_out_transport_id == NULL) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Fabric does not" " containg a valid tpg_parse_pr_out_transport_id" " function pointer\n"); - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -EINVAL; goto out; } initiator_str = dest_tf_ops->tpg_parse_pr_out_transport_id(dest_se_tpg, @@ -3460,7 +3516,8 @@ static int core_scsi3_emulate_pro_register_and_move( if (!initiator_str) { pr_err("SPC-3 PR REGISTER_AND_MOVE: Unable to locate" " initiator_str from Transport ID\n"); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } @@ -3489,7 +3546,8 @@ static int core_scsi3_emulate_pro_register_and_move( pr_err("SPC-3 PR REGISTER_AND_MOVE: TransportID: %s" " matches: %s on received I_T Nexus\n", initiator_str, pr_reg_nacl->initiatorname); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } if (!strcmp(iport_ptr, pr_reg->pr_reg_isid)) { @@ -3497,7 +3555,8 @@ static int core_scsi3_emulate_pro_register_and_move( " matches: %s %s on received I_T Nexus\n", initiator_str, iport_ptr, pr_reg_nacl->initiatorname, pr_reg->pr_reg_isid); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } after_iport_check: @@ -3517,7 +3576,8 @@ after_iport_check: pr_err("Unable to locate %s dest_node_acl for" " TransportID%s\n", dest_tf_ops->get_fabric_name(), initiator_str); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } ret = core_scsi3_nodeacl_depend_item(dest_node_acl); @@ -3527,7 +3587,8 @@ after_iport_check: atomic_dec(&dest_node_acl->acl_pr_ref_count); smp_mb__after_atomic_dec(); dest_node_acl = NULL; - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } #if 0 @@ -3543,7 +3604,8 @@ after_iport_check: if (!dest_se_deve) { pr_err("Unable to locate %s dest_se_deve from RTPI:" " %hu\n", dest_tf_ops->get_fabric_name(), rtpi); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } @@ -3553,7 +3615,8 @@ after_iport_check: atomic_dec(&dest_se_deve->pr_ref_count); smp_mb__after_atomic_dec(); dest_se_deve = NULL; - ret = PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + ret = -EINVAL; goto out; } #if 0 @@ -3572,7 +3635,8 @@ after_iport_check: pr_warn("SPC-3 PR REGISTER_AND_MOVE: No reservation" " currently held\n"); spin_unlock(&dev->dev_reservation_lock); - ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + ret = -EINVAL; goto out; } /* @@ -3585,7 +3649,8 @@ after_iport_check: pr_warn("SPC-3 PR REGISTER_AND_MOVE: Calling I_T" " Nexus is not reservation holder\n"); spin_unlock(&dev->dev_reservation_lock); - ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + ret = -EINVAL; goto out; } /* @@ -3603,7 +3668,8 @@ after_iport_check: " reservation for type: %s\n", core_scsi3_pr_dump_type(pr_res_holder->pr_res_type)); spin_unlock(&dev->dev_reservation_lock); - ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + ret = -EINVAL; goto out; } pr_res_nacl = pr_res_holder->pr_reg_nacl; @@ -3640,7 +3706,8 @@ after_iport_check: sa_res_key, 0, aptpl, 2, 1); if (ret != 0) { spin_unlock(&dev->dev_reservation_lock); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, @@ -3771,7 +3838,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); - ret = PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + ret = EINVAL; goto out; } @@ -3779,13 +3847,16 @@ int target_scsi3_emulate_pr_out(struct se_task *task) * FIXME: A NULL struct se_session pointer means an this is not coming from * a $FABRIC_MOD's nexus, but from internal passthrough ops. */ - if (!cmd->se_sess) - return PYX_TRANSPORT_LU_COMM_FAILURE; + if (!cmd->se_sess) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -EINVAL; + } if (cmd->data_length < 24) { pr_warn("SPC-PR: Received PR OUT parameter list" " length too small: %u\n", cmd->data_length); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } /* @@ -3820,7 +3891,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) * SPEC_I_PT=1 is only valid for Service action: REGISTER */ if (spec_i_pt && ((cdb[1] & 0x1f) != PRO_REGISTER)) { - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } @@ -3837,7 +3909,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) (cmd->data_length != 24)) { pr_warn("SPC-PR: Received PR OUT illegal parameter" " list length: %u\n", cmd->data_length); - ret = PYX_TRANSPORT_INVALID_PARAMETER_LIST; + cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; + ret = -EINVAL; goto out; } /* @@ -3878,7 +3951,8 @@ int target_scsi3_emulate_pr_out(struct se_task *task) default: pr_err("Unknown PERSISTENT_RESERVE_OUT service" " action: 0x%02x\n", cdb[1] & 0x1f); - ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + ret = -EINVAL; break; } @@ -3906,7 +3980,8 @@ static int core_scsi3_pri_read_keys(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_KEYS SCSI Data Length: %u" " too small\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } buf = transport_kmap_first_data_page(cmd); @@ -3965,7 +4040,8 @@ static int core_scsi3_pri_read_reservation(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_RESERVATIONS SCSI Data Length: %u" " too small\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } buf = transport_kmap_first_data_page(cmd); @@ -4047,7 +4123,8 @@ static int core_scsi3_pri_report_capabilities(struct se_cmd *cmd) if (cmd->data_length < 6) { pr_err("PRIN SA REPORT_CAPABILITIES SCSI Data Length:" " %u too small\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } buf = transport_kmap_first_data_page(cmd); @@ -4108,7 +4185,8 @@ static int core_scsi3_pri_read_full_status(struct se_cmd *cmd) if (cmd->data_length < 8) { pr_err("PRIN SA READ_FULL_STATUS SCSI Data Length: %u" " too small\n", cmd->data_length); - return PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; } buf = transport_kmap_first_data_page(cmd); @@ -4255,7 +4333,8 @@ int target_scsi3_emulate_pr_in(struct se_task *task) pr_err("Received PERSISTENT_RESERVE CDB while legacy" " SPC-2 reservation is held, returning" " RESERVATION_CONFLICT\n"); - return PYX_TRANSPORT_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EINVAL; } switch (cmd->t_task_cdb[1] & 0x1f) { @@ -4274,7 +4353,8 @@ int target_scsi3_emulate_pr_in(struct se_task *task) default: pr_err("Unknown PERSISTENT_RESERVE_IN service" " action: 0x%02x\n", cmd->t_task_cdb[1] & 0x1f); - ret = PYX_TRANSPORT_INVALID_CDB_FIELD; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + ret = -EINVAL; break; } diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index ed32e1efe42..8b15e56b038 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -963,6 +963,7 @@ static inline struct bio *pscsi_get_bio(int sg_num) static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, struct bio **hbio) { + struct se_cmd *cmd = task->task_se_cmd; struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; u32 task_sg_num = task->task_sg_nents; struct bio *bio = NULL, *tbio = NULL; @@ -971,7 +972,7 @@ static int pscsi_map_sg(struct se_task *task, struct scatterlist *task_sg, u32 data_len = task->task_size, i, len, bytes, off; int nr_pages = (task->task_size + task_sg[0].offset + PAGE_SIZE - 1) >> PAGE_SHIFT; - int nr_vecs = 0, rc, ret = PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + int nr_vecs = 0, rc; int rw = (task->task_data_direction == DMA_TO_DEVICE); *hbio = NULL; @@ -1058,11 +1059,13 @@ fail: bio->bi_next = NULL; bio_endio(bio, 0); /* XXX: should be error */ } - return ret; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; } static int pscsi_do_task(struct se_task *task) { + struct se_cmd *cmd = task->task_se_cmd; struct pscsi_dev_virt *pdv = task->task_se_cmd->se_dev->dev_ptr; struct pscsi_plugin_task *pt = PSCSI_TASK(task); struct request *req; @@ -1078,7 +1081,9 @@ static int pscsi_do_task(struct se_task *task) if (!req || IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed: %ld\n", req ? IS_ERR(req) : -ENOMEM); - return PYX_TRANSPORT_LU_COMM_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENODEV; } } else { BUG_ON(!task->task_size); @@ -1087,8 +1092,11 @@ static int pscsi_do_task(struct se_task *task) * Setup the main struct request for the task->task_sg[] payload */ ret = pscsi_map_sg(task, task->task_sg, &hbio); - if (ret < 0) - return PYX_TRANSPORT_LU_COMM_FAILURE; + if (ret < 0) { + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return ret; + } req = blk_make_request(pdv->pdv_sd->request_queue, hbio, GFP_KERNEL); @@ -1115,7 +1123,7 @@ static int pscsi_do_task(struct se_task *task) (task->task_se_cmd->sam_task_attr == MSG_HEAD_TAG), pscsi_req_done); - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; fail: while (hbio) { @@ -1124,7 +1132,8 @@ fail: bio->bi_next = NULL; bio_endio(bio, 0); /* XXX: should be error */ } - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + return -ENOMEM; } /* pscsi_get_sense_buffer(): @@ -1198,9 +1207,8 @@ static inline void pscsi_process_SAM_status( " 0x%02x Result: 0x%08x\n", task, pt->pscsi_cdb[0], pt->pscsi_result); task->task_scsi_status = SAM_STAT_CHECK_CONDITION; - task->task_error_status = PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - task->task_se_cmd->transport_error_status = - PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + task->task_se_cmd->scsi_sense_reason = + TCM_UNSUPPORTED_SCSI_OPCODE; transport_complete_task(task, 0); break; } diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 5158d3846f1..02e51faa2f4 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -343,235 +343,74 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) return NULL; } -/* rd_MEMCPY_read(): - * - * - */ -static int rd_MEMCPY_read(struct rd_request *req) +static int rd_MEMCPY(struct rd_request *req, u32 read_rd) { struct se_task *task = &req->rd_task; struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr; struct rd_dev_sg_table *table; - struct scatterlist *sg_d, *sg_s; - void *dst, *src; - u32 i = 0, j = 0, dst_offset = 0, src_offset = 0; - u32 length, page_end = 0, table_sg_end; + struct scatterlist *rd_sg; + struct sg_mapping_iter m; u32 rd_offset = req->rd_offset; + u32 src_len; table = rd_get_sg_table(dev, req->rd_page); if (!table) return -EINVAL; - table_sg_end = (table->page_end_offset - req->rd_page); - sg_d = task->task_sg; - sg_s = &table->sg_table[req->rd_page - table->page_start_offset]; + rd_sg = &table->sg_table[req->rd_page - table->page_start_offset]; - pr_debug("RD[%u]: Read LBA: %llu, Size: %u Page: %u, Offset:" - " %u\n", dev->rd_dev_id, task->task_lba, req->rd_size, - req->rd_page, req->rd_offset); - - src_offset = rd_offset; + pr_debug("RD[%u]: %s LBA: %llu, Size: %u Page: %u, Offset: %u\n", + dev->rd_dev_id, read_rd ? "Read" : "Write", + task->task_lba, req->rd_size, req->rd_page, + rd_offset); + src_len = PAGE_SIZE - rd_offset; + sg_miter_start(&m, task->task_sg, task->task_sg_nents, + read_rd ? SG_MITER_TO_SG : SG_MITER_FROM_SG); while (req->rd_size) { - if ((sg_d[i].length - dst_offset) < - (sg_s[j].length - src_offset)) { - length = (sg_d[i].length - dst_offset); - - pr_debug("Step 1 - sg_d[%d]: %p length: %d" - " offset: %u sg_s[%d].length: %u\n", i, - &sg_d[i], sg_d[i].length, sg_d[i].offset, j, - sg_s[j].length); - pr_debug("Step 1 - length: %u dst_offset: %u" - " src_offset: %u\n", length, dst_offset, - src_offset); - - if (length > req->rd_size) - length = req->rd_size; - - dst = sg_virt(&sg_d[i++]) + dst_offset; - BUG_ON(!dst); - - src = sg_virt(&sg_s[j]) + src_offset; - BUG_ON(!src); - - dst_offset = 0; - src_offset = length; - page_end = 0; - } else { - length = (sg_s[j].length - src_offset); - - pr_debug("Step 2 - sg_d[%d]: %p length: %d" - " offset: %u sg_s[%d].length: %u\n", i, - &sg_d[i], sg_d[i].length, sg_d[i].offset, - j, sg_s[j].length); - pr_debug("Step 2 - length: %u dst_offset: %u" - " src_offset: %u\n", length, dst_offset, - src_offset); - - if (length > req->rd_size) - length = req->rd_size; - - dst = sg_virt(&sg_d[i]) + dst_offset; - BUG_ON(!dst); - - if (sg_d[i].length == length) { - i++; - dst_offset = 0; - } else - dst_offset = length; - - src = sg_virt(&sg_s[j++]) + src_offset; - BUG_ON(!src); - - src_offset = 0; - page_end = 1; - } + u32 len; + void *rd_addr; - memcpy(dst, src, length); + sg_miter_next(&m); + len = min((u32)m.length, src_len); + m.consumed = len; - pr_debug("page: %u, remaining size: %u, length: %u," - " i: %u, j: %u\n", req->rd_page, - (req->rd_size - length), length, i, j); + rd_addr = sg_virt(rd_sg) + rd_offset; - req->rd_size -= length; - if (!req->rd_size) - return 0; + if (read_rd) + memcpy(m.addr, rd_addr, len); + else + memcpy(rd_addr, m.addr, len); - if (!page_end) + req->rd_size -= len; + if (!req->rd_size) continue; - if (++req->rd_page <= table->page_end_offset) { - pr_debug("page: %u in same page table\n", - req->rd_page); + src_len -= len; + if (src_len) { + rd_offset += len; continue; } - pr_debug("getting new page table for page: %u\n", - req->rd_page); - - table = rd_get_sg_table(dev, req->rd_page); - if (!table) - return -EINVAL; - - sg_s = &table->sg_table[j = 0]; - } - - return 0; -} - -/* rd_MEMCPY_write(): - * - * - */ -static int rd_MEMCPY_write(struct rd_request *req) -{ - struct se_task *task = &req->rd_task; - struct rd_dev *dev = req->rd_task.task_se_cmd->se_dev->dev_ptr; - struct rd_dev_sg_table *table; - struct scatterlist *sg_d, *sg_s; - void *dst, *src; - u32 i = 0, j = 0, dst_offset = 0, src_offset = 0; - u32 length, page_end = 0, table_sg_end; - u32 rd_offset = req->rd_offset; - - table = rd_get_sg_table(dev, req->rd_page); - if (!table) - return -EINVAL; - - table_sg_end = (table->page_end_offset - req->rd_page); - sg_d = &table->sg_table[req->rd_page - table->page_start_offset]; - sg_s = task->task_sg; - - pr_debug("RD[%d] Write LBA: %llu, Size: %u, Page: %u," - " Offset: %u\n", dev->rd_dev_id, task->task_lba, req->rd_size, - req->rd_page, req->rd_offset); - - dst_offset = rd_offset; - - while (req->rd_size) { - if ((sg_s[i].length - src_offset) < - (sg_d[j].length - dst_offset)) { - length = (sg_s[i].length - src_offset); - - pr_debug("Step 1 - sg_s[%d]: %p length: %d" - " offset: %d sg_d[%d].length: %u\n", i, - &sg_s[i], sg_s[i].length, sg_s[i].offset, - j, sg_d[j].length); - pr_debug("Step 1 - length: %u src_offset: %u" - " dst_offset: %u\n", length, src_offset, - dst_offset); - - if (length > req->rd_size) - length = req->rd_size; - - src = sg_virt(&sg_s[i++]) + src_offset; - BUG_ON(!src); - - dst = sg_virt(&sg_d[j]) + dst_offset; - BUG_ON(!dst); - - src_offset = 0; - dst_offset = length; - page_end = 0; - } else { - length = (sg_d[j].length - dst_offset); - - pr_debug("Step 2 - sg_s[%d]: %p length: %d" - " offset: %d sg_d[%d].length: %u\n", i, - &sg_s[i], sg_s[i].length, sg_s[i].offset, - j, sg_d[j].length); - pr_debug("Step 2 - length: %u src_offset: %u" - " dst_offset: %u\n", length, src_offset, - dst_offset); - - if (length > req->rd_size) - length = req->rd_size; - - src = sg_virt(&sg_s[i]) + src_offset; - BUG_ON(!src); - - if (sg_s[i].length == length) { - i++; - src_offset = 0; - } else - src_offset = length; - - dst = sg_virt(&sg_d[j++]) + dst_offset; - BUG_ON(!dst); - - dst_offset = 0; - page_end = 1; - } - - memcpy(dst, src, length); - - pr_debug("page: %u, remaining size: %u, length: %u," - " i: %u, j: %u\n", req->rd_page, - (req->rd_size - length), length, i, j); - - req->rd_size -= length; - if (!req->rd_size) - return 0; - - if (!page_end) - continue; - - if (++req->rd_page <= table->page_end_offset) { - pr_debug("page: %u in same page table\n", - req->rd_page); + /* rd page completed, next one please */ + req->rd_page++; + rd_offset = 0; + src_len = PAGE_SIZE; + if (req->rd_page <= table->page_end_offset) { + rd_sg++; continue; } - pr_debug("getting new page table for page: %u\n", - req->rd_page); - table = rd_get_sg_table(dev, req->rd_page); - if (!table) + if (!table) { + sg_miter_stop(&m); return -EINVAL; + } - sg_d = &table->sg_table[j = 0]; + /* since we increment, the first sg entry is correct */ + rd_sg = table->sg_table; } - + sg_miter_stop(&m); return 0; } @@ -583,28 +422,21 @@ static int rd_MEMCPY_do_task(struct se_task *task) { struct se_device *dev = task->task_se_cmd->se_dev; struct rd_request *req = RD_REQ(task); - unsigned long long lba; + u64 tmp; int ret; - req->rd_page = (task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size) / PAGE_SIZE; - lba = task->task_lba; - req->rd_offset = (do_div(lba, - (PAGE_SIZE / dev->se_sub_dev->se_dev_attrib.block_size))) * - dev->se_sub_dev->se_dev_attrib.block_size; + tmp = task->task_lba * dev->se_sub_dev->se_dev_attrib.block_size; + req->rd_offset = do_div(tmp, PAGE_SIZE); + req->rd_page = tmp; req->rd_size = task->task_size; - if (task->task_data_direction == DMA_FROM_DEVICE) - ret = rd_MEMCPY_read(req); - else - ret = rd_MEMCPY_write(req); - + ret = rd_MEMCPY(req, task->task_data_direction == DMA_FROM_DEVICE); if (ret != 0) return ret; task->task_scsi_status = GOOD; transport_complete_task(task, 1); - - return PYX_TRANSPORT_SENT_TO_TRANSPORT; + return 0; } /* rd_free_task(): (Part of se_subsystem_api_t template) diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 217e29df629..684522805a1 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c @@ -345,10 +345,6 @@ static void core_tmr_drain_cmd_list( " %d t_fe_count: %d\n", (preempt_and_abort_list) ? "Preempt" : "", cmd, cmd->t_state, atomic_read(&cmd->t_fe_count)); - /* - * Signal that the command has failed via cmd->se_cmd_flags, - */ - transport_new_cmd_failure(cmd); core_tmr_handle_tas_abort(tmr_nacl, cmd, tas, atomic_read(&cmd->t_fe_count)); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3400ae6e93f..0257658e2e3 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -61,7 +61,6 @@ static int sub_api_initialized; static struct workqueue_struct *target_completion_wq; -static struct kmem_cache *se_cmd_cache; static struct kmem_cache *se_sess_cache; struct kmem_cache *se_tmr_req_cache; struct kmem_cache *se_ua_cache; @@ -82,24 +81,18 @@ static int transport_generic_get_mem(struct se_cmd *cmd); static void transport_put_cmd(struct se_cmd *cmd); static void transport_remove_cmd_from_queue(struct se_cmd *cmd); static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); -static void transport_generic_request_failure(struct se_cmd *, int, int); +static void transport_generic_request_failure(struct se_cmd *); static void target_complete_ok_work(struct work_struct *work); int init_se_kmem_caches(void) { - se_cmd_cache = kmem_cache_create("se_cmd_cache", - sizeof(struct se_cmd), __alignof__(struct se_cmd), 0, NULL); - if (!se_cmd_cache) { - pr_err("kmem_cache_create for struct se_cmd failed\n"); - goto out; - } se_tmr_req_cache = kmem_cache_create("se_tmr_cache", sizeof(struct se_tmr_req), __alignof__(struct se_tmr_req), 0, NULL); if (!se_tmr_req_cache) { pr_err("kmem_cache_create() for struct se_tmr_req" " failed\n"); - goto out_free_cmd_cache; + goto out; } se_sess_cache = kmem_cache_create("se_sess_cache", sizeof(struct se_session), __alignof__(struct se_session), @@ -182,8 +175,6 @@ out_free_sess_cache: kmem_cache_destroy(se_sess_cache); out_free_tmr_req_cache: kmem_cache_destroy(se_tmr_req_cache); -out_free_cmd_cache: - kmem_cache_destroy(se_cmd_cache); out: return -ENOMEM; } @@ -191,7 +182,6 @@ out: void release_se_kmem_caches(void) { destroy_workqueue(target_completion_wq); - kmem_cache_destroy(se_cmd_cache); kmem_cache_destroy(se_tmr_req_cache); kmem_cache_destroy(se_sess_cache); kmem_cache_destroy(se_ua_cache); @@ -680,9 +670,9 @@ void transport_complete_sync_cache(struct se_cmd *cmd, int good) task->task_scsi_status = GOOD; } else { task->task_scsi_status = SAM_STAT_CHECK_CONDITION; - task->task_error_status = PYX_TRANSPORT_ILLEGAL_REQUEST; - task->task_se_cmd->transport_error_status = - PYX_TRANSPORT_ILLEGAL_REQUEST; + task->task_se_cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } transport_complete_task(task, good); @@ -693,7 +683,7 @@ static void target_complete_failure_work(struct work_struct *work) { struct se_cmd *cmd = container_of(work, struct se_cmd, work); - transport_generic_request_failure(cmd, 1, 1); + transport_generic_request_failure(cmd); } /* transport_complete_task(): @@ -755,10 +745,11 @@ void transport_complete_task(struct se_task *task, int success) if (cmd->t_tasks_failed) { if (!task->task_error_status) { task->task_error_status = - PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; - cmd->transport_error_status = - PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + INIT_WORK(&cmd->work, target_complete_failure_work); } else { atomic_set(&cmd->t_transport_complete, 1); @@ -1335,23 +1326,17 @@ struct se_device *transport_add_device_to_core_hba( dev->se_hba = hba; dev->se_sub_dev = se_dev; dev->transport = transport; - atomic_set(&dev->active_cmds, 0); INIT_LIST_HEAD(&dev->dev_list); INIT_LIST_HEAD(&dev->dev_sep_list); INIT_LIST_HEAD(&dev->dev_tmr_list); INIT_LIST_HEAD(&dev->execute_task_list); INIT_LIST_HEAD(&dev->delayed_cmd_list); - INIT_LIST_HEAD(&dev->ordered_cmd_list); INIT_LIST_HEAD(&dev->state_task_list); INIT_LIST_HEAD(&dev->qf_cmd_list); spin_lock_init(&dev->execute_task_lock); spin_lock_init(&dev->delayed_cmd_lock); - spin_lock_init(&dev->ordered_cmd_lock); - spin_lock_init(&dev->state_task_lock); - spin_lock_init(&dev->dev_alua_lock); spin_lock_init(&dev->dev_reservation_lock); spin_lock_init(&dev->dev_status_lock); - spin_lock_init(&dev->dev_status_thr_lock); spin_lock_init(&dev->se_port_lock); spin_lock_init(&dev->se_tmr_lock); spin_lock_init(&dev->qf_cmd_lock); @@ -1507,7 +1492,6 @@ void transport_init_se_cmd( { INIT_LIST_HEAD(&cmd->se_lun_node); INIT_LIST_HEAD(&cmd->se_delayed_node); - INIT_LIST_HEAD(&cmd->se_ordered_node); INIT_LIST_HEAD(&cmd->se_qf_node); INIT_LIST_HEAD(&cmd->se_queue_node); INIT_LIST_HEAD(&cmd->se_cmd_list); @@ -1573,6 +1557,8 @@ int transport_generic_allocate_tasks( pr_err("Received SCSI CDB with command_size: %d that" " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", scsi_command_size(cdb), SCSI_MAX_VARLEN_CDB_SIZE); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; return -EINVAL; } /* @@ -1588,6 +1574,9 @@ int transport_generic_allocate_tasks( " %u > sizeof(cmd->__t_task_cdb): %lu ops\n", scsi_command_size(cdb), (unsigned long)sizeof(cmd->__t_task_cdb)); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; return -ENOMEM; } } else @@ -1658,11 +1647,9 @@ int transport_handle_cdb_direct( * and call transport_generic_request_failure() if necessary.. */ ret = transport_generic_new_cmd(cmd); - if (ret < 0) { - cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, 0, - (cmd->data_direction != DMA_TO_DEVICE)); - } + if (ret < 0) + transport_generic_request_failure(cmd); + return 0; } EXPORT_SYMBOL(transport_handle_cdb_direct); @@ -1798,20 +1785,16 @@ static int transport_stop_tasks_for_cmd(struct se_cmd *cmd) /* * Handle SAM-esque emulation for generic transport request failures. */ -static void transport_generic_request_failure( - struct se_cmd *cmd, - int complete, - int sc) +static void transport_generic_request_failure(struct se_cmd *cmd) { int ret = 0; pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08x" " CDB: 0x%02x\n", cmd, cmd->se_tfo->get_task_tag(cmd), cmd->t_task_cdb[0]); - pr_debug("-----[ i_state: %d t_state: %d transport_error_status: %d\n", + pr_debug("-----[ i_state: %d t_state: %d scsi_sense_reason: %d\n", cmd->se_tfo->get_cmd_state(cmd), - cmd->t_state, - cmd->transport_error_status); + cmd->t_state, cmd->scsi_sense_reason); pr_debug("-----[ t_tasks: %d t_task_cdbs_left: %d" " t_task_cdbs_sent: %d t_task_cdbs_ex_left: %d --" " t_transport_active: %d t_transport_stop: %d" @@ -1829,46 +1812,19 @@ static void transport_generic_request_failure( if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) transport_complete_task_attr(cmd); - if (complete) { - cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE; - } - - switch (cmd->transport_error_status) { - case PYX_TRANSPORT_UNKNOWN_SAM_OPCODE: - cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; - break; - case PYX_TRANSPORT_REQ_TOO_MANY_SECTORS: - cmd->scsi_sense_reason = TCM_SECTOR_COUNT_TOO_MANY; - break; - case PYX_TRANSPORT_INVALID_CDB_FIELD: - cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; - break; - case PYX_TRANSPORT_INVALID_PARAMETER_LIST: - cmd->scsi_sense_reason = TCM_INVALID_PARAMETER_LIST; - break; - case PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES: - if (!sc) - transport_new_cmd_failure(cmd); - /* - * Currently for PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES, - * we force this session to fall back to session - * recovery. - */ - cmd->se_tfo->fall_back_to_erl0(cmd->se_sess); - cmd->se_tfo->stop_session(cmd->se_sess, 0, 0); - - goto check_stop; - case PYX_TRANSPORT_LU_COMM_FAILURE: - case PYX_TRANSPORT_ILLEGAL_REQUEST: - cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - break; - case PYX_TRANSPORT_UNKNOWN_MODE_PAGE: - cmd->scsi_sense_reason = TCM_UNKNOWN_MODE_PAGE; - break; - case PYX_TRANSPORT_WRITE_PROTECTED: - cmd->scsi_sense_reason = TCM_WRITE_PROTECTED; + switch (cmd->scsi_sense_reason) { + case TCM_NON_EXISTENT_LUN: + case TCM_UNSUPPORTED_SCSI_OPCODE: + case TCM_INVALID_CDB_FIELD: + case TCM_INVALID_PARAMETER_LIST: + case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: + case TCM_UNKNOWN_MODE_PAGE: + case TCM_WRITE_PROTECTED: + case TCM_CHECK_CONDITION_ABORT_CMD: + case TCM_CHECK_CONDITION_UNIT_ATTENTION: + case TCM_CHECK_CONDITION_NOT_READY: break; - case PYX_TRANSPORT_RESERVATION_CONFLICT: + case TCM_RESERVATION_CONFLICT: /* * No SENSE Data payload for this case, set SCSI Status * and queue the response to $FABRIC_MOD. @@ -1893,15 +1849,9 @@ static void transport_generic_request_failure( if (ret == -EAGAIN || ret == -ENOMEM) goto queue_full; goto check_stop; - case PYX_TRANSPORT_USE_SENSE_REASON: - /* - * struct se_cmd->scsi_sense_reason already set - */ - break; default: pr_err("Unknown transport error for CDB 0x%02x: %d\n", - cmd->t_task_cdb[0], - cmd->transport_error_status); + cmd->t_task_cdb[0], cmd->scsi_sense_reason); cmd->scsi_sense_reason = TCM_UNSUPPORTED_SCSI_OPCODE; break; } @@ -1912,14 +1862,10 @@ static void transport_generic_request_failure( * transport_send_check_condition_and_sense() after handling * possible unsoliticied write data payloads. */ - if (!sc && !cmd->se_tfo->new_cmd_map) - transport_new_cmd_failure(cmd); - else { - ret = transport_send_check_condition_and_sense(cmd, - cmd->scsi_sense_reason, 0); - if (ret == -EAGAIN || ret == -ENOMEM) - goto queue_full; - } + ret = transport_send_check_condition_and_sense(cmd, + cmd->scsi_sense_reason, 0); + if (ret == -EAGAIN || ret == -ENOMEM) + goto queue_full; check_stop: transport_lun_remove_cmd(cmd); @@ -2002,19 +1948,12 @@ static inline int transport_execute_task_attr(struct se_cmd *cmd) * to allow the passed struct se_cmd list of tasks to the front of the list. */ if (cmd->sam_task_attr == MSG_HEAD_TAG) { - atomic_inc(&cmd->se_dev->dev_hoq_count); - smp_mb__after_atomic_inc(); pr_debug("Added HEAD_OF_QUEUE for CDB:" " 0x%02x, se_ordered_id: %u\n", cmd->t_task_cdb[0], cmd->se_ordered_id); return 1; } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) { - spin_lock(&cmd->se_dev->ordered_cmd_lock); - list_add_tail(&cmd->se_ordered_node, - &cmd->se_dev->ordered_cmd_list); - spin_unlock(&cmd->se_dev->ordered_cmd_lock); - atomic_inc(&cmd->se_dev->dev_ordered_sync); smp_mb__after_atomic_inc(); @@ -2076,9 +2015,9 @@ static int transport_execute_tasks(struct se_cmd *cmd) { int add_tasks; - if (se_dev_check_online(cmd->se_orig_obj_ptr) != 0) { - cmd->transport_error_status = PYX_TRANSPORT_LU_COMM_FAILURE; - transport_generic_request_failure(cmd, 0, 1); + if (se_dev_check_online(cmd->se_dev) != 0) { + cmd->scsi_sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + transport_generic_request_failure(cmd); return 0; } @@ -2163,14 +2102,13 @@ check_depth: else error = dev->transport->do_task(task); if (error != 0) { - cmd->transport_error_status = error; spin_lock_irqsave(&cmd->t_state_lock, flags); task->task_flags &= ~TF_ACTIVE; spin_unlock_irqrestore(&cmd->t_state_lock, flags); atomic_set(&cmd->t_transport_sent, 0); transport_stop_tasks_for_cmd(cmd); atomic_inc(&dev->depth_left); - transport_generic_request_failure(cmd, 0, 1); + transport_generic_request_failure(cmd); } goto check_depth; @@ -2178,19 +2116,6 @@ check_depth: return 0; } -void transport_new_cmd_failure(struct se_cmd *se_cmd) -{ - unsigned long flags; - /* - * Any unsolicited data will get dumped for failed command inside of - * the fabric plugin - */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - se_cmd->se_cmd_flags |= SCF_SE_CMD_FAILED; - se_cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); -} - static inline u32 transport_get_sectors_6( unsigned char *cdb, struct se_cmd *cmd, @@ -2213,10 +2138,15 @@ static inline u32 transport_get_sectors_6( /* * Everything else assume TYPE_DISK Sector CDB location. - * Use 8-bit sector value. + * Use 8-bit sector value. SBC-3 says: + * + * A TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be written. Any other value + * specifies the number of logical blocks that shall be + * written. */ type_disk: - return (u32)cdb[4]; + return cdb[4] ? : 256; } static inline u32 transport_get_sectors_10( @@ -2460,27 +2390,6 @@ static int transport_get_sense_data(struct se_cmd *cmd) return -1; } -static int -transport_handle_reservation_conflict(struct se_cmd *cmd) -{ - cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; - cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; - /* - * For UA Interlock Code 11b, a RESERVATION CONFLICT will - * establish a UNIT ATTENTION with PREVIOUS RESERVATION - * CONFLICT STATUS. - * - * See spc4r17, section 7.4.6 Control Mode Page, Table 349 - */ - if (cmd->se_sess && - cmd->se_dev->se_sub_dev->se_dev_attrib.emulate_ua_intlck_ctrl == 2) - core_scsi3_ua_allocate(cmd->se_sess->se_node_acl, - cmd->orig_fe_lun, 0x2C, - ASCQ_2CH_PREVIOUS_RESERVATION_CONFLICT_STATUS); - return -EINVAL; -} - static inline long long transport_dev_end_lba(struct se_device *dev) { return dev->transport->get_blocks(dev) + 1; @@ -2595,8 +2504,12 @@ static int transport_generic_cmd_sequencer( */ if (su_dev->t10_pr.pr_ops.t10_reservation_check(cmd, &pr_reg_type) != 0) { if (su_dev->t10_pr.pr_ops.t10_seq_non_holder( - cmd, cdb, pr_reg_type) != 0) - return transport_handle_reservation_conflict(cmd); + cmd, cdb, pr_reg_type) != 0) { + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->se_cmd_flags |= SCF_SCSI_RESERVATION_CONFLICT; + cmd->scsi_sense_reason = TCM_RESERVATION_CONFLICT; + return -EBUSY; + } /* * This means the CDB is allowed for the SCSI Initiator port * when said port is *NOT* holding the legacy SPC-2 or @@ -2658,7 +2571,8 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_32(cdb); - cmd->t_tasks_fua = (cdb[1] & 0x8); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; case WRITE_12: @@ -2667,7 +2581,8 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_32(cdb); - cmd->t_tasks_fua = (cdb[1] & 0x8); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; case WRITE_16: @@ -2676,12 +2591,13 @@ static int transport_generic_cmd_sequencer( goto out_unsupported_cdb; size = transport_get_size(sectors, cdb, cmd); cmd->t_task_lba = transport_lba_64(cdb); - cmd->t_tasks_fua = (cdb[1] & 0x8); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; cmd->se_cmd_flags |= SCF_SCSI_DATA_SG_IO_CDB; break; case XDWRITEREAD_10: if ((cmd->data_direction != DMA_TO_DEVICE) || - !(cmd->t_tasks_bidi)) + !(cmd->se_cmd_flags & SCF_BIDI)) goto out_invalid_cdb_field; sectors = transport_get_sectors_10(cdb, cmd, §or_ret); if (sector_ret) @@ -2700,7 +2616,8 @@ static int transport_generic_cmd_sequencer( * Setup BIDI XOR callback to be run after I/O completion. */ cmd->transport_complete_callback = &transport_xor_callback; - cmd->t_tasks_fua = (cdb[1] & 0x8); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; break; case VARIABLE_LENGTH_CMD: service_action = get_unaligned_be16(&cdb[8]); @@ -2728,7 +2645,8 @@ static int transport_generic_cmd_sequencer( * completion. */ cmd->transport_complete_callback = &transport_xor_callback; - cmd->t_tasks_fua = (cdb[10] & 0x8); + if (cdb[1] & 0x8) + cmd->se_cmd_flags |= SCF_FUA; break; case WRITE_SAME_32: sectors = transport_get_sectors_32(cdb, cmd, §or_ret); @@ -3171,18 +3089,13 @@ static void transport_complete_task_attr(struct se_cmd *cmd) " SIMPLE: %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); } else if (cmd->sam_task_attr == MSG_HEAD_TAG) { - atomic_dec(&dev->dev_hoq_count); - smp_mb__after_atomic_dec(); dev->dev_cur_ordered_id++; pr_debug("Incremented dev_cur_ordered_id: %u for" " HEAD_OF_QUEUE: %u\n", dev->dev_cur_ordered_id, cmd->se_ordered_id); } else if (cmd->sam_task_attr == MSG_ORDERED_TAG) { - spin_lock(&dev->ordered_cmd_lock); - list_del(&cmd->se_ordered_node); atomic_dec(&dev->dev_ordered_sync); smp_mb__after_atomic_dec(); - spin_unlock(&dev->ordered_cmd_lock); dev->dev_cur_ordered_id++; pr_debug("Incremented dev_cur_ordered_id: %u for ORDERED:" @@ -3495,6 +3408,18 @@ int transport_generic_map_mem_to_cmd( if ((cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB) || (cmd->se_cmd_flags & SCF_SCSI_CONTROL_SG_IO_CDB)) { + /* + * Reject SCSI data overflow with map_mem_to_cmd() as incoming + * scatterlists already have been set to follow what the fabric + * passes for the original expected data transfer length. + */ + if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + pr_warn("Rejecting SCSI DATA overflow for fabric using" + " SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC\n"); + cmd->se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; + cmd->scsi_sense_reason = TCM_INVALID_CDB_FIELD; + return -EINVAL; + } cmd->t_data_sg = sgl; cmd->t_data_nents = sgl_count; @@ -3813,7 +3738,7 @@ int transport_generic_new_cmd(struct se_cmd *cmd) cmd->data_length) { ret = transport_generic_get_mem(cmd); if (ret < 0) - return ret; + goto out_fail; } /* @@ -3842,8 +3767,15 @@ int transport_generic_new_cmd(struct se_cmd *cmd) task_cdbs = transport_allocate_control_task(cmd); } - if (task_cdbs <= 0) + if (task_cdbs < 0) goto out_fail; + else if (!task_cdbs && (cmd->se_cmd_flags & SCF_SCSI_DATA_SG_IO_CDB)) { + cmd->t_state = TRANSPORT_COMPLETE; + atomic_set(&cmd->t_transport_active, 1); + INIT_WORK(&cmd->work, target_complete_ok_work); + queue_work(target_completion_wq, &cmd->work); + return 0; + } if (set_counts) { atomic_inc(&cmd->t_fe_count); @@ -3929,7 +3861,7 @@ static int transport_generic_write_pending(struct se_cmd *cmd) else if (ret < 0) return ret; - return PYX_TRANSPORT_WRITE_PENDING; + return 1; queue_full: pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); @@ -4602,9 +4534,6 @@ void transport_send_task_abort(struct se_cmd *cmd) if (cmd->se_tfo->write_pending_status(cmd) != 0) { atomic_inc(&cmd->t_transport_aborted); smp_mb__after_atomic_inc(); - cmd->scsi_status = SAM_STAT_TASK_ABORTED; - transport_new_cmd_failure(cmd); - return; } } cmd->scsi_status = SAM_STAT_TASK_ABORTED; @@ -4670,8 +4599,6 @@ static int transport_processing_thread(void *param) struct se_cmd *cmd; struct se_device *dev = (struct se_device *) param; - set_user_nice(current, -20); - while (!kthread_should_stop()) { ret = wait_event_interruptible(dev->dev_queue_obj.thread_wq, atomic_read(&dev->dev_queue_obj.queue_cnt) || @@ -4698,18 +4625,13 @@ get_cmd: } ret = cmd->se_tfo->new_cmd_map(cmd); if (ret < 0) { - cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, - 0, (cmd->data_direction != - DMA_TO_DEVICE)); + transport_generic_request_failure(cmd); break; } ret = transport_generic_new_cmd(cmd); if (ret < 0) { - cmd->transport_error_status = ret; - transport_generic_request_failure(cmd, - 0, (cmd->data_direction != - DMA_TO_DEVICE)); + transport_generic_request_failure(cmd); + break; } break; case TRANSPORT_PROCESS_WRITE: diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index 4fac37c4c61..71fc9cea5dc 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c @@ -200,7 +200,7 @@ int ft_write_pending(struct se_cmd *se_cmd) lport = ep->lp; fp = fc_frame_alloc(lport, sizeof(*txrdy)); if (!fp) - return PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES; + return -ENOMEM; /* Signal QUEUE_FULL */ txrdy = fc_frame_payload_get(fp, sizeof(*txrdy)); memset(txrdy, 0, sizeof(*txrdy)); diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index 5f770412ca4..9402b7387ca 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c @@ -436,8 +436,7 @@ static void ft_del_lport(struct se_wwn *wwn) struct ft_lport_acl *lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); - pr_debug("del lport %s\n", - config_item_name(&wwn->wwn_group.cg_item)); + pr_debug("del lport %s\n", lacl->name); mutex_lock(&ft_lport_lock); list_del(&lacl->list); mutex_unlock(&ft_lport_lock); diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 708f8e92771..dd9a5743fa9 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c @@ -678,10 +678,10 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, return; if (delay > 1000) - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), round_jiffies(msecs_to_jiffies(delay))); else - schedule_delayed_work(&(tz->poll_queue), + queue_delayed_work(system_freezable_wq, &(tz->poll_queue), msecs_to_jiffies(delay)); } diff --git a/drivers/tty/hvc/hvc_dcc.c b/drivers/tty/hvc/hvc_dcc.c index 435f6facbc2..44fbebab507 100644 --- a/drivers/tty/hvc/hvc_dcc.c +++ b/drivers/tty/hvc/hvc_dcc.c @@ -46,6 +46,7 @@ static inline char __dcc_getchar(void) asm volatile("mrc p14, 0, %0, c0, c5, 0 @ read comms data reg" : "=r" (__c)); + isb(); return __c; } @@ -55,6 +56,7 @@ static inline void __dcc_putchar(char c) asm volatile("mcr p14, 0, %0, c0, c5, 0 @ write a char" : /* no output register */ : "r" (c)); + isb(); } static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 4cb0d0a3e57..fc7bbba585c 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -66,14 +66,16 @@ static int debug; module_param(debug, int, 0600); -#define T1 (HZ/10) -#define T2 (HZ/3) -#define N2 3 +/* Defaults: these are from the specification */ + +#define T1 10 /* 100mS */ +#define T2 34 /* 333mS */ +#define N2 3 /* Retry 3 times */ /* Use long timers for testing at low speed with debug on */ #ifdef DEBUG_TIMING -#define T1 HZ -#define T2 (2 * HZ) +#define T1 100 +#define T2 200 #endif /* diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 5f479dada6f..925a1e547a8 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1560,7 +1560,7 @@ config SERIAL_IFX6X60 Support for the IFX6x60 modem devices on Intel MID platforms. config SERIAL_PCH_UART - tristate "Intel EG20T PCH / OKI SEMICONDUCTOR IOH(ML7213/ML7223) UART" + tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" depends on PCI select SERIAL_CORE help @@ -1568,12 +1568,12 @@ config SERIAL_PCH_UART which is an IOH(Input/Output Hub) for x86 embedded processor. Enabling PCH_DMA, this PCH UART works as DMA mode. - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7213 and ML7223. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use and ML7223 IOH is - for MP(Media Phone) use. - ML7213/ML7223 is companion chip for Intel Atom E6xx series. - ML7213/ML7223 is completely compatible for Intel EG20T PCH. + This driver also can be used for LAPIS Semiconductor IOH(Input/ + Output Hub), ML7213, ML7223 and ML7831. + ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is + for MP(Media Phone) use and ML7831 IOH is for general purpose use. + ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. config SERIAL_MSM_SMD bool "Enable tty device interface for some SMD ports" diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 4a0f86fa1e9..4c823f341d9 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -228,7 +228,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf) if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) + if ((rs485conf->delay_rts_after_send) > 0) UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { @@ -304,7 +304,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) if (atmel_port->rs485.flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + if ((atmel_port->rs485.delay_rts_after_send) > 0) UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; @@ -1228,7 +1228,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, if (atmel_port->rs485.flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); - if (atmel_port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + if ((atmel_port->rs485.delay_rts_after_send) > 0) UART_PUT_TTGR(port, atmel_port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; @@ -1447,16 +1447,6 @@ static void __devinit atmel_of_init_port(struct atmel_uart_port *atmel_port, rs485conf->delay_rts_after_send = rs485_delay[1]; rs485conf->flags = 0; - if (rs485conf->delay_rts_before_send == 0 && - rs485conf->delay_rts_after_send == 0) { - rs485conf->flags |= SER_RS485_RTS_ON_SEND; - } else { - if (rs485conf->delay_rts_before_send) - rs485conf->flags |= SER_RS485_RTS_BEFORE_SEND; - if (rs485conf->delay_rts_after_send) - rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; - } - if (of_get_property(np, "rs485-rx-during-tx", NULL)) rs485conf->flags |= SER_RS485_RX_DURING_TX; diff --git a/drivers/tty/serial/crisv10.c b/drivers/tty/serial/crisv10.c index b7435043f2f..1dfba7b779c 100644 --- a/drivers/tty/serial/crisv10.c +++ b/drivers/tty/serial/crisv10.c @@ -3234,9 +3234,8 @@ rs_write(struct tty_struct *tty, e100_disable_rx(info); e100_enable_rx_irq(info); #endif - if ((info->rs485.flags & SER_RS485_RTS_BEFORE_SEND) && - (info->rs485.delay_rts_before_send > 0)) - msleep(info->rs485.delay_rts_before_send); + if (info->rs485.delay_rts_before_send > 0) + msleep(info->rs485.delay_rts_before_send); } #endif /* CONFIG_ETRAX_RS485 */ @@ -3693,10 +3692,6 @@ rs_ioctl(struct tty_struct *tty, rs485data.delay_rts_before_send = rs485ctrl.delay_rts_before_send; rs485data.flags = 0; - if (rs485data.delay_rts_before_send != 0) - rs485data.flags |= SER_RS485_RTS_BEFORE_SEND; - else - rs485data.flags &= ~(SER_RS485_RTS_BEFORE_SEND); if (rs485ctrl.enabled) rs485data.flags |= SER_RS485_ENABLED; @@ -4531,7 +4526,6 @@ static int __init rs_init(void) /* Set sane defaults */ info->rs485.flags &= ~(SER_RS485_RTS_ON_SEND); info->rs485.flags |= SER_RS485_RTS_AFTER_SEND; - info->rs485.flags &= ~(SER_RS485_RTS_BEFORE_SEND); info->rs485.delay_rts_before_send = 0; info->rs485.flags &= ~(SER_RS485_ENABLED); #endif diff --git a/drivers/tty/serial/mfd.c b/drivers/tty/serial/mfd.c index 286c386d9c4..e272d3919c6 100644 --- a/drivers/tty/serial/mfd.c +++ b/drivers/tty/serial/mfd.c @@ -884,7 +884,6 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, { struct uart_hsu_port *up = container_of(port, struct uart_hsu_port, port); - struct tty_struct *tty = port->state->port.tty; unsigned char cval, fcr = 0; unsigned long flags; unsigned int baud, quot; @@ -907,8 +906,7 @@ serial_hsu_set_termios(struct uart_port *port, struct ktermios *termios, } /* CMSPAR isn't supported by this driver */ - if (tty) - tty->termios->c_cflag &= ~CMSPAR; + termios->c_cflag &= ~CMSPAR; if (termios->c_cflag & CSTOPB) cval |= UART_LCR_STOP; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 21febef926a..d6aba8c087e 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1,5 +1,5 @@ /* - *Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + *Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * *This program is free software; you can redistribute it and/or modify *it under the terms of the GNU General Public License as published by @@ -46,8 +46,8 @@ enum { /* Set the max number of UART port * Intel EG20T PCH: 4 port - * OKI SEMICONDUCTOR ML7213 IOH: 3 port - * OKI SEMICONDUCTOR ML7223 IOH: 2 port + * LAPIS Semiconductor ML7213 IOH: 3 port + * LAPIS Semiconductor ML7223 IOH: 2 port */ #define PCH_UART_NR 4 @@ -258,6 +258,8 @@ enum pch_uart_num_t { pch_ml7213_uart2, pch_ml7223_uart0, pch_ml7223_uart1, + pch_ml7831_uart0, + pch_ml7831_uart1, }; static struct pch_uart_driver_data drv_dat[] = { @@ -270,6 +272,8 @@ static struct pch_uart_driver_data drv_dat[] = { [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, [pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, + [pch_ml7831_uart0] = {PCH_UART_8LINE, 0}, + [pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, }; static unsigned int default_baud = 9600; @@ -628,6 +632,7 @@ static void pch_request_dma(struct uart_port *port) dev_err(priv->port.dev, "%s:dma_request_channel FAILS(Rx)\n", __func__); dma_release_channel(priv->chan_tx); + priv->chan_tx = NULL; return; } @@ -1215,8 +1220,7 @@ static void pch_uart_shutdown(struct uart_port *port) dev_err(priv->port.dev, "pch_uart_hal_set_fifo Failed(ret=%d)\n", ret); - if (priv->use_dma_flag) - pch_free_dma(port); + pch_free_dma(port); free_irq(priv->port.irq, priv); } @@ -1280,6 +1284,7 @@ static void pch_uart_set_termios(struct uart_port *port, if (rtn) goto out; + pch_uart_set_mctrl(&priv->port, priv->port.mctrl); /* Don't rewrite B0 */ if (tty_termios_baud_rate(termios)) tty_termios_encode_baud_rate(termios, baud, baud); @@ -1552,6 +1557,10 @@ static DEFINE_PCI_DEVICE_TABLE(pch_uart_pci_id) = { .driver_data = pch_ml7223_uart0}, {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x800D), .driver_data = pch_ml7223_uart1}, + {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8811), + .driver_data = pch_ml7831_uart0}, + {PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8812), + .driver_data = pch_ml7831_uart1}, {0,}, }; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 1945c70539c..aff9d612dff 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -207,6 +207,25 @@ static struct plat_sci_reg sci_regmap[SCIx_NR_REGTYPES][SCIx_NR_REGS] = { }, /* + * Common SH-2(A) SCIF definitions for ports with FIFO data + * count registers. + */ + [SCIx_SH2_SCIF_FIFODATA_REGTYPE] = { + [SCSMR] = { 0x00, 16 }, + [SCBRR] = { 0x04, 8 }, + [SCSCR] = { 0x08, 16 }, + [SCxTDR] = { 0x0c, 8 }, + [SCxSR] = { 0x10, 16 }, + [SCxRDR] = { 0x14, 8 }, + [SCFCR] = { 0x18, 16 }, + [SCFDR] = { 0x1c, 16 }, + [SCTFDR] = sci_reg_invalid, + [SCRFDR] = sci_reg_invalid, + [SCSPTR] = { 0x20, 16 }, + [SCLSR] = { 0x24, 16 }, + }, + + /* * Common SH-3 SCIF definitions. */ [SCIx_SH3_SCIF_REGTYPE] = { diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 512c49f98e8..8e0924f5544 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -36,6 +36,7 @@ #include <linux/kmod.h> #include <linux/nsproxy.h> +#include <linux/ratelimit.h> /* * This guards the refcounted line discipline lists. The lock @@ -547,15 +548,16 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) /** * tty_ldisc_wait_idle - wait for the ldisc to become idle * @tty: tty to wait for + * @timeout: for how long to wait at most * * Wait for the line discipline to become idle. The discipline must * have been halted for this to guarantee it remains idle. */ -static int tty_ldisc_wait_idle(struct tty_struct *tty) +static int tty_ldisc_wait_idle(struct tty_struct *tty, long timeout) { - int ret; + long ret; ret = wait_event_timeout(tty_ldisc_idle, - atomic_read(&tty->ldisc->users) == 1, 5 * HZ); + atomic_read(&tty->ldisc->users) == 1, timeout); if (ret < 0) return ret; return ret > 0 ? 0 : -EBUSY; @@ -665,7 +667,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_ldisc_flush_works(tty); - retval = tty_ldisc_wait_idle(tty); + retval = tty_ldisc_wait_idle(tty, 5 * HZ); tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -762,8 +764,6 @@ static int tty_ldisc_reinit(struct tty_struct *tty, int ldisc) if (IS_ERR(ld)) return -1; - WARN_ON_ONCE(tty_ldisc_wait_idle(tty)); - tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); tty->ldisc = NULL; @@ -838,7 +838,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) tty_unlock(); cancel_work_sync(&tty->buf.work); mutex_unlock(&tty->ldisc_mutex); - +retry: tty_lock(); mutex_lock(&tty->ldisc_mutex); @@ -847,6 +847,22 @@ void tty_ldisc_hangup(struct tty_struct *tty) it means auditing a lot of other paths so this is a FIXME */ if (tty->ldisc) { /* Not yet closed */ + if (atomic_read(&tty->ldisc->users) != 1) { + char cur_n[TASK_COMM_LEN], tty_n[64]; + long timeout = 3 * HZ; + tty_unlock(); + + while (tty_ldisc_wait_idle(tty, timeout) == -EBUSY) { + timeout = MAX_SCHEDULE_TIMEOUT; + printk_ratelimited(KERN_WARNING + "%s: waiting (%s) for %s took too long, but we keep waiting...\n", + __func__, get_task_comm(cur_n, current), + tty_name(tty, tty_n)); + } + mutex_unlock(&tty->ldisc_mutex); + goto retry; + } + if (reset == 0) { if (!tty_ldisc_reinit(tty, tty->termios->c_line)) diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 6960715c506..a8078d0638f 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -539,7 +539,6 @@ static void acm_port_down(struct acm *acm) { int i; - mutex_lock(&open_mutex); if (acm->dev) { usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); @@ -551,14 +550,15 @@ static void acm_port_down(struct acm *acm) acm->control->needs_remote_wakeup = 0; usb_autopm_put_interface(acm->control); } - mutex_unlock(&open_mutex); } static void acm_tty_hangup(struct tty_struct *tty) { struct acm *acm = tty->driver_data; tty_port_hangup(&acm->port); + mutex_lock(&open_mutex); acm_port_down(acm); + mutex_unlock(&open_mutex); } static void acm_tty_close(struct tty_struct *tty, struct file *filp) @@ -569,8 +569,9 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) shutdown */ if (!acm) return; + + mutex_lock(&open_mutex); if (tty_port_close_start(&acm->port, tty, filp) == 0) { - mutex_lock(&open_mutex); if (!acm->dev) { tty_port_tty_set(&acm->port, NULL); acm_tty_unregister(acm); @@ -582,6 +583,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) acm_port_down(acm); tty_port_close_end(&acm->port, tty); tty_port_tty_set(&acm->port, NULL); + mutex_unlock(&open_mutex); } static int acm_tty_write(struct tty_struct *tty, @@ -1456,6 +1458,16 @@ static const struct usb_device_id acm_ids[] = { }, { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */ }, + /* Motorola H24 HSPA module: */ + { USB_DEVICE(0x22b8, 0x2d91) }, /* modem */ + { USB_DEVICE(0x22b8, 0x2d92) }, /* modem + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d93) }, /* modem + AT port */ + { USB_DEVICE(0x22b8, 0x2d95) }, /* modem + AT port + diagnostics */ + { USB_DEVICE(0x22b8, 0x2d96) }, /* modem + NMEA */ + { USB_DEVICE(0x22b8, 0x2d97) }, /* modem + diagnostics + NMEA */ + { USB_DEVICE(0x22b8, 0x2d99) }, /* modem + AT port + NMEA */ + { USB_DEVICE(0x22b8, 0x2d9a) }, /* modem + AT port + diagnostics + NMEA */ + { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */ .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on data interface instead of diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 96f05b29c9a..79781461eec 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -813,6 +813,12 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) USB_PORT_FEAT_C_PORT_LINK_STATE); } + if ((portchange & USB_PORT_STAT_C_BH_RESET) && + hub_is_superspeed(hub->hdev)) { + need_debounce_delay = true; + clear_port_feature(hub->hdev, port1, + USB_PORT_FEAT_C_BH_PORT_RESET); + } /* We can forget about a "removed" device when there's a * physical disconnect or the connect status changes. */ diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index d6a8d8269bf..ecf12e15a7e 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -50,15 +50,42 @@ static const struct usb_device_id usb_quirk_list[] = { /* Logitech Webcam B/C500 */ { USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C600 */ + { USB_DEVICE(0x046d, 0x0808), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam Pro 9000 */ { USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C905 */ + { USB_DEVICE(0x046d, 0x080a), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C210 */ + { USB_DEVICE(0x046d, 0x0819), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C260 */ + { USB_DEVICE(0x046d, 0x081a), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C310 */ { USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C910 */ + { USB_DEVICE(0x046d, 0x0821), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Webcam C160 */ + { USB_DEVICE(0x046d, 0x0824), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Webcam C270 */ { USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Quickcam Pro 9000 */ + { USB_DEVICE(0x046d, 0x0990), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam E3500 */ + { USB_DEVICE(0x046d, 0x09a4), .driver_info = USB_QUIRK_RESET_RESUME }, + + /* Logitech Quickcam Vision Pro */ + { USB_DEVICE(0x046d, 0x09a6), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Logitech Harmony 700-series */ { USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT }, diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 717ebc9ff94..600d8234851 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -264,7 +264,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) ret = -ENODEV; goto err0; } - dwc->revision = reg & DWC3_GSNPSREV_MASK; + dwc->revision = reg; dwc3_core_soft_reset(dwc); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index fa824cfdd2e..25dbd8614e7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1284,6 +1284,7 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc) int ret; dep->endpoint.maxpacket = 1024; + dep->endpoint.max_streams = 15; dep->endpoint.ops = &dwc3_gadget_ep_ops; list_add_tail(&dep->endpoint.ep_list, &dwc->gadget.ep_list); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index b21cd376c11..23a447373c5 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -469,7 +469,7 @@ config USB_LANGWELL gadget drivers to also be dynamically linked. config USB_EG20T - tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC" + tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" depends on PCI select USB_GADGET_DUALSPEED help @@ -485,10 +485,11 @@ config USB_EG20T This driver dose not support interrupt transfer or isochronous transfer modes. - This driver also can be used for OKI SEMICONDUCTOR's ML7213 which is + This driver also can be used for LAPIS Semiconductor's ML7213 which is for IVI(In-Vehicle Infotainment) use. - ML7213 is companion chip for Intel Atom E6xx series. - ML7213 is completely compatible for Intel EG20T PCH. + ML7831 is for general purpose use. + ML7213/ML7831 is companion chip for Intel Atom E6xx series. + ML7213/ML7831 is completely compatible for Intel EG20T PCH. config USB_CI13XXX_MSM tristate "MIPS USB CI13xxx for MSM" diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 4730016d7cd..45f422ac103 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, u32 tmp; if (!driver || !bind || !driver->setup - || driver->speed != USB_SPEED_HIGH) + || driver->speed < USB_SPEED_HIGH) return -EINVAL; if (!dev) return -ENODEV; diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c index 4eedfe55715..1fc612914c5 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/gadget/ci13xxx_msm.c @@ -122,3 +122,5 @@ static int __init ci13xxx_msm_init(void) return platform_driver_register(&ci13xxx_msm_driver); } module_init(ci13xxx_msm_init); + +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c index 83428f56253..9a0c3979ff4 100644 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ b/drivers/usb/gadget/ci13xxx_udc.c @@ -71,6 +71,9 @@ /****************************************************************************** * DEFINE *****************************************************************************/ + +#define DMA_ADDR_INVALID (~(dma_addr_t)0) + /* ctrl register bank access */ static DEFINE_SPINLOCK(udc_lock); @@ -1434,7 +1437,7 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) return -EALREADY; mReq->req.status = -EALREADY; - if (length && !mReq->req.dma) { + if (length && mReq->req.dma == DMA_ADDR_INVALID) { mReq->req.dma = \ dma_map_single(mEp->device, mReq->req.buf, length, mEp->dir ? DMA_TO_DEVICE : @@ -1453,7 +1456,7 @@ static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) dma_unmap_single(mEp->device, mReq->req.dma, length, mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = 0; + mReq->req.dma = DMA_ADDR_INVALID; mReq->map = 0; } return -ENOMEM; @@ -1549,7 +1552,7 @@ static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) if (mReq->map) { dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = 0; + mReq->req.dma = DMA_ADDR_INVALID; mReq->map = 0; } @@ -1610,7 +1613,6 @@ __acquires(mEp->lock) * @gadget: gadget * * This function returns an error code - * Caller must hold lock */ static int _gadget_stop_activity(struct usb_gadget *gadget) { @@ -2189,6 +2191,7 @@ static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); if (mReq != NULL) { INIT_LIST_HEAD(&mReq->queue); + mReq->req.dma = DMA_ADDR_INVALID; mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, &mReq->dma); @@ -2328,7 +2331,7 @@ static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) if (mReq->map) { dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = 0; + mReq->req.dma = DMA_ADDR_INVALID; mReq->map = 0; } req->status = -ECONNRESET; @@ -2500,12 +2503,12 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget) spin_lock_irqsave(udc->lock, flags); if (!udc->remote_wakeup) { ret = -EOPNOTSUPP; - dbg_trace("remote wakeup feature is not enabled\n"); + trace("remote wakeup feature is not enabled\n"); goto out; } if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { ret = -EINVAL; - dbg_trace("port is not suspended\n"); + trace("port is not suspended\n"); goto out; } hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); @@ -2703,7 +2706,9 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver) if (udc->udc_driver->notify_event) udc->udc_driver->notify_event(udc, CI13XXX_CONTROLLER_STOPPED_EVENT); + spin_unlock_irqrestore(udc->lock, flags); _gadget_stop_activity(&udc->gadget); + spin_lock_irqsave(udc->lock, flags); pm_runtime_put(&udc->gadget.dev); } @@ -2850,7 +2855,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, struct ci13xxx *udc; int retval = 0; - trace("%p, %p, %p", dev, regs, name); + trace("%p, %p, %p", dev, regs, driver->name); if (dev == NULL || regs == NULL || driver == NULL || driver->name == NULL) diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index 596a0b464e6..4dff83d2f26 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -130,9 +130,6 @@ ep_matches ( num_req_streams = ep_comp->bmAttributes & 0x1f; if (num_req_streams > ep->max_streams) return 0; - /* Update the ep_comp descriptor if needed */ - if (num_req_streams != ep->max_streams) - ep_comp->bmAttributes = ep->max_streams; } } diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index 52583a23533..1a6f415c0d0 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -624,7 +624,8 @@ static int fsg_setup(struct usb_function *f, if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != fsg->interface_number || w_value != 0) + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 0) return -EDOM; /* @@ -639,7 +640,8 @@ static int fsg_setup(struct usb_function *f, if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != fsg->interface_number || w_value != 0) + if (w_index != fsg->interface_number || w_value != 0 || + w_length != 1) return -EDOM; VDBG(fsg, "get max LUN\n"); *(u8 *)req->buf = fsg->common->nluns - 1; @@ -2973,6 +2975,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) fsg_common_put(common); usb_free_descriptors(fsg->function.descriptors); usb_free_descriptors(fsg->function.hs_descriptors); + usb_free_descriptors(fsg->function.ss_descriptors); kfree(fsg); } diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c index 67b222908cf..3797b3d6c62 100644 --- a/drivers/usb/gadget/f_midi.c +++ b/drivers/usb/gadget/f_midi.c @@ -95,7 +95,6 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); -DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16); DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16); /* B.3.1 Standard AC Interface Descriptor */ @@ -140,26 +139,6 @@ static struct usb_ms_header_descriptor ms_header_desc __initdata = { /* .wTotalLength = DYNAMIC */ }; -/* B.4.3 Embedded MIDI IN Jack Descriptor */ -static struct usb_midi_in_jack_descriptor jack_in_emb_desc = { - .bLength = USB_DT_MIDI_IN_SIZE, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_IN_JACK, - .bJackType = USB_MS_EMBEDDED, - /* .bJackID = DYNAMIC */ -}; - -/* B.4.4 Embedded MIDI OUT Jack Descriptor */ -static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = { - /* .bLength = DYNAMIC */ - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK, - .bJackType = USB_MS_EMBEDDED, - /* .bJackID = DYNAMIC */ - /* .bNrInputPins = DYNAMIC */ - /* .pins = DYNAMIC */ -}; - /* B.5.1 Standard Bulk OUT Endpoint Descriptor */ static struct usb_endpoint_descriptor bulk_out_desc = { .bLength = USB_DT_ENDPOINT_AUDIO_SIZE, @@ -758,9 +737,11 @@ fail: static int __init f_midi_bind(struct usb_configuration *c, struct usb_function *f) { - struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12]; + struct usb_descriptor_header **midi_function; struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS]; + struct usb_midi_in_jack_descriptor jack_in_emb_desc[MAX_PORTS]; struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS]; + struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc[MAX_PORTS]; struct usb_composite_dev *cdev = c->cdev; struct f_midi *midi = func_to_midi(f); int status, n, jack = 1, i = 0; @@ -798,6 +779,14 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) goto fail; midi->out_ep->driver_data = cdev; /* claim */ + /* allocate temporary function list */ + midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(midi_function), + GFP_KERNEL); + if (!midi_function) { + status = -ENOMEM; + goto fail; + } + /* * construct the function's descriptor set. As the number of * input and output MIDI ports is configurable, we have to do @@ -811,73 +800,74 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) /* calculate the header's wTotalLength */ n = USB_DT_MS_HEADER_SIZE - + (1 + midi->in_ports) * USB_DT_MIDI_IN_SIZE - + (1 + midi->out_ports) * USB_DT_MIDI_OUT_SIZE(1); + + (midi->in_ports + midi->out_ports) * + (USB_DT_MIDI_IN_SIZE + USB_DT_MIDI_OUT_SIZE(1)); ms_header_desc.wTotalLength = cpu_to_le16(n); midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc; - /* we have one embedded IN jack */ - jack_in_emb_desc.bJackID = jack++; - midi_function[i++] = (struct usb_descriptor_header *) &jack_in_emb_desc; - - /* and a dynamic amount of external IN jacks */ - for (n = 0; n < midi->in_ports; n++) { - struct usb_midi_in_jack_descriptor *ext = &jack_in_ext_desc[n]; - - ext->bLength = USB_DT_MIDI_IN_SIZE; - ext->bDescriptorType = USB_DT_CS_INTERFACE; - ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; - ext->bJackType = USB_MS_EXTERNAL; - ext->bJackID = jack++; - ext->iJack = 0; - - midi_function[i++] = (struct usb_descriptor_header *) ext; - } - - /* one embedded OUT jack ... */ - jack_out_emb_desc.bLength = USB_DT_MIDI_OUT_SIZE(midi->in_ports); - jack_out_emb_desc.bJackID = jack++; - jack_out_emb_desc.bNrInputPins = midi->in_ports; - /* ... which referencess all external IN jacks */ + /* configure the external IN jacks, each linked to an embedded OUT jack */ for (n = 0; n < midi->in_ports; n++) { - jack_out_emb_desc.pins[n].baSourceID = jack_in_ext_desc[n].bJackID; - jack_out_emb_desc.pins[n].baSourcePin = 1; + struct usb_midi_in_jack_descriptor *in_ext = &jack_in_ext_desc[n]; + struct usb_midi_out_jack_descriptor_1 *out_emb = &jack_out_emb_desc[n]; + + in_ext->bLength = USB_DT_MIDI_IN_SIZE; + in_ext->bDescriptorType = USB_DT_CS_INTERFACE; + in_ext->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; + in_ext->bJackType = USB_MS_EXTERNAL; + in_ext->bJackID = jack++; + in_ext->iJack = 0; + midi_function[i++] = (struct usb_descriptor_header *) in_ext; + + out_emb->bLength = USB_DT_MIDI_OUT_SIZE(1); + out_emb->bDescriptorType = USB_DT_CS_INTERFACE; + out_emb->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; + out_emb->bJackType = USB_MS_EMBEDDED; + out_emb->bJackID = jack++; + out_emb->bNrInputPins = 1; + out_emb->pins[0].baSourcePin = 1; + out_emb->pins[0].baSourceID = in_ext->bJackID; + out_emb->iJack = 0; + midi_function[i++] = (struct usb_descriptor_header *) out_emb; + + /* link it to the endpoint */ + ms_in_desc.baAssocJackID[n] = out_emb->bJackID; } - midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc; - - /* and multiple external OUT jacks ... */ + /* configure the external OUT jacks, each linked to an embedded IN jack */ for (n = 0; n < midi->out_ports; n++) { - struct usb_midi_out_jack_descriptor_1 *ext = &jack_out_ext_desc[n]; - int m; - - ext->bLength = USB_DT_MIDI_OUT_SIZE(1); - ext->bDescriptorType = USB_DT_CS_INTERFACE; - ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; - ext->bJackType = USB_MS_EXTERNAL; - ext->bJackID = jack++; - ext->bNrInputPins = 1; - ext->iJack = 0; - /* ... which all reference the same embedded IN jack */ - for (m = 0; m < midi->out_ports; m++) { - ext->pins[m].baSourceID = jack_in_emb_desc.bJackID; - ext->pins[m].baSourcePin = 1; - } - - midi_function[i++] = (struct usb_descriptor_header *) ext; + struct usb_midi_in_jack_descriptor *in_emb = &jack_in_emb_desc[n]; + struct usb_midi_out_jack_descriptor_1 *out_ext = &jack_out_ext_desc[n]; + + in_emb->bLength = USB_DT_MIDI_IN_SIZE; + in_emb->bDescriptorType = USB_DT_CS_INTERFACE; + in_emb->bDescriptorSubtype = USB_MS_MIDI_IN_JACK; + in_emb->bJackType = USB_MS_EMBEDDED; + in_emb->bJackID = jack++; + in_emb->iJack = 0; + midi_function[i++] = (struct usb_descriptor_header *) in_emb; + + out_ext->bLength = USB_DT_MIDI_OUT_SIZE(1); + out_ext->bDescriptorType = USB_DT_CS_INTERFACE; + out_ext->bDescriptorSubtype = USB_MS_MIDI_OUT_JACK; + out_ext->bJackType = USB_MS_EXTERNAL; + out_ext->bJackID = jack++; + out_ext->bNrInputPins = 1; + out_ext->iJack = 0; + out_ext->pins[0].baSourceID = in_emb->bJackID; + out_ext->pins[0].baSourcePin = 1; + midi_function[i++] = (struct usb_descriptor_header *) out_ext; + + /* link it to the endpoint */ + ms_out_desc.baAssocJackID[n] = in_emb->bJackID; } /* configure the endpoint descriptors ... */ ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports); ms_out_desc.bNumEmbMIDIJack = midi->in_ports; - for (n = 0; n < midi->in_ports; n++) - ms_out_desc.baAssocJackID[n] = jack_in_emb_desc.bJackID; ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports); ms_in_desc.bNumEmbMIDIJack = midi->out_ports; - for (n = 0; n < midi->out_ports; n++) - ms_in_desc.baAssocJackID[n] = jack_out_emb_desc.bJackID; /* ... and add them to the list */ midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc; @@ -901,6 +891,8 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f) f->descriptors = usb_copy_descriptors(midi_function); } + kfree(midi_function); + return 0; fail: diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c index 34907703333..16a509ae517 100644 --- a/drivers/usb/gadget/f_phonet.c +++ b/drivers/usb/gadget/f_phonet.c @@ -346,7 +346,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) } skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - skb->len == 0, req->actual); + skb->len <= 1, req->actual); page = NULL; if (req->actual < req->length) { /* Last fragment */ diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c index 91fdf790ed2..cf33a8d0fd5 100644 --- a/drivers/usb/gadget/f_serial.c +++ b/drivers/usb/gadget/f_serial.c @@ -131,8 +131,8 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } if (!gser->port.in->desc || !gser->port.out->desc) { DBG(cdev, "activate generic ttyGS%d\n", gser->port_num); - if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) || - !config_ep_by_speed(cdev->gadget, f, gser->port.out)) { + if (config_ep_by_speed(cdev->gadget, f, gser->port.in) || + config_ep_by_speed(cdev->gadget, f, gser->port.out)) { gser->port.in->desc = NULL; gser->port.out->desc = NULL; return -EINVAL; diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index f7e39b0365c..11b5196284a 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -859,7 +859,7 @@ static int class_setup_req(struct fsg_dev *fsg, if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0 || w_value != 0) { + if (w_index != 0 || w_value != 0 || w_length != 0) { value = -EDOM; break; } @@ -875,7 +875,7 @@ static int class_setup_req(struct fsg_dev *fsg, if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) break; - if (w_index != 0 || w_value != 0) { + if (w_index != 0 || w_value != 0 || w_length != 1) { value = -EDOM; break; } diff --git a/drivers/usb/gadget/fsl_mxc_udc.c b/drivers/usb/gadget/fsl_mxc_udc.c index 43a49ecc1f3..dcbc0a2e48d 100644 --- a/drivers/usb/gadget/fsl_mxc_udc.c +++ b/drivers/usb/gadget/fsl_mxc_udc.c @@ -16,6 +16,7 @@ #include <linux/err.h> #include <linux/fsl_devices.h> #include <linux/platform_device.h> +#include <linux/io.h> #include <mach/hardware.h> @@ -88,7 +89,6 @@ eenahb: void fsl_udc_clk_finalize(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; -#if defined(CONFIG_SOC_IMX35) if (cpu_is_mx35()) { unsigned int v; @@ -101,7 +101,6 @@ void fsl_udc_clk_finalize(struct platform_device *pdev) USBPHYCTRL_OTGBASE_OFFSET)); } } -#endif /* ULPI transceivers don't need usbpll */ if (pdata->phy_mode == FSL_USB2_PHY_ULPI) { diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 2a03e4de11c..e00cf92409c 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,8 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) + if (!driver || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b2c44e1d581..dd28ef3def7 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -696,12 +696,31 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req) kfree(req); } -/*-------------------------------------------------------------------------*/ +/* Actually add a dTD chain to an empty dQH and let go */ +static void fsl_prime_ep(struct fsl_ep *ep, struct ep_td_struct *td) +{ + struct ep_queue_head *qh = get_qh_by_ep(ep); + + /* Write dQH next pointer and terminate bit to 0 */ + qh->next_dtd_ptr = cpu_to_hc32(td->td_dma + & EP_QUEUE_HEAD_NEXT_POINTER_MASK); + + /* Clear active and halt bit */ + qh->size_ioc_int_sts &= cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE + | EP_QUEUE_HEAD_STATUS_HALT)); + + /* Ensure that updates to the QH will occur before priming. */ + wmb(); + + /* Prime endpoint by writing correct bit to ENDPTPRIME */ + fsl_writel(ep_is_in(ep) ? (1 << (ep_index(ep) + 16)) + : (1 << (ep_index(ep))), &dr_regs->endpointprime); +} + +/* Add dTD chain to the dQH of an EP */ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) { - int i = ep_index(ep) * 2 + ep_is_in(ep); u32 temp, bitmask, tmp_stat; - struct ep_queue_head *dQH = &ep->udc->ep_qh[i]; /* VDBG("QH addr Register 0x%8x", dr_regs->endpointlistaddr); VDBG("ep_qh[%d] addr is 0x%8x", i, (u32)&(ep->udc->ep_qh[i])); */ @@ -719,7 +738,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); /* Read prime bit, if 1 goto done */ if (fsl_readl(&dr_regs->endpointprime) & bitmask) - goto out; + return; do { /* Set ATDTW bit in USBCMD */ @@ -736,28 +755,10 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) fsl_writel(temp & ~USB_CMD_ATDTW, &dr_regs->usbcmd); if (tmp_stat) - goto out; + return; } - /* Write dQH next pointer and terminate bit to 0 */ - temp = req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK; - dQH->next_dtd_ptr = cpu_to_hc32(temp); - - /* Clear active and halt bit */ - temp = cpu_to_hc32(~(EP_QUEUE_HEAD_STATUS_ACTIVE - | EP_QUEUE_HEAD_STATUS_HALT)); - dQH->size_ioc_int_sts &= temp; - - /* Ensure that updates to the QH will occur before priming. */ - wmb(); - - /* Prime endpoint by writing 1 to ENDPTPRIME */ - temp = ep_is_in(ep) - ? (1 << (ep_index(ep) + 16)) - : (1 << (ep_index(ep))); - fsl_writel(temp, &dr_regs->endpointprime); -out: - return; + fsl_prime_ep(ep, req->head); } /* Fill in the dTD structure @@ -877,7 +878,7 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad ep", __func__); return -EINVAL; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (usb_endpoint_xfer_isoc(ep->desc)) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -973,25 +974,20 @@ static int fsl_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) /* The request isn't the last request in this ep queue */ if (req->queue.next != &ep->queue) { - struct ep_queue_head *qh; struct fsl_req *next_req; - qh = ep->qh; next_req = list_entry(req->queue.next, struct fsl_req, queue); - /* Point the QH to the first TD of next request */ - fsl_writel((u32) next_req->head, &qh->curr_dtd_ptr); + /* prime with dTD of next request */ + fsl_prime_ep(ep, next_req->head); } - - /* The request hasn't been processed, patch up the TD chain */ + /* The request hasn't been processed, patch up the TD chain */ } else { struct fsl_req *prev_req; prev_req = list_entry(req->queue.prev, struct fsl_req, queue); - fsl_writel(fsl_readl(&req->tail->next_td_ptr), - &prev_req->tail->next_td_ptr); - + prev_req->tail->next_td_ptr = req->tail->next_td_ptr; } done(ep, req, -ECONNRESET); @@ -1032,7 +1028,7 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value) goto out; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (usb_endpoint_xfer_isoc(ep->desc)) { status = -EOPNOTSUPP; goto out; } @@ -1068,7 +1064,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) struct fsl_udc *udc; int size = 0; u32 bitmask; - struct ep_queue_head *d_qh; + struct ep_queue_head *qh; ep = container_of(_ep, struct fsl_ep, ep); if (!_ep || (!ep->desc && ep_index(ep) != 0)) @@ -1079,13 +1075,13 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; - d_qh = &ep->udc->ep_qh[ep_index(ep) * 2 + ep_is_in(ep)]; + qh = get_qh_by_ep(ep); bitmask = (ep_is_in(ep)) ? (1 << (ep_index(ep) + 16)) : (1 << (ep_index(ep))); if (fsl_readl(&dr_regs->endptstatus) & bitmask) - size = (d_qh->size_ioc_int_sts & DTD_PACKET_SIZE) + size = (qh->size_ioc_int_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS; pr_debug("%s %u\n", __func__, size); @@ -1717,7 +1713,7 @@ static void dtd_complete_irq(struct fsl_udc *udc) static inline enum usb_device_speed portscx_device_speed(u32 reg) { - switch (speed & PORTSCX_PORT_SPEED_MASK) { + switch (reg & PORTSCX_PORT_SPEED_MASK) { case PORTSCX_PORT_SPEED_HIGH: return USB_SPEED_HIGH; case PORTSCX_PORT_SPEED_FULL: @@ -1938,8 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) + if (!driver || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -2480,8 +2475,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifndef CONFIG_ARCH_MXC if (pdata->have_sysif_regs) - usb_sys_regs = (struct usb_sys_interface *) - ((u32)dr_regs + USB_DR_SYS_OFFSET); + usb_sys_regs = (void *)dr_regs + USB_DR_SYS_OFFSET; #endif /* Initialize USB clocks */ diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index 1d51be83fda..f781f5dec41 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -569,6 +569,16 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length) * 2 + ((windex & USB_DIR_IN) ? 1 : 0)) #define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP)) +static inline struct ep_queue_head *get_qh_by_ep(struct fsl_ep *ep) +{ + /* we only have one ep0 structure but two queue heads */ + if (ep_index(ep) != 0) + return ep->qh; + else + return &ep->udc->ep_qh[(ep->udc->ep0_dir == + USB_DIR_IN) ? 1 : 0]; +} + struct platform_device; #ifdef CONFIG_ARCH_MXC int fsl_udc_clk_init(struct platform_device *pdev); diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index a392ec0d2d5..6ccae2707e5 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -1730,8 +1730,9 @@ static void gadgetfs_disconnect (struct usb_gadget *gadget) { struct dev_data *dev = get_gadget_data (gadget); + unsigned long flags; - spin_lock (&dev->lock); + spin_lock_irqsave (&dev->lock, flags); if (dev->state == STATE_DEV_UNCONNECTED) goto exit; dev->state = STATE_DEV_UNCONNECTED; @@ -1740,7 +1741,7 @@ gadgetfs_disconnect (struct usb_gadget *gadget) next_event (dev, GADGETFS_DISCONNECT); ep0_readable (dev); exit: - spin_unlock (&dev->lock); + spin_unlock_irqrestore (&dev->lock, flags); } static void diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 91d0af2a24a..9aa1cbbee45 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->speed != USB_SPEED_HIGH + || driver->speed < USB_SPEED_HIGH || !bind || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index 7f1bc9a73cd..da2b9d0be3c 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget, * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE) * "must not be used in normal operation" */ - if (!driver || driver->speed != USB_SPEED_HIGH + if (!driver || driver->speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 550d6dcdf10..5048a0c0764 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD. + * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -354,6 +354,7 @@ struct pch_udc_dev { #define PCI_DEVICE_ID_INTEL_EG20T_UDC 0x8808 #define PCI_VENDOR_ID_ROHM 0x10DB #define PCI_DEVICE_ID_ML7213_IOH_UDC 0x801D +#define PCI_DEVICE_ID_ML7831_IOH_UDC 0x8808 static const char ep0_string[] = "ep0in"; static DEFINE_SPINLOCK(udc_stall_spinlock); /* stall spin lock */ @@ -2970,6 +2971,11 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, .class_mask = 0xffffffff, }, + { + PCI_DEVICE(PCI_VENDOR_ID_ROHM, PCI_DEVICE_ID_ML7831_IOH_UDC), + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, + .class_mask = 0xffffffff, + }, { 0 }, }; @@ -2999,5 +3005,5 @@ static void __exit pch_udc_pci_exit(void) module_exit(pch_udc_pci_exit); MODULE_DESCRIPTION("Intel EG20T USB Device Controller"); -MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>"); +MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 68a826a1b86..fc719a3f855 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1718,6 +1718,8 @@ static void r8a66597_fifo_flush(struct usb_ep *_ep) if (list_empty(&ep->queue) && !ep->busy) { pipe_stop(ep->r8a66597, ep->pipenum); r8a66597_bclr(ep->r8a66597, BCLR, ep->fifoctr); + r8a66597_write(ep->r8a66597, ACLRM, ep->pipectr); + r8a66597_write(ep->r8a66597, 0, ep->pipectr); } spin_unlock_irqrestore(&ep->r8a66597->lock, flags); } @@ -1742,26 +1744,16 @@ static int r8a66597_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); - int retval; if (!driver - || driver->speed != USB_SPEED_HIGH + || driver->speed < USB_SPEED_HIGH || !driver->setup) return -EINVAL; if (!r8a66597) return -ENODEV; /* hook up the driver */ - driver->driver.bus = NULL; r8a66597->driver = driver; - r8a66597->gadget.dev.driver = &driver->driver; - - retval = device_add(&r8a66597->gadget.dev); - if (retval) { - dev_err(r8a66597_to_dev(r8a66597), "device_add error (%d)\n", - retval); - goto error; - } init_controller(r8a66597); r8a66597_bset(r8a66597, VBSE, INTENB0); @@ -1775,12 +1767,6 @@ static int r8a66597_start(struct usb_gadget *gadget, } return 0; - -error: - r8a66597->driver = NULL; - r8a66597->gadget.dev.driver = NULL; - - return retval; } static int r8a66597_stop(struct usb_gadget *gadget, @@ -1794,7 +1780,6 @@ static int r8a66597_stop(struct usb_gadget *gadget, disable_controller(r8a66597); spin_unlock_irqrestore(&r8a66597->lock, flags); - device_del(&r8a66597->gadget.dev); r8a66597->driver = NULL; return 0; } @@ -1845,6 +1830,7 @@ static int __exit r8a66597_remove(struct platform_device *pdev) clk_put(r8a66597->clk); } #endif + device_unregister(&r8a66597->gadget.dev); kfree(r8a66597); return 0; } @@ -1924,13 +1910,17 @@ static int __init r8a66597_probe(struct platform_device *pdev) r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW; r8a66597->gadget.ops = &r8a66597_gadget_ops; - device_initialize(&r8a66597->gadget.dev); dev_set_name(&r8a66597->gadget.dev, "gadget"); r8a66597->gadget.is_dualspeed = 1; r8a66597->gadget.dev.parent = &pdev->dev; r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; r8a66597->gadget.dev.release = pdev->dev.release; r8a66597->gadget.name = udc_name; + ret = device_register(&r8a66597->gadget.dev); + if (ret < 0) { + dev_err(&pdev->dev, "device_register failed\n"); + goto clean_up; + } init_timer(&r8a66597->timer); r8a66597->timer.function = r8a66597_timer; @@ -1945,7 +1935,7 @@ static int __init r8a66597_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot get clock \"%s\"\n", clk_name); ret = PTR_ERR(r8a66597->clk); - goto clean_up; + goto clean_up_dev; } clk_enable(r8a66597->clk); } @@ -2014,7 +2004,9 @@ clean_up2: clk_disable(r8a66597->clk); clk_put(r8a66597->clk); } +clean_up_dev: #endif + device_unregister(&r8a66597->gadget.dev); clean_up: if (r8a66597) { if (r8a66597->sudmac_reg) diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index a552453dc94..b31448229f0 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -2586,10 +2586,8 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return -EINVAL; } - if (driver->speed != USB_SPEED_HIGH && - driver->speed != USB_SPEED_FULL) { + if (driver->speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); - } if (!bind || !driver->setup) { dev_err(hsotg->dev, "%s: missing entry points\n", __func__); diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 8d54f893cef..20a553b46ae 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -1142,8 +1142,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, int ret; if (!driver - || (driver->speed != USB_SPEED_FULL && - driver->speed != USB_SPEED_HIGH) + || driver->speed < USB_SPEED_FULL || !bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c index 022baeca7c9..6939e17f458 100644 --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -210,10 +210,10 @@ static void usb_gadget_remove_driver(struct usb_udc *udc) kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE); if (udc_is_newstyle(udc)) { - usb_gadget_disconnect(udc->gadget); + udc->driver->disconnect(udc->gadget); udc->driver->unbind(udc->gadget); usb_gadget_udc_stop(udc->gadget, udc->driver); - + usb_gadget_disconnect(udc->gadget); } else { usb_gadget_stop(udc->gadget, udc->driver); } @@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver); static ssize_t usb_udc_srp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { - struct usb_udc *udc = dev_get_drvdata(dev); + struct usb_udc *udc = container_of(dev, struct usb_udc, dev); if (sysfs_streq(buf, "1")) usb_gadget_wakeup(udc->gadget); @@ -378,7 +378,7 @@ static ssize_t usb_udc_speed_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%s\n", usb_speed_string(udc->gadget->speed)); } -static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL); +static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL); #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ @@ -389,7 +389,7 @@ ssize_t usb_udc_##name##_show(struct device *dev, \ \ return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name); \ } \ -static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL) +static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL) static USB_UDC_ATTR(is_dualspeed); static USB_UDC_ATTR(is_otg); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 2e829fae648..a60679cbbf8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1475,30 +1475,36 @@ iso_stream_schedule ( * jump until after the queue is primed. */ else { + int done = 0; start = SCHEDULE_SLOP + (now & ~0x07); /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ - /* find a uframe slot with enough bandwidth */ - next = start + period; - for (; start < next; start++) { - + /* find a uframe slot with enough bandwidth. + * Early uframes are more precious because full-speed + * iso IN transfers can't use late uframes, + * and therefore they should be allocated last. + */ + next = start; + start += period; + do { + start--; /* check schedule: enough space? */ if (stream->highspeed) { if (itd_slot_ok(ehci, mod, start, stream->usecs, period)) - break; + done = 1; } else { if ((start % 8) >= 6) continue; if (sitd_slot_ok(ehci, mod, stream, start, sched, period)) - break; + done = 1; } - } + } while (start > next && !done); /* no room in the schedule */ - if (start == next) { + if (!done) { ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", urb, now, now + mod); status = -ENOSPC; diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c index fe74bd67601..b4fb511d24b 100644 --- a/drivers/usb/host/ehci-xls.c +++ b/drivers/usb/host/ehci-xls.c @@ -19,7 +19,7 @@ static int ehci_xls_setup(struct usb_hcd *hcd) ehci->caps = hcd->regs; ehci->regs = hcd->regs + - HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); + HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase)); dbg_hcs_params(ehci, "reset"); dbg_hcc_params(ehci, "reset"); diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index a7dc1e1d45f..2ac4ac2e4ef 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -18,7 +18,7 @@ #include "isp1760-hcd.h" -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) #include <linux/slab.h> #include <linux/of.h> #include <linux/of_platform.h> @@ -31,7 +31,7 @@ #include <linux/pci.h> #endif -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) struct isp1760 { struct usb_hcd *hcd; int rst_gpio; @@ -437,7 +437,7 @@ static int __init isp1760_init(void) ret = platform_driver_register(&isp1760_plat_driver); if (!ret) any_ret = 0; -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) ret = platform_driver_register(&isp1760_of_driver); if (!ret) any_ret = 0; @@ -457,7 +457,7 @@ module_init(isp1760_init); static void __exit isp1760_exit(void) { platform_driver_unregister(&isp1760_plat_driver); -#ifdef CONFIG_OF +#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ) platform_driver_unregister(&isp1760_of_driver); #endif #ifdef CONFIG_PCI diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index ba3a46b78b7..95a9fec38e8 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -223,6 +223,9 @@ static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int if (port < 0 || port >= 2) return; + if (pdata->vbus_pin[port] <= 0) + return; + gpio_set_value(pdata->vbus_pin[port], !pdata->vbus_pin_inverted ^ enable); } @@ -231,6 +234,9 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) if (port < 0 || port >= 2) return -EINVAL; + if (pdata->vbus_pin[port] <= 0) + return -EINVAL; + return gpio_get_value(pdata->vbus_pin[port]) ^ !pdata->vbus_pin_inverted; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 34efd479e06..b2639191549 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd) struct ohci_hcd *ohci; ohci = hcd_to_ohci (hcd); - ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); - ohci->hc_control = ohci_readl(ohci, &ohci->regs->control); + ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable); - /* If the SHUTDOWN quirk is set, don't put the controller in RESET */ - ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ? - OHCI_CTRL_RWC | OHCI_CTRL_HCFS : - OHCI_CTRL_RWC); - ohci_writel(ohci, ohci->hc_control, &ohci->regs->control); + /* Software reset, after which the controller goes into SUSPEND */ + ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus); + ohci_readl(ohci, &ohci->regs->cmdstatus); /* flush the writes */ + udelay(10); - /* flush the writes */ - (void) ohci_readl (ohci, &ohci->regs->control); + ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval); } static int check_ed(struct ohci_hcd *ohci, struct ed *ed) diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index ad8166c681e..bc01b064585 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd) return 0; } -/* nVidia controllers continue to drive Reset signalling on the bus - * even after system shutdown, wasting power. This flag tells the - * shutdown routine to leave the controller OPERATIONAL instead of RESET. - */ -static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd) -{ - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - struct ohci_hcd *ohci = hcd_to_ohci(hcd); - - /* Evidently nVidia fixed their later hardware; this is a guess at - * the changeover point. - */ -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB 0x026d - - if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) { - ohci->flags |= OHCI_QUIRK_SHUTDOWN; - ohci_dbg(ohci, "enabled nVidia shutdown quirk\n"); - } - - return 0; -} - static void sb800_prefetch(struct ohci_hcd *ohci, int on) { struct pci_dev *pdev; @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_pci_quirks[] = { PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399), .driver_data = (unsigned long)ohci_quirk_amd700, }, - { - PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), - .driver_data = (unsigned long) ohci_quirk_nvidia_shutdown, - }, /* FIXME for some of the early AMD 760 southbridges, OHCI * won't work at all. blacklist them. diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 35e5fd640ce..0795b934d00 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -403,7 +403,6 @@ struct ohci_hcd { #define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */ #define OHCI_QUIRK_AMD_PLL 0x200 /* AMD PLL quirk*/ #define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */ -#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */ // there are also chip quirks/bugs in init logic struct work_struct nec_work; /* Worker for NEC quirk */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 27a3dec32fa..caf87428ca4 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -37,6 +37,7 @@ #define OHCI_INTRENABLE 0x10 #define OHCI_INTRDISABLE 0x14 #define OHCI_FMINTERVAL 0x34 +#define OHCI_HCFS (3 << 6) /* hc functional state */ #define OHCI_HCR (1 << 0) /* host controller reset */ #define OHCI_OCR (1 << 3) /* ownership change request */ #define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ @@ -466,6 +467,8 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) { void __iomem *base; u32 control; + u32 fminterval; + int cnt; if (!mmio_resource_enabled(pdev, 0)) return; @@ -498,41 +501,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev) } #endif - /* reset controller, preserving RWC (and possibly IR) */ - writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); - readl(base + OHCI_CONTROL); + /* disable interrupts */ + writel((u32) ~0, base + OHCI_INTRDISABLE); - /* Some NVIDIA controllers stop working if kept in RESET for too long */ - if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { - u32 fminterval; - int cnt; + /* Reset the USB bus, if the controller isn't already in RESET */ + if (control & OHCI_HCFS) { + /* Go into RESET, preserving RWC (and possibly IR) */ + writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL); + readl(base + OHCI_CONTROL); - /* drive reset for at least 50 ms (7.1.7.5) */ + /* drive bus reset for at least 50 ms (7.1.7.5) */ msleep(50); + } - /* software reset of the controller, preserving HcFmInterval */ - fminterval = readl(base + OHCI_FMINTERVAL); - writel(OHCI_HCR, base + OHCI_CMDSTATUS); + /* software reset of the controller, preserving HcFmInterval */ + fminterval = readl(base + OHCI_FMINTERVAL); + writel(OHCI_HCR, base + OHCI_CMDSTATUS); - /* reset requires max 10 us delay */ - for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ - if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) - break; - udelay(1); - } - writel(fminterval, base + OHCI_FMINTERVAL); - - /* Now we're in the SUSPEND state with all devices reset - * and wakeups and interrupts disabled - */ + /* reset requires max 10 us delay */ + for (cnt = 30; cnt > 0; --cnt) { /* ... allow extra time */ + if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0) + break; + udelay(1); } + writel(fminterval, base + OHCI_FMINTERVAL); - /* - * disable interrupts - */ - writel(~(u32)0, base + OHCI_INTRDISABLE); - writel(~(u32)0, base + OHCI_INTRSTATUS); - + /* Now the controller is safely in SUSPEND and nothing can wake it up */ iounmap(base); } @@ -627,7 +621,7 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) void __iomem *base, *op_reg_base; u32 hcc_params, cap, val; u8 offset, cap_length; - int wait_time, delta, count = 256/4; + int wait_time, count = 256/4; if (!mmio_resource_enabled(pdev, 0)) return; @@ -673,11 +667,10 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev) writel(val, op_reg_base + EHCI_USBCMD); wait_time = 2000; - delta = 100; do { writel(0x3f, op_reg_base + EHCI_USBSTS); - udelay(delta); - wait_time -= delta; + udelay(100); + wait_time -= 100; val = readl(op_reg_base + EHCI_USBSTS); if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) { break; diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index d6e17542861..a403b53e86b 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c @@ -124,7 +124,7 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) { qset->td_start = qset->td_end = qset->ntds = 0; - qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); + qset->qh.link = cpu_to_le64(QH_LINK_NTDS(8) | QH_LINK_T); qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; qset->qh.err_count = 0; qset->qh.scratch[0] = 0; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 42a22b8e692..0e4b25fa3bc 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -982,7 +982,6 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud struct xhci_virt_device *dev; struct xhci_ep_ctx *ep0_ctx; struct xhci_slot_ctx *slot_ctx; - struct xhci_input_control_ctx *ctrl_ctx; u32 port_num; struct usb_device *top_dev; @@ -994,12 +993,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud return -EINVAL; } ep0_ctx = xhci_get_ep_ctx(xhci, dev->in_ctx, 0); - ctrl_ctx = xhci_get_input_control_ctx(xhci, dev->in_ctx); slot_ctx = xhci_get_slot_ctx(xhci, dev->in_ctx); - /* 2) New slot context and endpoint 0 context are valid*/ - ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); - /* 3) Only the control endpoint is valid - one endpoint context */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route); switch (udev->speed) { diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 940321b3ec6..9f1d4b15d81 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -816,23 +816,24 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) struct xhci_ring *ring; struct xhci_td *cur_td; int ret, i, j; + unsigned long flags; ep = (struct xhci_virt_ep *) arg; xhci = ep->xhci; - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); ep->stop_cmds_pending--; if (xhci->xhc_state & XHCI_STATE_DYING) { xhci_dbg(xhci, "Stop EP timer ran, but another timer marked " "xHCI as DYING, exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { xhci_dbg(xhci, "Stop EP timer ran, but no command pending, " "exiting.\n"); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); return; } @@ -844,11 +845,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) xhci->xhc_state |= XHCI_STATE_DYING; /* Disable interrupts from the host controller and start halting it */ xhci_quiesce(xhci); - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); ret = xhci_halt(xhci); - spin_lock(&xhci->lock); + spin_lock_irqsave(&xhci->lock, flags); if (ret < 0) { /* This is bad; the host is not responding to commands and it's * not allowing itself to be halted. At least interrupts are @@ -896,7 +897,7 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) } } } - spin_unlock(&xhci->lock); + spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg(xhci, "Calling usb_hc_died()\n"); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); xhci_dbg(xhci, "xHCI host controller is dead.\n"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1ff95a0df57..a1afb7c39f7 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -711,7 +711,10 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) ring = xhci->cmd_ring; seg = ring->deq_seg; do { - memset(seg->trbs, 0, SEGMENT_SIZE); + memset(seg->trbs, 0, + sizeof(union xhci_trb) * (TRBS_PER_SEGMENT - 1)); + seg->trbs[TRBS_PER_SEGMENT - 1].link.control &= + cpu_to_le32(~TRB_CYCLE); seg = seg->next; } while (seg != ring->deq_seg); @@ -799,7 +802,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) u32 command, temp = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); struct usb_hcd *secondary_hcd; - int retval; + int retval = 0; /* Wait a bit if either of the roothubs need to settle from the * transition into bus suspend. @@ -809,6 +812,9 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) xhci->bus_state[1].next_statechange)) msleep(100); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); + spin_lock_irq(&xhci->lock); if (xhci->quirks & XHCI_RESET_ON_RESUME) hibernated = true; @@ -878,20 +884,13 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) return retval; xhci_dbg(xhci, "Start the primary HCD\n"); retval = xhci_run(hcd->primary_hcd); - if (retval) - goto failed_restart; - - xhci_dbg(xhci, "Start the secondary HCD\n"); - retval = xhci_run(secondary_hcd); if (!retval) { - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, - &xhci->shared_hcd->flags); + xhci_dbg(xhci, "Start the secondary HCD\n"); + retval = xhci_run(secondary_hcd); } -failed_restart: hcd->state = HC_STATE_SUSPENDED; xhci->shared_hcd->state = HC_STATE_SUSPENDED; - return retval; + goto done; } /* step 4: set Run/Stop bit */ @@ -910,11 +909,14 @@ failed_restart: * Running endpoints by ringing their doorbells */ - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - set_bit(HCD_FLAG_HW_ACCESSIBLE, &xhci->shared_hcd->flags); - spin_unlock_irq(&xhci->lock); - return 0; + + done: + if (retval == 0) { + usb_hcd_resume_root_hub(hcd); + usb_hcd_resume_root_hub(xhci->shared_hcd); + } + return retval; } #endif /* CONFIG_PM */ @@ -3504,6 +3506,10 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) /* Otherwise, update the control endpoint ring enqueue pointer. */ else xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev); + ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); + ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG); + ctrl_ctx->drop_flags = 0; + xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id); xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2); @@ -3585,7 +3591,6 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) virt_dev->address = (le32_to_cpu(slot_ctx->dev_state) & DEV_ADDR_MASK) + 1; /* Zero the input context control for later use */ - ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx); ctrl_ctx->add_flags = 0; ctrl_ctx->drop_flags = 0; diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index fc34b8b1191..07a03460a59 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -11,6 +11,7 @@ config USB_MUSB_HDRC select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS + select USB_GADGET_DUALSPEED tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' help Say Y here if your system has a dual role high speed USB @@ -60,7 +61,7 @@ config USB_MUSB_BLACKFIN config USB_MUSB_UX500 tristate "U8500 and U5500" - depends on (ARCH_U8500 && AB8500_USB) || (ARCH_U5500) + depends on (ARCH_U8500 && AB8500_USB) endchoice diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 08f1d0b662a..e233d2b7d33 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -27,6 +27,7 @@ */ #include <linux/init.h> +#include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/platform_device.h> diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index 4da7492ddbd..2613bfdb09b 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -27,6 +27,7 @@ */ #include <linux/init.h> +#include <linux/module.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/platform_device.h> diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 20a28731c33..b63ab157010 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1477,8 +1477,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb) /*-------------------------------------------------------------------------*/ #if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \ - defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) || \ - defined(CONFIG_ARCH_U5500) + defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500) static irqreturn_t generic_interrupt(int irq, void *__hci) { @@ -2302,18 +2301,12 @@ static int musb_suspend(struct device *dev) */ } - musb_save_context(musb); - spin_unlock_irqrestore(&musb->lock, flags); return 0; } static int musb_resume_noirq(struct device *dev) { - struct musb *musb = dev_to_musb(dev); - - musb_restore_context(musb); - /* for static cmos like DaVinci, register values were preserved * unless for some reason the whole soc powered down or the USB * module got reset through the PSC (vs just being disabled). diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index ae4a20acef6..922148ff8d2 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1903,7 +1903,7 @@ static int musb_gadget_start(struct usb_gadget *g, unsigned long flags; int retval = -EINVAL; - if (driver->speed != USB_SPEED_HIGH) + if (driver->speed < USB_SPEED_HIGH) goto err0; pm_runtime_get_sync(musb->controller); @@ -1999,10 +1999,6 @@ static void stop_activity(struct musb *musb, struct usb_gadget_driver *driver) nuke(&hw_ep->ep_out, -ESHUTDOWN); } } - - spin_unlock(&musb->lock); - driver->disconnect(&musb->g); - spin_lock(&musb->lock); } } diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 60ddba8066e..79cb0af779f 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -774,6 +774,10 @@ static void musb_ep_program(struct musb *musb, u8 epnum, if (musb->double_buffer_not_ok) musb_writew(epio, MUSB_TXMAXP, hw_ep->max_packet_sz_tx); + else if (can_bulk_split(musb, qh->type)) + musb_writew(epio, MUSB_TXMAXP, packet_sz + | ((hw_ep->max_packet_sz_tx / + packet_sz) - 1) << 11); else musb_writew(epio, MUSB_TXMAXP, qh->maxpacket | diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index d2e2efaba65..08c679c0dde 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -405,7 +405,7 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) /* * platform functions */ -static int __devinit usbhs_probe(struct platform_device *pdev) +static int usbhs_probe(struct platform_device *pdev) { struct renesas_usbhs_platform_info *info = pdev->dev.platform_data; struct renesas_usbhs_driver_callback *dfunc; diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 8da685e796d..ffdf5d15085 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -820,7 +820,7 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done) if (len % 4) /* 32bit alignment */ goto usbhsf_pio_prepare_push; - if ((*(u32 *) pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ + if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ goto usbhsf_pio_prepare_push; /* get enable DMA fifo */ @@ -897,7 +897,7 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done) if (!fifo) goto usbhsf_pio_prepare_pop; - if ((*(u32 *) pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ + if ((uintptr_t)(pkt->buf + pkt->actual) & 0x7) /* 8byte alignment */ goto usbhsf_pio_prepare_pop; ret = usbhsf_fifo_select(pipe, fifo, 0); diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 053f86d7000..ad96a389672 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -349,7 +349,7 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) if (mod->irq_attch) intenb1 |= ATTCHE; - if (mod->irq_attch) + if (mod->irq_dtch) intenb1 |= DTCHE; if (mod->irq_sign) diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h index 8ae3733031c..6c6875533f0 100644 --- a/drivers/usb/renesas_usbhs/mod.h +++ b/drivers/usb/renesas_usbhs/mod.h @@ -143,8 +143,8 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod); */ #if defined(CONFIG_USB_RENESAS_USBHS_HCD) || \ defined(CONFIG_USB_RENESAS_USBHS_HCD_MODULE) -extern int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv); -extern int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv); +extern int usbhs_mod_host_probe(struct usbhs_priv *priv); +extern int usbhs_mod_host_remove(struct usbhs_priv *priv); #else static inline int usbhs_mod_host_probe(struct usbhs_priv *priv) { @@ -157,8 +157,8 @@ static inline void usbhs_mod_host_remove(struct usbhs_priv *priv) #if defined(CONFIG_USB_RENESAS_USBHS_UDC) || \ defined(CONFIG_USB_RENESAS_USBHS_UDC_MODULE) -extern int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv); -extern void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv); +extern int usbhs_mod_gadget_probe(struct usbhs_priv *priv); +extern void usbhs_mod_gadget_remove(struct usbhs_priv *priv); #else static inline int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 4cc7ee0babc..7f4e8033857 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -751,53 +751,32 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); - struct usbhs_priv *priv; - struct device *dev; - int ret; + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); if (!driver || !driver->setup || - driver->speed != USB_SPEED_HIGH) + driver->speed < USB_SPEED_FULL) return -EINVAL; - dev = usbhsg_gpriv_to_dev(gpriv); - priv = usbhsg_gpriv_to_priv(gpriv); - /* first hook up the driver ... */ gpriv->driver = driver; gpriv->gadget.dev.driver = &driver->driver; - ret = device_add(&gpriv->gadget.dev); - if (ret) { - dev_err(dev, "device_add error %d\n", ret); - goto add_fail; - } - return usbhsg_try_start(priv, USBHSG_STATUS_REGISTERD); - -add_fail: - gpriv->driver = NULL; - gpriv->gadget.dev.driver = NULL; - - return ret; } static int usbhsg_gadget_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); - struct usbhs_priv *priv; - struct device *dev; + struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv); if (!driver || !driver->unbind) return -EINVAL; - dev = usbhsg_gpriv_to_dev(gpriv); - priv = usbhsg_gpriv_to_priv(gpriv); - usbhsg_try_stop(priv, USBHSG_STATUS_REGISTERD); - device_del(&gpriv->gadget.dev); + gpriv->gadget.dev.driver = NULL; gpriv->driver = NULL; return 0; @@ -827,10 +806,17 @@ static int usbhsg_start(struct usbhs_priv *priv) static int usbhsg_stop(struct usbhs_priv *priv) { + struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); + + /* cable disconnect */ + if (gpriv->driver && + gpriv->driver->disconnect) + gpriv->driver->disconnect(&gpriv->gadget); + return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED); } -int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) +int usbhs_mod_gadget_probe(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv; struct usbhsg_uep *uep; @@ -876,12 +862,14 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) /* * init gadget */ - device_initialize(&gpriv->gadget.dev); dev_set_name(&gpriv->gadget.dev, "gadget"); gpriv->gadget.dev.parent = dev; gpriv->gadget.name = "renesas_usbhs_udc"; gpriv->gadget.ops = &usbhsg_gadget_ops; gpriv->gadget.is_dualspeed = 1; + ret = device_register(&gpriv->gadget.dev); + if (ret < 0) + goto err_add_udc; INIT_LIST_HEAD(&gpriv->gadget.ep_list); @@ -912,12 +900,15 @@ int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv) ret = usb_add_gadget_udc(dev, &gpriv->gadget); if (ret) - goto err_add_udc; + goto err_register; dev_info(dev, "gadget probed\n"); return 0; + +err_register: + device_unregister(&gpriv->gadget.dev); err_add_udc: kfree(gpriv->uep); @@ -927,12 +918,14 @@ usbhs_mod_gadget_probe_err_gpriv: return ret; } -void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv) +void usbhs_mod_gadget_remove(struct usbhs_priv *priv) { struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); usb_del_gadget_udc(&gpriv->gadget); + device_unregister(&gpriv->gadget.dev); + usbhsg_controller_unregister(gpriv); kfree(gpriv->uep); diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 1a7208a50af..7955de58995 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -103,7 +103,7 @@ struct usbhsh_hpriv { u32 port_stat; /* USB_PORT_STAT_xxx */ - struct completion *done; + struct completion setup_ack_done; /* see usbhsh_req_alloc/free */ struct list_head ureq_link_active; @@ -355,6 +355,7 @@ static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, struct usbhsh_device *udev, struct usb_host_endpoint *ep, + int dir_in_req, gfp_t mem_flags) { struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); @@ -364,27 +365,38 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, struct usbhs_pipe *pipe, *best_pipe; struct device *dev = usbhsh_hcd_to_dev(hcd); struct usb_endpoint_descriptor *desc = &ep->desc; - int type, i; + int type, i, dir_in; unsigned int min_usr; + dir_in_req = !!dir_in_req; + uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); if (!uep) { dev_err(dev, "usbhsh_ep alloc fail\n"); return NULL; } - type = usb_endpoint_type(desc); + + if (usb_endpoint_xfer_control(desc)) { + best_pipe = usbhsh_hpriv_to_dcp(hpriv); + goto usbhsh_endpoint_alloc_find_pipe; + } /* * find best pipe for endpoint * see * HARDWARE LIMITATION */ + type = usb_endpoint_type(desc); min_usr = ~0; best_pipe = NULL; - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { + usbhs_for_each_pipe(pipe, priv, i) { if (!usbhs_pipe_type_is(pipe, type)) continue; + dir_in = !!usbhs_pipe_is_dir_in(pipe); + if (0 != (dir_in - dir_in_req)) + continue; + info = usbhsh_pipe_info(pipe); if (min_usr > info->usr_cnt) { @@ -398,7 +410,7 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, kfree(uep); return NULL; } - +usbhsh_endpoint_alloc_find_pipe: /* * init uep */ @@ -423,6 +435,7 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, * see * DCPMAXP/PIPEMAXP */ + usbhs_pipe_sequence_data0(uep->pipe); usbhs_pipe_config_update(uep->pipe, usbhsh_device_number(hpriv, udev), usb_endpoint_num(desc), @@ -430,7 +443,7 @@ struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, usbhsh_device_number(hpriv, udev), - usbhs_pipe_name(pipe), uep); + usbhs_pipe_name(uep->pipe), uep); return uep; } @@ -549,8 +562,7 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, * usbhsh_irq_setup_ack() * usbhsh_irq_setup_err() */ - DECLARE_COMPLETION(done); - hpriv->done = &done; + init_completion(&hpriv->setup_ack_done); /* copy original request */ memcpy(&req, urb->setup_packet, sizeof(struct usb_ctrlrequest)); @@ -572,8 +584,7 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, /* * wait setup packet ACK */ - wait_for_completion(&done); - hpriv->done = NULL; + wait_for_completion(&hpriv->setup_ack_done); dev_dbg(dev, "%s done\n", __func__); } @@ -724,11 +735,11 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, struct usbhsh_device *udev, *new_udev = NULL; struct usbhs_pipe *pipe; struct usbhsh_ep *uep; + int is_dir_in = usb_pipein(urb->pipe); int ret; - dev_dbg(dev, "%s (%s)\n", - __func__, usb_pipein(urb->pipe) ? "in" : "out"); + dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out"); ret = usb_hcd_link_urb_to_ep(hcd, urb); if (ret) @@ -751,7 +762,8 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd, */ uep = usbhsh_ep_to_uep(ep); if (!uep) { - uep = usbhsh_endpoint_alloc(hpriv, udev, ep, mem_flags); + uep = usbhsh_endpoint_alloc(hpriv, udev, ep, + is_dir_in, mem_flags); if (!uep) goto usbhsh_urb_enqueue_error_free_device; } @@ -1095,10 +1107,7 @@ static int usbhsh_irq_setup_ack(struct usbhs_priv *priv, dev_dbg(dev, "setup packet OK\n"); - if (unlikely(!hpriv->done)) - dev_err(dev, "setup ack happen without necessary data\n"); - else - complete(hpriv->done); /* see usbhsh_urb_enqueue() */ + complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ return 0; } @@ -1111,10 +1120,7 @@ static int usbhsh_irq_setup_err(struct usbhs_priv *priv, dev_dbg(dev, "setup packet Err\n"); - if (unlikely(!hpriv->done)) - dev_err(dev, "setup err happen without necessary data\n"); - else - complete(hpriv->done); /* see usbhsh_urb_enqueue() */ + complete(&hpriv->setup_ack_done); /* see usbhsh_urb_enqueue() */ return 0; } @@ -1221,8 +1227,18 @@ static int usbhsh_stop(struct usbhs_priv *priv) { struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); + struct usbhs_mod *mod = usbhs_mod_get_current(priv); struct device *dev = usbhs_priv_to_dev(priv); + /* + * disable irq callback + */ + mod->irq_attch = NULL; + mod->irq_dtch = NULL; + mod->irq_sack = NULL; + mod->irq_sign = NULL; + usbhs_irq_callback_update(priv, mod); + usb_remove_hcd(hcd); /* disable sys */ @@ -1235,7 +1251,7 @@ static int usbhsh_stop(struct usbhs_priv *priv) return 0; } -int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv) +int usbhs_mod_host_probe(struct usbhs_priv *priv) { struct usbhsh_hpriv *hpriv; struct usb_hcd *hcd; @@ -1251,6 +1267,7 @@ int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv) dev_err(dev, "Failed to create hcd\n"); return -ENOMEM; } + hcd->has_tt = 1; /* for low/full speed */ pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL); if (!pipe_info) { @@ -1279,7 +1296,6 @@ int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv) hpriv->mod.stop = usbhsh_stop; hpriv->pipe_info = pipe_info; hpriv->pipe_size = pipe_size; - hpriv->done = NULL; usbhsh_req_list_init(hpriv); usbhsh_port_stat_init(hpriv); @@ -1299,7 +1315,7 @@ usbhs_mod_host_probe_err: return -ENOMEM; } -int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv) +int usbhs_mod_host_remove(struct usbhs_priv *priv) { struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 5cdb9d91227..18e875b92e0 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -42,7 +42,7 @@ static int debug; * Version information */ -#define DRIVER_VERSION "v0.6" +#define DRIVER_VERSION "v0.7" #define DRIVER_AUTHOR "Bart Hartgers <bart.hartgers+ark3116@gmail.com>" #define DRIVER_DESC "USB ARK3116 serial/IrDA driver" #define DRIVER_DEV_DESC "ARK3116 RS232/IrDA" @@ -380,10 +380,6 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) goto err_out; } - /* setup termios */ - if (tty) - ark3116_set_termios(tty, port, NULL); - /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); @@ -406,6 +402,10 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) /* enable DMA */ ark3116_write_reg(port->serial, UART_FCR, UART_FCR_DMA_SELECT); + /* setup termios */ + if (tty) + ark3116_set_termios(tty, port, NULL); + err_out: kfree(buf); return result; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 8fe034d2d3e..ff3db5d056a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -736,6 +736,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(TML_VID, TML_USB_SERIAL_PID) }, { USB_DEVICE(FTDI_VID, FTDI_ELSTER_UNICOM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_PROPOX_JTAGCABLEII_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_PROPOX_ISPCABLEIII_PID) }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(OLIMEX_VID, OLIMEX_ARM_USB_OCD_H_PID), @@ -2104,13 +2105,19 @@ static void ftdi_set_termios(struct tty_struct *tty, cflag = termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to - compare old_termios and tty->termios */ + if (old_termios->c_cflag == termios->c_cflag + && old_termios->c_ispeed == termios->c_ispeed + && old_termios->c_ospeed == termios->c_ospeed) + goto no_c_cflag_changes; + /* NOTE These routines can get interrupted by ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ + if ((old_termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)) == + (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB))) + goto no_data_parity_stop_changes; + /* Set number of data bits, parity, stop bits */ urb_value = 0; @@ -2151,6 +2158,7 @@ static void ftdi_set_termios(struct tty_struct *tty, } /* Now do the baudrate */ +no_data_parity_stop_changes: if ((cflag & CBAUD) == B0) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -2178,6 +2186,7 @@ static void ftdi_set_termios(struct tty_struct *tty, /* Set flow control */ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ +no_c_cflag_changes: if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __func__); if (usb_control_msg(dev, diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 571fa96b49c..055b64ef0bb 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -112,6 +112,7 @@ /* Propox devices */ #define FTDI_PROPOX_JTAGCABLEII_PID 0xD738 +#define FTDI_PROPOX_ISPCABLEIII_PID 0xD739 /* Lenz LI-USB Computer Interface. */ #define FTDI_LENZ_LIUSB_PID 0xD780 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 89ae1f65e1b..6dd64534fad 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -156,6 +156,7 @@ static void option_instat_callback(struct urb *urb); #define HUAWEI_PRODUCT_K4511 0x14CC #define HUAWEI_PRODUCT_ETS1220 0x1803 #define HUAWEI_PRODUCT_E353 0x1506 +#define HUAWEI_PRODUCT_E173S 0x1C05 #define QUANTA_VENDOR_ID 0x0408 #define QUANTA_PRODUCT_Q101 0xEA02 @@ -316,6 +317,9 @@ static void option_instat_callback(struct urb *urb); #define ZTE_PRODUCT_AC8710 0xfff1 #define ZTE_PRODUCT_AC2726 0xfff5 #define ZTE_PRODUCT_AC8710T 0xffff +#define ZTE_PRODUCT_MC2718 0xffe8 +#define ZTE_PRODUCT_AD3812 0xffeb +#define ZTE_PRODUCT_MC2716 0xffed #define BENQ_VENDOR_ID 0x04a5 #define BENQ_PRODUCT_H10 0x4068 @@ -468,6 +472,10 @@ static void option_instat_callback(struct urb *urb); #define YUGA_PRODUCT_CLU528 0x260D #define YUGA_PRODUCT_CLU526 0x260F +/* Viettel products */ +#define VIETTEL_VENDOR_ID 0x2262 +#define VIETTEL_PRODUCT_VT1000 0x0002 + /* some devices interfaces need special handling due to a number of reasons */ enum option_blacklist_reason { OPTION_BLACKLIST_NONE = 0, @@ -500,6 +508,18 @@ static const struct option_blacklist_info zte_k3765_z_blacklist = { .reserved = BIT(4), }; +static const struct option_blacklist_info zte_ad3812_z_blacklist = { + .sendsetup = BIT(0) | BIT(1) | BIT(2), +}; + +static const struct option_blacklist_info zte_mc2718_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3) | BIT(4), +}; + +static const struct option_blacklist_info zte_mc2716_z_blacklist = { + .sendsetup = BIT(1) | BIT(2) | BIT(3), +}; + static const struct option_blacklist_info huawei_cdc12_blacklist = { .reserved = BIT(1) | BIT(2), }; @@ -622,6 +642,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E173S, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4505, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t) &huawei_cdc12_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K3765, 0xff, 0xff, 0xff), @@ -640,6 +661,14 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x31) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_K4511, 0xff, 0x01, 0x32) }, { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x01) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x02) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x03) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x10) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x12) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x01, 0x13) }, + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x01) }, /* E398 3G Modem */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x02) }, /* E398 3G PC UI Interface */ + { USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E353, 0xff, 0x02, 0x03) }, /* E398 3G Application Interface */ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V740) }, @@ -726,6 +755,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_PRODUCT_KPC680) }, { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6000)}, /* ZTE AC8700 */ { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x6613)}, /* Onda H600/ZTE MF330 */ + { USB_DEVICE(QUALCOMM_VENDOR_ID, 0x9000)}, /* SIMCom SIM5218 */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6280) }, /* BP3-USB & BP3-EXT HSDPA */ { USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) }, { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) }, @@ -1043,6 +1073,12 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC2726, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AC8710T, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2718, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2718_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_AD3812, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_ad3812_z_blacklist }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MC2716, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&zte_mc2716_z_blacklist }, { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) }, { USB_DEVICE(DLINK_VENDOR_ID, DLINK_PRODUCT_DWM_652) }, { USB_DEVICE(ALINK_VENDOR_ID, DLINK_PRODUCT_DWM_652_U5) }, /* Yes, ALINK_VENDOR_ID */ @@ -1141,6 +1177,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU516) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) }, { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) }, + { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 9083d1e616b..fc2d66f7f4e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -91,7 +91,6 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_QN3USB_PRODUCT_ID) }, { USB_DEVICE(SANWA_VENDOR_ID, SANWA_PRODUCT_ID) }, { USB_DEVICE(ADLINK_VENDOR_ID, ADLINK_ND6530_PRODUCT_ID) }, - { USB_DEVICE(WINCHIPHEAD_VENDOR_ID, WINCHIPHEAD_USBSER_PRODUCT_ID) }, { USB_DEVICE(SMART_VENDOR_ID, SMART_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 3d10d7f0207..c38b8c00c06 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -145,10 +145,6 @@ #define ADLINK_VENDOR_ID 0x0b63 #define ADLINK_ND6530_PRODUCT_ID 0x6530 -/* WinChipHead USB->RS 232 adapter */ -#define WINCHIPHEAD_VENDOR_ID 0x4348 -#define WINCHIPHEAD_USBSER_PRODUCT_ID 0x5523 - /* SMART USB Serial Adapter */ #define SMART_VENDOR_ID 0x0b8c #define SMART_PRODUCT_ID 0x2303 diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 4dca3ef0668..9fbe742343c 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1762,10 +1762,9 @@ static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); } else { void *buf; - int offset; + int offset = 0; u16 PhyBlockAddr; u8 PageNum; - u32 result; u16 len, oldphy, newphy; buf = kmalloc(blenByte, GFP_KERNEL); diff --git a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c index 93c1a4d86f5..82dd834709c 100644 --- a/drivers/usb/storage/protocol.c +++ b/drivers/usb/storage/protocol.c @@ -59,7 +59,9 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) { - /* Pad the SCSI command with zeros out to 12 bytes + /* + * Pad the SCSI command with zeros out to 12 bytes. If the + * command already is 12 bytes or longer, leave it alone. * * NOTE: This only works because a scsi_cmnd struct field contains * a unsigned char cmnd[16], so we know we have storage available @@ -67,9 +69,6 @@ void usb_stor_pad12_command(struct scsi_cmnd *srb, struct us_data *us) for (; srb->cmd_len<12; srb->cmd_len++) srb->cmnd[srb->cmd_len] = 0; - /* set command length to 12 bytes */ - srb->cmd_len = 12; - /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 3041a974faf..24caba79d72 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1854,6 +1854,13 @@ UNUSUAL_DEV( 0x1370, 0x6828, 0x0110, 0x0110, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Qinglin Ye <yestyle@gmail.com> */ +UNUSUAL_DEV( 0x13fe, 0x3600, 0x0100, 0x0100, + "Kingston", + "DT 101 G2", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG ), + /* Reported by Francesco Foresti <frafore@tiscali.it> */ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201, "Super Top", diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 55f91d9ab00..29577bf1f55 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c @@ -116,6 +116,7 @@ /* Clock registers available only on Version 2 */ #define LCD_CLK_ENABLE_REG 0x6c #define LCD_CLK_RESET_REG 0x70 +#define LCD_CLK_MAIN_RESET BIT(3) #define LCD_NUM_BUFFERS 2 @@ -244,6 +245,10 @@ static inline void lcd_enable_raster(void) { u32 reg; + /* Bring LCDC out of reset */ + if (lcd_revision == LCD_VERSION_2) + lcdc_write(0, LCD_CLK_RESET_REG); + reg = lcdc_read(LCD_RASTER_CTRL_REG); if (!(reg & LCD_RASTER_ENABLE)) lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); @@ -257,6 +262,10 @@ static inline void lcd_disable_raster(void) reg = lcdc_read(LCD_RASTER_CTRL_REG); if (reg & LCD_RASTER_ENABLE) lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); + + if (lcd_revision == LCD_VERSION_2) + /* Write 1 to reset LCDC */ + lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG); } static void lcd_blit(int load_mode, struct da8xx_fb_par *par) @@ -584,8 +593,12 @@ static void lcd_reset(struct da8xx_fb_par *par) lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG); - if (lcd_revision == LCD_VERSION_2) + if (lcd_revision == LCD_VERSION_2) { lcdc_write(0, LCD_INT_ENABLE_SET_REG); + /* Write 1 to reset */ + lcdc_write(LCD_CLK_MAIN_RESET, LCD_CLK_RESET_REG); + lcdc_write(0, LCD_CLK_RESET_REG); + } } static void lcd_calc_clk_divider(struct da8xx_fb_par *par) diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c index 0ccd7adf47b..6f61e781f15 100644 --- a/drivers/video/omap/dispc.c +++ b/drivers/video/omap/dispc.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include <linux/kernel.h> +#include <linux/module.h> #include <linux/dma-mapping.h> #include <linux/mm.h> #include <linux/vmalloc.h> diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 3532782551c..5c81533eaca 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -1720,12 +1720,11 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); unsigned long fclk = 0; - if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { - if (width != out_width || height != out_height) - return -EINVAL; - else - return 0; - } + if (width == out_width && height == out_height) + return 0; + + if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) + return -EINVAL; if (out_width < width / maxdownscale || out_width > width * 8) diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 3262f0f1fa3..c56378c555b 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c @@ -269,7 +269,7 @@ static void update_hdmi_timings(struct hdmi_config *cfg, unsigned long hdmi_get_pixel_clock(void) { /* HDMI Pixel Clock in Mhz */ - return hdmi.ip_data.cfg.timings.timings.pixel_clock * 10000; + return hdmi.ip_data.cfg.timings.timings.pixel_clock * 1000; } static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, diff --git a/drivers/video/via/share.h b/drivers/video/via/share.h index 69d882cbe70..c01c1c16272 100644 --- a/drivers/video/via/share.h +++ b/drivers/video/via/share.h @@ -559,8 +559,8 @@ #define M1200X720_R60_VSP POSITIVE /* 1200x900@60 Sync Polarity (DCON) */ -#define M1200X900_R60_HSP NEGATIVE -#define M1200X900_R60_VSP NEGATIVE +#define M1200X900_R60_HSP POSITIVE +#define M1200X900_R60_VSP POSITIVE /* 1280x600@60 Sync Polarity (GTF Mode) */ #define M1280x600_R60_HSP NEGATIVE diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 816ed08e7cf..1a61939b85f 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -37,7 +37,7 @@ config VIRTIO_BALLOON config VIRTIO_MMIO tristate "Platform bus driver for memory mapped virtio devices (EXPERIMENTAL)" - depends on EXPERIMENTAL + depends on HAS_IOMEM && EXPERIMENTAL select VIRTIO select VIRTIO_RING ---help--- diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index acc5e43c373..7317dc2ec42 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -118,7 +118,7 @@ static void vm_finalize_features(struct virtio_device *vdev) vring_transport_features(vdev); for (i = 0; i < ARRAY_SIZE(vdev->features); i++) { - writel(i, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SET); + writel(i, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL); writel(vdev->features[i], vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES); } diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index 79a31e5b4b6..03d1984bd36 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c @@ -169,11 +169,29 @@ static void vp_set_status(struct virtio_device *vdev, u8 status) iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS); } +/* wait for pending irq handlers */ +static void vp_synchronize_vectors(struct virtio_device *vdev) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + int i; + + if (vp_dev->intx_enabled) + synchronize_irq(vp_dev->pci_dev->irq); + + for (i = 0; i < vp_dev->msix_vectors; ++i) + synchronize_irq(vp_dev->msix_entries[i].vector); +} + static void vp_reset(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); /* 0 status means a reset. */ iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS); + /* Flush out the status write, and flush in device writes, + * including MSi-X interrupts, if any. */ + ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS); + /* Flush pending VQ/configuration callbacks. */ + vp_synchronize_vectors(vdev); } /* the notify function used when creating a virt queue */ @@ -594,11 +612,11 @@ static struct virtio_config_ops virtio_pci_config_ops = { static void virtio_pci_release_dev(struct device *_d) { - struct virtio_device *dev = container_of(_d, struct virtio_device, - dev); - struct virtio_pci_device *vp_dev = to_vp_device(dev); - - kfree(vp_dev); + /* + * No need for a release method as we allocate/free + * all devices together with the pci devices. + * Provide an empty one to avoid getting a warning from core. + */ } /* the PCI probing function */ @@ -686,6 +704,7 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) pci_iounmap(pci_dev, vp_dev->ioaddr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); + kfree(vp_dev); } #ifdef CONFIG_PM diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 6285867a935..79fd606b7cd 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -314,13 +314,6 @@ config NUC900_WATCHDOG To compile this driver as a module, choose M here: the module will be called nuc900_wdt. -config ADX_WATCHDOG - tristate "Avionic Design Xanthos watchdog" - depends on ARCH_PXA_ADX - help - Say Y here if you want support for the watchdog timer on Avionic - Design Xanthos boards. - config TS72XX_WATCHDOG tristate "TS-72XX SBC Watchdog" depends on MACH_TS72XX diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 55bd5740e91..fe893e91935 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -51,7 +51,6 @@ obj-$(CONFIG_ORION_WATCHDOG) += orion_wdt.o obj-$(CONFIG_COH901327_WATCHDOG) += coh901327_wdt.o obj-$(CONFIG_STMP3XXX_WATCHDOG) += stmp3xxx_wdt.o obj-$(CONFIG_NUC900_WATCHDOG) += nuc900_wdt.o -obj-$(CONFIG_ADX_WATCHDOG) += adx_wdt.o obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o diff --git a/drivers/watchdog/adx_wdt.c b/drivers/watchdog/adx_wdt.c deleted file mode 100644 index af6e6b16475..00000000000 --- a/drivers/watchdog/adx_wdt.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (C) 2008-2009 Avionic Design GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include <linux/fs.h> -#include <linux/gfp.h> -#include <linux/io.h> -#include <linux/miscdevice.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/types.h> -#include <linux/uaccess.h> -#include <linux/watchdog.h> - -#define WATCHDOG_NAME "adx-wdt" - -/* register offsets */ -#define ADX_WDT_CONTROL 0x00 -#define ADX_WDT_CONTROL_ENABLE (1 << 0) -#define ADX_WDT_CONTROL_nRESET (1 << 1) -#define ADX_WDT_TIMEOUT 0x08 - -static struct platform_device *adx_wdt_dev; -static unsigned long driver_open; - -#define WDT_STATE_STOP 0 -#define WDT_STATE_START 1 - -struct adx_wdt { - void __iomem *base; - unsigned long timeout; - unsigned int state; - unsigned int wake; - spinlock_t lock; -}; - -static const struct watchdog_info adx_wdt_info = { - .identity = "Avionic Design Xanthos Watchdog", - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, -}; - -static void adx_wdt_start_locked(struct adx_wdt *wdt) -{ - u32 ctrl; - - ctrl = readl(wdt->base + ADX_WDT_CONTROL); - ctrl |= ADX_WDT_CONTROL_ENABLE; - writel(ctrl, wdt->base + ADX_WDT_CONTROL); - wdt->state = WDT_STATE_START; -} - -static void adx_wdt_start(struct adx_wdt *wdt) -{ - unsigned long flags; - - spin_lock_irqsave(&wdt->lock, flags); - adx_wdt_start_locked(wdt); - spin_unlock_irqrestore(&wdt->lock, flags); -} - -static void adx_wdt_stop_locked(struct adx_wdt *wdt) -{ - u32 ctrl; - - ctrl = readl(wdt->base + ADX_WDT_CONTROL); - ctrl &= ~ADX_WDT_CONTROL_ENABLE; - writel(ctrl, wdt->base + ADX_WDT_CONTROL); - wdt->state = WDT_STATE_STOP; -} - -static void adx_wdt_stop(struct adx_wdt *wdt) -{ - unsigned long flags; - - spin_lock_irqsave(&wdt->lock, flags); - adx_wdt_stop_locked(wdt); - spin_unlock_irqrestore(&wdt->lock, flags); -} - -static void adx_wdt_set_timeout(struct adx_wdt *wdt, unsigned long seconds) -{ - unsigned long timeout = seconds * 1000; - unsigned long flags; - unsigned int state; - - spin_lock_irqsave(&wdt->lock, flags); - state = wdt->state; - adx_wdt_stop_locked(wdt); - writel(timeout, wdt->base + ADX_WDT_TIMEOUT); - - if (state == WDT_STATE_START) - adx_wdt_start_locked(wdt); - - wdt->timeout = timeout; - spin_unlock_irqrestore(&wdt->lock, flags); -} - -static void adx_wdt_get_timeout(struct adx_wdt *wdt, unsigned long *seconds) -{ - *seconds = wdt->timeout / 1000; -} - -static void adx_wdt_keepalive(struct adx_wdt *wdt) -{ - unsigned long flags; - - spin_lock_irqsave(&wdt->lock, flags); - writel(wdt->timeout, wdt->base + ADX_WDT_TIMEOUT); - spin_unlock_irqrestore(&wdt->lock, flags); -} - -static int adx_wdt_open(struct inode *inode, struct file *file) -{ - struct adx_wdt *wdt = platform_get_drvdata(adx_wdt_dev); - - if (test_and_set_bit(0, &driver_open)) - return -EBUSY; - - file->private_data = wdt; - adx_wdt_set_timeout(wdt, 30); - adx_wdt_start(wdt); - - return nonseekable_open(inode, file); -} - -static int adx_wdt_release(struct inode *inode, struct file *file) -{ - struct adx_wdt *wdt = file->private_data; - - adx_wdt_stop(wdt); - clear_bit(0, &driver_open); - - return 0; -} - -static long adx_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct adx_wdt *wdt = file->private_data; - void __user *argp = (void __user *)arg; - unsigned long __user *p = argp; - unsigned long seconds = 0; - unsigned int options; - long ret = -EINVAL; - - switch (cmd) { - case WDIOC_GETSUPPORT: - if (copy_to_user(argp, &adx_wdt_info, sizeof(adx_wdt_info))) - return -EFAULT; - else - return 0; - - case WDIOC_GETSTATUS: - case WDIOC_GETBOOTSTATUS: - return put_user(0, p); - - case WDIOC_KEEPALIVE: - adx_wdt_keepalive(wdt); - return 0; - - case WDIOC_SETTIMEOUT: - if (get_user(seconds, p)) - return -EFAULT; - - adx_wdt_set_timeout(wdt, seconds); - - /* fallthrough */ - case WDIOC_GETTIMEOUT: - adx_wdt_get_timeout(wdt, &seconds); - return put_user(seconds, p); - - case WDIOC_SETOPTIONS: - if (copy_from_user(&options, argp, sizeof(options))) - return -EFAULT; - - if (options & WDIOS_DISABLECARD) { - adx_wdt_stop(wdt); - ret = 0; - } - - if (options & WDIOS_ENABLECARD) { - adx_wdt_start(wdt); - ret = 0; - } - - return ret; - - default: - break; - } - - return -ENOTTY; -} - -static ssize_t adx_wdt_write(struct file *file, const char __user *data, - size_t len, loff_t *ppos) -{ - struct adx_wdt *wdt = file->private_data; - - if (len) - adx_wdt_keepalive(wdt); - - return len; -} - -static const struct file_operations adx_wdt_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = adx_wdt_open, - .release = adx_wdt_release, - .unlocked_ioctl = adx_wdt_ioctl, - .write = adx_wdt_write, -}; - -static struct miscdevice adx_wdt_miscdev = { - .minor = WATCHDOG_MINOR, - .name = "watchdog", - .fops = &adx_wdt_fops, -}; - -static int __devinit adx_wdt_probe(struct platform_device *pdev) -{ - struct resource *res; - struct adx_wdt *wdt; - int ret = 0; - u32 ctrl; - - wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); - if (!wdt) { - dev_err(&pdev->dev, "cannot allocate WDT structure\n"); - return -ENOMEM; - } - - spin_lock_init(&wdt->lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "cannot obtain I/O memory region\n"); - return -ENXIO; - } - - res = devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), res->name); - if (!res) { - dev_err(&pdev->dev, "cannot request I/O memory region\n"); - return -ENXIO; - } - - wdt->base = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - if (!wdt->base) { - dev_err(&pdev->dev, "cannot remap I/O memory region\n"); - return -ENXIO; - } - - /* disable watchdog and reboot on timeout */ - ctrl = readl(wdt->base + ADX_WDT_CONTROL); - ctrl &= ~ADX_WDT_CONTROL_ENABLE; - ctrl &= ~ADX_WDT_CONTROL_nRESET; - writel(ctrl, wdt->base + ADX_WDT_CONTROL); - - platform_set_drvdata(pdev, wdt); - adx_wdt_dev = pdev; - - ret = misc_register(&adx_wdt_miscdev); - if (ret) { - dev_err(&pdev->dev, "cannot register miscdev on minor %d " - "(err=%d)\n", WATCHDOG_MINOR, ret); - return ret; - } - - return 0; -} - -static int __devexit adx_wdt_remove(struct platform_device *pdev) -{ - struct adx_wdt *wdt = platform_get_drvdata(pdev); - - misc_deregister(&adx_wdt_miscdev); - adx_wdt_stop(wdt); - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static void adx_wdt_shutdown(struct platform_device *pdev) -{ - struct adx_wdt *wdt = platform_get_drvdata(pdev); - adx_wdt_stop(wdt); -} - -#ifdef CONFIG_PM -static int adx_wdt_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct adx_wdt *wdt = platform_get_drvdata(pdev); - - wdt->wake = (wdt->state == WDT_STATE_START) ? 1 : 0; - adx_wdt_stop(wdt); - - return 0; -} - -static int adx_wdt_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct adx_wdt *wdt = platform_get_drvdata(pdev); - - if (wdt->wake) - adx_wdt_start(wdt); - - return 0; -} - -static const struct dev_pm_ops adx_wdt_pm_ops = { - .suspend = adx_wdt_suspend, - .resume = adx_wdt_resume, -}; - -# define ADX_WDT_PM_OPS (&adx_wdt_pm_ops) -#else -# define ADX_WDT_PM_OPS NULL -#endif - -static struct platform_driver adx_wdt_driver = { - .probe = adx_wdt_probe, - .remove = __devexit_p(adx_wdt_remove), - .shutdown = adx_wdt_shutdown, - .driver = { - .name = WATCHDOG_NAME, - .owner = THIS_MODULE, - .pm = ADX_WDT_PM_OPS, - }, -}; - -static int __init adx_wdt_init(void) -{ - return platform_driver_register(&adx_wdt_driver); -} - -static void __exit adx_wdt_exit(void) -{ - platform_driver_unregister(&adx_wdt_driver); -} - -module_init(adx_wdt_init); -module_exit(adx_wdt_exit); - -MODULE_DESCRIPTION("Avionic Design Xanthos Watchdog Driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index 03f449a430d..5b89f7d6cd0 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -76,8 +76,6 @@ static int irq; static void __iomem *virtbase; static unsigned long coh901327_users; static unsigned long boot_status; -static u16 wdogenablestore; -static u16 irqmaskstore; static struct device *parent; /* @@ -461,6 +459,10 @@ out: } #ifdef CONFIG_PM + +static u16 wdogenablestore; +static u16 irqmaskstore; + static int coh901327_suspend(struct platform_device *pdev, pm_message_t state) { irqmaskstore = readw(virtbase + U300_WDOG_IMR) & 0x0001U; diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 3774c9b8dac..8464ea1c36a 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -231,6 +231,7 @@ static int __devinit cru_detect(unsigned long map_entry, cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; + set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE)); asminline_call(&cmn_regs, bios32_entrypoint); if (cmn_regs.u1.ral != 0) { @@ -248,8 +249,10 @@ static int __devinit cru_detect(unsigned long map_entry, if ((physical_bios_base + physical_bios_offset)) { cru_rom_addr = ioremap(cru_physical_address, cru_length); - if (cru_rom_addr) + if (cru_rom_addr) { + set_memory_x((unsigned long)cru_rom_addr, cru_length); retval = 0; + } } printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n", diff --git a/drivers/watchdog/iTCO_wdt.c b/drivers/watchdog/iTCO_wdt.c index ba6ad662635..99796c5d913 100644 --- a/drivers/watchdog/iTCO_wdt.c +++ b/drivers/watchdog/iTCO_wdt.c @@ -384,10 +384,10 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static int turn_SMI_watchdog_clear_off = 0; +static int turn_SMI_watchdog_clear_off = 1; module_param(turn_SMI_watchdog_clear_off, int, 0); MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, - "Turn off SMI clearing watchdog (default=0)"); + "Turn off SMI clearing watchdog (depends on TCO-version)(default=1)"); /* * Some TCO specific functions @@ -813,7 +813,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev, ret = -EIO; goto out_unmap; } - if (turn_SMI_watchdog_clear_off) { + if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) { /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */ val32 = inl(SMI_EN); val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 5de7e4fa5b8..a79e3840782 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -401,8 +401,8 @@ static int __devinit s3c2410wdt_probe(struct platform_device *pdev) dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n", (wtcon & S3C2410_WTCON_ENABLE) ? "" : "in", - (wtcon & S3C2410_WTCON_RSTEN) ? "" : "dis", - (wtcon & S3C2410_WTCON_INTEN) ? "" : "en"); + (wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis", + (wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis"); return 0; diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index cc2cfbe33b3..bfaf9bb1ee0 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -351,7 +351,7 @@ static int __devexit sp805_wdt_remove(struct amba_device *adev) return 0; } -static struct amba_id sp805_wdt_ids[] __initdata = { +static struct amba_id sp805_wdt_ids[] = { { .id = 0x00141805, .mask = 0x00ffffff, diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 7be38556aed..e789a47db41 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -150,7 +150,7 @@ static int wm831x_wdt_set_timeout(struct watchdog_device *wdt_dev, if (wm831x_wdt_cfgs[i].time == timeout) break; if (i == ARRAY_SIZE(wm831x_wdt_cfgs)) - ret = -EINVAL; + return -EINVAL; ret = wm831x_reg_unlock(wm831x); if (ret == 0) { diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index a767884a6c7..31ab82fda38 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -501,7 +501,7 @@ EXPORT_SYMBOL_GPL(balloon_set_new_target); * alloc_xenballooned_pages - get pages that have been ballooned out * @nr_pages: Number of pages to get * @pages: pages returned - * @highmem: highmem or lowmem pages + * @highmem: allow highmem pages * @return 0 on success, error otherwise */ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) @@ -511,7 +511,7 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem) mutex_lock(&balloon_mutex); while (pgno < nr_pages) { page = balloon_retrieve(highmem); - if (page && PageHighMem(page) == highmem) { + if (page && (highmem || !PageHighMem(page))) { pages[pgno++] = page; } else { enum bp_state st; diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index f6832f46aea..e1c4c6e5b46 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -135,7 +135,7 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op, /* Grant foreign access to the page. */ gref->gref_id = gnttab_grant_foreign_access(op->domid, pfn_to_mfn(page_to_pfn(gref->page)), readonly); - if (gref->gref_id < 0) { + if ((int)gref->gref_id < 0) { rc = gref->gref_id; goto undo; } @@ -280,7 +280,7 @@ static long gntalloc_ioctl_alloc(struct gntalloc_file_private_data *priv, goto out; } - gref_ids = kzalloc(sizeof(gref_ids[0]) * op.count, GFP_TEMPORARY); + gref_ids = kcalloc(op.count, sizeof(gref_ids[0]), GFP_TEMPORARY); if (!gref_ids) { rc = -ENOMEM; goto out; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 39871326afa..afca14d9042 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -114,11 +114,11 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count) if (NULL == add) return NULL; - add->grants = kzalloc(sizeof(add->grants[0]) * count, GFP_KERNEL); - add->map_ops = kzalloc(sizeof(add->map_ops[0]) * count, GFP_KERNEL); - add->unmap_ops = kzalloc(sizeof(add->unmap_ops[0]) * count, GFP_KERNEL); - add->kmap_ops = kzalloc(sizeof(add->kmap_ops[0]) * count, GFP_KERNEL); - add->pages = kzalloc(sizeof(add->pages[0]) * count, GFP_KERNEL); + add->grants = kcalloc(count, sizeof(add->grants[0]), GFP_KERNEL); + add->map_ops = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL); + add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL); + add->kmap_ops = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL); + add->pages = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL); if (NULL == add->grants || NULL == add->map_ops || NULL == add->unmap_ops || diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 8e964b91c44..284798aaf8b 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -166,7 +166,7 @@ retry: /* * Get IO TLB memory from any location. */ - xen_io_tlb_start = alloc_bootmem(bytes); + xen_io_tlb_start = alloc_bootmem_pages(PAGE_ALIGN(bytes)); if (!xen_io_tlb_start) { m = "Cannot allocate Xen-SWIOTLB buffer!\n"; goto error; @@ -179,7 +179,7 @@ retry: bytes, xen_io_tlb_nslabs); if (rc) { - free_bootmem(__pa(xen_io_tlb_start), bytes); + free_bootmem(__pa(xen_io_tlb_start), PAGE_ALIGN(bytes)); m = "Failed to get contiguous memory for DMA from Xen!\n"\ "You either: don't have the permissions, do not have"\ " enough free memory under 4GB, or the hypervisor memory"\ diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index 81c3ce6b8bb..1906125eab4 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -35,6 +35,7 @@ #include <linux/vmalloc.h> #include <linux/export.h> #include <asm/xen/hypervisor.h> +#include <asm/xen/page.h> #include <xen/interface/xen.h> #include <xen/interface/event_channel.h> #include <xen/events.h> @@ -436,19 +437,20 @@ EXPORT_SYMBOL_GPL(xenbus_free_evtchn); int xenbus_map_ring_valloc(struct xenbus_device *dev, int gnt_ref, void **vaddr) { struct gnttab_map_grant_ref op = { - .flags = GNTMAP_host_map, + .flags = GNTMAP_host_map | GNTMAP_contains_pte, .ref = gnt_ref, .dom = dev->otherend_id, }; struct vm_struct *area; + pte_t *pte; *vaddr = NULL; - area = alloc_vm_area(PAGE_SIZE); + area = alloc_vm_area(PAGE_SIZE, &pte); if (!area) return -ENOMEM; - op.host_addr = (unsigned long)area->addr; + op.host_addr = arbitrary_virt_to_machine(pte).maddr; if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1)) BUG(); @@ -527,6 +529,7 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) struct gnttab_unmap_grant_ref op = { .host_addr = (unsigned long)vaddr, }; + unsigned int level; /* It'd be nice if linux/vmalloc.h provided a find_vm_area(void *addr) * method so that we don't have to muck with vmalloc internals here. @@ -548,6 +551,8 @@ int xenbus_unmap_ring_vfree(struct xenbus_device *dev, void *vaddr) } op.handle = (grant_handle_t)area->phys_addr; + op.host_addr = arbitrary_virt_to_machine( + lookup_address((unsigned long)vaddr, &level)).maddr; if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1)) BUG(); diff --git a/drivers/xen/xenbus/xenbus_xs.c b/drivers/xen/xenbus/xenbus_xs.c index b3b8f2f3ad1..ede860f921d 100644 --- a/drivers/xen/xenbus/xenbus_xs.c +++ b/drivers/xen/xenbus/xenbus_xs.c @@ -621,15 +621,6 @@ static struct xenbus_watch *find_watch(const char *token) return NULL; } -static void xs_reset_watches(void) -{ - int err; - - err = xs_error(xs_single(XBT_NIL, XS_RESET_WATCHES, "", NULL)); - if (err && err != -EEXIST) - printk(KERN_WARNING "xs_reset_watches failed: %d\n", err); -} - /* Register callback to watch this node. */ int register_xenbus_watch(struct xenbus_watch *watch) { @@ -906,9 +897,5 @@ int xs_init(void) if (IS_ERR(task)) return PTR_ERR(task); - /* shutdown watches for kexec boot */ - if (xen_hvm_domain()) - xs_reset_watches(); - return 0; } |