diff options
Diffstat (limited to 'drivers')
1289 files changed, 26130 insertions, 16509 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 9ed087853dee..a391bbc48105 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -55,7 +55,7 @@ acpi-$(CONFIG_DEBUG_FS) += debugfs.o acpi-$(CONFIG_ACPI_NUMA) += numa.o acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o acpi-y += acpi_lpat.o -acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o +acpi-$(CONFIG_ACPI_GENERIC_GSI) += irq.o acpi-$(CONFIG_ACPI_WATCHDOG) += acpi_watchdog.o # These are (potentially) separate modules diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index b3842ffc19ba..a15270a806fc 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -212,6 +212,7 @@ static bool __init extlog_get_l1addr(void) } static struct notifier_block extlog_mce_dec = { .notifier_call = extlog_print, + .priority = MCE_PRIO_EXTLOG, }; static int __init extlog_init(void) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 3de3b6b8f0f1..4467a8089ab8 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -165,7 +165,7 @@ static int acpi_processor_errata(void) #ifdef CONFIG_ACPI_HOTPLUG_CPU int __weak acpi_map_cpu(acpi_handle handle, - phys_cpuid_t physid, int *pcpu) + phys_cpuid_t physid, u32 acpi_id, int *pcpu) { return -ENODEV; } @@ -203,7 +203,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr) cpu_maps_update_begin(); cpu_hotplug_begin(); - ret = acpi_map_cpu(pr->handle, pr->phys_id, &pr->id); + ret = acpi_map_cpu(pr->handle, pr->phys_id, pr->acpi_id, &pr->id); if (ret) goto out; diff --git a/drivers/acpi/acpi_watchdog.c b/drivers/acpi/acpi_watchdog.c index 13caebd679f5..8c4e0a18460a 100644 --- a/drivers/acpi/acpi_watchdog.c +++ b/drivers/acpi/acpi_watchdog.c @@ -114,7 +114,7 @@ void __init acpi_watchdog_init(void) pdev = platform_device_register_simple("wdat_wdt", PLATFORM_DEVID_NONE, resources, nresources); if (IS_ERR(pdev)) - pr_err("Failed to create platform device\n"); + pr_err("Device creation failed: %ld\n", PTR_ERR(pdev)); kfree(resources); diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h index 0bd6307e1f3c..b65f2731e9e2 100644 --- a/drivers/acpi/acpica/acapps.h +++ b/drivers/acpi/acpica/acapps.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,26 +51,26 @@ /* Common info for tool signons */ #define ACPICA_NAME "Intel ACPI Component Architecture" -#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2016 Intel Corporation" +#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2017 Intel Corporation" #if ACPI_MACHINE_WIDTH == 64 -#define ACPI_WIDTH "-64" +#define ACPI_WIDTH " (64-bit version)" #elif ACPI_MACHINE_WIDTH == 32 -#define ACPI_WIDTH "-32" +#define ACPI_WIDTH " (32-bit version)" #else #error unknown ACPI_MACHINE_WIDTH -#define ACPI_WIDTH "-??" +#define ACPI_WIDTH " (unknown bit width, not 32 or 64)" #endif /* Macros for signons and file headers */ #define ACPI_COMMON_SIGNON(utility_name) \ - "\n%s\n%s version %8.8X%s\n%s\n\n", \ + "\n%s\n%s version %8.8X\n%s\n\n", \ ACPICA_NAME, \ - utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, \ + utility_name, ((u32) ACPI_CA_VERSION), \ ACPICA_COPYRIGHT #define ACPI_COMMON_HEADER(utility_name, prefix) \ diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h index 19d6ec815d12..49bf47ca5477 100644 --- a/drivers/acpi/acpica/accommon.h +++ b/drivers/acpi/acpica/accommon.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 94737f8845ac..71743e5252f5 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 dcd48bfedb4d..0d95c85cce06 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 8a0049d5cdf3..a2adfd42f85c 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index edbb42e251a6..1d955fe216c4 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h index 27addcf50c37..fd4f3cacb356 100644 --- a/drivers/acpi/acpica/achware.h +++ b/drivers/acpi/acpica/achware.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 7ead235555cf..29a863c85318 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 792660054992..8fd495e8fdce 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -770,7 +770,7 @@ union acpi_parse_value { char *operator_symbol;/* Used for C-style operator name strings */\ char aml_op_name[16]) /* Op name (debug only) */ -/* Flags for disasm_flags field above */ +/* Internal opcodes for disasm_opcode field above */ #define ACPI_DASM_BUFFER 0x00 /* Buffer is a simple data buffer */ #define ACPI_DASM_RESOURCE 0x01 /* Buffer is a Resource Descriptor */ @@ -783,7 +783,10 @@ union acpi_parse_value { #define ACPI_DASM_LNOT_PREFIX 0x08 /* Start of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_LNOT_SUFFIX 0x09 /* End of a Lnot_equal (etc.) pair of opcodes */ #define ACPI_DASM_HID_STRING 0x0A /* String is a _HID or _CID */ -#define ACPI_DASM_IGNORE 0x0B /* Not used at this time */ +#define ACPI_DASM_IGNORE_SINGLE 0x0B /* Ignore the opcode but not it's children */ +#define ACPI_DASM_SWITCH_PREDICATE 0x0C /* Object is a predicate for a Switch or Case block */ +#define ACPI_DASM_CASE 0x0D /* If/Else is a Case in a Switch/Case block */ +#define ACPI_DASM_DEFAULT 0x0E /* Else is a Default in a Switch/Case block */ /* * Generic operation (for example: If, While, Store) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index a3b95431b7c5..c3337514e0ed 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ /* * Extract data using a pointer. Any more than a byte and we - * get into potential aligment issues -- see the STORE macros below. + * get into potential alignment issues -- see the STORE macros below. * Use with care. */ #define ACPI_CAST8(ptr) ACPI_CAST_PTR (u8, (ptr)) @@ -63,7 +63,7 @@ #define ACPI_SET64(ptr, val) (*ACPI_CAST64 (ptr) = (u64) (val)) /* - * printf() format helper. This macros is a workaround for the difficulties + * printf() format helper. This macro is a workaround for the difficulties * with emitting 64-bit integers and 64-bit pointers with the same code * for both 32-bit and 64-bit hosts. */ @@ -260,8 +260,70 @@ #define ACPI_IS_MISALIGNED(value) (((acpi_size) value) & (sizeof(acpi_size)-1)) +/* Generic bit manipulation */ + +#ifndef ACPI_USE_NATIVE_BIT_FINDER + +#define __ACPI_FIND_LAST_BIT_2(a, r) ((((u8) (a)) & 0x02) ? (r)+1 : (r)) +#define __ACPI_FIND_LAST_BIT_4(a, r) ((((u8) (a)) & 0x0C) ? \ + __ACPI_FIND_LAST_BIT_2 ((a)>>2, (r)+2) : \ + __ACPI_FIND_LAST_BIT_2 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_8(a, r) ((((u8) (a)) & 0xF0) ? \ + __ACPI_FIND_LAST_BIT_4 ((a)>>4, (r)+4) : \ + __ACPI_FIND_LAST_BIT_4 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_16(a, r) ((((u16) (a)) & 0xFF00) ? \ + __ACPI_FIND_LAST_BIT_8 ((a)>>8, (r)+8) : \ + __ACPI_FIND_LAST_BIT_8 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_32(a, r) ((((u32) (a)) & 0xFFFF0000) ? \ + __ACPI_FIND_LAST_BIT_16 ((a)>>16, (r)+16) : \ + __ACPI_FIND_LAST_BIT_16 ((a), (r))) +#define __ACPI_FIND_LAST_BIT_64(a, r) ((((u64) (a)) & 0xFFFFFFFF00000000) ? \ + __ACPI_FIND_LAST_BIT_32 ((a)>>32, (r)+32) : \ + __ACPI_FIND_LAST_BIT_32 ((a), (r))) + +#define ACPI_FIND_LAST_BIT_8(a) ((a) ? __ACPI_FIND_LAST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_16(a) ((a) ? __ACPI_FIND_LAST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_32(a) ((a) ? __ACPI_FIND_LAST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_LAST_BIT_64(a) ((a) ? __ACPI_FIND_LAST_BIT_64 (a, 1) : 0) + +#define __ACPI_FIND_FIRST_BIT_2(a, r) ((((u8) (a)) & 0x01) ? (r) : (r)+1) +#define __ACPI_FIND_FIRST_BIT_4(a, r) ((((u8) (a)) & 0x03) ? \ + __ACPI_FIND_FIRST_BIT_2 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_2 ((a)>>2, (r)+2)) +#define __ACPI_FIND_FIRST_BIT_8(a, r) ((((u8) (a)) & 0x0F) ? \ + __ACPI_FIND_FIRST_BIT_4 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_4 ((a)>>4, (r)+4)) +#define __ACPI_FIND_FIRST_BIT_16(a, r) ((((u16) (a)) & 0x00FF) ? \ + __ACPI_FIND_FIRST_BIT_8 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_8 ((a)>>8, (r)+8)) +#define __ACPI_FIND_FIRST_BIT_32(a, r) ((((u32) (a)) & 0x0000FFFF) ? \ + __ACPI_FIND_FIRST_BIT_16 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_16 ((a)>>16, (r)+16)) +#define __ACPI_FIND_FIRST_BIT_64(a, r) ((((u64) (a)) & 0x00000000FFFFFFFF) ? \ + __ACPI_FIND_FIRST_BIT_32 ((a), (r)) : \ + __ACPI_FIND_FIRST_BIT_32 ((a)>>32, (r)+32)) + +#define ACPI_FIND_FIRST_BIT_8(a) ((a) ? __ACPI_FIND_FIRST_BIT_8 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_16(a) ((a) ? __ACPI_FIND_FIRST_BIT_16 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_32(a) ((a) ? __ACPI_FIND_FIRST_BIT_32 (a, 1) : 0) +#define ACPI_FIND_FIRST_BIT_64(a) ((a) ? __ACPI_FIND_FIRST_BIT_64 (a, 1) : 0) + +#endif /* ACPI_USE_NATIVE_BIT_FINDER */ + /* Generic (power-of-two) rounding */ +#define ACPI_ROUND_UP_POWER_OF_TWO_8(a) ((u8) \ + (((u16) 1) << ACPI_FIND_LAST_BIT_8 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_8(a) ((u8) \ + (((u16) 1) << (ACPI_FIND_LAST_BIT_8 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_16(a) ((u16) \ + (((u32) 1) << ACPI_FIND_LAST_BIT_16 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_16(a) ((u16) \ + (((u32) 1) << (ACPI_FIND_LAST_BIT_16 ((a)) - 1))) +#define ACPI_ROUND_UP_POWER_OF_TWO_32(a) ((u32) \ + (((u64) 1) << ACPI_FIND_LAST_BIT_32 ((a) - 1))) +#define ACPI_ROUND_DOWN_POWER_OF_TWO_32(a) ((u32) \ + (((u64) 1) << (ACPI_FIND_LAST_BIT_32 ((a)) - 1))) #define ACPI_IS_ALIGNED(a, s) (((a) & ((s) - 1)) == 0) #define ACPI_IS_POWER_OF_TWO(a) ACPI_IS_ALIGNED(a, a) @@ -270,8 +332,8 @@ * Bit positions start at zero. * MASK_BITS_ABOVE creates a mask starting AT the position and above * MASK_BITS_BELOW creates a mask starting one bit BELOW the position - * MASK_BITS_ABOVE/BELOW accpets a bit offset to create a mask - * MASK_BITS_ABOVE/BELOW_32/64 accpets a bit width to create a mask + * MASK_BITS_ABOVE/BELOW accepts a bit offset to create a mask + * MASK_BITS_ABOVE/BELOW_32/64 accepts a bit width to create a mask * Note: The ACPI_INTEGER_BIT_SIZE check is used to bypass compiler * differences with the shift operator */ @@ -389,7 +451,7 @@ */ #ifndef ACPI_NO_ERROR_MESSAGES /* - * Error reporting. Callers module and line number are inserted by AE_INFO, + * Error reporting. The callers module and line number are inserted by AE_INFO, * the plist contains a set of parens to allow variable-length lists. * These macros are used for both the debug and non-debug versions of the code. */ diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 7affdcdfcc81..54a0c51b3e37 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 094b042678f7..27c3f982d810 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h index ca4bda1a60be..e758f098ff4b 100644 --- a/drivers/acpi/acpica/acopcode.h +++ b/drivers/acpi/acpica/acopcode.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,7 +92,7 @@ #define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) #define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET) -#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_NAME_OR_REF,ARGP_TARGET) +#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SIMPLENAME, ARGP_TARGET) #define ARGP_CONNECTFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_CONTINUE_OP ARG_NONE #define ARGP_COPY_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SIMPLENAME) @@ -105,7 +105,7 @@ #define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_DEBUG_OP ARG_NONE #define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME) -#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG) +#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST) #define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET) #define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA) @@ -152,14 +152,14 @@ #define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING) #define ARGP_NOOP_OP ARG_NONE #define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG) -#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_OBJECT_TYPE_OP ARGP_LIST1 (ARGP_SIMPLENAME) #define ARGP_ONE_OP ARG_NONE #define ARGP_ONES_OP ARG_NONE #define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST) #define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST) #define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST) #define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA) -#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_NAME_OR_REF) +#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SIMPLENAME) #define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG) #define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME) #define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING) @@ -249,7 +249,7 @@ #define ARGI_FIELD_OP ARGI_INVALID_OPCODE #define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) -#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_IF_OP ARGI_INVALID_OPCODE #define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF) #define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE @@ -313,12 +313,12 @@ #define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE #define ARGI_TIMER_OP ARG_NONE -#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET) -#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET) -#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET) +#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF) +#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_TARGETREF) +#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_TARGETREF) #define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE) #define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER) #define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER) diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 939d41113970..c23c47328060 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 888440b2cf2e..dcfc05d40e36 100644 --- a/drivers/acpi/acpica/acpredef.h +++ b/drivers/acpi/acpica/acpredef.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h index 63da1e37caba..b4d22f6e48e2 100644 --- a/drivers/acpi/acpica/acresrc.h +++ b/drivers/acpi/acpica/acresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 6235642e31d3..62134bdbeda6 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 94be8a8e6c08..c8da453bd960 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 845afb180a7e..6f28cfae2212 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index 6bd8d4bcff65..b536fd471292 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h @@ -7,7 +7,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -277,9 +277,23 @@ #define ARGI_DEVICE_REF 0x0D #define ARGI_REFERENCE 0x0E #define ARGI_TARGETREF 0x0F /* Target, subject to implicit conversion */ -#define ARGI_FIXED_TARGET 0x10 /* Target, no implicit conversion */ -#define ARGI_SIMPLE_TARGET 0x11 /* Name, Local, Arg -- no implicit conversion */ -#define ARGI_STORE_TARGET 0x12 /* Target for store is TARGETREF + package objects */ +#define ARGI_SIMPLE_TARGET 0x10 /* Name, Local, Arg -- no implicit conversion */ +#define ARGI_STORE_TARGET 0x11 /* Target for store is TARGETREF + package objects */ +/* + * #define ARGI_FIXED_TARGET 0x10 Target, no implicit conversion + * + * Removed 10/2016. ARGI_FIXED_TARGET was used for these operators: + * from_BCD + * to_BCD + * to_decimal_string + * to_hex_string + * to_integer + * to_buffer + * The purpose of this type was to disable "implicit result conversion", + * but this was incorrect per the ACPI spec and other ACPI implementations. + * These operators now have the target operand defined as a normal + * ARGI_TARGETREF. + */ /* Multiple/complex types */ diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h index dee6c7ea4773..653a3d1ef5d5 100644 --- a/drivers/acpi/acpica/amlresrc.h +++ b/drivers/acpi/acpica/amlresrc.h @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbcmds.c b/drivers/acpi/acpica/dbcmds.c index 62bd446535f5..5984b90eb590 100644 --- a/drivers/acpi/acpica/dbcmds.c +++ b/drivers/acpi/acpica/dbcmds.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbconvert.c b/drivers/acpi/acpica/dbconvert.c index 147ce8894f76..251f9477a984 100644 --- a/drivers/acpi/acpica/dbconvert.c +++ b/drivers/acpi/acpica/dbconvert.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbdisply.c b/drivers/acpi/acpica/dbdisply.c index 502bb587f112..46bf270ac525 100644 --- a/drivers/acpi/acpica/dbdisply.c +++ b/drivers/acpi/acpica/dbdisply.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbexec.c b/drivers/acpi/acpica/dbexec.c index fe3da7c31bb7..b611cd92b5f5 100644 --- a/drivers/acpi/acpica/dbexec.c +++ b/drivers/acpi/acpica/dbexec.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbfileio.c b/drivers/acpi/acpica/dbfileio.c index 6f05b8c271a5..4d81ea291d93 100644 --- a/drivers/acpi/acpica/dbfileio.c +++ b/drivers/acpi/acpica/dbfileio.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbhistry.c b/drivers/acpi/acpica/dbhistry.c index 46bd65d38df9..7d08974c64c2 100644 --- a/drivers/acpi/acpica/dbhistry.c +++ b/drivers/acpi/acpica/dbhistry.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbinput.c b/drivers/acpi/acpica/dbinput.c index 068214f9cc9d..2626d79db064 100644 --- a/drivers/acpi/acpica/dbinput.c +++ b/drivers/acpi/acpica/dbinput.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbmethod.c b/drivers/acpi/acpica/dbmethod.c index 314b94cf086a..15c8237b8a80 100644 --- a/drivers/acpi/acpica/dbmethod.c +++ b/drivers/acpi/acpica/dbmethod.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbnames.c b/drivers/acpi/acpica/dbnames.c index 8667f14d535e..8c207c772517 100644 --- a/drivers/acpi/acpica/dbnames.c +++ b/drivers/acpi/acpica/dbnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbobject.c b/drivers/acpi/acpica/dbobject.c index 08eaaf350b24..f2252b1ac0b3 100644 --- a/drivers/acpi/acpica/dbobject.c +++ b/drivers/acpi/acpica/dbobject.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbstats.c b/drivers/acpi/acpica/dbstats.c index a414e1fa6f9d..99fb0160b8fb 100644 --- a/drivers/acpi/acpica/dbstats.c +++ b/drivers/acpi/acpica/dbstats.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbtest.c b/drivers/acpi/acpica/dbtest.c index 74aa38156cdc..c6bee6143266 100644 --- a/drivers/acpi/acpica/dbtest.c +++ b/drivers/acpi/acpica/dbtest.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbutils.c b/drivers/acpi/acpica/dbutils.c index ae80106d1000..bfa972b64171 100644 --- a/drivers/acpi/acpica/dbutils.c +++ b/drivers/acpi/acpica/dbutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dbxface.c b/drivers/acpi/acpica/dbxface.c index 124db237775d..205b8e0eded5 100644 --- a/drivers/acpi/acpica/dbxface.c +++ b/drivers/acpi/acpica/dbxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -430,7 +430,7 @@ acpi_status acpi_initialize_debugger(void) /* These were created with one unit, grab it */ - status = acpi_os_initialize_command_signals(); + status = acpi_os_initialize_debugger(); if (ACPI_FAILURE(status)) { acpi_os_printf("Could not get debugger mutex\n"); return_ACPI_STATUS(status); @@ -482,7 +482,7 @@ void acpi_terminate_debugger(void) acpi_os_sleep(100); } - acpi_os_terminate_command_signals(); + acpi_os_terminate_debugger(); } if (acpi_gbl_db_buffer) { diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index ad0413beeeae..287b3fd73cfc 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 4ddcbf100234..d31b49feaa79 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 56c3aadb4cba..4d885eb8eda9 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 6a4b603d0e83..c5dccc54307d 100644 --- a/drivers/acpi/acpica/dsfield.c +++ b/drivers/acpi/acpica/dsfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 5de3f10cab03..b1842dd4edf7 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 2b3210f42a46..31c9c7aec3d5 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 45cbebaa32c0..adcc72cd53a7 100644 --- a/drivers/acpi/acpica/dsmthdat.c +++ b/drivers/acpi/acpica/dsmthdat.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 a91de2b4603c..8deaa16493a0 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 77fd7c84ec39..148523205d41 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 7d8ef52fb88d..049fbab4e5a6 100644 --- a/drivers/acpi/acpica/dsutils.c +++ b/drivers/acpi/acpica/dsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 438597cf6cc5..78f8e6a4f72f 100644 --- a/drivers/acpi/acpica/dswexec.c +++ b/drivers/acpi/acpica/dswexec.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 fd34040d4f44..cafb3ab567ab 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 651f35a66cc2..44d4553dfbdd 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 9f32e08a07d9..3e081983d2ee 100644 --- a/drivers/acpi/acpica/dswscope.c +++ b/drivers/acpi/acpica/dswscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 e3338698e56b..da111a1f5bfb 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 80fc0b9b11e5..d3b6b314fa50 100644 --- a/drivers/acpi/acpica/evevent.c +++ b/drivers/acpi/acpica/evevent.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c index 9f015782cdd3..0ce33b0f430c 100644 --- a/drivers/acpi/acpica/evglock.c +++ b/drivers/acpi/acpica/evglock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c index bdb10bee13ce..229382035550 100644 --- a/drivers/acpi/acpica/evgpe.c +++ b/drivers/acpi/acpica/evgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 d54014cab01d..9c941947a063 100644 --- a/drivers/acpi/acpica/evgpeblk.c +++ b/drivers/acpi/acpica/evgpeblk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 16ce4835e7d0..8649c6242478 100644 --- a/drivers/acpi/acpica/evgpeinit.c +++ b/drivers/acpi/acpica/evgpeinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 3f150d567e64..c8adb400330a 100644 --- a/drivers/acpi/acpica/evgpeutil.c +++ b/drivers/acpi/acpica/evgpeutil.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c index 24768ca03f19..2db61ef1b4a3 100644 --- a/drivers/acpi/acpica/evhandler.c +++ b/drivers/acpi/acpica/evhandler.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 f51d43adb7d1..4f6bb3f016ab 100644 --- a/drivers/acpi/acpica/evmisc.c +++ b/drivers/acpi/acpica/evmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 4c6f79514040..28b447ff92df 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index a9092251ce80..93ec528bcd9a 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 3b7757c9c916..8ce73b962006 100644 --- a/drivers/acpi/acpica/evsci.c +++ b/drivers/acpi/acpica/evsci.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 e4e9260cdc57..dd1b9dd64cef 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 9179e9abe3db..82e8971f23a4 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 d7a3b2775505..57718a3e029a 100644 --- a/drivers/acpi/acpica/evxfgpe.c +++ b/drivers/acpi/acpica/evxfgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 d2743067126a..beba9d56a0d8 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconcat.c b/drivers/acpi/acpica/exconcat.c index 5429c2a6bc41..76bfb7dcae2f 100644 --- a/drivers/acpi/acpica/exconcat.c +++ b/drivers/acpi/acpica/exconcat.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 c32c7829878a..61813bd43f9e 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c index 588ad1409dbe..f71028e334ee 100644 --- a/drivers/acpi/acpica/exconvrt.c +++ b/drivers/acpi/acpica/exconvrt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -592,7 +592,6 @@ acpi_ex_convert_to_target_type(acpi_object_type destination_type, */ switch (GET_CURRENT_ARG_TYPE(walk_state->op_info->runtime_args)) { case ARGI_SIMPLE_TARGET: - case ARGI_FIXED_TARGET: case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */ switch (destination_type) { diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index 613ba6eb08bb..d43d7da4c734 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 37a509d016da..ec614f5a3bcb 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 fce6b2e10209..970dc6c53994 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c index d7d3ee36338b..5fda981f6498 100644 --- a/drivers/acpi/acpica/exfield.c +++ b/drivers/acpi/acpica/exfield.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index ee76d299b3d0..a656608dca84 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c index 37c88b424a02..1a6f59079ea5 100644 --- a/drivers/acpi/acpica/exmisc.c +++ b/drivers/acpi/acpica/exmisc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 26faa91e930c..ecd95b3f35f1 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 3d6af93fe561..ee7b62a86661 100644 --- a/drivers/acpi/acpica/exnames.c +++ b/drivers/acpi/acpica/exnames.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 007300433cde..af73fcde7e5c 100644 --- a/drivers/acpi/acpica/exoparg1.c +++ b/drivers/acpi/acpica/exoparg1.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 79ef3b6811a9..44ecba50c0da 100644 --- a/drivers/acpi/acpica/exoparg2.c +++ b/drivers/acpi/acpica/exoparg2.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 69e4e269ad2f..ce857addc8db 100644 --- a/drivers/acpi/acpica/exoparg3.c +++ b/drivers/acpi/acpica/exoparg3.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 786d53b0bb37..31e4df97cbe1 100644 --- a/drivers/acpi/acpica/exoparg6.c +++ b/drivers/acpi/acpica/exoparg6.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 aed8d3459220..8de060664204 100644 --- a/drivers/acpi/acpica/exprep.c +++ b/drivers/acpi/acpica/exprep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c index 31b381cae94d..7bcc9d809b7e 100644 --- a/drivers/acpi/acpica/exregion.c +++ b/drivers/acpi/acpica/exregion.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 a183cb740d24..91c1de046442 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 e1d3878be2c6..7fecefc2e1b4 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 f29eba1dc5e9..c4852429e2ff 100644 --- a/drivers/acpi/acpica/exresop.c +++ b/drivers/acpi/acpica/exresop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -305,7 +305,6 @@ acpi_ex_resolve_operands(u16 opcode, case ARGI_OBJECT_REF: case ARGI_DEVICE_REF: case ARGI_TARGETREF: /* Allows implicit conversion rules before store */ - case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */ case ARGI_SIMPLE_TARGET: /* Name, Local, or arg - no implicit conversion */ case ARGI_STORE_TARGET: diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index cd70cbcf6de6..a2f8001aeb86 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 13bbb2b241a3..85db4716a043 100644 --- a/drivers/acpi/acpica/exstoren.c +++ b/drivers/acpi/acpica/exstoren.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 1dab82746d06..4ba7fcbf23b0 100644 --- a/drivers/acpi/acpica/exstorob.c +++ b/drivers/acpi/acpica/exstorob.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 ac09c31cc70e..ad3b610057f3 100644 --- a/drivers/acpi/acpica/exsystem.c +++ b/drivers/acpi/acpica/exsystem.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/extrace.c b/drivers/acpi/acpica/extrace.c index c9ca82610d77..ae9df8672d9e 100644 --- a/drivers/acpi/acpica/extrace.c +++ b/drivers/acpi/acpica/extrace.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 a8b857a7e9fb..34d608358eaf 100644 --- a/drivers/acpi/acpica/exutils.c +++ b/drivers/acpi/acpica/exutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c index 3ebbb09030b4..fad249e774b4 100644 --- a/drivers/acpi/acpica/hwacpi.c +++ b/drivers/acpi/acpica/hwacpi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c index 3f2fb4b31fdc..12626d021a9b 100644 --- a/drivers/acpi/acpica/hwesleep.c +++ b/drivers/acpi/acpica/hwesleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,6 @@ */ #include <acpi/acpi.h> -#include <linux/acpi.h> #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -103,7 +102,7 @@ void acpi_hw_execute_sleep_method(char *method_pathname, u32 integer_argument) acpi_status acpi_hw_extended_sleep(u8 sleep_state) { acpi_status status; - u8 sleep_type_value; + u8 sleep_control; u64 sleep_status; ACPI_FUNCTION_TRACE(hw_extended_sleep); @@ -125,18 +124,6 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) acpi_gbl_system_awake_and_running = FALSE; - /* Flush caches, as per ACPI specification */ - - ACPI_FLUSH_CPU_CACHE(); - - status = acpi_os_prepare_extended_sleep(sleep_state, - acpi_gbl_sleep_type_a, - acpi_gbl_sleep_type_b); - if (ACPI_SKIP(status)) - return_ACPI_STATUS(AE_OK); - if (ACPI_FAILURE(status)) - return_ACPI_STATUS(status); - /* * Set the SLP_TYP and SLP_EN bits. * @@ -146,12 +133,22 @@ acpi_status acpi_hw_extended_sleep(u8 sleep_state) ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Entering sleep state [S%u]\n", sleep_state)); - sleep_type_value = - ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & - ACPI_X_SLEEP_TYPE_MASK); + sleep_control = ((acpi_gbl_sleep_type_a << ACPI_X_SLEEP_TYPE_POSITION) & + ACPI_X_SLEEP_TYPE_MASK) | ACPI_X_SLEEP_ENABLE; + + /* Flush caches, as per ACPI specification */ + + ACPI_FLUSH_CPU_CACHE(); + + status = acpi_os_enter_sleep(sleep_state, sleep_control, 0); + if (status == AE_CTRL_TERMINATE) { + return_ACPI_STATUS(AE_OK); + } + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } - status = acpi_write((u64)(sleep_type_value | ACPI_X_SLEEP_ENABLE), - &acpi_gbl_FADT.sleep_control); + status = acpi_write((u64)sleep_control, &acpi_gbl_FADT.sleep_control); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c index 76b0e350f5bb..5eb11b30a79e 100644 --- a/drivers/acpi/acpica/hwgpe.c +++ b/drivers/acpi/acpica/hwgpe.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 3dd60c96aa07..283819930be6 100644 --- a/drivers/acpi/acpica/hwpci.c +++ b/drivers/acpi/acpica/hwpci.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 3b7fb99362b6..de74a4c25085 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,8 @@ ACPI_MODULE_NAME("hwregs") #if (!ACPI_REDUCED_HARDWARE) /* Local Prototypes */ static u8 -acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, +acpi_hw_get_access_bit_width(u64 address, + struct acpi_generic_address *reg, u8 max_bit_width); static acpi_status @@ -71,7 +72,8 @@ acpi_hw_write_multiple(u32 value, * * FUNCTION: acpi_hw_get_access_bit_width * - * PARAMETERS: reg - GAS register structure + * PARAMETERS: address - GAS register address + * reg - GAS register structure * max_bit_width - Max bit_width supported (32 or 64) * * RETURN: Status @@ -81,27 +83,59 @@ acpi_hw_write_multiple(u32 value, ******************************************************************************/ static u8 -acpi_hw_get_access_bit_width(struct acpi_generic_address *reg, u8 max_bit_width) +acpi_hw_get_access_bit_width(u64 address, + struct acpi_generic_address *reg, u8 max_bit_width) { - if (!reg->access_width) { - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { - max_bit_width = 32; - } + u8 access_bit_width; - /* - * Detect old register descriptors where only the bit_width field - * makes senses. - */ - if (reg->bit_width < max_bit_width && - !reg->bit_offset && reg->bit_width && - ACPI_IS_POWER_OF_TWO(reg->bit_width) && - ACPI_IS_ALIGNED(reg->bit_width, 8)) { - return (reg->bit_width); - } - return (max_bit_width); + /* + * GAS format "register", used by FADT: + * 1. Detected if bit_offset is 0 and bit_width is 8/16/32/64; + * 2. access_size field is ignored and bit_width field is used for + * determining the boundary of the IO accesses. + * GAS format "region", used by APEI registers: + * 1. Detected if bit_offset is not 0 or bit_width is not 8/16/32/64; + * 2. access_size field is used for determining the boundary of the + * IO accesses; + * 3. bit_offset/bit_width fields are used to describe the "region". + * + * Note: This algorithm assumes that the "Address" fields should always + * contain aligned values. + */ + if (!reg->bit_offset && reg->bit_width && + ACPI_IS_POWER_OF_TWO(reg->bit_width) && + ACPI_IS_ALIGNED(reg->bit_width, 8)) { + access_bit_width = reg->bit_width; + } else if (reg->access_width) { + access_bit_width = (1 << (reg->access_width + 2)); } else { - return (1 << (reg->access_width + 2)); + access_bit_width = + ACPI_ROUND_UP_POWER_OF_TWO_8(reg->bit_offset + + reg->bit_width); + if (access_bit_width <= 8) { + access_bit_width = 8; + } else { + while (!ACPI_IS_ALIGNED(address, access_bit_width >> 3)) { + access_bit_width >>= 1; + } + } } + + /* Maximum IO port access bit width is 32 */ + + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { + max_bit_width = 32; + } + + /* + * Return access width according to the requested maximum access bit width, + * as the caller should know the format of the register and may enforce + * a 32-bit accesses. + */ + if (access_bit_width < max_bit_width) { + return (access_bit_width); + } + return (max_bit_width); } /****************************************************************************** @@ -163,7 +197,8 @@ acpi_hw_validate_register(struct acpi_generic_address *reg, /* Validate the bit_width, convert access_width into number of bits */ - access_width = acpi_hw_get_access_bit_width(reg, max_bit_width); + access_width = + acpi_hw_get_access_bit_width(*address, reg, max_bit_width); bit_width = ACPI_ROUND_UP(reg->bit_offset + reg->bit_width, access_width); if (max_bit_width < bit_width) { @@ -219,7 +254,7 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) * into number of bits based */ *value = 0; - access_width = acpi_hw_get_access_bit_width(reg, 32); + access_width = acpi_hw_get_access_bit_width(address, reg, 32); bit_width = reg->bit_offset + reg->bit_width; bit_offset = reg->bit_offset; @@ -252,20 +287,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) &value32, access_width); } - - /* - * Use offset style bit masks because: - * bit_offset < access_width/bit_width < access_width, and - * access_width is ensured to be less than 32-bits by - * acpi_hw_validate_register(). - */ - if (bit_offset) { - value32 &= ACPI_MASK_BITS_BELOW(bit_offset); - bit_offset = 0; - } - if (bit_width < access_width) { - value32 &= ACPI_MASK_BITS_ABOVE(bit_width); - } } /* @@ -306,6 +327,12 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg) acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) { u64 address; + u8 access_width; + u32 bit_width; + u8 bit_offset; + u64 value64; + u32 value32; + u8 index; acpi_status status; ACPI_FUNCTION_NAME(hw_write); @@ -317,23 +344,61 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) return (status); } + /* Convert access_width into number of bits based */ + + access_width = acpi_hw_get_access_bit_width(address, reg, 32); + bit_width = reg->bit_offset + reg->bit_width; + bit_offset = reg->bit_offset; + /* * Two address spaces supported: Memory or IO. PCI_Config is * not supported here because the GAS structure is insufficient */ - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - status = acpi_os_write_memory((acpi_physical_address) - address, (u64)value, - reg->bit_width); - } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ - - status = acpi_hw_write_port((acpi_io_address) - address, value, reg->bit_width); + index = 0; + while (bit_width) { + /* + * Use offset style bit reads because "Index * AccessWidth" is + * ensured to be less than 32-bits by acpi_hw_validate_register(). + */ + value32 = ACPI_GET_BITS(&value, index * access_width, + ACPI_MASK_BITS_ABOVE_32(access_width)); + + if (bit_offset >= access_width) { + bit_offset -= access_width; + } else { + if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { + value64 = (u64)value32; + status = + acpi_os_write_memory((acpi_physical_address) + address + + index * + ACPI_DIV_8 + (access_width), + value64, access_width); + } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ + + status = acpi_hw_write_port((acpi_io_address) + address + + index * + ACPI_DIV_8 + (access_width), + value32, + access_width); + } + } + + /* + * Index * access_width is ensured to be less than 32-bits by + * acpi_hw_validate_register(). + */ + bit_width -= + bit_width > access_width ? access_width : bit_width; + index++; } ACPI_DEBUG_PRINT((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", - value, reg->bit_width, ACPI_FORMAT_UINT64(address), + value, access_width, ACPI_FORMAT_UINT64(address), acpi_ut_get_region_name(reg->space_id))); return (status); diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c index d00c9810845b..1fe7387a00e6 100644 --- a/drivers/acpi/acpica/hwsleep.c +++ b/drivers/acpi/acpica/hwsleep.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -43,7 +43,6 @@ */ #include <acpi/acpi.h> -#include <linux/acpi.h> #include "accommon.h" #define _COMPONENT ACPI_HARDWARE @@ -152,12 +151,14 @@ acpi_status acpi_hw_legacy_sleep(u8 sleep_state) ACPI_FLUSH_CPU_CACHE(); - status = acpi_os_prepare_sleep(sleep_state, pm1a_control, - pm1b_control); - if (ACPI_SKIP(status)) + status = acpi_os_enter_sleep(sleep_state, pm1a_control, pm1b_control); + if (status == AE_CTRL_TERMINATE) { return_ACPI_STATUS(AE_OK); - if (ACPI_FAILURE(status)) + } + if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); + } + /* Write #2: Write both SLP_TYP + SLP_EN */ status = acpi_hw_write_pm1_control(pm1a_control, pm1b_control); diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c index 04cc9406c7d8..b3c5d8c754bb 100644 --- a/drivers/acpi/acpica/hwtimer.c +++ b/drivers/acpi/acpica/hwtimer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 ad0a745712a9..531620abed80 100644 --- a/drivers/acpi/acpica/hwvalid.c +++ b/drivers/acpi/acpica/hwvalid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 98c26ff39409..34684ae89981 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index f76e0eab32b8..5733b1167e46 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 73f98d3fed25..498bb8f70e6b 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 c2cf73fd3918..8ba5b32c9f71 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c index f45bff632692..9095d51f6b37 100644 --- a/drivers/acpi/acpica/nsarguments.c +++ b/drivers/acpi/acpica/nsarguments.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c index 2b85dee6d4c0..e4a7da8a11f0 100644 --- a/drivers/acpi/acpica/nsconvert.c +++ b/drivers/acpi/acpica/nsconvert.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 84f35dd27033..4123b5077a7d 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 7060a5668989..5026594763ea 100644 --- a/drivers/acpi/acpica/nsdumpdv.c +++ b/drivers/acpi/acpica/nsdumpdv.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 5d59cfcef6f4..d22167cbd0ca 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 36643a8cf65a..ce33e7297ea7 100644 --- a/drivers/acpi/acpica/nsinit.c +++ b/drivers/acpi/acpica/nsinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 d1f20143bb11..d2915e186ae1 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 94d5d3339845..3db9ca25a620 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 cfa2bb7162d8..707b2aa501e1 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 4f14e9205bff..2fc33a5203f4 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 6d7844580b2a..3dbbecf22087 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c index fbedc6e8ab36..4954cb6c9090 100644 --- a/drivers/acpi/acpica/nsprepkg.c +++ b/drivers/acpi/acpica/nsprepkg.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index 9523d41c7ae9..38316266521e 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index d5336122486b..352265498e90 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index 61036d210274..5de8957f5ef0 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 691814dfed31..661676714f7b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 ebd731fe8e45..6b6e6f498cff 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 d2a9b4fd739f..8e365c0e766b 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 e525cbe7d83b..106966235805 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -6,7 +6,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 32d372b85243..47f689ec3fcb 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c @@ -6,7 +6,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 c29c930ffa08..05b62ad44c3e 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -269,23 +269,27 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, */ if (ACPI_SUCCESS(status) && possible_method_call && (node->type == ACPI_TYPE_METHOD)) { - if (walk_state->opcode == AML_UNLOAD_OP) { + if ((GET_CURRENT_ARG_TYPE(walk_state->arg_types) == + ARGP_SUPERNAME) + || (GET_CURRENT_ARG_TYPE(walk_state->arg_types) == + ARGP_TARGET)) { /* - * acpi_ps_get_next_namestring has increased the AML pointer, - * so we need to restore the saved AML pointer for method call. + * acpi_ps_get_next_namestring has increased the AML pointer past + * the method invocation namestring, so we need to restore the + * saved AML pointer back to the original method invocation + * namestring. */ walk_state->parser_state.aml = start; walk_state->arg_count = 1; acpi_ps_init_op(arg, AML_INT_METHODCALL_OP); - return_ACPI_STATUS(AE_OK); } /* This name is actually a control method invocation */ method_desc = acpi_ns_get_attached_object(node); ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Control Method - %p Desc %p Path=%p\n", node, - method_desc, path)); + "Control Method invocation %4.4s - %p Desc %p Path=%p\n", + node->name.ascii, node, method_desc, path)); name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start); if (!name_op) { @@ -719,6 +723,10 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_get_next_arg, parser_state); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Expected argument type ARGP: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), arg_type)); + switch (arg_type) { case ARGP_BYTEDATA: case ARGP_WORDDATA: @@ -796,11 +804,14 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, } break; - case ARGP_TARGET: - case ARGP_SUPERNAME: case ARGP_SIMPLENAME: case ARGP_NAME_OR_REF: + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** SimpleName/NameOrRef: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + subop = acpi_ps_peek_opcode(parser_state); if (subop == 0 || acpi_ps_is_leading_char(subop) || @@ -816,28 +827,49 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, return_ACPI_STATUS(AE_NO_MEMORY); } - /* To support super_name arg of Unload */ - - if (walk_state->opcode == AML_UNLOAD_OP) { - status = - acpi_ps_get_next_namepath(walk_state, - parser_state, arg, - ACPI_POSSIBLE_METHOD_CALL); - - /* - * If the super_name argument is a method call, we have - * already restored the AML pointer, just free this Arg - */ - if (arg->common.aml_opcode == - AML_INT_METHODCALL_OP) { - acpi_ps_free_op(arg); - arg = NULL; - } - } else { - status = - acpi_ps_get_next_namepath(walk_state, - parser_state, arg, - ACPI_NOT_METHOD_CALL); + status = + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_NOT_METHOD_CALL); + } else { + /* Single complex argument, nothing returned */ + + walk_state->arg_count = 1; + } + break; + + case ARGP_TARGET: + case ARGP_SUPERNAME: + + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** Target/Supername: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + + subop = acpi_ps_peek_opcode(parser_state); + if (subop == 0 || + acpi_ps_is_leading_char(subop) || + ACPI_IS_ROOT_PREFIX(subop) || + ACPI_IS_PARENT_PREFIX(subop)) { + + /* NULL target (zero). Convert to a NULL namepath */ + + arg = + acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, + parser_state->aml); + if (!arg) { + return_ACPI_STATUS(AE_NO_MEMORY); + } + + status = + acpi_ps_get_next_namepath(walk_state, parser_state, + arg, + ACPI_POSSIBLE_METHOD_CALL); + + if (arg->common.aml_opcode == AML_INT_METHODCALL_OP) { + acpi_ps_free_op(arg); + arg = NULL; + walk_state->arg_count = 1; } } else { /* Single complex argument, nothing returned */ @@ -849,6 +881,11 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, case ARGP_DATAOBJ: case ARGP_TERMARG: + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "**** TermArg/DataObj: %s (%2.2X)\n", + acpi_ut_get_argument_type_name(arg_type), + arg_type)); + /* Single complex argument, nothing returned */ walk_state->arg_count = 1; diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 6a9f5059f682..14d689606d2f 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,6 +92,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state); + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Get arguments for opcode [%s]\n", + op->common.aml_op_name)); + switch (op->common.aml_opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index db0e90342e82..5c4aff0f4f26 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -348,7 +348,15 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, argument_count) { op->common.flags |= ACPI_PARSEOP_TARGET; } - } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) { + } + + /* + * Special case for both Increment() and Decrement(), where + * the lone argument is both a source and a target. + */ + else if ((parent_scope->common.aml_opcode == AML_INCREMENT_OP) + || (parent_scope->common.aml_opcode == + AML_DECREMENT_OP)) { op->common.flags |= ACPI_PARSEOP_TARGET; } } diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c index 8e0c97dca01f..451b672915f1 100644 --- a/drivers/acpi/acpica/psopcode.c +++ b/drivers/acpi/acpica/psopcode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c index 177b05b239b7..89f95b7f26e9 100644 --- a/drivers/acpi/acpica/psopinfo.c +++ b/drivers/acpi/acpica/psopinfo.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 1ce26d9f8ff6..a813bbbd5a8b 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 560c3684ef43..22d7f1d6849b 100644 --- a/drivers/acpi/acpica/psscope.c +++ b/drivers/acpi/acpica/psscope.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 0288cdbda88e..9677fff8fd47 100644 --- a/drivers/acpi/acpica/pstree.c +++ b/drivers/acpi/acpica/pstree.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -129,10 +129,10 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) union acpi_parse_object *prev_arg; const struct acpi_opcode_info *op_info; - ACPI_FUNCTION_ENTRY(); + ACPI_FUNCTION_TRACE(ps_append_arg); if (!op) { - return; + return_VOID; } /* Get the info structure for this opcode */ @@ -144,7 +144,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) ACPI_ERROR((AE_INFO, "Invalid AML Opcode: 0x%2.2X", op->common.aml_opcode)); - return; + return_VOID; } /* Check if this opcode requires argument sub-objects */ @@ -153,7 +153,7 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) /* Has no linked argument objects */ - return; + return_VOID; } /* Append the argument to the linked argument list */ @@ -181,6 +181,8 @@ acpi_ps_append_arg(union acpi_parse_object *op, union acpi_parse_object *arg) op->common.arg_list_length++; } + + return_VOID; } /******************************************************************************* diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 89cb4bffcc7c..2fa38bb76a55 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 04f98c0a7684..22a37c82af19 100644 --- a/drivers/acpi/acpica/pswalk.c +++ b/drivers/acpi/acpica/pswalk.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 f3c87264bd1b..c88a681586bf 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 492d5b011f33..a131a28bb09d 100644 --- a/drivers/acpi/acpica/rsaddr.c +++ b/drivers/acpi/acpica/rsaddr.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 f1e83addd5b4..74e47f829ccb 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 809b61c114fe..f72ff0b54a63 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c index 5ffdb5602d8d..f4cdf8d832dc 100644 --- a/drivers/acpi/acpica/rsdump.c +++ b/drivers/acpi/acpica/rsdump.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c index 61e8f16c857d..8aacd28293fa 100644 --- a/drivers/acpi/acpica/rsdumpinfo.c +++ b/drivers/acpi/acpica/rsdumpinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c index 8e067cb73973..475da9d6aed5 100644 --- a/drivers/acpi/acpica/rsinfo.c +++ b/drivers/acpi/acpica/rsinfo.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c index 07dfbed10d55..b7a47fbc519b 100644 --- a/drivers/acpi/acpica/rsio.c +++ b/drivers/acpi/acpica/rsio.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 bc8f34590d95..092a733c42b8 100644 --- a/drivers/acpi/acpica/rsirq.c +++ b/drivers/acpi/acpica/rsirq.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c index 8c42dd734559..36a6657dd34d 100644 --- a/drivers/acpi/acpica/rslist.c +++ b/drivers/acpi/acpica/rslist.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c index 88b53ef9105d..273eecb3001b 100644 --- a/drivers/acpi/acpica/rsmemory.c +++ b/drivers/acpi/acpica/rsmemory.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 25165ca42051..2ae79613f6b7 100644 --- a/drivers/acpi/acpica/rsmisc.c +++ b/drivers/acpi/acpica/rsmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c index b82c061f205a..c20e6d07928d 100644 --- a/drivers/acpi/acpica/rsserial.c +++ b/drivers/acpi/acpica/rsserial.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c index fa491c64c040..b2aeca01204a 100644 --- a/drivers/acpi/acpica/rsutils.c +++ b/drivers/acpi/acpica/rsutils.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 465ed8137167..59a4f9ed06a7 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c index 82b0b5710979..27c5c27d4818 100644 --- a/drivers/acpi/acpica/tbdata.c +++ b/drivers/acpi/acpica/tbdata.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -852,23 +852,18 @@ acpi_tb_install_and_load_table(acpi_physical_address address, ACPI_FUNCTION_TRACE(tb_install_and_load_table); - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); - /* Install the table and load it into the namespace */ status = acpi_tb_install_standard_table(address, flags, TRUE, override, &i); if (ACPI_FAILURE(status)) { - goto unlock_and_exit; + goto exit; } - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); status = acpi_tb_load_table(i, acpi_gbl_root_node); - (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); -unlock_and_exit: +exit: *table_index = i; - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 81473a4880ce..51860bfc111e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index f6b9b4e4298b..fea89c8d305c 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 5fdf251a9f97..4620f3c68c13 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -217,6 +217,10 @@ acpi_tb_install_standard_table(acpi_physical_address address, goto release_and_exit; } + /* Acquire the table lock */ + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + if (reload) { /* * Validate the incoming table signature. @@ -244,7 +248,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, new_table_desc.signature.integer)); status = AE_BAD_SIGNATURE; - goto release_and_exit; + goto unlock_and_exit; } /* Check if table is already registered */ @@ -279,7 +283,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Table is still loaded, this is an error */ status = AE_ALREADY_EXISTS; - goto release_and_exit; + goto unlock_and_exit; } else { /* * Table was unloaded, allow it to be reloaded. @@ -290,6 +294,7 @@ acpi_tb_install_standard_table(acpi_physical_address address, * indicate the re-installation. */ acpi_tb_uninstall_table(&new_table_desc); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); *table_index = i; return_ACPI_STATUS(AE_OK); } @@ -303,11 +308,19 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Invoke table handler if present */ + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); if (acpi_gbl_table_handler) { (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer, acpi_gbl_table_handler_context); } + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + +unlock_and_exit: + + /* Release the table lock */ + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); release_and_exit: diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c index 26d61dbace0a..edfd7b10be19 100644 --- a/drivers/acpi/acpica/tbprint.c +++ b/drivers/acpi/acpica/tbprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 86854e846800..5a968a78652b 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index 7684707b254b..010b1c43df92 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 82019c01a0e5..b71ce3b817ea 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 0adb1c78d863..f9f9a7da2cad 100644 --- a/drivers/acpi/acpica/tbxfroot.c +++ b/drivers/acpi/acpica/tbxfroot.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 index 433d822798b6..26a0633115be 100644 --- a/drivers/acpi/acpica/utaddress.c +++ b/drivers/acpi/acpica/utaddress.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c index 13324a27b99b..a3401bd29413 100644 --- a/drivers/acpi/acpica/utalloc.c +++ b/drivers/acpi/acpica/utalloc.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utascii.c b/drivers/acpi/acpica/utascii.c index 706c1f346490..909bdb198651 100644 --- a/drivers/acpi/acpica/utascii.c +++ b/drivers/acpi/acpica/utascii.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c index ff2981275b9a..f17eaa009dde 100644 --- a/drivers/acpi/acpica/utbuffer.c +++ b/drivers/acpi/acpica/utbuffer.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c index 3b8d23ef351f..11c7f72f2d56 100644 --- a/drivers/acpi/acpica/utcache.c +++ b/drivers/acpi/acpica/utcache.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 82f971402d85..e9382255d6c6 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 044df9b0356e..bd5ea3101eb7 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 b3d8421cfb80..60868309e326 100644 --- a/drivers/acpi/acpica/utdecode.c +++ b/drivers/acpi/acpica/utdecode.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -238,7 +238,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) if (!obj_desc) { ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Null Object Descriptor\n")); - return_PTR("[NULL Object Descriptor]"); + return_STR("[NULL Object Descriptor]"); } /* These descriptor types share a common area */ @@ -251,7 +251,7 @@ const char *acpi_ut_get_object_type_name(union acpi_operand_object *obj_desc) acpi_ut_get_descriptor_name(obj_desc), obj_desc)); - return_PTR("Invalid object"); + return_STR("Invalid object"); } return_STR(acpi_ut_get_type_name(obj_desc->common.type)); diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 529d6c38ea7c..c6eb9fae70f9 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -421,8 +421,10 @@ acpi_ut_update_ref_count(union acpi_operand_object *object, u32 action) } ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS, - "Obj %p Type %.2X Refs %.2X [Incremented]\n", - object, object->common.type, new_count)); + "Obj %p Type %.2X [%s] Refs %.2X [Incremented]\n", + object, object->common.type, + acpi_ut_get_object_type_name(object), + new_count)); break; case REF_DECREMENT: diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c index 475932cecf1a..e3368186e1c1 100644 --- a/drivers/acpi/acpica/uterror.c +++ b/drivers/acpi/acpica/uterror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c index 7bad13f2e518..3fce7519c690 100644 --- a/drivers/acpi/acpica/uteval.c +++ b/drivers/acpi/acpica/uteval.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c index 695240338e00..eb6dcab33d2f 100644 --- a/drivers/acpi/acpica/utexcep.c +++ b/drivers/acpi/acpica/utexcep.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 dd3fd7f97f8e..230a50c82f22 100644 --- a/drivers/acpi/acpica/utglobal.c +++ b/drivers/acpi/acpica/utglobal.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c index 36d2fc789088..6600bc257516 100644 --- a/drivers/acpi/acpica/uthex.c +++ b/drivers/acpi/acpica/uthex.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c index f7cd2d52643b..a6eb580ee21d 100644 --- a/drivers/acpi/acpica/utids.c +++ b/drivers/acpi/acpica/utids.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 1711fdf41709..23e766d1691d 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c index 3cd0978925ef..db2d9910866e 100644 --- a/drivers/acpi/acpica/utlock.c +++ b/drivers/acpi/acpica/utlock.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 2d6530ee7e51..aa0502d1d019 100644 --- a/drivers/acpi/acpica/utmath.c +++ b/drivers/acpi/acpica/utmath.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 389de3bd1ff1..443ffad01209 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 15073375bd00..586354788018 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c index 2514239282c2..792664982ea3 100644 --- a/drivers/acpi/acpica/utnonansi.c +++ b/drivers/acpi/acpica/utnonansi.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c index 72b9a062bbab..64e6641bfe82 100644 --- a/drivers/acpi/acpica/utobject.c +++ b/drivers/acpi/acpica/utobject.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 f0484b058c44..3175b133c0e4 100644 --- a/drivers/acpi/acpica/utosi.c +++ b/drivers/acpi/acpica/utosi.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c index 3cd573c5f7f9..c82399f9b456 100644 --- a/drivers/acpi/acpica/utownerid.c +++ b/drivers/acpi/acpica/utownerid.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c index ce18346b6144..350709f23e4c 100644 --- a/drivers/acpi/acpica/utpredef.c +++ b/drivers/acpi/acpica/utpredef.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c index 40eba804d49c..7e6e1ae6140f 100644 --- a/drivers/acpi/acpica/utprint.c +++ b/drivers/acpi/acpica/utprint.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 1de3376da66a..c86bae7b1d0f 100644 --- a/drivers/acpi/acpica/utresrc.c +++ b/drivers/acpi/acpica/utresrc.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -421,8 +421,10 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ut_walk_aml_resources); - /* The absolute minimum resource template is one end_tag descriptor */ - + /* + * The absolute minimum resource template is one end_tag descriptor. + * However, we will treat a lone end_tag as just a simple buffer. + */ if (aml_length < sizeof(struct aml_resource_end_tag)) { return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); } @@ -454,9 +456,8 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, /* Invoke the user function */ if (user_function) { - status = - user_function(aml, length, offset, resource_index, - context); + status = user_function(aml, length, offset, + resource_index, context); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -480,6 +481,12 @@ acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state, *context = aml; } + /* Check if buffer is defined to be longer than the resource length */ + + if (aml_length > (offset + length)) { + return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG); + } + /* Normal exit */ return_ACPI_STATUS(AE_OK); diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c index f3d4dbd5fac0..64308c304ade 100644 --- a/drivers/acpi/acpica/utstate.c +++ b/drivers/acpi/acpica/utstate.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 288913a0e709..9eacbcb9e4f4 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utstrtoul64.c b/drivers/acpi/acpica/utstrtoul64.c index b4f341c98a95..f42be01d99fd 100644 --- a/drivers/acpi/acpica/utstrtoul64.c +++ b/drivers/acpi/acpica/utstrtoul64.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c index df31d71ce596..9a07a42cae34 100644 --- a/drivers/acpi/acpica/uttrack.c +++ b/drivers/acpi/acpica/uttrack.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c index 81088ff9d67b..5028e06718b1 100644 --- a/drivers/acpi/acpica/utuuid.c +++ b/drivers/acpi/acpica/utuuid.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 ec503c862961..6b9ba4029f8e 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c index d9f15cbcd8a0..a16bd9eac653 100644 --- a/drivers/acpi/acpica/utxferror.c +++ b/drivers/acpi/acpica/utxferror.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index a5ca0f57cd08..6d5180601cf2 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -5,7 +5,7 @@ *****************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, 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 index 850de0155528..c016211c35ae 100644 --- a/drivers/acpi/acpica/utxfmutex.c +++ b/drivers/acpi/acpica/utxfmutex.c @@ -5,7 +5,7 @@ ******************************************************************************/ /* - * Copyright (C) 2000 - 2016, Intel Corp. + * Copyright (C) 2000 - 2017, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index eebb7e39c49c..ec50c32ea3da 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -711,7 +711,7 @@ static int __init einj_init(void) rc = einj_check_table(einj_tab); if (rc) { - pr_warn(FW_BUG "Invalid EINJ table.n"); + pr_warn(FW_BUG "Invalid EINJ table.\n"); return -EINVAL; } diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index e0d2e6e6e40c..3752521c62ab 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -536,7 +536,7 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, if (!iort_fwnode) return NULL; - ops = iommu_get_instance(iort_fwnode); + ops = iommu_ops_from_fwnode(iort_fwnode); if (!ops) return NULL; diff --git a/drivers/acpi/bgrt.c b/drivers/acpi/bgrt.c index 75f128e766a9..ca28aa572aa9 100644 --- a/drivers/acpi/bgrt.c +++ b/drivers/acpi/bgrt.c @@ -15,40 +15,41 @@ #include <linux/sysfs.h> #include <linux/efi-bgrt.h> +static void *bgrt_image; static struct kobject *bgrt_kobj; static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->version); + return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.version); } static DEVICE_ATTR(version, S_IRUGO, show_version, NULL); static ssize_t show_status(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->status); + return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.status); } static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_type); + return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_type); } static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); static ssize_t show_xoffset(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_x); + return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_x); } static DEVICE_ATTR(xoffset, S_IRUGO, show_xoffset, NULL); static ssize_t show_yoffset(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab->image_offset_y); + return snprintf(buf, PAGE_SIZE, "%d\n", bgrt_tab.image_offset_y); } static DEVICE_ATTR(yoffset, S_IRUGO, show_yoffset, NULL); @@ -84,15 +85,24 @@ static int __init bgrt_init(void) { int ret; - if (!bgrt_image) + if (!bgrt_tab.image_address) return -ENODEV; + bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, + MEMREMAP_WB); + if (!bgrt_image) { + pr_notice("Ignoring BGRT: failed to map image memory\n"); + return -ENOMEM; + } + bin_attr_image.private = bgrt_image; bin_attr_image.size = bgrt_image_size; bgrt_kobj = kobject_create_and_add("bgrt", acpi_kobj); - if (!bgrt_kobj) - return -EINVAL; + if (!bgrt_kobj) { + ret = -EINVAL; + goto out_memmap; + } ret = sysfs_create_group(bgrt_kobj, &bgrt_attribute_group); if (ret) @@ -102,6 +112,8 @@ static int __init bgrt_init(void) out_kobject: kobject_put(bgrt_kobj); +out_memmap: + memunmap(bgrt_image); return ret; } device_initcall(bgrt_init); diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 95855cb9d6fb..80cb5eb75b63 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -677,6 +677,48 @@ static bool acpi_of_match_device(struct acpi_device *adev, return false; } +static bool acpi_of_modalias(struct acpi_device *adev, + char *modalias, size_t len) +{ + const union acpi_object *of_compatible; + const union acpi_object *obj; + const char *str, *chr; + + of_compatible = adev->data.of_compatible; + if (!of_compatible) + return false; + + if (of_compatible->type == ACPI_TYPE_PACKAGE) + obj = of_compatible->package.elements; + else /* Must be ACPI_TYPE_STRING. */ + obj = of_compatible; + + str = obj->string.pointer; + chr = strchr(str, ','); + strlcpy(modalias, chr ? chr + 1 : str, len); + + return true; +} + +/** + * acpi_set_modalias - Set modalias using "compatible" property or supplied ID + * @adev: ACPI device object to match + * @default_id: ID string to use as default if no compatible string found + * @modalias: Pointer to buffer that modalias value will be copied into + * @len: Length of modalias buffer + * + * This is a counterpart of of_modalias_node() for struct acpi_device objects. + * If there is a compatible string for @adev, it will be copied to @modalias + * with the vendor prefix stripped; otherwise, @default_id will be used. + */ +void acpi_set_modalias(struct acpi_device *adev, const char *default_id, + char *modalias, size_t len) +{ + if (!acpi_of_modalias(adev, modalias, len)) + strlcpy(modalias, default_id, len); +} +EXPORT_SYMBOL_GPL(acpi_set_modalias); + static bool __acpi_match_device_cls(const struct acpi_device_id *id, struct acpi_hardware_id *hwid) { diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index e19f530f1083..668137e4a069 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -57,7 +57,6 @@ #define ACPI_BUTTON_LID_INIT_IGNORE 0x00 #define ACPI_BUTTON_LID_INIT_OPEN 0x01 -#define ACPI_BUTTON_LID_INIT_METHOD 0x02 #define _COMPONENT ACPI_BUTTON_COMPONENT ACPI_MODULE_NAME("button"); @@ -113,7 +112,7 @@ struct acpi_button { static BLOCKING_NOTIFIER_HEAD(acpi_lid_notifier); static struct acpi_device *lid_device; -static u8 lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; +static u8 lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; static unsigned long lid_report_interval __read_mostly = 500; module_param(lid_report_interval, ulong, 0644); @@ -377,9 +376,6 @@ static void acpi_lid_initialize_state(struct acpi_device *device) case ACPI_BUTTON_LID_INIT_OPEN: (void)acpi_lid_notify_state(device, 1); break; - case ACPI_BUTTON_LID_INIT_METHOD: - (void)acpi_lid_update_state(device); - break; case ACPI_BUTTON_LID_INIT_IGNORE: default: break; @@ -563,9 +559,6 @@ static int param_set_lid_init_state(const char *val, struct kernel_param *kp) if (!strncmp(val, "open", sizeof("open") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_OPEN; pr_info("Notify initial lid state as open\n"); - } else if (!strncmp(val, "method", sizeof("method") - 1)) { - lid_init_state = ACPI_BUTTON_LID_INIT_METHOD; - pr_info("Notify initial lid state with _LID return value\n"); } else if (!strncmp(val, "ignore", sizeof("ignore") - 1)) { lid_init_state = ACPI_BUTTON_LID_INIT_IGNORE; pr_info("Do not notify initial lid state\n"); @@ -579,8 +572,6 @@ static int param_get_lid_init_state(char *buffer, struct kernel_param *kp) switch (lid_init_state) { case ACPI_BUTTON_LID_INIT_OPEN: return sprintf(buffer, "open"); - case ACPI_BUTTON_LID_INIT_METHOD: - return sprintf(buffer, "method"); case ACPI_BUTTON_LID_INIT_IGNORE: return sprintf(buffer, "ignore"); default: diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 48e19d013170..c24235d8fb52 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -188,7 +188,6 @@ EXPORT_SYMBOL(first_ec); static bool boot_ec_is_ecdt = false; static struct workqueue_struct *ec_query_wq; -static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */ static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */ static int EC_FLAGS_CORRECT_ECDT; /* Needs ECDT port address correction */ @@ -492,26 +491,6 @@ static inline void __acpi_ec_disable_event(struct acpi_ec *ec) ec_log_drv("event blocked"); } -/* - * Process _Q events that might have accumulated in the EC. - * Run with locked ec mutex. - */ -static void acpi_ec_clear(struct acpi_ec *ec) -{ - int i, status; - u8 value = 0; - - for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) { - status = acpi_ec_query(ec, &value); - if (status || !value) - break; - } - if (unlikely(i == ACPI_EC_CLEAR_MAX)) - pr_warn("Warning: Maximum of %d stale EC events cleared\n", i); - else - pr_info("%d stale EC events cleared\n", i); -} - static void acpi_ec_enable_event(struct acpi_ec *ec) { unsigned long flags; @@ -520,10 +499,6 @@ static void acpi_ec_enable_event(struct acpi_ec *ec) if (acpi_ec_started(ec)) __acpi_ec_enable_event(ec); spin_unlock_irqrestore(&ec->lock, flags); - - /* Drain additional events if hardware requires that */ - if (EC_FLAGS_CLEAR_ON_RESUME) - acpi_ec_clear(ec); } #ifdef CONFIG_PM_SLEEP @@ -729,12 +704,12 @@ static void start_transaction(struct acpi_ec *ec) static int ec_guard(struct acpi_ec *ec) { - unsigned long guard = usecs_to_jiffies(ec_polling_guard); + unsigned long guard = usecs_to_jiffies(ec->polling_guard); unsigned long timeout = ec->timestamp + guard; /* Ensure guarding period before polling EC status */ do { - if (ec_busy_polling) { + if (ec->busy_polling) { /* Perform busy polling */ if (ec_transaction_completed(ec)) return 0; @@ -998,6 +973,28 @@ static void acpi_ec_stop(struct acpi_ec *ec, bool suspending) spin_unlock_irqrestore(&ec->lock, flags); } +static void acpi_ec_enter_noirq(struct acpi_ec *ec) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + ec->busy_polling = true; + ec->polling_guard = 0; + ec_log_drv("interrupt blocked"); + spin_unlock_irqrestore(&ec->lock, flags); +} + +static void acpi_ec_leave_noirq(struct acpi_ec *ec) +{ + unsigned long flags; + + spin_lock_irqsave(&ec->lock, flags); + ec->busy_polling = ec_busy_polling; + ec->polling_guard = ec_polling_guard; + ec_log_drv("interrupt unblocked"); + spin_unlock_irqrestore(&ec->lock, flags); +} + void acpi_ec_block_transactions(void) { struct acpi_ec *ec = first_ec; @@ -1278,7 +1275,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, if (function != ACPI_READ && function != ACPI_WRITE) return AE_BAD_PARAMETER; - if (ec_busy_polling || bits > 8) + if (ec->busy_polling || bits > 8) acpi_ec_burst_enable(ec); for (i = 0; i < bytes; ++i, ++address, ++value) @@ -1286,7 +1283,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address, acpi_ec_read(ec, address, value) : acpi_ec_write(ec, address, *value); - if (ec_busy_polling || bits > 8) + if (ec->busy_polling || bits > 8) acpi_ec_burst_disable(ec); switch (result) { @@ -1329,6 +1326,8 @@ static struct acpi_ec *acpi_ec_alloc(void) spin_lock_init(&ec->lock); INIT_WORK(&ec->work, acpi_ec_event_handler); ec->timestamp = jiffies; + ec->busy_polling = true; + ec->polling_guard = 0; return ec; } @@ -1390,6 +1389,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) acpi_ec_start(ec, false); if (!test_bit(EC_FLAGS_EC_HANDLER_INSTALLED, &ec->flags)) { + acpi_ec_enter_noirq(ec); status = acpi_install_address_space_handler(ec->handle, ACPI_ADR_SPACE_EC, &acpi_ec_space_handler, @@ -1429,6 +1429,7 @@ static int ec_install_handlers(struct acpi_ec *ec, bool handle_events) /* This is not fatal as we can poll EC events */ if (ACPI_SUCCESS(status)) { set_bit(EC_FLAGS_GPE_HANDLER_INSTALLED, &ec->flags); + acpi_ec_leave_noirq(ec); if (test_bit(EC_FLAGS_STARTED, &ec->flags) && ec->reference_count >= 1) acpi_ec_enable_gpe(ec, true); @@ -1741,31 +1742,6 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id) #endif /* - * On some hardware it is necessary to clear events accumulated by the EC during - * sleep. These ECs stop reporting GPEs until they are manually polled, if too - * many events are accumulated. (e.g. Samsung Series 5/9 notebooks) - * - * https://bugzilla.kernel.org/show_bug.cgi?id=44161 - * - * Ideally, the EC should also be instructed NOT to accumulate events during - * sleep (which Windows seems to do somehow), but the interface to control this - * behaviour is not known at this time. - * - * Models known to be affected are Samsung 530Uxx/535Uxx/540Uxx/550Pxx/900Xxx, - * however it is very likely that other Samsung models are affected. - * - * On systems which don't accumulate _Q events during sleep, this extra check - * should be harmless. - */ -static int ec_clear_on_resume(const struct dmi_system_id *id) -{ - pr_debug("Detected system needing EC poll on resume.\n"); - EC_FLAGS_CLEAR_ON_RESUME = 1; - ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS; - return 0; -} - -/* * Some ECDTs contain wrong register addresses. * MSI MS-171F * https://bugzilla.kernel.org/show_bug.cgi?id=12461 @@ -1782,9 +1758,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = { ec_correct_ecdt, "MSI MS-171F", { DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"), DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL}, - { - ec_clear_on_resume, "Samsung hardware", { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL}, {}, }; @@ -1839,34 +1812,6 @@ error: } #ifdef CONFIG_PM_SLEEP -static void acpi_ec_enter_noirq(struct acpi_ec *ec) -{ - unsigned long flags; - - if (ec == first_ec) { - spin_lock_irqsave(&ec->lock, flags); - ec->saved_busy_polling = ec_busy_polling; - ec->saved_polling_guard = ec_polling_guard; - ec_busy_polling = true; - ec_polling_guard = 0; - ec_log_drv("interrupt blocked"); - spin_unlock_irqrestore(&ec->lock, flags); - } -} - -static void acpi_ec_leave_noirq(struct acpi_ec *ec) -{ - unsigned long flags; - - if (ec == first_ec) { - spin_lock_irqsave(&ec->lock, flags); - ec_busy_polling = ec->saved_busy_polling; - ec_polling_guard = ec->saved_polling_guard; - ec_log_drv("interrupt unblocked"); - spin_unlock_irqrestore(&ec->lock, flags); - } -} - static int acpi_ec_suspend_noirq(struct device *dev) { struct acpi_ec *ec = diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index f8d65647ea79..fb19e1cdb641 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -98,7 +98,15 @@ static int find_child_checks(struct acpi_device *adev, bool check_children) if (check_children && list_empty(&adev->children)) return -ENODEV; - return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; + /* + * If the device has a _HID (or _CID) returning a valid ACPI/PNP + * device ID, it is better to make it look less attractive here, so that + * the other device with the same _ADR value (that may not have a valid + * device ID) can be matched going forward. [This means a second spec + * violation in a row, so whatever we do here is best effort anyway.] + */ + return sta_present && list_empty(&adev->pnp.ids) ? + FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } struct acpi_device *acpi_find_child_device(struct acpi_device *parent, @@ -250,7 +258,6 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) return 0; err: - acpi_dma_deconfigure(dev); ACPI_COMPANION_SET(dev, NULL); put_device(dev); put_device(&acpi_dev->dev); diff --git a/drivers/acpi/gsi.c b/drivers/acpi/gsi.c deleted file mode 100644 index ee9e0f27b2bf..000000000000 --- a/drivers/acpi/gsi.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ACPI GSI IRQ layer - * - * Copyright (C) 2015 ARM Ltd. - * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include <linux/acpi.h> -#include <linux/irq.h> -#include <linux/irqdomain.h> -#include <linux/of.h> - -enum acpi_irq_model_id acpi_irq_model; - -static struct fwnode_handle *acpi_gsi_domain_id; - -/** - * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI - * @gsi: GSI IRQ number to map - * @irq: pointer where linux IRQ number is stored - * - * irq location updated with irq value [>0 on success, 0 on failure] - * - * Returns: linux IRQ number on success (>0) - * -EINVAL on failure - */ -int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) -{ - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, - DOMAIN_BUS_ANY); - - *irq = irq_find_mapping(d, gsi); - /* - * *irq == 0 means no mapping, that should - * be reported as a failure - */ - return (*irq > 0) ? *irq : -EINVAL; -} -EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); - -/** - * acpi_register_gsi() - Map a GSI to a linux IRQ number - * @dev: device for which IRQ has to be mapped - * @gsi: GSI IRQ number - * @trigger: trigger type of the GSI number to be mapped - * @polarity: polarity of the GSI to be mapped - * - * Returns: a valid linux IRQ number on success - * -EINVAL on failure - */ -int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, - int polarity) -{ - struct irq_fwspec fwspec; - - if (WARN_ON(!acpi_gsi_domain_id)) { - pr_warn("GSI: No registered irqchip, giving up\n"); - return -EINVAL; - } - - fwspec.fwnode = acpi_gsi_domain_id; - fwspec.param[0] = gsi; - fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); - fwspec.param_count = 2; - - return irq_create_fwspec_mapping(&fwspec); -} -EXPORT_SYMBOL_GPL(acpi_register_gsi); - -/** - * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping - * @gsi: GSI IRQ number - */ -void acpi_unregister_gsi(u32 gsi) -{ - struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, - DOMAIN_BUS_ANY); - int irq = irq_find_mapping(d, gsi); - - irq_dispose_mapping(irq); -} -EXPORT_SYMBOL_GPL(acpi_unregister_gsi); - -/** - * acpi_set_irq_model - Setup the GSI irqdomain information - * @model: the value assigned to acpi_irq_model - * @fwnode: the irq_domain identifier for mapping and looking up - * GSI interrupts - */ -void __init acpi_set_irq_model(enum acpi_irq_model_id model, - struct fwnode_handle *fwnode) -{ - acpi_irq_model = model; - acpi_gsi_domain_id = fwnode; -} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 1b41a2739dac..219b90bc0922 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -37,6 +37,7 @@ void acpi_amba_init(void); static inline void acpi_amba_init(void) {} #endif int acpi_sysfs_init(void); +void acpi_gpe_apply_masked_gpes(void); void acpi_container_init(void); void acpi_memory_hotplug_init(void); #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC @@ -171,8 +172,8 @@ struct acpi_ec { struct work_struct work; unsigned long timestamp; unsigned long nr_pending_queries; - bool saved_busy_polling; - unsigned int saved_polling_guard; + bool busy_polling; + unsigned int polling_guard; }; extern struct acpi_ec *first_ec; diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c new file mode 100644 index 000000000000..830299a74b84 --- /dev/null +++ b/drivers/acpi/irq.c @@ -0,0 +1,297 @@ +/* + * ACPI GSI IRQ layer + * + * Copyright (C) 2015 ARM Ltd. + * Author: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/acpi.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> +#include <linux/of.h> + +enum acpi_irq_model_id acpi_irq_model; + +static struct fwnode_handle *acpi_gsi_domain_id; + +/** + * acpi_gsi_to_irq() - Retrieve the linux irq number for a given GSI + * @gsi: GSI IRQ number to map + * @irq: pointer where linux IRQ number is stored + * + * irq location updated with irq value [>0 on success, 0 on failure] + * + * Returns: linux IRQ number on success (>0) + * -EINVAL on failure + */ +int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +{ + struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, + DOMAIN_BUS_ANY); + + *irq = irq_find_mapping(d, gsi); + /* + * *irq == 0 means no mapping, that should + * be reported as a failure + */ + return (*irq > 0) ? *irq : -EINVAL; +} +EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); + +/** + * acpi_register_gsi() - Map a GSI to a linux IRQ number + * @dev: device for which IRQ has to be mapped + * @gsi: GSI IRQ number + * @trigger: trigger type of the GSI number to be mapped + * @polarity: polarity of the GSI to be mapped + * + * Returns: a valid linux IRQ number on success + * -EINVAL on failure + */ +int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) +{ + struct irq_fwspec fwspec; + + if (WARN_ON(!acpi_gsi_domain_id)) { + pr_warn("GSI: No registered irqchip, giving up\n"); + return -EINVAL; + } + + fwspec.fwnode = acpi_gsi_domain_id; + fwspec.param[0] = gsi; + fwspec.param[1] = acpi_dev_get_irq_type(trigger, polarity); + fwspec.param_count = 2; + + return irq_create_fwspec_mapping(&fwspec); +} +EXPORT_SYMBOL_GPL(acpi_register_gsi); + +/** + * acpi_unregister_gsi() - Free a GSI<->linux IRQ number mapping + * @gsi: GSI IRQ number + */ +void acpi_unregister_gsi(u32 gsi) +{ + struct irq_domain *d = irq_find_matching_fwnode(acpi_gsi_domain_id, + DOMAIN_BUS_ANY); + int irq = irq_find_mapping(d, gsi); + + irq_dispose_mapping(irq); +} +EXPORT_SYMBOL_GPL(acpi_unregister_gsi); + +/** + * acpi_get_irq_source_fwhandle() - Retrieve fwhandle from IRQ resource source. + * @source: acpi_resource_source to use for the lookup. + * + * Description: + * Retrieve the fwhandle of the device referenced by the given IRQ resource + * source. + * + * Return: + * The referenced device fwhandle or NULL on failure + */ +static struct fwnode_handle * +acpi_get_irq_source_fwhandle(const struct acpi_resource_source *source) +{ + struct fwnode_handle *result; + struct acpi_device *device; + acpi_handle handle; + acpi_status status; + + if (!source->string_length) + return acpi_gsi_domain_id; + + status = acpi_get_handle(NULL, source->string_ptr, &handle); + if (WARN_ON(ACPI_FAILURE(status))) + return NULL; + + device = acpi_bus_get_acpi_device(handle); + if (WARN_ON(!device)) + return NULL; + + result = &device->fwnode; + acpi_bus_put_acpi_device(device); + return result; +} + +/* + * Context for the resource walk used to lookup IRQ resources. + * Contains a return code, the lookup index, and references to the flags + * and fwspec where the result is returned. + */ +struct acpi_irq_parse_one_ctx { + int rc; + unsigned int index; + unsigned long *res_flags; + struct irq_fwspec *fwspec; +}; + +/** + * acpi_irq_parse_one_match - Handle a matching IRQ resource. + * @fwnode: matching fwnode + * @hwirq: hardware IRQ number + * @triggering: triggering attributes of hwirq + * @polarity: polarity attributes of hwirq + * @polarity: polarity attributes of hwirq + * @shareable: shareable attributes of hwirq + * @ctx: acpi_irq_parse_one_ctx updated by this function + * + * Description: + * Handle a matching IRQ resource by populating the given ctx with + * the information passed. + */ +static inline void acpi_irq_parse_one_match(struct fwnode_handle *fwnode, + u32 hwirq, u8 triggering, + u8 polarity, u8 shareable, + struct acpi_irq_parse_one_ctx *ctx) +{ + if (!fwnode) + return; + ctx->rc = 0; + *ctx->res_flags = acpi_dev_irq_flags(triggering, polarity, shareable); + ctx->fwspec->fwnode = fwnode; + ctx->fwspec->param[0] = hwirq; + ctx->fwspec->param[1] = acpi_dev_get_irq_type(triggering, polarity); + ctx->fwspec->param_count = 2; +} + +/** + * acpi_irq_parse_one_cb - Handle the given resource. + * @ares: resource to handle + * @context: context for the walk + * + * Description: + * This is called by acpi_walk_resources passing each resource returned by + * the _CRS method. We only inspect IRQ resources. Since IRQ resources + * might contain multiple interrupts we check if the index is within this + * one's interrupt array, otherwise we subtract the current resource IRQ + * count from the lookup index to prepare for the next resource. + * Once a match is found we call acpi_irq_parse_one_match to populate + * the result and end the walk by returning AE_CTRL_TERMINATE. + * + * Return: + * AE_OK if the walk should continue, AE_CTRL_TERMINATE if a matching + * IRQ resource was found. + */ +static acpi_status acpi_irq_parse_one_cb(struct acpi_resource *ares, + void *context) +{ + struct acpi_irq_parse_one_ctx *ctx = context; + struct acpi_resource_irq *irq; + struct acpi_resource_extended_irq *eirq; + struct fwnode_handle *fwnode; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IRQ: + irq = &ares->data.irq; + if (ctx->index >= irq->interrupt_count) { + ctx->index -= irq->interrupt_count; + return AE_OK; + } + fwnode = acpi_gsi_domain_id; + acpi_irq_parse_one_match(fwnode, irq->interrupts[ctx->index], + irq->triggering, irq->polarity, + irq->sharable, ctx); + return AE_CTRL_TERMINATE; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + eirq = &ares->data.extended_irq; + if (eirq->producer_consumer == ACPI_PRODUCER) + return AE_OK; + if (ctx->index >= eirq->interrupt_count) { + ctx->index -= eirq->interrupt_count; + return AE_OK; + } + fwnode = acpi_get_irq_source_fwhandle(&eirq->resource_source); + acpi_irq_parse_one_match(fwnode, eirq->interrupts[ctx->index], + eirq->triggering, eirq->polarity, + eirq->sharable, ctx); + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +/** + * acpi_irq_parse_one - Resolve an interrupt for a device + * @handle: the device whose interrupt is to be resolved + * @index: index of the interrupt to resolve + * @fwspec: structure irq_fwspec filled by this function + * @flags: resource flags filled by this function + * + * Description: + * Resolves an interrupt for a device by walking its CRS resources to find + * the appropriate ACPI IRQ resource and populating the given struct irq_fwspec + * and flags. + * + * Return: + * The result stored in ctx.rc by the callback, or the default -EINVAL value + * if an error occurs. + */ +static int acpi_irq_parse_one(acpi_handle handle, unsigned int index, + struct irq_fwspec *fwspec, unsigned long *flags) +{ + struct acpi_irq_parse_one_ctx ctx = { -EINVAL, index, flags, fwspec }; + + acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_parse_one_cb, &ctx); + return ctx.rc; +} + +/** + * acpi_irq_get - Lookup an ACPI IRQ resource and use it to initialize resource. + * @handle: ACPI device handle + * @index: ACPI IRQ resource index to lookup + * @res: Linux IRQ resource to initialize + * + * Description: + * Look for the ACPI IRQ resource with the given index and use it to initialize + * the given Linux IRQ resource. + * + * Return: + * 0 on success + * -EINVAL if an error occurs + * -EPROBE_DEFER if the IRQ lookup/conversion failed + */ +int acpi_irq_get(acpi_handle handle, unsigned int index, struct resource *res) +{ + struct irq_fwspec fwspec; + struct irq_domain *domain; + unsigned long flags; + int rc; + + rc = acpi_irq_parse_one(handle, index, &fwspec, &flags); + if (rc) + return rc; + + domain = irq_find_matching_fwnode(fwspec.fwnode, DOMAIN_BUS_ANY); + if (!domain) + return -EPROBE_DEFER; + + rc = irq_create_fwspec_mapping(&fwspec); + if (rc <= 0) + return -EINVAL; + + res->start = rc; + res->end = rc; + res->flags = flags; + + return 0; +} +EXPORT_SYMBOL_GPL(acpi_irq_get); + +/** + * acpi_set_irq_model - Setup the GSI irqdomain information + * @model: the value assigned to acpi_irq_model + * @fwnode: the irq_domain identifier for mapping and looking up + * GSI interrupts + */ +void __init acpi_set_irq_model(enum acpi_irq_model_id model, + struct fwnode_handle *fwnode) +{ + acpi_irq_model = model; + acpi_gsi_domain_id = fwnode; +} diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 2f82b8eba360..7361d00818e2 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2704,6 +2704,7 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) struct acpi_nfit_desc *acpi_desc = to_acpi_nfit_desc(nd_desc); struct device *dev = acpi_desc->dev; struct acpi_nfit_flush_work flush; + int rc; /* bounce the device lock to flush acpi_nfit_add / acpi_nfit_notify */ device_lock(dev); @@ -2716,7 +2717,10 @@ static int acpi_nfit_flush_probe(struct nvdimm_bus_descriptor *nd_desc) INIT_WORK_ONSTACK(&flush.work, flush_probe); COMPLETION_INITIALIZER_ONSTACK(flush.cmp); queue_work(nfit_wq, &flush.work); - return wait_for_completion_interruptible(&flush.cmp); + + rc = wait_for_completion_interruptible(&flush.cmp); + cancel_work_sync(&flush.work); + return rc; } static int acpi_nfit_clear_to_send(struct nvdimm_bus_descriptor *nd_desc, diff --git a/drivers/acpi/nfit/mce.c b/drivers/acpi/nfit/mce.c index e5ce81c38eed..3ba1c3472cf9 100644 --- a/drivers/acpi/nfit/mce.c +++ b/drivers/acpi/nfit/mce.c @@ -90,6 +90,7 @@ static int nfit_handle_mce(struct notifier_block *nb, unsigned long val, static struct notifier_block nfit_mce_dec = { .notifier_call = nfit_handle_mce, + .priority = MCE_PRIO_NFIT, }; void nfit_mce_register(void) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 57fb5f468ac2..db78d353bab1 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -1686,7 +1686,7 @@ acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, if (rc < 0) return AE_ERROR; else if (rc > 0) - return AE_CTRL_SKIP; + return AE_CTRL_TERMINATE; return AE_OK; } @@ -1697,6 +1697,7 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, __acpi_os_prepare_sleep = func; } +#if (ACPI_REDUCED_HARDWARE) acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, u32 val_b) { @@ -1707,13 +1708,35 @@ acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, if (rc < 0) return AE_ERROR; else if (rc > 0) - return AE_CTRL_SKIP; + return AE_CTRL_TERMINATE; return AE_OK; } +#else +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, + u32 val_b) +{ + return AE_OK; +} +#endif void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, u32 val_a, u32 val_b)) { __acpi_os_prepare_extended_sleep = func; } + +acpi_status acpi_os_enter_sleep(u8 sleep_state, + u32 reg_a_value, u32 reg_b_value) +{ + acpi_status status; + + if (acpi_gbl_reduced_hardware) + status = acpi_os_prepare_extended_sleep(sleep_state, + reg_a_value, + reg_b_value); + else + status = acpi_os_prepare_sleep(sleep_state, + reg_a_value, reg_b_value); + return status; +} diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index f0b4a981b8d3..18b72eec3507 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -75,10 +75,8 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, struct acpi_processor *pr; unsigned int ppc = 0; - if (event == CPUFREQ_START && ignore_ppc <= 0) { + if (ignore_ppc < 0) ignore_ppc = 0; - return 0; - } if (ignore_ppc) return 0; diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index cb57962ef7c4..8b11d6d385dc 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -43,6 +43,19 @@ static inline bool acpi_iospace_resource_valid(struct resource *res) { return true; } #endif +#if IS_ENABLED(CONFIG_ACPI_GENERIC_GSI) +static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq) +{ + return ext_irq->resource_source.string_length == 0 && + ext_irq->producer_consumer == ACPI_CONSUMER; +} +#else +static inline bool is_gsi(struct acpi_resource_extended_irq *ext_irq) +{ + return true; +} +#endif + static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io) { u64 reslen = end - start + 1; @@ -470,9 +483,12 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, acpi_dev_irqresource_disabled(res, 0); return false; } - acpi_dev_get_irqresource(res, ext_irq->interrupts[index], + if (is_gsi(ext_irq)) + acpi_dev_get_irqresource(res, ext_irq->interrupts[index], ext_irq->triggering, ext_irq->polarity, ext_irq->sharable, false); + else + acpi_dev_irqresource_disabled(res, 0); break; default: res->flags = 0; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 45dec874ea55..192691880d55 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -2074,6 +2074,7 @@ int __init acpi_scan_init(void) } } + acpi_gpe_apply_masked_gpes(); acpi_update_all_gpes(); acpi_ec_ecdt_start(); diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 9b6cebe227a0..a4327af676fe 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -130,6 +130,12 @@ void __init acpi_nvs_nosave_s3(void) nvs_nosave_s3 = true; } +static int __init init_nvs_save_s3(const struct dmi_system_id *d) +{ + nvs_nosave_s3 = false; + return 0; +} + /* * ACPI 1.0 wants us to execute _PTS before suspending devices, so we allow the * user to request that behavior by using the 'acpi_old_suspend_ordering' @@ -324,6 +330,19 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"), }, }, + /* + * https://bugzilla.kernel.org/show_bug.cgi?id=189431 + * Lenovo G50-45 is a platform later than 2012, but needs nvs memory + * saving during S3. + */ + { + .callback = init_nvs_save_s3, + .ident = "Lenovo G50-45", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "80E3"), + }, + }, {}, }; @@ -674,14 +693,6 @@ static void acpi_sleep_suspend_setup(void) if (acpi_sleep_state_supported(i)) sleep_states[i] = 1; - /* - * Use suspend-to-idle by default if ACPI_FADT_LOW_POWER_S0 is set and - * the default suspend mode was not selected from the command line. - */ - if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0 && - mem_sleep_default > PM_SUSPEND_MEM) - mem_sleep_default = PM_SUSPEND_FREEZE; - suspend_set_ops(old_suspend_ordering ? &acpi_suspend_ops_old : &acpi_suspend_ops); freeze_set_ops(&acpi_freeze_ops); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 703c26e7022c..cf05ae973381 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -708,6 +708,62 @@ end: return result ? result : size; } +/* + * A Quirk Mechanism for GPE Flooding Prevention: + * + * Quirks may be needed to prevent GPE flooding on a specific GPE. The + * flooding typically cannot be detected and automatically prevented by + * ACPI_GPE_DISPATCH_NONE check because there is a _Lxx/_Exx prepared in + * the AML tables. This normally indicates a feature gap in Linux, thus + * instead of providing endless quirk tables, we provide a boot parameter + * for those who want this quirk. For example, if the users want to prevent + * the GPE flooding for GPE 00, they need to specify the following boot + * parameter: + * acpi_mask_gpe=0x00 + * The masking status can be modified by the following runtime controlling + * interface: + * echo unmask > /sys/firmware/acpi/interrupts/gpe00 + */ + +/* + * Currently, the GPE flooding prevention only supports to mask the GPEs + * numbered from 00 to 7f. + */ +#define ACPI_MASKABLE_GPE_MAX 0x80 + +static u64 __initdata acpi_masked_gpes; + +static int __init acpi_gpe_set_masked_gpes(char *val) +{ + u8 gpe; + + if (kstrtou8(val, 0, &gpe) || gpe > ACPI_MASKABLE_GPE_MAX) + return -EINVAL; + acpi_masked_gpes |= ((u64)1<<gpe); + + return 1; +} +__setup("acpi_mask_gpe=", acpi_gpe_set_masked_gpes); + +void __init acpi_gpe_apply_masked_gpes(void) +{ + acpi_handle handle; + acpi_status status; + u8 gpe; + + for (gpe = 0; + gpe < min_t(u8, ACPI_MASKABLE_GPE_MAX, acpi_current_gpe_count); + gpe++) { + if (acpi_masked_gpes & ((u64)1<<gpe)) { + status = acpi_get_gpe_device(gpe, &handle); + if (ACPI_SUCCESS(status)) { + pr_info("Masking GPE 0x%x.\n", gpe); + (void)acpi_mask_gpe(handle, gpe, TRUE); + } + } + } +} + void acpi_irq_stats_init(void) { acpi_status status; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 02ded25c82e4..7f48156cbc0c 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -305,17 +305,6 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Dell System XPS L702X"), }, }, - { - /* https://bugzilla.redhat.com/show_bug.cgi?id=1204476 */ - /* https://bugs.launchpad.net/ubuntu/+source/linux-lts-trusty/+bug/1416940 */ - .callback = video_detect_force_native, - .ident = "HP Pavilion dv6", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion dv6 Notebook PC"), - }, - }, - { }, }; diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 9cd0a2d41816..c2d3785ec227 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1702,6 +1702,8 @@ unsigned ata_exec_internal_sg(struct ata_device *dev, if (qc->err_mask & ~AC_ERR_OTHER) qc->err_mask &= ~AC_ERR_OTHER; + } else if (qc->tf.command == ATA_CMD_REQ_SENSE_DATA) { + qc->result_tf.command |= ATA_SENSE; } /* finish up */ @@ -4356,10 +4358,10 @@ static const struct ata_blacklist_entry ata_device_blacklist [] = { { "ST380013AS", "3.20", ATA_HORKAGE_MAX_SEC_1024 }, /* - * Device times out with higher max sects. + * These devices time out with higher max sects. * https://bugzilla.kernel.org/show_bug.cgi?id=121671 */ - { "LITEON CX1-JB256-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, + { "LITEON CX1-JB*-HP", NULL, ATA_HORKAGE_MAX_SEC_1024 }, /* Devices we expect to fail diagnostics */ diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 1f863e757ee4..c771d4c341ea 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1265,13 +1265,13 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev) */ static int atapi_drain_needed(struct request *rq) { - if (likely(rq->cmd_type != REQ_TYPE_BLOCK_PC)) + if (likely(!blk_rq_is_passthrough(rq))) return 0; if (!blk_rq_bytes(rq) || op_is_write(req_op(rq))) return 0; - return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC; + return atapi_cmd_type(scsi_req(rq)->cmd[0]) == ATAPI_MISC; } static int ata_scsi_dev_config(struct scsi_device *sdev, diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 823e938c9a78..2f32782cea6d 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4132,6 +4132,9 @@ static int mv_platform_probe(struct platform_device *pdev) host->iomap = NULL; hpriv->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!hpriv->base) + return -ENOMEM; + hpriv->base -= SATAHC0_REG_BASE; hpriv->clk = clk_get(&pdev->dev, NULL); diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index 4ef4c5caed4f..8a8e403644d6 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -132,9 +132,9 @@ config HT16K33 tristate "Holtek Ht16K33 LED controller with keyscan" depends on FB && OF && I2C && INPUT select FB_SYS_FOPS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT select INPUT_MATRIXKMAP select FB_BACKLIGHT help diff --git a/drivers/base/base.h b/drivers/base/base.h index ada9dce34e6d..e19b1008e5fb 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -141,8 +141,6 @@ extern void device_unblock_probing(void); extern struct kset *devices_kset; extern void devices_kset_move_last(struct device *dev); -extern struct device_attribute dev_attr_deferred_probe; - #if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) extern void module_add_driver(struct module *mod, struct device_driver *drv); extern void module_remove_driver(struct device_driver *drv); diff --git a/drivers/base/core.c b/drivers/base/core.c index 020ea7f05520..8c25e68e67d7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1060,14 +1060,8 @@ static int device_add_attrs(struct device *dev) goto err_remove_dev_groups; } - error = device_create_file(dev, &dev_attr_deferred_probe); - if (error) - goto err_remove_online; - return 0; - err_remove_online: - device_remove_file(dev, &dev_attr_online); err_remove_dev_groups: device_remove_groups(dev, dev->groups); err_remove_type_groups: @@ -1085,7 +1079,6 @@ static void device_remove_attrs(struct device *dev) struct class *class = dev->class; const struct device_type *type = dev->type; - device_remove_file(dev, &dev_attr_deferred_probe); device_remove_file(dev, &dev_attr_online); device_remove_groups(dev, dev->groups); diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 4c28e1a09786..2c3b359b3536 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -17,6 +17,7 @@ #include <linux/of.h> #include <linux/cpufeature.h> #include <linux/tick.h> +#include <linux/pm_qos.h> #include "base.h" @@ -376,6 +377,7 @@ int register_cpu(struct cpu *cpu, int num) per_cpu(cpu_sys_devices, num) = &cpu->dev; register_cpu_under_node(num, cpu_to_node(num)); + dev_pm_qos_expose_latency_limit(&cpu->dev, 0); return 0; } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a8b258e5407b..a1fbf55c4d3a 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -53,19 +53,6 @@ static LIST_HEAD(deferred_probe_pending_list); static LIST_HEAD(deferred_probe_active_list); static atomic_t deferred_trigger_count = ATOMIC_INIT(0); -static ssize_t deferred_probe_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - bool value; - - mutex_lock(&deferred_probe_mutex); - value = !list_empty(&dev->p->deferred_probe); - mutex_unlock(&deferred_probe_mutex); - - return sprintf(buf, "%d\n", value); -} -DEVICE_ATTR_RO(deferred_probe); - /* * In some cases, like suspend to RAM or hibernation, It might be reasonable * to prohibit probing of devices as it could be unsafe. diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 4497d263209f..ac350c518e0c 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -558,9 +558,6 @@ static void fw_load_abort(struct firmware_priv *fw_priv) struct firmware_buf *buf = fw_priv->buf; __fw_load_abort(buf); - - /* avoid user action after loading abort */ - fw_priv->buf = NULL; } static LIST_HEAD(pending_fw_head); @@ -713,7 +710,7 @@ static ssize_t firmware_loading_store(struct device *dev, mutex_lock(&fw_lock); fw_buf = fw_priv->buf; - if (!fw_buf) + if (fw_state_is_aborted(&fw_buf->fw_st)) goto out; switch (loading) { diff --git a/drivers/base/memory.c b/drivers/base/memory.c index 8ab8ea1253e6..fa26ffd25fa6 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -389,33 +389,33 @@ static ssize_t show_valid_zones(struct device *dev, { struct memory_block *mem = to_memory_block(dev); unsigned long start_pfn, end_pfn; + unsigned long valid_start, valid_end, valid_pages; unsigned long nr_pages = PAGES_PER_SECTION * sections_per_block; - struct page *first_page; struct zone *zone; int zone_shift = 0; start_pfn = section_nr_to_pfn(mem->start_section_nr); end_pfn = start_pfn + nr_pages; - first_page = pfn_to_page(start_pfn); /* The block contains more than one zone can not be offlined. */ - if (!test_pages_in_a_zone(start_pfn, end_pfn)) + if (!test_pages_in_a_zone(start_pfn, end_pfn, &valid_start, &valid_end)) return sprintf(buf, "none\n"); - zone = page_zone(first_page); + zone = page_zone(pfn_to_page(valid_start)); + valid_pages = valid_end - valid_start; /* MMOP_ONLINE_KEEP */ sprintf(buf, "%s", zone->name); /* MMOP_ONLINE_KERNEL */ - zone_shift = zone_can_shift(start_pfn, nr_pages, ZONE_NORMAL); + zone_can_shift(valid_start, valid_pages, ZONE_NORMAL, &zone_shift); if (zone_shift) { strcat(buf, " "); strcat(buf, (zone + zone_shift)->name); } /* MMOP_ONLINE_MOVABLE */ - zone_shift = zone_can_shift(start_pfn, nr_pages, ZONE_MOVABLE); + zone_can_shift(valid_start, valid_pages, ZONE_MOVABLE, &zone_shift); if (zone_shift) { strcat(buf, " "); strcat(buf, (zone + zone_shift)->name); diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c index be6a599bc0c1..0fc7c4da7756 100644 --- a/drivers/base/platform-msi.c +++ b/drivers/base/platform-msi.c @@ -206,7 +206,7 @@ platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec, { struct platform_msi_priv_data *datap; /* - * Limit the number of interrupts to 256 per device. Should we + * Limit the number of interrupts to 2048 per device. Should we * need to bump this up, DEV_ID_SHIFT should be adjusted * accordingly (which would impact the max number of MSI * capable devices). diff --git a/drivers/base/platform.c b/drivers/base/platform.c index c4af00385502..647e4761dbf3 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -102,6 +102,16 @@ int platform_get_irq(struct platform_device *dev, unsigned int num) } r = platform_get_resource(dev, IORESOURCE_IRQ, num); + if (has_acpi_companion(&dev->dev)) { + if (r && r->flags & IORESOURCE_DISABLED) { + int ret; + + ret = acpi_irq_get(ACPI_HANDLE(&dev->dev), num, r); + if (ret) + return ret; + } + } + /* * The resources may pass trigger flags to the irqs that need * to be set up. It so happens that the trigger flags for diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a5e1262b964b..3a75fb1b4126 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -130,7 +130,7 @@ static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev, ret = pm_runtime_is_irq_safe(dev) && !genpd_is_irq_safe(genpd); - /* Warn once for each IRQ safe dev in no sleep domain */ + /* Warn once if IRQ safe dev in no sleep domain */ if (ret) dev_warn_once(dev, "PM domain %s will not be powered off\n", genpd->name); @@ -201,7 +201,7 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd) smp_mb__after_atomic(); } -static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) +static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; ktime_t time_start; @@ -231,7 +231,7 @@ static int genpd_power_on(struct generic_pm_domain *genpd, bool timed) return ret; } -static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) +static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed) { unsigned int state_idx = genpd->state_idx; ktime_t time_start; @@ -262,10 +262,10 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) } /** - * genpd_queue_power_off_work - Queue up the execution of genpd_poweroff(). + * genpd_queue_power_off_work - Queue up the execution of genpd_power_off(). * @genpd: PM domain to power off. * - * Queue up the execution of genpd_poweroff() unless it's already been done + * Queue up the execution of genpd_power_off() unless it's already been done * before. */ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) @@ -274,14 +274,14 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) } /** - * genpd_poweron - Restore power to a given PM domain and its masters. + * genpd_power_on - Restore power to a given PM domain and its masters. * @genpd: PM domain to power up. * @depth: nesting count for lockdep. * * Restore power to @genpd and all of its masters so that it is possible to * resume a device belonging to it. */ -static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) +static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth) { struct gpd_link *link; int ret = 0; @@ -300,7 +300,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) genpd_sd_counter_inc(master); genpd_lock_nested(master, depth + 1); - ret = genpd_poweron(master, depth + 1); + ret = genpd_power_on(master, depth + 1); genpd_unlock(master); if (ret) { @@ -309,7 +309,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) } } - ret = genpd_power_on(genpd, true); + ret = _genpd_power_on(genpd, true); if (ret) goto err; @@ -368,14 +368,14 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, } /** - * genpd_poweroff - Remove power from a given PM domain. + * genpd_power_off - Remove power from a given PM domain. * @genpd: PM domain to power down. * @is_async: PM domain is powered down from a scheduled work * * If all of the @genpd's devices have been suspended and all of its subdomains * have been powered down, remove power from @genpd. */ -static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async) +static int genpd_power_off(struct generic_pm_domain *genpd, bool is_async) { struct pm_domain_data *pdd; struct gpd_link *link; @@ -427,13 +427,13 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async) /* * If sd_count > 0 at this point, one of the subdomains hasn't - * managed to call genpd_poweron() for the master yet after - * incrementing it. In that case genpd_poweron() will wait + * managed to call genpd_power_on() for the master yet after + * incrementing it. In that case genpd_power_on() will wait * for us to drop the lock, so we can call .power_off() and let - * the genpd_poweron() restore power for us (this shouldn't + * the genpd_power_on() restore power for us (this shouldn't * happen very often). */ - ret = genpd_power_off(genpd, true); + ret = _genpd_power_off(genpd, true); if (ret) return ret; } @@ -459,7 +459,7 @@ static void genpd_power_off_work_fn(struct work_struct *work) genpd = container_of(work, struct generic_pm_domain, power_off_work); genpd_lock(genpd); - genpd_poweroff(genpd, true); + genpd_power_off(genpd, true); genpd_unlock(genpd); } @@ -578,7 +578,7 @@ static int genpd_runtime_suspend(struct device *dev) return 0; genpd_lock(genpd); - genpd_poweroff(genpd, false); + genpd_power_off(genpd, false); genpd_unlock(genpd); return 0; @@ -618,7 +618,7 @@ static int genpd_runtime_resume(struct device *dev) } genpd_lock(genpd); - ret = genpd_poweron(genpd, 0); + ret = genpd_power_on(genpd, 0); genpd_unlock(genpd); if (ret) @@ -626,6 +626,7 @@ static int genpd_runtime_resume(struct device *dev) out: /* Measure resume latency. */ + time_start = 0; if (timed && runtime_pm) time_start = ktime_get(); @@ -657,7 +658,7 @@ err_poweroff: if (!pm_runtime_is_irq_safe(dev) || (pm_runtime_is_irq_safe(dev) && genpd_is_irq_safe(genpd))) { genpd_lock(genpd); - genpd_poweroff(genpd, 0); + genpd_power_off(genpd, 0); genpd_unlock(genpd); } @@ -673,9 +674,9 @@ static int __init pd_ignore_unused_setup(char *__unused) __setup("pd_ignore_unused", pd_ignore_unused_setup); /** - * genpd_poweroff_unused - Power off all PM domains with no devices in use. + * genpd_power_off_unused - Power off all PM domains with no devices in use. */ -static int __init genpd_poweroff_unused(void) +static int __init genpd_power_off_unused(void) { struct generic_pm_domain *genpd; @@ -693,7 +694,7 @@ static int __init genpd_poweroff_unused(void) return 0; } -late_initcall(genpd_poweroff_unused); +late_initcall(genpd_power_off_unused); #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF) @@ -726,18 +727,20 @@ static bool genpd_dev_active_wakeup(struct generic_pm_domain *genpd, } /** - * genpd_sync_poweroff - Synchronously power off a PM domain and its masters. + * genpd_sync_power_off - Synchronously power off a PM domain and its masters. * @genpd: PM domain to power off, if possible. + * @use_lock: use the lock. + * @depth: nesting count for lockdep. * * Check if the given PM domain can be powered off (during system suspend or * hibernation) and do that if so. Also, in that case propagate to its masters. * * This function is only called in "noirq" and "syscore" stages of system power - * transitions, so it need not acquire locks (all of the "noirq" callbacks are - * executed sequentially, so it is guaranteed that it will never run twice in - * parallel). + * transitions. The "noirq" callbacks may be executed asynchronously, thus in + * these cases the lock must be held. */ -static void genpd_sync_poweroff(struct generic_pm_domain *genpd) +static void genpd_sync_power_off(struct generic_pm_domain *genpd, bool use_lock, + unsigned int depth) { struct gpd_link *link; @@ -750,26 +753,35 @@ static void genpd_sync_poweroff(struct generic_pm_domain *genpd) /* Choose the deepest state when suspending */ genpd->state_idx = genpd->state_count - 1; - genpd_power_off(genpd, false); + _genpd_power_off(genpd, false); genpd->status = GPD_STATE_POWER_OFF; list_for_each_entry(link, &genpd->slave_links, slave_node) { genpd_sd_counter_dec(link->master); - genpd_sync_poweroff(link->master); + + if (use_lock) + genpd_lock_nested(link->master, depth + 1); + + genpd_sync_power_off(link->master, use_lock, depth + 1); + + if (use_lock) + genpd_unlock(link->master); } } /** - * genpd_sync_poweron - Synchronously power on a PM domain and its masters. + * genpd_sync_power_on - Synchronously power on a PM domain and its masters. * @genpd: PM domain to power on. + * @use_lock: use the lock. + * @depth: nesting count for lockdep. * * This function is only called in "noirq" and "syscore" stages of system power - * transitions, so it need not acquire locks (all of the "noirq" callbacks are - * executed sequentially, so it is guaranteed that it will never run twice in - * parallel). + * transitions. The "noirq" callbacks may be executed asynchronously, thus in + * these cases the lock must be held. */ -static void genpd_sync_poweron(struct generic_pm_domain *genpd) +static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock, + unsigned int depth) { struct gpd_link *link; @@ -777,11 +789,18 @@ static void genpd_sync_poweron(struct generic_pm_domain *genpd) return; list_for_each_entry(link, &genpd->slave_links, slave_node) { - genpd_sync_poweron(link->master); genpd_sd_counter_inc(link->master); + + if (use_lock) + genpd_lock_nested(link->master, depth + 1); + + genpd_sync_power_on(link->master, use_lock, depth + 1); + + if (use_lock) + genpd_unlock(link->master); } - genpd_power_on(genpd, false); + _genpd_power_on(genpd, false); genpd->status = GPD_STATE_ACTIVE; } @@ -887,13 +906,10 @@ static int pm_genpd_suspend_noirq(struct device *dev) return ret; } - /* - * Since all of the "noirq" callbacks are executed sequentially, it is - * guaranteed that this function will never run twice in parallel for - * the same PM domain, so it is not necessary to use locking here. - */ + genpd_lock(genpd); genpd->suspended_count++; - genpd_sync_poweroff(genpd); + genpd_sync_power_off(genpd, true, 0); + genpd_unlock(genpd); return 0; } @@ -918,13 +934,10 @@ static int pm_genpd_resume_noirq(struct device *dev) if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)) return 0; - /* - * Since all of the "noirq" callbacks are executed sequentially, it is - * guaranteed that this function will never run twice in parallel for - * the same PM domain, so it is not necessary to use locking here. - */ - genpd_sync_poweron(genpd); + genpd_lock(genpd); + genpd_sync_power_on(genpd, true, 0); genpd->suspended_count--; + genpd_unlock(genpd); if (genpd->dev_ops.stop && genpd->dev_ops.start) ret = pm_runtime_force_resume(dev); @@ -1001,22 +1014,20 @@ static int pm_genpd_restore_noirq(struct device *dev) return -EINVAL; /* - * Since all of the "noirq" callbacks are executed sequentially, it is - * guaranteed that this function will never run twice in parallel for - * the same PM domain, so it is not necessary to use locking here. - * * At this point suspended_count == 0 means we are being run for the * first time for the given domain in the present cycle. */ + genpd_lock(genpd); if (genpd->suspended_count++ == 0) /* * The boot kernel might put the domain into arbitrary state, - * so make it appear as powered off to genpd_sync_poweron(), + * so make it appear as powered off to genpd_sync_power_on(), * so that it tries to power it on in case it was really off. */ genpd->status = GPD_STATE_POWER_OFF; - genpd_sync_poweron(genpd); + genpd_sync_power_on(genpd, true, 0); + genpd_unlock(genpd); if (genpd->dev_ops.stop && genpd->dev_ops.start) ret = pm_runtime_force_resume(dev); @@ -1071,9 +1082,9 @@ static void genpd_syscore_switch(struct device *dev, bool suspend) if (suspend) { genpd->suspended_count++; - genpd_sync_poweroff(genpd); + genpd_sync_power_off(genpd, false, 0); } else { - genpd_sync_poweron(genpd); + genpd_sync_power_on(genpd, false, 0); genpd->suspended_count--; } } @@ -2042,7 +2053,7 @@ int genpd_dev_pm_attach(struct device *dev) dev->pm_domain->sync = genpd_dev_pm_sync; genpd_lock(pd); - ret = genpd_poweron(pd, 0); + ret = genpd_power_on(pd, 0); genpd_unlock(pd); out: return ret ? -EPROBE_DEFER : 0; diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index 35ff06283738..91ec3232d630 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c @@ -32,13 +32,7 @@ LIST_HEAD(opp_tables); /* Lock to allow exclusive modification to the device and opp lists */ DEFINE_MUTEX(opp_table_lock); -#define opp_rcu_lockdep_assert() \ -do { \ - RCU_LOCKDEP_WARN(!rcu_read_lock_held() && \ - !lockdep_is_held(&opp_table_lock), \ - "Missing rcu_read_lock() or " \ - "opp_table_lock protection"); \ -} while (0) +static void dev_pm_opp_get(struct dev_pm_opp *opp); static struct opp_device *_find_opp_dev(const struct device *dev, struct opp_table *opp_table) @@ -52,38 +46,46 @@ static struct opp_device *_find_opp_dev(const struct device *dev, return NULL; } +static struct opp_table *_find_opp_table_unlocked(struct device *dev) +{ + struct opp_table *opp_table; + + list_for_each_entry(opp_table, &opp_tables, node) { + if (_find_opp_dev(dev, opp_table)) { + _get_opp_table_kref(opp_table); + + return opp_table; + } + } + + return ERR_PTR(-ENODEV); +} + /** * _find_opp_table() - find opp_table struct using device pointer * @dev: device pointer used to lookup OPP table * - * Search OPP table for one containing matching device. Does a RCU reader - * operation to grab the pointer needed. + * Search OPP table for one containing matching device. * * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or * -EINVAL based on type of error. * - * Locking: For readers, this function must be called under rcu_read_lock(). - * opp_table is a RCU protected pointer, which means that opp_table is valid - * as long as we are under RCU lock. - * - * For Writers, this function must be called with opp_table_lock held. + * The callers must call dev_pm_opp_put_opp_table() after the table is used. */ struct opp_table *_find_opp_table(struct device *dev) { struct opp_table *opp_table; - opp_rcu_lockdep_assert(); - if (IS_ERR_OR_NULL(dev)) { pr_err("%s: Invalid parameters\n", __func__); return ERR_PTR(-EINVAL); } - list_for_each_entry_rcu(opp_table, &opp_tables, node) - if (_find_opp_dev(dev, opp_table)) - return opp_table; + mutex_lock(&opp_table_lock); + opp_table = _find_opp_table_unlocked(dev); + mutex_unlock(&opp_table_lock); - return ERR_PTR(-ENODEV); + return opp_table; } /** @@ -94,29 +96,15 @@ struct opp_table *_find_opp_table(struct device *dev) * return 0 * * This is useful only for devices with single power supply. - * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. This means that opp which could have been fetched by - * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are - * under RCU lock. The pointer returned by the opp_find_freq family must be - * used in the same section as the usage of this function with the pointer - * prior to unlocking with rcu_read_unlock() to maintain the integrity of the - * pointer. */ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) { - struct dev_pm_opp *tmp_opp; - unsigned long v = 0; - - opp_rcu_lockdep_assert(); - - tmp_opp = rcu_dereference(opp); - if (IS_ERR_OR_NULL(tmp_opp)) + if (IS_ERR_OR_NULL(opp)) { pr_err("%s: Invalid parameters\n", __func__); - else - v = tmp_opp->supplies[0].u_volt; + return 0; + } - return v; + return opp->supplies[0].u_volt; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage); @@ -126,29 +114,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage); * * Return: frequency in hertz corresponding to the opp, else * return 0 - * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. This means that opp which could have been fetched by - * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are - * under RCU lock. The pointer returned by the opp_find_freq family must be - * used in the same section as the usage of this function with the pointer - * prior to unlocking with rcu_read_unlock() to maintain the integrity of the - * pointer. */ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) { - struct dev_pm_opp *tmp_opp; - unsigned long f = 0; - - opp_rcu_lockdep_assert(); - - tmp_opp = rcu_dereference(opp); - if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) + if (IS_ERR_OR_NULL(opp) || !opp->available) { pr_err("%s: Invalid parameters\n", __func__); - else - f = tmp_opp->rate; + return 0; + } - return f; + return opp->rate; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); @@ -161,28 +135,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq); * quickly. Running on them for longer times may overheat the chip. * * Return: true if opp is turbo opp, else false. - * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. This means that opp which could have been fetched by - * opp_find_freq_{exact,ceil,floor} functions is valid as long as we are - * under RCU lock. The pointer returned by the opp_find_freq family must be - * used in the same section as the usage of this function with the pointer - * prior to unlocking with rcu_read_unlock() to maintain the integrity of the - * pointer. */ bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp) { - struct dev_pm_opp *tmp_opp; - - opp_rcu_lockdep_assert(); - - tmp_opp = rcu_dereference(opp); - if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) { + if (IS_ERR_OR_NULL(opp) || !opp->available) { pr_err("%s: Invalid parameters\n", __func__); return false; } - return tmp_opp->turbo; + return opp->turbo; } EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo); @@ -191,52 +152,29 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo); * @dev: device for which we do this operation * * Return: This function returns the max clock latency in nanoseconds. - * - * Locking: This function takes rcu_read_lock(). */ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) { struct opp_table *opp_table; unsigned long clock_latency_ns; - rcu_read_lock(); - opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) - clock_latency_ns = 0; - else - clock_latency_ns = opp_table->clock_latency_ns_max; - - rcu_read_unlock(); - return clock_latency_ns; -} -EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); - -static int _get_regulator_count(struct device *dev) -{ - struct opp_table *opp_table; - int count; + return 0; - rcu_read_lock(); + clock_latency_ns = opp_table->clock_latency_ns_max; - opp_table = _find_opp_table(dev); - if (!IS_ERR(opp_table)) - count = opp_table->regulator_count; - else - count = 0; + dev_pm_opp_put_opp_table(opp_table); - rcu_read_unlock(); - - return count; + return clock_latency_ns; } +EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); /** * dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds * @dev: device for which we do this operation * * Return: This function returns the max voltage latency in nanoseconds. - * - * Locking: This function takes rcu_read_lock(). */ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) { @@ -250,35 +188,33 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) unsigned long max; } *uV; - count = _get_regulator_count(dev); + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return 0; + + count = opp_table->regulator_count; /* Regulator may not be required for the device */ if (!count) - return 0; + goto put_opp_table; regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL); if (!regulators) - return 0; + goto put_opp_table; uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL); if (!uV) goto free_regulators; - rcu_read_lock(); - - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - rcu_read_unlock(); - goto free_uV; - } - memcpy(regulators, opp_table->regulators, count * sizeof(*regulators)); + mutex_lock(&opp_table->lock); + for (i = 0; i < count; i++) { uV[i].min = ~0; uV[i].max = 0; - list_for_each_entry_rcu(opp, &opp_table->opp_list, node) { + list_for_each_entry(opp, &opp_table->opp_list, node) { if (!opp->available) continue; @@ -289,7 +225,7 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) } } - rcu_read_unlock(); + mutex_unlock(&opp_table->lock); /* * The caller needs to ensure that opp_table (and hence the regulator) @@ -301,10 +237,11 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) latency_ns += ret * 1000; } -free_uV: kfree(uV); free_regulators: kfree(regulators); +put_opp_table: + dev_pm_opp_put_opp_table(opp_table); return latency_ns; } @@ -317,8 +254,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_volt_latency); * * Return: This function returns the max transition latency, in nanoseconds, to * switch from one OPP to other. - * - * Locking: This function takes rcu_read_lock(). */ unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev) { @@ -328,32 +263,29 @@ unsigned long dev_pm_opp_get_max_transition_latency(struct device *dev) EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_transition_latency); /** - * dev_pm_opp_get_suspend_opp() - Get suspend opp + * dev_pm_opp_get_suspend_opp_freq() - Get frequency of suspend opp in Hz * @dev: device for which we do this operation * - * Return: This function returns pointer to the suspend opp if it is - * defined and available, otherwise it returns NULL. - * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. The reason for the same is that the opp pointer which is - * returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * Return: This function returns the frequency of the OPP marked as suspend_opp + * if one is available, else returns 0; */ -struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) +unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev) { struct opp_table *opp_table; - - opp_rcu_lockdep_assert(); + unsigned long freq = 0; opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table) || !opp_table->suspend_opp || - !opp_table->suspend_opp->available) - return NULL; + if (IS_ERR(opp_table)) + return 0; + + if (opp_table->suspend_opp && opp_table->suspend_opp->available) + freq = dev_pm_opp_get_freq(opp_table->suspend_opp); - return opp_table->suspend_opp; + dev_pm_opp_put_opp_table(opp_table); + + return freq; } -EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp); +EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); /** * dev_pm_opp_get_opp_count() - Get number of opps available in the opp table @@ -361,8 +293,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp); * * Return: This function returns the number of available opps if there are any, * else returns 0 if none or the corresponding error value. - * - * Locking: This function takes rcu_read_lock(). */ int dev_pm_opp_get_opp_count(struct device *dev) { @@ -370,23 +300,24 @@ int dev_pm_opp_get_opp_count(struct device *dev) struct dev_pm_opp *temp_opp; int count = 0; - rcu_read_lock(); - opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { count = PTR_ERR(opp_table); dev_err(dev, "%s: OPP table not found (%d)\n", __func__, count); - goto out_unlock; + return count; } - list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { + mutex_lock(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { if (temp_opp->available) count++; } -out_unlock: - rcu_read_unlock(); + mutex_unlock(&opp_table->lock); + dev_pm_opp_put_opp_table(opp_table); + return count; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); @@ -411,11 +342,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); * This provides a mechanism to enable an opp which is not available currently * or the opposite as well. * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. The reason for the same is that the opp pointer which is - * returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. */ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, @@ -424,8 +352,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, struct opp_table *opp_table; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); - opp_rcu_lockdep_assert(); - opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { int r = PTR_ERR(opp_table); @@ -434,14 +360,22 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, return ERR_PTR(r); } - list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { + mutex_lock(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { if (temp_opp->available == available && temp_opp->rate == freq) { opp = temp_opp; + + /* Increment the reference count of OPP */ + dev_pm_opp_get(opp); break; } } + mutex_unlock(&opp_table->lock); + dev_pm_opp_put_opp_table(opp_table); + return opp; } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); @@ -451,14 +385,21 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table, { struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); - list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { + mutex_lock(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { if (temp_opp->available && temp_opp->rate >= *freq) { opp = temp_opp; *freq = opp->rate; + + /* Increment the reference count of OPP */ + dev_pm_opp_get(opp); break; } } + mutex_unlock(&opp_table->lock); + return opp; } @@ -477,18 +418,14 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table, * ERANGE: no match found for search * ENODEV: if device not found in list of registered devices * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. The reason for the same is that the opp pointer which is - * returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. */ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, unsigned long *freq) { struct opp_table *opp_table; - - opp_rcu_lockdep_assert(); + struct dev_pm_opp *opp; if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); @@ -499,7 +436,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, if (IS_ERR(opp_table)) return ERR_CAST(opp_table); - return _find_freq_ceil(opp_table, freq); + opp = _find_freq_ceil(opp_table, freq); + + dev_pm_opp_put_opp_table(opp_table); + + return opp; } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil); @@ -518,11 +459,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil); * ERANGE: no match found for search * ENODEV: if device not found in list of registered devices * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. The reason for the same is that the opp pointer which is - * returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. */ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, unsigned long *freq) @@ -530,8 +468,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, struct opp_table *opp_table; struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); - opp_rcu_lockdep_assert(); - if (!dev || !freq) { dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq); return ERR_PTR(-EINVAL); @@ -541,7 +477,9 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, if (IS_ERR(opp_table)) return ERR_CAST(opp_table); - list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { + mutex_lock(&opp_table->lock); + + list_for_each_entry(temp_opp, &opp_table->opp_list, node) { if (temp_opp->available) { /* go to the next node, before choosing prev */ if (temp_opp->rate > *freq) @@ -550,6 +488,13 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, opp = temp_opp; } } + + /* Increment the reference count of OPP */ + if (!IS_ERR(opp)) + dev_pm_opp_get(opp); + mutex_unlock(&opp_table->lock); + dev_pm_opp_put_opp_table(opp_table); + if (!IS_ERR(opp)) *freq = opp->rate; @@ -557,34 +502,6 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, } EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor); -/* - * The caller needs to ensure that opp_table (and hence the clk) isn't freed, - * while clk returned here is used. - */ -static struct clk *_get_opp_clk(struct device *dev) -{ - struct opp_table *opp_table; - struct clk *clk; - - rcu_read_lock(); - - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - dev_err(dev, "%s: device opp doesn't exist\n", __func__); - clk = ERR_CAST(opp_table); - goto unlock; - } - - clk = opp_table->clk; - if (IS_ERR(clk)) - dev_err(dev, "%s: No clock available for the device\n", - __func__); - -unlock: - rcu_read_unlock(); - return clk; -} - static int _set_opp_voltage(struct device *dev, struct regulator *reg, struct dev_pm_opp_supply *supply) { @@ -680,8 +597,6 @@ restore_voltage: * * This configures the power-supplies and clock source to the levels specified * by the OPP corresponding to the target_freq. - * - * Locking: This function takes rcu_read_lock(). */ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) { @@ -700,9 +615,19 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) return -EINVAL; } - clk = _get_opp_clk(dev); - if (IS_ERR(clk)) - return PTR_ERR(clk); + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) { + dev_err(dev, "%s: device opp doesn't exist\n", __func__); + return PTR_ERR(opp_table); + } + + clk = opp_table->clk; + if (IS_ERR(clk)) { + dev_err(dev, "%s: No clock available for the device\n", + __func__); + ret = PTR_ERR(clk); + goto put_opp_table; + } freq = clk_round_rate(clk, target_freq); if ((long)freq <= 0) @@ -714,16 +639,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) if (old_freq == freq) { dev_dbg(dev, "%s: old/new frequencies (%lu Hz) are same, nothing to do\n", __func__, freq); - return 0; - } - - rcu_read_lock(); - - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - dev_err(dev, "%s: device opp doesn't exist\n", __func__); - rcu_read_unlock(); - return PTR_ERR(opp_table); + ret = 0; + goto put_opp_table; } old_opp = _find_freq_ceil(opp_table, &old_freq); @@ -737,8 +654,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) ret = PTR_ERR(opp); dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n", __func__, freq, ret); - rcu_read_unlock(); - return ret; + goto put_old_opp; } dev_dbg(dev, "%s: switching OPP: %lu Hz --> %lu Hz\n", __func__, @@ -748,8 +664,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) /* Only frequency scaling */ if (!regulators) { - rcu_read_unlock(); - return _generic_set_opp_clk_only(dev, clk, old_freq, freq); + ret = _generic_set_opp_clk_only(dev, clk, old_freq, freq); + goto put_opps; } if (opp_table->set_opp) @@ -773,28 +689,26 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) data->new_opp.rate = freq; memcpy(data->new_opp.supplies, opp->supplies, size); - rcu_read_unlock(); + ret = set_opp(data); - return set_opp(data); +put_opps: + dev_pm_opp_put(opp); +put_old_opp: + if (!IS_ERR(old_opp)) + dev_pm_opp_put(old_opp); +put_opp_table: + dev_pm_opp_put_opp_table(opp_table); + return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_set_rate); /* OPP-dev Helpers */ -static void _kfree_opp_dev_rcu(struct rcu_head *head) -{ - struct opp_device *opp_dev; - - opp_dev = container_of(head, struct opp_device, rcu_head); - kfree_rcu(opp_dev, rcu_head); -} - static void _remove_opp_dev(struct opp_device *opp_dev, struct opp_table *opp_table) { opp_debug_unregister(opp_dev, opp_table); list_del(&opp_dev->node); - call_srcu(&opp_table->srcu_head.srcu, &opp_dev->rcu_head, - _kfree_opp_dev_rcu); + kfree(opp_dev); } struct opp_device *_add_opp_dev(const struct device *dev, @@ -809,7 +723,7 @@ struct opp_device *_add_opp_dev(const struct device *dev, /* Initialize opp-dev */ opp_dev->dev = dev; - list_add_rcu(&opp_dev->node, &opp_table->dev_list); + list_add(&opp_dev->node, &opp_table->dev_list); /* Create debugfs entries for the opp_table */ ret = opp_debug_register(opp_dev, opp_table); @@ -820,26 +734,12 @@ struct opp_device *_add_opp_dev(const struct device *dev, return opp_dev; } -/** - * _add_opp_table() - Find OPP table or allocate a new one - * @dev: device for which we do this operation - * - * It tries to find an existing table first, if it couldn't find one, it - * allocates a new OPP table and returns that. - * - * Return: valid opp_table pointer if success, else NULL. - */ -static struct opp_table *_add_opp_table(struct device *dev) +static struct opp_table *_allocate_opp_table(struct device *dev) { struct opp_table *opp_table; struct opp_device *opp_dev; int ret; - /* Check for existing table for 'dev' first */ - opp_table = _find_opp_table(dev); - if (!IS_ERR(opp_table)) - return opp_table; - /* * Allocate a new OPP table. In the infrequent case where a new * device is needed to be added, we pay this penalty. @@ -867,50 +767,45 @@ static struct opp_table *_add_opp_table(struct device *dev) ret); } - srcu_init_notifier_head(&opp_table->srcu_head); + BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head); INIT_LIST_HEAD(&opp_table->opp_list); + mutex_init(&opp_table->lock); + kref_init(&opp_table->kref); /* Secure the device table modification */ - list_add_rcu(&opp_table->node, &opp_tables); + list_add(&opp_table->node, &opp_tables); return opp_table; } -/** - * _kfree_device_rcu() - Free opp_table RCU handler - * @head: RCU head - */ -static void _kfree_device_rcu(struct rcu_head *head) +void _get_opp_table_kref(struct opp_table *opp_table) { - struct opp_table *opp_table = container_of(head, struct opp_table, - rcu_head); - - kfree_rcu(opp_table, rcu_head); + kref_get(&opp_table->kref); } -/** - * _remove_opp_table() - Removes a OPP table - * @opp_table: OPP table to be removed. - * - * Removes/frees OPP table if it doesn't contain any OPPs. - */ -static void _remove_opp_table(struct opp_table *opp_table) +struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) { - struct opp_device *opp_dev; + struct opp_table *opp_table; - if (!list_empty(&opp_table->opp_list)) - return; + /* Hold our table modification lock here */ + mutex_lock(&opp_table_lock); - if (opp_table->supported_hw) - return; + opp_table = _find_opp_table_unlocked(dev); + if (!IS_ERR(opp_table)) + goto unlock; - if (opp_table->prop_name) - return; + opp_table = _allocate_opp_table(dev); - if (opp_table->regulators) - return; +unlock: + mutex_unlock(&opp_table_lock); - if (opp_table->set_opp) - return; + return opp_table; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_table); + +static void _opp_table_kref_release(struct kref *kref) +{ + struct opp_table *opp_table = container_of(kref, struct opp_table, kref); + struct opp_device *opp_dev; /* Release clk */ if (!IS_ERR(opp_table->clk)) @@ -924,63 +819,60 @@ static void _remove_opp_table(struct opp_table *opp_table) /* dev_list must be empty now */ WARN_ON(!list_empty(&opp_table->dev_list)); - list_del_rcu(&opp_table->node); - call_srcu(&opp_table->srcu_head.srcu, &opp_table->rcu_head, - _kfree_device_rcu); + mutex_destroy(&opp_table->lock); + list_del(&opp_table->node); + kfree(opp_table); + + mutex_unlock(&opp_table_lock); } -/** - * _kfree_opp_rcu() - Free OPP RCU handler - * @head: RCU head - */ -static void _kfree_opp_rcu(struct rcu_head *head) +void dev_pm_opp_put_opp_table(struct opp_table *opp_table) { - struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head); + kref_put_mutex(&opp_table->kref, _opp_table_kref_release, + &opp_table_lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_put_opp_table); - kfree_rcu(opp, rcu_head); +void _opp_free(struct dev_pm_opp *opp) +{ + kfree(opp); } -/** - * _opp_remove() - Remove an OPP from a table definition - * @opp_table: points back to the opp_table struct this opp belongs to - * @opp: pointer to the OPP to remove - * @notify: OPP_EVENT_REMOVE notification should be sent or not - * - * This function removes an opp definition from the opp table. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * It is assumed that the caller holds required mutex for an RCU updater - * strategy. - */ -void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp, - bool notify) +static void _opp_kref_release(struct kref *kref) { + struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref); + struct opp_table *opp_table = opp->opp_table; + /* * Notify the changes in the availability of the operable * frequency/voltage list. */ - if (notify) - srcu_notifier_call_chain(&opp_table->srcu_head, - OPP_EVENT_REMOVE, opp); + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_REMOVE, opp); opp_debug_remove_one(opp); - list_del_rcu(&opp->node); - call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); + list_del(&opp->node); + kfree(opp); - _remove_opp_table(opp_table); + mutex_unlock(&opp_table->lock); + dev_pm_opp_put_opp_table(opp_table); +} + +static void dev_pm_opp_get(struct dev_pm_opp *opp) +{ + kref_get(&opp->kref); } +void dev_pm_opp_put(struct dev_pm_opp *opp) +{ + kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock); +} +EXPORT_SYMBOL_GPL(dev_pm_opp_put); + /** * dev_pm_opp_remove() - Remove an OPP from OPP table * @dev: device for which we do this operation * @freq: OPP to remove with matching 'freq' * * This function removes an opp from the opp table. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_remove(struct device *dev, unsigned long freq) { @@ -988,12 +880,11 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) struct opp_table *opp_table; bool found = false; - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); - opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) - goto unlock; + return; + + mutex_lock(&opp_table->lock); list_for_each_entry(opp, &opp_table->opp_list, node) { if (opp->rate == freq) { @@ -1002,28 +893,23 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) } } - if (!found) { + mutex_unlock(&opp_table->lock); + + if (found) { + dev_pm_opp_put(opp); + } else { dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", __func__, freq); - goto unlock; } - _opp_remove(opp_table, opp, true); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove); -struct dev_pm_opp *_allocate_opp(struct device *dev, - struct opp_table **opp_table) +struct dev_pm_opp *_opp_allocate(struct opp_table *table) { struct dev_pm_opp *opp; int count, supply_size; - struct opp_table *table; - - table = _add_opp_table(dev); - if (!table) - return NULL; /* Allocate space for at least one supply */ count = table->regulator_count ? table->regulator_count : 1; @@ -1031,17 +917,13 @@ struct dev_pm_opp *_allocate_opp(struct device *dev, /* allocate new OPP node and supplies structures */ opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL); - if (!opp) { - kfree(table); + if (!opp) return NULL; - } /* Put the supplies at the end of the OPP structure as an empty array */ opp->supplies = (struct dev_pm_opp_supply *)(opp + 1); INIT_LIST_HEAD(&opp->node); - *opp_table = table; - return opp; } @@ -1067,11 +949,21 @@ static bool _opp_supported_by_regulators(struct dev_pm_opp *opp, return true; } +/* + * Returns: + * 0: On success. And appropriate error message for duplicate OPPs. + * -EBUSY: For OPP with same freq/volt and is available. The callers of + * _opp_add() must return 0 if they receive -EBUSY from it. This is to make + * sure we don't print error messages unnecessarily if different parts of + * kernel try to initialize the OPP table. + * -EEXIST: For OPP with same freq but different volt or is unavailable. This + * should be considered an error by the callers of _opp_add(). + */ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table) { struct dev_pm_opp *opp; - struct list_head *head = &opp_table->opp_list; + struct list_head *head; int ret; /* @@ -1082,7 +974,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * loop, don't replace it with head otherwise it will become an infinite * loop. */ - list_for_each_entry_rcu(opp, &opp_table->opp_list, node) { + mutex_lock(&opp_table->lock); + head = &opp_table->opp_list; + + list_for_each_entry(opp, &opp_table->opp_list, node) { if (new_opp->rate > opp->rate) { head = &opp->node; continue; @@ -1098,12 +993,21 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, new_opp->supplies[0].u_volt, new_opp->available); /* Should we compare voltages for all regulators here ? */ - return opp->available && - new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST; + ret = opp->available && + new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? -EBUSY : -EEXIST; + + mutex_unlock(&opp_table->lock); + return ret; } + list_add(&new_opp->node, head); + mutex_unlock(&opp_table->lock); + new_opp->opp_table = opp_table; - list_add_rcu(&new_opp->node, head); + kref_init(&new_opp->kref); + + /* Get a reference to the OPP table */ + _get_opp_table_kref(opp_table); ret = opp_debug_create_one(new_opp, opp_table); if (ret) @@ -1121,6 +1025,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, /** * _opp_add_v1() - Allocate a OPP based on v1 bindings. + * @opp_table: OPP table * @dev: device for which we do this operation * @freq: Frequency in Hz for this OPP * @u_volt: Voltage in uVolts for this OPP @@ -1133,12 +1038,6 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * NOTE: "dynamic" parameter impacts OPPs added by the dev_pm_opp_of_add_table * and freed by dev_pm_opp_of_remove_table. * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - * * Return: * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available @@ -1146,22 +1045,16 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * Duplicate OPPs (both freq and volt are same) and !opp->available * -ENOMEM Memory allocation failure */ -int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, - bool dynamic) +int _opp_add_v1(struct opp_table *opp_table, struct device *dev, + unsigned long freq, long u_volt, bool dynamic) { - struct opp_table *opp_table; struct dev_pm_opp *new_opp; unsigned long tol; int ret; - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); - - new_opp = _allocate_opp(dev, &opp_table); - if (!new_opp) { - ret = -ENOMEM; - goto unlock; - } + new_opp = _opp_allocate(opp_table); + if (!new_opp) + return -ENOMEM; /* populate the opp table */ new_opp->rate = freq; @@ -1173,22 +1066,23 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, new_opp->dynamic = dynamic; ret = _opp_add(dev, new_opp, opp_table); - if (ret) + if (ret) { + /* Don't return error for duplicate OPPs */ + if (ret == -EBUSY) + ret = 0; goto free_opp; - - mutex_unlock(&opp_table_lock); + } /* * Notify the changes in the availability of the operable * frequency/voltage list. */ - srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp); + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp); return 0; free_opp: - _opp_remove(opp_table, new_opp, false); -unlock: - mutex_unlock(&opp_table_lock); + _opp_free(new_opp); + return ret; } @@ -1202,27 +1096,16 @@ unlock: * specify the hierarchy of versions it supports. OPP layer will then enable * OPPs, which are available for those versions, based on its 'opp-supported-hw' * property. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ -int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, - unsigned int count) +struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, + const u32 *versions, unsigned int count) { struct opp_table *opp_table; - int ret = 0; - - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); + int ret; - opp_table = _add_opp_table(dev); - if (!opp_table) { - ret = -ENOMEM; - goto unlock; - } + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return ERR_PTR(-ENOMEM); /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); @@ -1243,65 +1126,40 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, } opp_table->supported_hw_count = count; - mutex_unlock(&opp_table_lock); - return 0; + + return opp_table; err: - _remove_opp_table(opp_table); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); - return ret; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_set_supported_hw); /** * dev_pm_opp_put_supported_hw() - Releases resources blocked for supported hw - * @dev: Device for which supported-hw has to be put. + * @opp_table: OPP table returned by dev_pm_opp_set_supported_hw(). * * This is required only for the V2 bindings, and is called for a matching * dev_pm_opp_set_supported_hw(). Until this is called, the opp_table structure * will not be freed. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ -void dev_pm_opp_put_supported_hw(struct device *dev) +void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) { - struct opp_table *opp_table; - - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); - - /* Check for existing table for 'dev' first */ - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - dev_err(dev, "Failed to find opp_table: %ld\n", - PTR_ERR(opp_table)); - goto unlock; - } - /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); if (!opp_table->supported_hw) { - dev_err(dev, "%s: Doesn't have supported hardware list\n", - __func__); - goto unlock; + pr_err("%s: Doesn't have supported hardware list\n", + __func__); + return; } kfree(opp_table->supported_hw); opp_table->supported_hw = NULL; opp_table->supported_hw_count = 0; - /* Try freeing opp_table if this was the last blocking resource */ - _remove_opp_table(opp_table); - -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); @@ -1314,26 +1172,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw); * specify the extn to be used for certain property names. The properties to * which the extension will apply are opp-microvolt and opp-microamp. OPP core * should postfix the property name with -<name> while looking for them. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ -int dev_pm_opp_set_prop_name(struct device *dev, const char *name) +struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name) { struct opp_table *opp_table; - int ret = 0; - - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); + int ret; - opp_table = _add_opp_table(dev); - if (!opp_table) { - ret = -ENOMEM; - goto unlock; - } + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return ERR_PTR(-ENOMEM); /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); @@ -1352,63 +1199,37 @@ int dev_pm_opp_set_prop_name(struct device *dev, const char *name) goto err; } - mutex_unlock(&opp_table_lock); - return 0; + return opp_table; err: - _remove_opp_table(opp_table); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); - return ret; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_set_prop_name); /** * dev_pm_opp_put_prop_name() - Releases resources blocked for prop-name - * @dev: Device for which the prop-name has to be put. + * @opp_table: OPP table returned by dev_pm_opp_set_prop_name(). * * This is required only for the V2 bindings, and is called for a matching * dev_pm_opp_set_prop_name(). Until this is called, the opp_table structure * will not be freed. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ -void dev_pm_opp_put_prop_name(struct device *dev) +void dev_pm_opp_put_prop_name(struct opp_table *opp_table) { - struct opp_table *opp_table; - - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); - - /* Check for existing table for 'dev' first */ - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - dev_err(dev, "Failed to find opp_table: %ld\n", - PTR_ERR(opp_table)); - goto unlock; - } - /* Make sure there are no concurrent readers while updating opp_table */ WARN_ON(!list_empty(&opp_table->opp_list)); if (!opp_table->prop_name) { - dev_err(dev, "%s: Doesn't have a prop-name\n", __func__); - goto unlock; + pr_err("%s: Doesn't have a prop-name\n", __func__); + return; } kfree(opp_table->prop_name); opp_table->prop_name = NULL; - /* Try freeing opp_table if this was the last blocking resource */ - _remove_opp_table(opp_table); - -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name); @@ -1455,12 +1276,6 @@ static void _free_set_opp_data(struct opp_table *opp_table) * well. * * This must be called before any OPPs are initialized for the device. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], @@ -1470,13 +1285,9 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, struct regulator *reg; int ret, i; - mutex_lock(&opp_table_lock); - - opp_table = _add_opp_table(dev); - if (!opp_table) { - ret = -ENOMEM; - goto unlock; - } + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return ERR_PTR(-ENOMEM); /* This should be called before OPPs are initialized */ if (WARN_ON(!list_empty(&opp_table->opp_list))) { @@ -1518,7 +1329,6 @@ struct opp_table *dev_pm_opp_set_regulators(struct device *dev, if (ret) goto free_regulators; - mutex_unlock(&opp_table_lock); return opp_table; free_regulators: @@ -1529,9 +1339,7 @@ free_regulators: opp_table->regulators = NULL; opp_table->regulator_count = 0; err: - _remove_opp_table(opp_table); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); return ERR_PTR(ret); } @@ -1540,22 +1348,14 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators); /** * dev_pm_opp_put_regulators() - Releases resources blocked for regulator * @opp_table: OPP table returned from dev_pm_opp_set_regulators(). - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_put_regulators(struct opp_table *opp_table) { int i; - mutex_lock(&opp_table_lock); - if (!opp_table->regulators) { pr_err("%s: Doesn't have regulators set\n", __func__); - goto unlock; + return; } /* Make sure there are no concurrent readers while updating opp_table */ @@ -1570,11 +1370,7 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) opp_table->regulators = NULL; opp_table->regulator_count = 0; - /* Try freeing opp_table if this was the last blocking resource */ - _remove_opp_table(opp_table); - -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); @@ -1587,29 +1383,19 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators); * regulators per device), instead of the generic OPP set rate helper. * * This must be called before any OPPs are initialized for the device. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ -int dev_pm_opp_register_set_opp_helper(struct device *dev, +struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)) { struct opp_table *opp_table; int ret; if (!set_opp) - return -EINVAL; - - mutex_lock(&opp_table_lock); + return ERR_PTR(-EINVAL); - opp_table = _add_opp_table(dev); - if (!opp_table) { - ret = -ENOMEM; - goto unlock; - } + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return ERR_PTR(-ENOMEM); /* This should be called before OPPs are initialized */ if (WARN_ON(!list_empty(&opp_table->opp_list))) { @@ -1625,47 +1411,28 @@ int dev_pm_opp_register_set_opp_helper(struct device *dev, opp_table->set_opp = set_opp; - mutex_unlock(&opp_table_lock); - return 0; + return opp_table; err: - _remove_opp_table(opp_table); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); - return ret; + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(dev_pm_opp_register_set_opp_helper); /** * dev_pm_opp_register_put_opp_helper() - Releases resources blocked for * set_opp helper - * @dev: Device for which custom set_opp helper has to be cleared. + * @opp_table: OPP table returned from dev_pm_opp_register_set_opp_helper(). * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. + * Release resources blocked for platform specific set_opp helper. */ -void dev_pm_opp_register_put_opp_helper(struct device *dev) +void dev_pm_opp_register_put_opp_helper(struct opp_table *opp_table) { - struct opp_table *opp_table; - - mutex_lock(&opp_table_lock); - - /* Check for existing table for 'dev' first */ - opp_table = _find_opp_table(dev); - if (IS_ERR(opp_table)) { - dev_err(dev, "Failed to find opp_table: %ld\n", - PTR_ERR(opp_table)); - goto unlock; - } - if (!opp_table->set_opp) { - dev_err(dev, "%s: Doesn't have custom set_opp helper set\n", - __func__); - goto unlock; + pr_err("%s: Doesn't have custom set_opp helper set\n", + __func__); + return; } /* Make sure there are no concurrent readers while updating opp_table */ @@ -1673,11 +1440,7 @@ void dev_pm_opp_register_put_opp_helper(struct device *dev) opp_table->set_opp = NULL; - /* Try freeing opp_table if this was the last blocking resource */ - _remove_opp_table(opp_table); - -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper); @@ -1691,12 +1454,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper); * The opp is made available by default and it can be controlled using * dev_pm_opp_enable/disable functions. * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - * * Return: * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available @@ -1706,7 +1463,17 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_register_put_opp_helper); */ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) { - return _opp_add_v1(dev, freq, u_volt, true); + struct opp_table *opp_table; + int ret; + + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return -ENOMEM; + + ret = _opp_add_v1(opp_table, dev, freq, u_volt, true); + + dev_pm_opp_put_opp_table(opp_table); + return ret; } EXPORT_SYMBOL_GPL(dev_pm_opp_add); @@ -1716,41 +1483,30 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_add); * @freq: OPP frequency to modify availability * @availability_req: availability status requested for this opp * - * Set the availability of an OPP with an RCU operation, opp_{enable,disable} - * share a common logic which is isolated here. + * Set the availability of an OPP, opp_{enable,disable} share a common logic + * which is isolated here. * * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modification was done OR modification was * successful. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks to - * keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex locking or synchronize_rcu() blocking calls cannot be used. */ static int _opp_set_availability(struct device *dev, unsigned long freq, bool availability_req) { struct opp_table *opp_table; - struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV); + struct dev_pm_opp *tmp_opp, *opp = ERR_PTR(-ENODEV); int r = 0; - /* keep the node allocated */ - new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL); - if (!new_opp) - return -ENOMEM; - - mutex_lock(&opp_table_lock); - /* Find the opp_table */ opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) { r = PTR_ERR(opp_table); dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); - goto unlock; + return r; } + mutex_lock(&opp_table->lock); + /* Do we have the frequency? */ list_for_each_entry(tmp_opp, &opp_table->opp_list, node) { if (tmp_opp->rate == freq) { @@ -1758,6 +1514,7 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, break; } } + if (IS_ERR(opp)) { r = PTR_ERR(opp); goto unlock; @@ -1766,29 +1523,20 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, /* Is update really needed? */ if (opp->available == availability_req) goto unlock; - /* copy the old data over */ - *new_opp = *opp; - /* plug in new node */ - new_opp->available = availability_req; - - list_replace_rcu(&opp->node, &new_opp->node); - mutex_unlock(&opp_table_lock); - call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); + opp->available = availability_req; /* Notify the change of the OPP availability */ if (availability_req) - srcu_notifier_call_chain(&opp_table->srcu_head, - OPP_EVENT_ENABLE, new_opp); + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ENABLE, + opp); else - srcu_notifier_call_chain(&opp_table->srcu_head, - OPP_EVENT_DISABLE, new_opp); - - return 0; + blocking_notifier_call_chain(&opp_table->head, + OPP_EVENT_DISABLE, opp); unlock: - mutex_unlock(&opp_table_lock); - kfree(new_opp); + mutex_unlock(&opp_table->lock); + dev_pm_opp_put_opp_table(opp_table); return r; } @@ -1801,12 +1549,6 @@ unlock: * corresponding error value. It is meant to be used for users an OPP available * after being temporarily made unavailable with dev_pm_opp_disable. * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function indirectly uses RCU and mutex locks to keep the - * integrity of the internal data structures. Callers should ensure that - * this function is *NOT* called under RCU protection or in contexts where - * mutex locking or synchronize_rcu() blocking calls cannot be used. - * * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modification was done OR modification was * successful. @@ -1827,12 +1569,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable); * control by users to make this OPP not available until the circumstances are * right to make it available again (with a call to dev_pm_opp_enable). * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function indirectly uses RCU and mutex locks to keep the - * integrity of the internal data structures. Callers should ensure that - * this function is *NOT* called under RCU protection or in contexts where - * mutex locking or synchronize_rcu() blocking calls cannot be used. - * * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the * copy operation, returns 0 if no modification was done OR modification was * successful. @@ -1844,41 +1580,78 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq) EXPORT_SYMBOL_GPL(dev_pm_opp_disable); /** - * dev_pm_opp_get_notifier() - find notifier_head of the device with opp - * @dev: device pointer used to lookup OPP table. + * dev_pm_opp_register_notifier() - Register OPP notifier for the device + * @dev: Device for which notifier needs to be registered + * @nb: Notifier block to be registered * - * Return: pointer to notifier head if found, otherwise -ENODEV or - * -EINVAL based on type of error casted as pointer. value must be checked - * with IS_ERR to determine valid pointer or error result. + * Return: 0 on success or a negative error value. + */ +int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb) +{ + struct opp_table *opp_table; + int ret; + + opp_table = _find_opp_table(dev); + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); + + ret = blocking_notifier_chain_register(&opp_table->head, nb); + + dev_pm_opp_put_opp_table(opp_table); + + return ret; +} +EXPORT_SYMBOL(dev_pm_opp_register_notifier); + +/** + * dev_pm_opp_unregister_notifier() - Unregister OPP notifier for the device + * @dev: Device for which notifier needs to be unregistered + * @nb: Notifier block to be unregistered * - * Locking: This function must be called under rcu_read_lock(). opp_table is a - * RCU protected pointer. The reason for the same is that the opp pointer which - * is returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * Return: 0 on success or a negative error value. */ -struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev) +int dev_pm_opp_unregister_notifier(struct device *dev, + struct notifier_block *nb) { - struct opp_table *opp_table = _find_opp_table(dev); + struct opp_table *opp_table; + int ret; + opp_table = _find_opp_table(dev); if (IS_ERR(opp_table)) - return ERR_CAST(opp_table); /* matching type */ + return PTR_ERR(opp_table); + + ret = blocking_notifier_chain_unregister(&opp_table->head, nb); - return &opp_table->srcu_head; + dev_pm_opp_put_opp_table(opp_table); + + return ret; } -EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier); +EXPORT_SYMBOL(dev_pm_opp_unregister_notifier); /* * Free OPPs either created using static entries present in DT or even the * dynamically added entries based on remove_all param. */ -void _dev_pm_opp_remove_table(struct device *dev, bool remove_all) +void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, + bool remove_all) { - struct opp_table *opp_table; struct dev_pm_opp *opp, *tmp; - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); + /* Find if opp_table manages a single device */ + if (list_is_singular(&opp_table->dev_list)) { + /* Free static OPPs */ + list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { + if (remove_all || !opp->dynamic) + dev_pm_opp_put(opp); + } + } else { + _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); + } +} + +void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) +{ + struct opp_table *opp_table; /* Check for existing table for 'dev' */ opp_table = _find_opp_table(dev); @@ -1890,22 +1663,12 @@ void _dev_pm_opp_remove_table(struct device *dev, bool remove_all) IS_ERR_OR_NULL(dev) ? "Invalid device" : dev_name(dev), error); - goto unlock; + return; } - /* Find if opp_table manages a single device */ - if (list_is_singular(&opp_table->dev_list)) { - /* Free static OPPs */ - list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { - if (remove_all || !opp->dynamic) - _opp_remove(opp_table, opp, true); - } - } else { - _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); - } + _dev_pm_opp_remove_table(opp_table, dev, remove_all); -unlock: - mutex_unlock(&opp_table_lock); + dev_pm_opp_put_opp_table(opp_table); } /** @@ -1914,15 +1677,9 @@ unlock: * * Free both OPPs created using static entries present in DT and the * dynamically added entries. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function indirectly uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_remove_table(struct device *dev) { - _dev_pm_opp_remove_table(dev, true); + _dev_pm_opp_find_and_remove_table(dev, true); } EXPORT_SYMBOL_GPL(dev_pm_opp_remove_table); diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index 8c3434bdb26d..2d87bc1adf38 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c @@ -42,11 +42,6 @@ * * WARNING: It is important for the callers to ensure refreshing their copy of * the table if any of the mentioned functions have been invoked in the interim. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Since we just use the regular accessor functions to access the internal data - * structures, we use RCU read lock inside this function. As a result, users of - * this function DONOT need to use explicit locks for invoking. */ int dev_pm_opp_init_cpufreq_table(struct device *dev, struct cpufreq_frequency_table **table) @@ -56,19 +51,13 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, int i, max_opps, ret = 0; unsigned long rate; - rcu_read_lock(); - max_opps = dev_pm_opp_get_opp_count(dev); - if (max_opps <= 0) { - ret = max_opps ? max_opps : -ENODATA; - goto out; - } + if (max_opps <= 0) + return max_opps ? max_opps : -ENODATA; freq_table = kcalloc((max_opps + 1), sizeof(*freq_table), GFP_ATOMIC); - if (!freq_table) { - ret = -ENOMEM; - goto out; - } + if (!freq_table) + return -ENOMEM; for (i = 0, rate = 0; i < max_opps; i++, rate++) { /* find next rate */ @@ -83,6 +72,8 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, /* Is Boost/turbo opp ? */ if (dev_pm_opp_is_turbo(opp)) freq_table[i].flags = CPUFREQ_BOOST_FREQ; + + dev_pm_opp_put(opp); } freq_table[i].driver_data = i; @@ -91,7 +82,6 @@ int dev_pm_opp_init_cpufreq_table(struct device *dev, *table = &freq_table[0]; out: - rcu_read_unlock(); if (ret) kfree(freq_table); @@ -147,12 +137,6 @@ void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of) * This removes the OPP tables for CPUs present in the @cpumask. * This should be used to remove all the OPPs entries associated with * the cpus in @cpumask. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask) { @@ -169,12 +153,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_cpumask_remove_table); * @cpumask. * * Returns -ENODEV if OPP table isn't already present. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask) @@ -184,13 +162,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, struct device *dev; int cpu, ret = 0; - mutex_lock(&opp_table_lock); - opp_table = _find_opp_table(cpu_dev); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); - goto unlock; - } + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); for_each_cpu(cpu, cpumask) { if (cpu == cpu_dev->id) @@ -213,8 +187,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, /* Mark opp-table as multiple CPUs are sharing it now */ opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; } -unlock: - mutex_unlock(&opp_table_lock); + + dev_pm_opp_put_opp_table(opp_table); return ret; } @@ -229,12 +203,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus); * * Returns -ENODEV if OPP table isn't already present and -EINVAL if the OPP * table's status is access-unknown. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) { @@ -242,17 +210,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) struct opp_table *opp_table; int ret = 0; - mutex_lock(&opp_table_lock); - opp_table = _find_opp_table(cpu_dev); - if (IS_ERR(opp_table)) { - ret = PTR_ERR(opp_table); - goto unlock; - } + if (IS_ERR(opp_table)) + return PTR_ERR(opp_table); if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) { ret = -EINVAL; - goto unlock; + goto put_opp_table; } cpumask_clear(cpumask); @@ -264,8 +228,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) cpumask_set_cpu(cpu_dev->id, cpumask); } -unlock: - mutex_unlock(&opp_table_lock); +put_opp_table: + dev_pm_opp_put_opp_table(opp_table); return ret; } diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c index 3f7d2591b173..779428676f63 100644 --- a/drivers/base/power/opp/of.c +++ b/drivers/base/power/opp/of.c @@ -24,9 +24,11 @@ static struct opp_table *_managed_opp(const struct device_node *np) { - struct opp_table *opp_table; + struct opp_table *opp_table, *managed_table = NULL; + + mutex_lock(&opp_table_lock); - list_for_each_entry_rcu(opp_table, &opp_tables, node) { + list_for_each_entry(opp_table, &opp_tables, node) { if (opp_table->np == np) { /* * Multiple devices can point to the same OPP table and @@ -35,14 +37,18 @@ static struct opp_table *_managed_opp(const struct device_node *np) * But the OPPs will be considered as shared only if the * OPP table contains a "opp-shared" property. */ - if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) - return opp_table; + if (opp_table->shared_opp == OPP_TABLE_ACCESS_SHARED) { + _get_opp_table_kref(opp_table); + managed_table = opp_table; + } - return NULL; + break; } } - return NULL; + mutex_unlock(&opp_table_lock); + + return managed_table; } void _of_init_opp_table(struct opp_table *opp_table, struct device *dev) @@ -229,34 +235,28 @@ free_microvolt: * @dev: device pointer used to lookup OPP table. * * Free OPPs created using static entries present in DT. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function indirectly uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_of_remove_table(struct device *dev) { - _dev_pm_opp_remove_table(dev, false); + _dev_pm_opp_find_and_remove_table(dev, false); } EXPORT_SYMBOL_GPL(dev_pm_opp_of_remove_table); /* Returns opp descriptor node for a device, caller must do of_node_put() */ -static struct device_node *_of_get_opp_desc_node(struct device *dev) +struct device_node *dev_pm_opp_of_get_opp_desc_node(struct device *dev) { /* - * TODO: Support for multiple OPP tables. - * * There should be only ONE phandle present in "operating-points-v2" * property. */ return of_parse_phandle(dev->of_node, "operating-points-v2", 0); } +EXPORT_SYMBOL_GPL(dev_pm_opp_of_get_opp_desc_node); /** * _opp_add_static_v2() - Allocate static OPPs (As per 'v2' DT bindings) + * @opp_table: OPP table * @dev: device for which we do this operation * @np: device node * @@ -264,12 +264,6 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev) * opp can be controlled using dev_pm_opp_enable/disable functions and may be * removed by dev_pm_opp_remove. * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - * * Return: * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available @@ -278,22 +272,17 @@ static struct device_node *_of_get_opp_desc_node(struct device *dev) * -ENOMEM Memory allocation failure * -EINVAL Failed parsing the OPP node */ -static int _opp_add_static_v2(struct device *dev, struct device_node *np) +static int _opp_add_static_v2(struct opp_table *opp_table, struct device *dev, + struct device_node *np) { - struct opp_table *opp_table; struct dev_pm_opp *new_opp; u64 rate; u32 val; int ret; - /* Hold our table modification lock here */ - mutex_lock(&opp_table_lock); - - new_opp = _allocate_opp(dev, &opp_table); - if (!new_opp) { - ret = -ENOMEM; - goto unlock; - } + new_opp = _opp_allocate(opp_table); + if (!new_opp) + return -ENOMEM; ret = of_property_read_u64(np, "opp-hz", &rate); if (ret < 0) { @@ -327,8 +316,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) goto free_opp; ret = _opp_add(dev, new_opp, opp_table); - if (ret) + if (ret) { + /* Don't return error for duplicate OPPs */ + if (ret == -EBUSY) + ret = 0; goto free_opp; + } /* OPP to select on device suspend */ if (of_property_read_bool(np, "opp-suspend")) { @@ -345,8 +338,6 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) if (new_opp->clock_latency_ns > opp_table->clock_latency_ns_max) opp_table->clock_latency_ns_max = new_opp->clock_latency_ns; - mutex_unlock(&opp_table_lock); - pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n", __func__, new_opp->turbo, new_opp->rate, new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min, @@ -356,13 +347,12 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) * Notify the changes in the availability of the operable * frequency/voltage list. */ - srcu_notifier_call_chain(&opp_table->srcu_head, OPP_EVENT_ADD, new_opp); + blocking_notifier_call_chain(&opp_table->head, OPP_EVENT_ADD, new_opp); return 0; free_opp: - _opp_remove(opp_table, new_opp, false); -unlock: - mutex_unlock(&opp_table_lock); + _opp_free(new_opp); + return ret; } @@ -373,41 +363,35 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) struct opp_table *opp_table; int ret = 0, count = 0; - mutex_lock(&opp_table_lock); - opp_table = _managed_opp(opp_np); if (opp_table) { /* OPPs are already managed */ if (!_add_opp_dev(dev, opp_table)) ret = -ENOMEM; - mutex_unlock(&opp_table_lock); - return ret; + goto put_opp_table; } - mutex_unlock(&opp_table_lock); + + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return -ENOMEM; /* We have opp-table node now, iterate over it and add OPPs */ for_each_available_child_of_node(opp_np, np) { count++; - ret = _opp_add_static_v2(dev, np); + ret = _opp_add_static_v2(opp_table, dev, np); if (ret) { dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); - goto free_table; + _dev_pm_opp_remove_table(opp_table, dev, false); + goto put_opp_table; } } /* There should be one of more OPP defined */ - if (WARN_ON(!count)) - return -ENOENT; - - mutex_lock(&opp_table_lock); - - opp_table = _find_opp_table(dev); - if (WARN_ON(IS_ERR(opp_table))) { - ret = PTR_ERR(opp_table); - mutex_unlock(&opp_table_lock); - goto free_table; + if (WARN_ON(!count)) { + ret = -ENOENT; + goto put_opp_table; } opp_table->np = opp_np; @@ -416,12 +400,8 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np) else opp_table->shared_opp = OPP_TABLE_ACCESS_EXCLUSIVE; - mutex_unlock(&opp_table_lock); - - return 0; - -free_table: - dev_pm_opp_of_remove_table(dev); +put_opp_table: + dev_pm_opp_put_opp_table(opp_table); return ret; } @@ -429,9 +409,10 @@ free_table: /* Initializes OPP tables based on old-deprecated bindings */ static int _of_add_opp_table_v1(struct device *dev) { + struct opp_table *opp_table; const struct property *prop; const __be32 *val; - int nr; + int nr, ret = 0; prop = of_find_property(dev->of_node, "operating-points", NULL); if (!prop) @@ -449,18 +430,27 @@ static int _of_add_opp_table_v1(struct device *dev) return -EINVAL; } + opp_table = dev_pm_opp_get_opp_table(dev); + if (!opp_table) + return -ENOMEM; + val = prop->value; while (nr) { unsigned long freq = be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); - if (_opp_add_v1(dev, freq, volt, false)) - dev_warn(dev, "%s: Failed to add OPP %ld\n", - __func__, freq); + ret = _opp_add_v1(opp_table, dev, freq, volt, false); + if (ret) { + dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", + __func__, freq, ret); + _dev_pm_opp_remove_table(opp_table, dev, false); + break; + } nr -= 2; } - return 0; + dev_pm_opp_put_opp_table(opp_table); + return ret; } /** @@ -469,12 +459,6 @@ static int _of_add_opp_table_v1(struct device *dev) * * Register the initial OPP table with the OPP library for given device. * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function indirectly uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. - * * Return: * 0 On success OR * Duplicate OPPs (both freq and volt are same) and opp->available @@ -495,7 +479,7 @@ int dev_pm_opp_of_add_table(struct device *dev) * OPPs have two version of bindings now. The older one is deprecated, * try for the new binding first. */ - opp_np = _of_get_opp_desc_node(dev); + opp_np = dev_pm_opp_of_get_opp_desc_node(dev); if (!opp_np) { /* * Try old-deprecated bindings for backward compatibility with @@ -519,12 +503,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_add_table); * * This removes the OPP tables for CPUs present in the @cpumask. * This should be used only to remove static entries created from DT. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask) { @@ -537,12 +515,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_remove_table); * @cpumask: cpumask for which OPP table needs to be added. * * This adds the OPP tables for CPUs present in the @cpumask. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask) { @@ -590,12 +562,6 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_of_cpumask_add_table); * This updates the @cpumask with CPUs that are sharing OPPs with @cpu_dev. * * Returns -ENOENT if operating-points-v2 isn't present for @cpu_dev. - * - * Locking: The internal opp_table and opp structures are RCU protected. - * Hence this function internally uses RCU updater strategy with mutex locks - * to keep the integrity of the internal data structures. Callers should ensure - * that this function is *NOT* called under RCU protection or in contexts where - * mutex cannot be locked. */ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) @@ -605,7 +571,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, int cpu, ret = 0; /* Get OPP descriptor node */ - np = _of_get_opp_desc_node(cpu_dev); + np = dev_pm_opp_of_get_opp_desc_node(cpu_dev); if (!np) { dev_dbg(cpu_dev, "%s: Couldn't find opp node.\n", __func__); return -ENOENT; @@ -630,7 +596,7 @@ int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, } /* Get OPP descriptor node */ - tmp_np = _of_get_opp_desc_node(tcpu_dev); + tmp_np = dev_pm_opp_of_get_opp_desc_node(tcpu_dev); if (!tmp_np) { dev_err(tcpu_dev, "%s: Couldn't find opp node.\n", __func__); diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index af9f2b849a66..166eef990599 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h @@ -16,11 +16,11 @@ #include <linux/device.h> #include <linux/kernel.h> +#include <linux/kref.h> #include <linux/list.h> #include <linux/limits.h> #include <linux/pm_opp.h> -#include <linux/rculist.h> -#include <linux/rcupdate.h> +#include <linux/notifier.h> struct clk; struct regulator; @@ -51,11 +51,9 @@ extern struct list_head opp_tables; * @node: opp table node. The nodes are maintained throughout the lifetime * of boot. It is expected only an optimal set of OPPs are * added to the library by the SoC framework. - * RCU usage: opp table is traversed with RCU locks. node - * modification is possible realtime, hence the modifications - * are protected by the opp_table_lock for integrity. * IMPORTANT: the opp nodes should be maintained in increasing * order. + * @kref: for reference count of the OPP. * @available: true/false - marks if this OPP as available or not * @dynamic: not-created from static DT entries. * @turbo: true if turbo (boost) OPP @@ -65,7 +63,6 @@ extern struct list_head opp_tables; * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's * frequency from any other OPP's frequency. * @opp_table: points back to the opp_table struct this opp belongs to - * @rcu_head: RCU callback head used for deferred freeing * @np: OPP's device node. * @dentry: debugfs dentry pointer (per opp) * @@ -73,6 +70,7 @@ extern struct list_head opp_tables; */ struct dev_pm_opp { struct list_head node; + struct kref kref; bool available; bool dynamic; @@ -85,7 +83,6 @@ struct dev_pm_opp { unsigned long clock_latency_ns; struct opp_table *opp_table; - struct rcu_head rcu_head; struct device_node *np; @@ -98,7 +95,6 @@ struct dev_pm_opp { * struct opp_device - devices managed by 'struct opp_table' * @node: list node * @dev: device to which the struct object belongs - * @rcu_head: RCU callback head used for deferred freeing * @dentry: debugfs dentry pointer (per device) * * This is an internal data structure maintaining the devices that are managed @@ -107,7 +103,6 @@ struct dev_pm_opp { struct opp_device { struct list_head node; const struct device *dev; - struct rcu_head rcu_head; #ifdef CONFIG_DEBUG_FS struct dentry *dentry; @@ -125,12 +120,11 @@ enum opp_table_access { * @node: table node - contains the devices with OPPs that * have been registered. Nodes once added are not modified in this * table. - * RCU usage: nodes are not modified in the table of opp_table, - * however addition is possible and is secured by opp_table_lock - * @srcu_head: notifier head to notify the OPP availability changes. - * @rcu_head: RCU callback head used for deferred freeing + * @head: notifier head to notify the OPP availability changes. * @dev_list: list of devices that share these OPPs * @opp_list: table of opps + * @kref: for reference count of the table. + * @lock: mutex protecting the opp_list. * @np: struct device_node pointer for opp's DT node. * @clock_latency_ns_max: Max clock latency in nanoseconds. * @shared_opp: OPP is shared between multiple devices. @@ -151,18 +145,15 @@ enum opp_table_access { * This is an internal data structure maintaining the link to opps attached to * a device. This structure is not meant to be shared to users as it is * meant for book keeping and private to OPP library. - * - * Because the opp structures can be used from both rcu and srcu readers, we - * need to wait for the grace period of both of them before freeing any - * resources. And so we have used kfree_rcu() from within call_srcu() handlers. */ struct opp_table { struct list_head node; - struct srcu_notifier_head srcu_head; - struct rcu_head rcu_head; + struct blocking_notifier_head head; struct list_head dev_list; struct list_head opp_list; + struct kref kref; + struct mutex lock; struct device_node *np; unsigned long clock_latency_ns_max; @@ -190,14 +181,17 @@ struct opp_table { }; /* Routines internal to opp core */ +void _get_opp_table_kref(struct opp_table *opp_table); struct opp_table *_find_opp_table(struct device *dev); struct opp_device *_add_opp_dev(const struct device *dev, struct opp_table *opp_table); -void _dev_pm_opp_remove_table(struct device *dev, bool remove_all); -struct dev_pm_opp *_allocate_opp(struct device *dev, struct opp_table **opp_table); +void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, bool remove_all); +void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all); +struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); +void _opp_free(struct dev_pm_opp *opp); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); -void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp, bool notify); -int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt, bool dynamic); +int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, bool of); +struct opp_table *_add_opp_table(struct device *dev); #ifdef CONFIG_OF void _of_init_opp_table(struct opp_table *opp_table, struct device *dev); diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index 58fcc758334e..d888d9869b6a 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -281,7 +281,7 @@ void dev_pm_qos_constraints_destroy(struct device *dev) dev->power.qos = ERR_PTR(-ENODEV); spin_unlock_irq(&dev->power.lock); - kfree(c->notifiers); + kfree(qos->resume_latency.notifiers); kfree(qos); out: diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 872eac4cb1df..a14fac6a01d3 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -966,13 +966,13 @@ int __pm_runtime_idle(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); - if (rpmflags & RPM_GET_PUT) { if (!atomic_dec_and_test(&dev->power.usage_count)) return 0; } + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + spin_lock_irqsave(&dev->power.lock, flags); retval = rpm_idle(dev, rpmflags); spin_unlock_irqrestore(&dev->power.lock, flags); @@ -998,13 +998,13 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); - if (rpmflags & RPM_GET_PUT) { if (!atomic_dec_and_test(&dev->power.usage_count)) return 0; } + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + spin_lock_irqsave(&dev->power.lock, flags); retval = rpm_suspend(dev, rpmflags); spin_unlock_irqrestore(&dev->power.lock, flags); @@ -1029,7 +1029,8 @@ int __pm_runtime_resume(struct device *dev, int rpmflags) unsigned long flags; int retval; - might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe); + might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe && + dev->power.runtime_status != RPM_ACTIVE); if (rpmflags & RPM_GET_PUT) atomic_inc(&dev->power.usage_count); diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c index 404d94c6c8bc..ae0429827f31 100644 --- a/drivers/base/power/wakeirq.c +++ b/drivers/base/power/wakeirq.c @@ -141,6 +141,13 @@ static irqreturn_t handle_threaded_wake_irq(int irq, void *_wirq) struct wake_irq *wirq = _wirq; int res; + /* Maybe abort suspend? */ + if (irqd_is_wakeup_set(irq_get_irq_data(irq))) { + pm_wakeup_event(wirq->dev, 0); + + return IRQ_HANDLED; + } + /* We don't want RPM_ASYNC or RPM_NOWAIT here */ res = pm_runtime_resume(wirq->dev); if (res < 0) @@ -183,6 +190,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq) wirq->irq = irq; irq_set_status_flags(irq, IRQ_NOAUTOEN); + /* Prevent deferred spurious wakeirqs with disable_irq_nosync() */ + irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); + /* * Consumer device may need to power up and restore state * so we use a threaded irq. @@ -312,8 +322,12 @@ void dev_pm_arm_wake_irq(struct wake_irq *wirq) if (!wirq) return; - if (device_may_wakeup(wirq->dev)) + if (device_may_wakeup(wirq->dev)) { + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + enable_irq(wirq->irq); + enable_irq_wake(wirq->irq); + } } /** @@ -328,6 +342,10 @@ void dev_pm_disarm_wake_irq(struct wake_irq *wirq) if (!wirq) return; - if (device_may_wakeup(wirq->dev)) + if (device_may_wakeup(wirq->dev)) { disable_irq_wake(wirq->irq); + + if (wirq->status & WAKE_IRQ_DEDICATED_ALLOCATED) + disable_irq_nosync(wirq->irq); + } } diff --git a/drivers/base/property.c b/drivers/base/property.c index 43a36d68c3fd..c458c63e353f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -21,7 +21,7 @@ struct property_set { struct fwnode_handle fwnode; - struct property_entry *properties; + const struct property_entry *properties; }; static inline bool is_pset_node(struct fwnode_handle *fwnode) @@ -35,10 +35,10 @@ static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode) container_of(fwnode, struct property_set, fwnode) : NULL; } -static struct property_entry *pset_prop_get(struct property_set *pset, - const char *name) +static const struct property_entry *pset_prop_get(struct property_set *pset, + const char *name) { - struct property_entry *prop; + const struct property_entry *prop; if (!pset || !pset->properties) return NULL; @@ -50,11 +50,11 @@ static struct property_entry *pset_prop_get(struct property_set *pset, return NULL; } -static void *pset_prop_find(struct property_set *pset, const char *propname, - size_t length) +static const void *pset_prop_find(struct property_set *pset, + const char *propname, size_t length) { - struct property_entry *prop; - void *pointer; + const struct property_entry *prop; + const void *pointer; prop = pset_prop_get(pset, propname); if (!prop) @@ -74,7 +74,7 @@ static int pset_prop_read_u8_array(struct property_set *pset, const char *propname, u8 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -89,7 +89,7 @@ static int pset_prop_read_u16_array(struct property_set *pset, const char *propname, u16 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -104,7 +104,7 @@ static int pset_prop_read_u32_array(struct property_set *pset, const char *propname, u32 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -119,7 +119,7 @@ static int pset_prop_read_u64_array(struct property_set *pset, const char *propname, u64 *values, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*values); pointer = pset_prop_find(pset, propname, length); @@ -133,7 +133,7 @@ static int pset_prop_read_u64_array(struct property_set *pset, static int pset_prop_count_elems_of_size(struct property_set *pset, const char *propname, size_t length) { - struct property_entry *prop; + const struct property_entry *prop; prop = pset_prop_get(pset, propname); if (!prop) @@ -146,7 +146,7 @@ static int pset_prop_read_string_array(struct property_set *pset, const char *propname, const char **strings, size_t nval) { - void *pointer; + const void *pointer; size_t length = nval * sizeof(*strings); pointer = pset_prop_find(pset, propname, length); @@ -160,8 +160,8 @@ static int pset_prop_read_string_array(struct property_set *pset, static int pset_prop_read_string(struct property_set *pset, const char *propname, const char **strings) { - struct property_entry *prop; - const char **pointer; + const struct property_entry *prop; + const char * const *pointer; prop = pset_prop_get(pset, propname); if (!prop) @@ -682,77 +682,64 @@ out: } EXPORT_SYMBOL_GPL(fwnode_property_match_string); -/** - * pset_free_set - releases memory allocated for copied property set - * @pset: Property set to release - * - * Function takes previously copied property set and releases all the - * memory allocated to it. - */ -static void pset_free_set(struct property_set *pset) +static int property_copy_string_array(struct property_entry *dst, + const struct property_entry *src) { - const struct property_entry *prop; - size_t i, nval; + char **d; + size_t nval = src->length / sizeof(*d); + int i; - if (!pset) - return; + d = kcalloc(nval, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; - for (prop = pset->properties; prop->name; prop++) { - if (prop->is_array) { - if (prop->is_string && prop->pointer.str) { - nval = prop->length / sizeof(const char *); - for (i = 0; i < nval; i++) - kfree(prop->pointer.str[i]); - } - kfree(prop->pointer.raw_data); - } else if (prop->is_string) { - kfree(prop->value.str); + for (i = 0; i < nval; i++) { + d[i] = kstrdup(src->pointer.str[i], GFP_KERNEL); + if (!d[i] && src->pointer.str[i]) { + while (--i >= 0) + kfree(d[i]); + kfree(d); + return -ENOMEM; } - kfree(prop->name); } - kfree(pset->properties); - kfree(pset); + dst->pointer.raw_data = d; + return 0; } -static int pset_copy_entry(struct property_entry *dst, - const struct property_entry *src) +static int property_entry_copy_data(struct property_entry *dst, + const struct property_entry *src) { - const char **d, **s; - size_t i, nval; + int error; dst->name = kstrdup(src->name, GFP_KERNEL); if (!dst->name) return -ENOMEM; if (src->is_array) { - if (!src->length) - return -ENODATA; + if (!src->length) { + error = -ENODATA; + goto out_free_name; + } if (src->is_string) { - nval = src->length / sizeof(const char *); - dst->pointer.str = kcalloc(nval, sizeof(const char *), - GFP_KERNEL); - if (!dst->pointer.str) - return -ENOMEM; - - d = dst->pointer.str; - s = src->pointer.str; - for (i = 0; i < nval; i++) { - d[i] = kstrdup(s[i], GFP_KERNEL); - if (!d[i] && s[i]) - return -ENOMEM; - } + error = property_copy_string_array(dst, src); + if (error) + goto out_free_name; } else { dst->pointer.raw_data = kmemdup(src->pointer.raw_data, src->length, GFP_KERNEL); - if (!dst->pointer.raw_data) - return -ENOMEM; + if (!dst->pointer.raw_data) { + error = -ENOMEM; + goto out_free_name; + } } } else if (src->is_string) { dst->value.str = kstrdup(src->value.str, GFP_KERNEL); - if (!dst->value.str && src->value.str) - return -ENOMEM; + if (!dst->value.str && src->value.str) { + error = -ENOMEM; + goto out_free_name; + } } else { dst->value.raw_data = src->value.raw_data; } @@ -762,6 +749,95 @@ static int pset_copy_entry(struct property_entry *dst, dst->is_string = src->is_string; return 0; + +out_free_name: + kfree(dst->name); + return error; +} + +static void property_entry_free_data(const struct property_entry *p) +{ + size_t i, nval; + + if (p->is_array) { + if (p->is_string && p->pointer.str) { + nval = p->length / sizeof(const char *); + for (i = 0; i < nval; i++) + kfree(p->pointer.str[i]); + } + kfree(p->pointer.raw_data); + } else if (p->is_string) { + kfree(p->value.str); + } + kfree(p->name); +} + +/** + * property_entries_dup - duplicate array of properties + * @properties: array of properties to copy + * + * This function creates a deep copy of the given NULL-terminated array + * of property entries. + */ +struct property_entry * +property_entries_dup(const struct property_entry *properties) +{ + struct property_entry *p; + int i, n = 0; + + while (properties[n].name) + n++; + + p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < n; i++) { + int ret = property_entry_copy_data(&p[i], &properties[i]); + if (ret) { + while (--i >= 0) + property_entry_free_data(&p[i]); + kfree(p); + return ERR_PTR(ret); + } + } + + return p; +} +EXPORT_SYMBOL_GPL(property_entries_dup); + +/** + * property_entries_free - free previously allocated array of properties + * @properties: array of properties to destroy + * + * This function frees given NULL-terminated array of property entries, + * along with their data. + */ +void property_entries_free(const struct property_entry *properties) +{ + const struct property_entry *p; + + for (p = properties; p->name; p++) + property_entry_free_data(p); + + kfree(properties); +} +EXPORT_SYMBOL_GPL(property_entries_free); + +/** + * pset_free_set - releases memory allocated for copied property set + * @pset: Property set to release + * + * Function takes previously copied property set and releases all the + * memory allocated to it. + */ +static void pset_free_set(struct property_set *pset) +{ + if (!pset) + return; + + property_entries_free(pset->properties); + kfree(pset); } /** @@ -776,32 +852,20 @@ static int pset_copy_entry(struct property_entry *dst, */ static struct property_set *pset_copy_set(const struct property_set *pset) { - const struct property_entry *entry; + struct property_entry *properties; struct property_set *p; - size_t i, n = 0; p = kzalloc(sizeof(*p), GFP_KERNEL); if (!p) return ERR_PTR(-ENOMEM); - while (pset->properties[n].name) - n++; - - p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL); - if (!p->properties) { + properties = property_entries_dup(pset->properties); + if (IS_ERR(properties)) { kfree(p); - return ERR_PTR(-ENOMEM); - } - - for (i = 0; i < n; i++) { - int ret = pset_copy_entry(&p->properties[i], - &pset->properties[i]); - if (ret) { - pset_free_set(p); - return ERR_PTR(ret); - } + return ERR_CAST(properties); } + p->properties = properties; return p; } @@ -847,7 +911,8 @@ EXPORT_SYMBOL_GPL(device_remove_properties); * @dev as its secondary firmware node. The function takes a copy of * @properties. */ -int device_add_properties(struct device *dev, struct property_entry *properties) +int device_add_properties(struct device *dev, + const struct property_entry *properties) { struct property_set *p, pset; diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index b11af3f2c1db..b1e9aae9a5d0 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -81,7 +81,7 @@ static struct regcache_rbtree_node *regcache_rbtree_lookup(struct regmap *map, node = rbtree_ctx->root.rb_node; while (node) { - rbnode = container_of(node, struct regcache_rbtree_node, node); + rbnode = rb_entry(node, struct regcache_rbtree_node, node); regcache_rbtree_get_base_top_reg(map, rbnode, &base_reg, &top_reg); if (reg >= base_reg && reg <= top_reg) { @@ -108,8 +108,7 @@ static int regcache_rbtree_insert(struct regmap *map, struct rb_root *root, parent = NULL; new = &root->rb_node; while (*new) { - rbnode_tmp = container_of(*new, struct regcache_rbtree_node, - node); + rbnode_tmp = rb_entry(*new, struct regcache_rbtree_node, node); /* base and top registers of the current rbnode */ regcache_rbtree_get_base_top_reg(map, rbnode_tmp, &base_reg_tmp, &top_reg_tmp); @@ -152,7 +151,7 @@ static int rbtree_show(struct seq_file *s, void *ignored) for (node = rb_first(&rbtree_ctx->root); node != NULL; node = rb_next(node)) { - n = container_of(node, struct regcache_rbtree_node, node); + n = rb_entry(node, struct regcache_rbtree_node, node); mem_size += sizeof(*n); mem_size += (n->blklen * map->cache_word_size); mem_size += BITS_TO_LONGS(n->blklen) * sizeof(long); diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 4e582561e1e7..b0a0dcf32fb7 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -224,7 +224,7 @@ void regcache_exit(struct regmap *map) } /** - * regcache_read: Fetch the value of a given register from the cache. + * regcache_read - Fetch the value of a given register from the cache. * * @map: map to configure. * @reg: The register index. @@ -255,7 +255,7 @@ int regcache_read(struct regmap *map, } /** - * regcache_write: Set the value of a given register in the cache. + * regcache_write - Set the value of a given register in the cache. * * @map: map to configure. * @reg: The register index. @@ -328,7 +328,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, } /** - * regcache_sync: Sync the register cache with the hardware. + * regcache_sync - Sync the register cache with the hardware. * * @map: map to configure. * @@ -396,7 +396,7 @@ out: EXPORT_SYMBOL_GPL(regcache_sync); /** - * regcache_sync_region: Sync part of the register cache with the hardware. + * regcache_sync_region - Sync part of the register cache with the hardware. * * @map: map to sync. * @min: first register to sync @@ -452,7 +452,7 @@ out: EXPORT_SYMBOL_GPL(regcache_sync_region); /** - * regcache_drop_region: Discard part of the register cache + * regcache_drop_region - Discard part of the register cache * * @map: map to operate on * @min: first register to discard @@ -483,10 +483,10 @@ int regcache_drop_region(struct regmap *map, unsigned int min, EXPORT_SYMBOL_GPL(regcache_drop_region); /** - * regcache_cache_only: Put a register map into cache only mode + * regcache_cache_only - Put a register map into cache only mode * * @map: map to configure - * @cache_only: flag if changes should be written to the hardware + * @enable: flag if changes should be written to the hardware * * When a register map is marked as cache only writes to the register * map API will only update the register cache, they will not cause @@ -505,7 +505,7 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Indicate that HW registers were reset to default values + * regcache_mark_dirty - Indicate that HW registers were reset to default values * * @map: map to mark * @@ -527,10 +527,10 @@ void regcache_mark_dirty(struct regmap *map) EXPORT_SYMBOL_GPL(regcache_mark_dirty); /** - * regcache_cache_bypass: Put a register map into cache bypass mode + * regcache_cache_bypass - Put a register map into cache bypass mode * * @map: map to configure - * @cache_bypass: flag if changes should not be written to the cache + * @enable: flag if changes should not be written to the cache * * When a register map is marked with the cache bypass option, writes * to the register map API will only update the hardware and not the diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index ec262476d043..cd54189f2b1d 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -398,13 +398,14 @@ static const struct irq_domain_ops regmap_domain_ops = { }; /** - * regmap_add_irq_chip(): Use standard regmap IRQ controller handling + * regmap_add_irq_chip() - Use standard regmap IRQ controller handling * - * map: The regmap for the device. - * irq: The IRQ the device uses to signal interrupts - * irq_flags: The IRQF_ flags to use for the primary interrupt. - * chip: Configuration for the interrupt controller. - * data: Runtime data structure for the controller, allocated on success + * @map: The regmap for the device. + * @irq: The IRQ the device uses to signal interrupts. + * @irq_flags: The IRQF_ flags to use for the primary interrupt. + * @irq_base: Allocate at specific IRQ number if irq_base > 0. + * @chip: Configuration for the interrupt controller. + * @data: Runtime data structure for the controller, allocated on success. * * Returns 0 on success or an errno on failure. * @@ -659,12 +660,12 @@ err_alloc: EXPORT_SYMBOL_GPL(regmap_add_irq_chip); /** - * regmap_del_irq_chip(): Stop interrupt handling for a regmap IRQ chip + * regmap_del_irq_chip() - Stop interrupt handling for a regmap IRQ chip * * @irq: Primary IRQ for the device - * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() + * @d: ®map_irq_chip_data allocated by regmap_add_irq_chip() * - * This function also dispose all mapped irq on chip. + * This function also disposes of all mapped IRQs on the chip. */ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d) { @@ -723,18 +724,19 @@ static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data) } /** - * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip() + * devm_regmap_add_irq_chip() - Resource manager regmap_add_irq_chip() * - * @dev: The device pointer on which irq_chip belongs to. - * @map: The regmap for the device. - * @irq: The IRQ the device uses to signal interrupts + * @dev: The device pointer on which irq_chip belongs to. + * @map: The regmap for the device. + * @irq: The IRQ the device uses to signal interrupts * @irq_flags: The IRQF_ flags to use for the primary interrupt. - * @chip: Configuration for the interrupt controller. - * @data: Runtime data structure for the controller, allocated on success + * @irq_base: Allocate at specific IRQ number if irq_base > 0. + * @chip: Configuration for the interrupt controller. + * @data: Runtime data structure for the controller, allocated on success * * Returns 0 on success or an errno on failure. * - * The regmap_irq_chip data automatically be released when the device is + * The ®map_irq_chip_data will be automatically released when the device is * unbound. */ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, @@ -765,11 +767,13 @@ int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq, EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip); /** - * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip() + * devm_regmap_del_irq_chip() - Resource managed regmap_del_irq_chip() * * @dev: Device for which which resource was allocated. - * @irq: Primary IRQ for the device - * @d: regmap_irq_chip_data allocated by regmap_add_irq_chip() + * @irq: Primary IRQ for the device. + * @data: ®map_irq_chip_data allocated by regmap_add_irq_chip(). + * + * A resource managed version of regmap_del_irq_chip(). */ void devm_regmap_del_irq_chip(struct device *dev, int irq, struct regmap_irq_chip_data *data) @@ -786,11 +790,11 @@ void devm_regmap_del_irq_chip(struct device *dev, int irq, EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip); /** - * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip + * regmap_irq_chip_get_base() - Retrieve interrupt base for a regmap IRQ chip * - * Useful for drivers to request their own IRQs. + * @data: regmap irq controller to operate on. * - * @data: regmap_irq controller to operate on. + * Useful for drivers to request their own IRQs. */ int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) { @@ -800,12 +804,12 @@ int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data) EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base); /** - * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * regmap_irq_get_virq() - Map an interrupt on a chip to a virtual IRQ * - * Useful for drivers to request their own IRQs. + * @data: regmap irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs. * - * @data: regmap_irq controller to operate on. - * @irq: index of the interrupt requested in the chip IRQs + * Useful for drivers to request their own IRQs. */ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) { @@ -818,14 +822,14 @@ int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq) EXPORT_SYMBOL_GPL(regmap_irq_get_virq); /** - * regmap_irq_get_domain(): Retrieve the irq_domain for the chip + * regmap_irq_get_domain() - Retrieve the irq_domain for the chip + * + * @data: regmap_irq controller to operate on. * * Useful for drivers to request their own IRQs and for integration * with subsystems. For ease of integration NULL is accepted as a * domain, allowing devices to just call this even if no domain is * allocated. - * - * @data: regmap_irq controller to operate on. */ struct irq_domain *regmap_irq_get_domain(struct regmap_irq_chip_data *data) { diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index ae63bb0875ea..b9a779a4a739 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -459,7 +459,7 @@ static bool _regmap_range_add(struct regmap *map, while (*new) { struct regmap_range_node *this = - container_of(*new, struct regmap_range_node, node); + rb_entry(*new, struct regmap_range_node, node); parent = *new; if (data->range_max < this->range_min) @@ -483,7 +483,7 @@ static struct regmap_range_node *_regmap_range_lookup(struct regmap *map, while (node) { struct regmap_range_node *this = - container_of(node, struct regmap_range_node, node); + rb_entry(node, struct regmap_range_node, node); if (reg < this->range_min) node = node->rb_left; @@ -1091,8 +1091,7 @@ static void regmap_field_init(struct regmap_field *rm_field, } /** - * devm_regmap_field_alloc(): Allocate and initialise a register field - * in a register map. + * devm_regmap_field_alloc() - Allocate and initialise a register field. * * @dev: Device that will be interacted with * @regmap: regmap bank in which this register field is located. @@ -1118,13 +1117,15 @@ struct regmap_field *devm_regmap_field_alloc(struct device *dev, EXPORT_SYMBOL_GPL(devm_regmap_field_alloc); /** - * devm_regmap_field_free(): Free register field allocated using - * devm_regmap_field_alloc. Usally drivers need not call this function, - * as the memory allocated via devm will be freed as per device-driver - * life-cyle. + * devm_regmap_field_free() - Free a register field allocated using + * devm_regmap_field_alloc. * * @dev: Device that will be interacted with * @field: regmap field which should be freed. + * + * Free register field allocated using devm_regmap_field_alloc(). Usually + * drivers need not call this function, as the memory allocated via devm + * will be freed as per device-driver life-cyle. */ void devm_regmap_field_free(struct device *dev, struct regmap_field *field) @@ -1134,8 +1135,7 @@ void devm_regmap_field_free(struct device *dev, EXPORT_SYMBOL_GPL(devm_regmap_field_free); /** - * regmap_field_alloc(): Allocate and initialise a register field - * in a register map. + * regmap_field_alloc() - Allocate and initialise a register field. * * @regmap: regmap bank in which this register field is located. * @reg_field: Register field with in the bank. @@ -1159,7 +1159,8 @@ struct regmap_field *regmap_field_alloc(struct regmap *regmap, EXPORT_SYMBOL_GPL(regmap_field_alloc); /** - * regmap_field_free(): Free register field allocated using regmap_field_alloc + * regmap_field_free() - Free register field allocated using + * regmap_field_alloc. * * @field: regmap field which should be freed. */ @@ -1170,7 +1171,7 @@ void regmap_field_free(struct regmap_field *field) EXPORT_SYMBOL_GPL(regmap_field_free); /** - * regmap_reinit_cache(): Reinitialise the current register cache + * regmap_reinit_cache() - Reinitialise the current register cache * * @map: Register map to operate on. * @config: New configuration. Only the cache data will be used. @@ -1205,7 +1206,9 @@ int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config) EXPORT_SYMBOL_GPL(regmap_reinit_cache); /** - * regmap_exit(): Free a previously allocated register map + * regmap_exit() - Free a previously allocated register map + * + * @map: Register map to operate on. */ void regmap_exit(struct regmap *map) { @@ -1245,7 +1248,7 @@ static int dev_get_regmap_match(struct device *dev, void *res, void *data) } /** - * dev_get_regmap(): Obtain the regmap (if any) for a device + * dev_get_regmap() - Obtain the regmap (if any) for a device * * @dev: Device to retrieve the map for * @name: Optional name for the register map, usually NULL. @@ -1268,7 +1271,7 @@ struct regmap *dev_get_regmap(struct device *dev, const char *name) EXPORT_SYMBOL_GPL(dev_get_regmap); /** - * regmap_get_device(): Obtain the device from a regmap + * regmap_get_device() - Obtain the device from a regmap * * @map: Register map to operate on. * @@ -1654,7 +1657,7 @@ int _regmap_write(struct regmap *map, unsigned int reg, } /** - * regmap_write(): Write a value to a single register + * regmap_write() - Write a value to a single register * * @map: Register map to write to * @reg: Register to write to @@ -1681,7 +1684,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write); /** - * regmap_write_async(): Write a value to a single register asynchronously + * regmap_write_async() - Write a value to a single register asynchronously * * @map: Register map to write to * @reg: Register to write to @@ -1712,7 +1715,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val) EXPORT_SYMBOL_GPL(regmap_write_async); /** - * regmap_raw_write(): Write raw values to one or more registers + * regmap_raw_write() - Write raw values to one or more registers * * @map: Register map to write to * @reg: Initial register to write to @@ -1750,9 +1753,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, EXPORT_SYMBOL_GPL(regmap_raw_write); /** - * regmap_field_update_bits_base(): - * Perform a read/modify/write cycle on the register field - * with change, async, force option + * regmap_field_update_bits_base() - Perform a read/modify/write cycle a + * register field. * * @field: Register field to write to * @mask: Bitmask to change @@ -1761,6 +1763,9 @@ EXPORT_SYMBOL_GPL(regmap_raw_write); * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * + * Perform a read/modify/write cycle on the register field with change, + * async, force option. + * * A value of zero will be returned on success, a negative errno will * be returned in error cases. */ @@ -1777,9 +1782,8 @@ int regmap_field_update_bits_base(struct regmap_field *field, EXPORT_SYMBOL_GPL(regmap_field_update_bits_base); /** - * regmap_fields_update_bits_base(): - * Perform a read/modify/write cycle on the register field - * with change, async, force option + * regmap_fields_update_bits_base() - Perform a read/modify/write cycle a + * register field with port ID * * @field: Register field to write to * @id: port ID @@ -1808,8 +1812,8 @@ int regmap_fields_update_bits_base(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_update_bits_base); -/* - * regmap_bulk_write(): Write multiple registers to the device +/** + * regmap_bulk_write() - Write multiple registers to the device * * @map: Register map to write to * @reg: First register to be write from @@ -2174,18 +2178,18 @@ static int _regmap_multi_reg_write(struct regmap *map, return _regmap_raw_multi_reg_write(map, regs, num_regs); } -/* - * regmap_multi_reg_write(): Write multiple registers to the device - * - * where the set of register,value pairs are supplied in any order, - * possibly not all in a single range. +/** + * regmap_multi_reg_write() - Write multiple registers to the device * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * + * Write multiple registers to the device where the set of register, value + * pairs are supplied in any order, possibly not all in a single range. + * * The 'normal' block write mode will send ultimately send data on the - * target bus as R,V1,V2,V3,..,Vn where successively higer registers are + * target bus as R,V1,V2,V3,..,Vn where successively higher registers are * addressed. However, this alternative block multi write mode will send * the data as R1,V1,R2,V2,..,Rn,Vn on the target bus. The target device * must of course support the mode. @@ -2208,16 +2212,17 @@ int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, } EXPORT_SYMBOL_GPL(regmap_multi_reg_write); -/* - * regmap_multi_reg_write_bypassed(): Write multiple registers to the - * device but not the cache - * - * where the set of register are supplied in any order +/** + * regmap_multi_reg_write_bypassed() - Write multiple registers to the + * device but not the cache * * @map: Register map to write to * @regs: Array of structures containing register,value to be written * @num_regs: Number of registers to write * + * Write multiple registers to the device but not the cache where the set + * of register are supplied in any order. + * * This function is intended to be used for writing a large block of data * atomically to the device in single transfer for those I2C client devices * that implement this alternative block write mode. @@ -2248,8 +2253,8 @@ int regmap_multi_reg_write_bypassed(struct regmap *map, EXPORT_SYMBOL_GPL(regmap_multi_reg_write_bypassed); /** - * regmap_raw_write_async(): Write raw values to one or more registers - * asynchronously + * regmap_raw_write_async() - Write raw values to one or more registers + * asynchronously * * @map: Register map to write to * @reg: Initial register to write to @@ -2385,7 +2390,7 @@ static int _regmap_read(struct regmap *map, unsigned int reg, } /** - * regmap_read(): Read a value from a single register + * regmap_read() - Read a value from a single register * * @map: Register map to read from * @reg: Register to be read from @@ -2412,7 +2417,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_read); /** - * regmap_raw_read(): Read raw data from the device + * regmap_raw_read() - Read raw data from the device * * @map: Register map to read from * @reg: First register to be read from @@ -2477,7 +2482,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, EXPORT_SYMBOL_GPL(regmap_raw_read); /** - * regmap_field_read(): Read a value to a single register field + * regmap_field_read() - Read a value to a single register field * * @field: Register field to read from * @val: Pointer to store read value @@ -2502,7 +2507,7 @@ int regmap_field_read(struct regmap_field *field, unsigned int *val) EXPORT_SYMBOL_GPL(regmap_field_read); /** - * regmap_fields_read(): Read a value to a single register field with port ID + * regmap_fields_read() - Read a value to a single register field with port ID * * @field: Register field to read from * @id: port ID @@ -2535,7 +2540,7 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id, EXPORT_SYMBOL_GPL(regmap_fields_read); /** - * regmap_bulk_read(): Read multiple registers from the device + * regmap_bulk_read() - Read multiple registers from the device * * @map: Register map to read from * @reg: First register to be read from @@ -2692,9 +2697,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, } /** - * regmap_update_bits_base: - * Perform a read/modify/write cycle on the - * register map with change, async, force option + * regmap_update_bits_base() - Perform a read/modify/write cycle on a register * * @map: Register map to update * @reg: Register to update @@ -2704,10 +2707,14 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, * @async: Boolean indicating asynchronously * @force: Boolean indicating use force update * - * if async was true, - * With most buses the read must be done synchronously so this is most - * useful for devices with a cache which do not need to interact with - * the hardware to determine the current register value. + * Perform a read/modify/write cycle on a register map with change, async, force + * options. + * + * If async is true: + * + * With most buses the read must be done synchronously so this is most useful + * for devices with a cache which do not need to interact with the hardware to + * determine the current register value. * * Returns zero for success, a negative number on error. */ @@ -2765,7 +2772,7 @@ static int regmap_async_is_done(struct regmap *map) } /** - * regmap_async_complete: Ensure all asynchronous I/O has completed. + * regmap_async_complete - Ensure all asynchronous I/O has completed. * * @map: Map to operate on. * @@ -2797,8 +2804,8 @@ int regmap_async_complete(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_async_complete); /** - * regmap_register_patch: Register and apply register updates to be applied - * on device initialistion + * regmap_register_patch - Register and apply register updates to be applied + * on device initialistion * * @map: Register map to apply updates to. * @regs: Values to update. @@ -2855,8 +2862,10 @@ int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, } EXPORT_SYMBOL_GPL(regmap_register_patch); -/* - * regmap_get_val_bytes(): Report the size of a register value +/** + * regmap_get_val_bytes() - Report the size of a register value + * + * @map: Register map to operate on. * * Report the size of a register value, mainly intended to for use by * generic infrastructure built on top of regmap. @@ -2871,7 +2880,9 @@ int regmap_get_val_bytes(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_get_val_bytes); /** - * regmap_get_max_register(): Report the max register value + * regmap_get_max_register() - Report the max register value + * + * @map: Register map to operate on. * * Report the max register value, mainly intended to for use by * generic infrastructure built on top of regmap. @@ -2883,7 +2894,9 @@ int regmap_get_max_register(struct regmap *map) EXPORT_SYMBOL_GPL(regmap_get_max_register); /** - * regmap_get_reg_stride(): Report the register address stride + * regmap_get_reg_stride() - Report the register address stride + * + * @map: Register map to operate on. * * Report the register address stride, mainly intended to for use by * generic infrastructure built on top of regmap. diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index f642c4264c27..168fa175d65a 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -45,6 +45,9 @@ int bcma_sprom_get(struct bcma_bus *bus); void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc); void bcma_core_chipcommon_init(struct bcma_drv_cc *cc); void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable); +#ifdef CONFIG_BCMA_DRIVER_MIPS +void bcma_chipco_serial_init(struct bcma_drv_cc *cc); +#endif /* CONFIG_BCMA_DRIVER_MIPS */ /* driver_chipcommon_b.c */ int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb); diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index b4f6520e74f0..62f5bfa5065d 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -15,8 +15,6 @@ #include <linux/platform_device.h> #include <linux/bcma/bcma.h> -static void bcma_chipco_serial_init(struct bcma_drv_cc *cc); - static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset, u32 mask, u32 value) { @@ -186,9 +184,6 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc) if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_early_init(cc); - if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC) - bcma_chipco_serial_init(cc); - if (bus->hosttype == BCMA_HOSTTYPE_SOC) bcma_core_chipcommon_flash_detect(cc); @@ -378,9 +373,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value) return res; } -static void bcma_chipco_serial_init(struct bcma_drv_cc *cc) +#ifdef CONFIG_BCMA_DRIVER_MIPS +void bcma_chipco_serial_init(struct bcma_drv_cc *cc) { -#if IS_BUILTIN(CONFIG_BCM47XX) unsigned int irq; u32 baud_base; u32 i; @@ -422,5 +417,5 @@ static void bcma_chipco_serial_init(struct bcma_drv_cc *cc) ports[i].baud_base = baud_base; ports[i].reg_shift = 0; } -#endif /* CONFIG_BCM47XX */ } +#endif /* CONFIG_BCMA_DRIVER_MIPS */ diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index 96f171328200..89af807cf29c 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -278,9 +278,12 @@ static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore) void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { + struct bcma_bus *bus = mcore->core->bus; + if (mcore->early_setup_done) return; + bcma_chipco_serial_init(&bus->drv_cc); bcma_core_mips_nvram_init(mcore); mcore->early_setup_done = true; diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 223ff2fcae7e..f744de7a0f9b 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -69,6 +69,7 @@ config AMIGA_Z2RAM config GDROM tristate "SEGA Dreamcast GD-ROM drive" depends on SH_DREAMCAST + select BLK_SCSI_REQUEST # only for the generic cdrom code help A standard SEGA Dreamcast comes with a modified CD ROM drive called a "GD-ROM" by SEGA to signify it is capable of reading special disks @@ -114,6 +115,7 @@ config BLK_CPQ_CISS_DA tristate "Compaq Smart Array 5xxx support" depends on PCI select CHECK_SIGNATURE + select BLK_SCSI_REQUEST help This is the driver for Compaq Smart Array 5xxx controllers. Everyone using these boards should say Y here. @@ -386,6 +388,7 @@ config BLK_DEV_RAM_DAX config CDROM_PKTCDVD tristate "Packet writing on CD/DVD media (DEPRECATED)" depends on !UML + select BLK_SCSI_REQUEST help Note: This driver is deprecated and will be removed from the kernel in the near future! @@ -501,6 +504,16 @@ config VIRTIO_BLK This is the virtual block driver for virtio. It can be used with lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. +config VIRTIO_BLK_SCSI + bool "SCSI passthrough request for the Virtio block driver" + depends on VIRTIO_BLK + select BLK_SCSI_REQUEST + ---help--- + Enable support for SCSI passthrough (e.g. the SG_IO ioctl) on + virtio-blk devices. This is only supported for the legacy + virtio protocol and not enabled by default by any hypervisor. + Your probably want to virtio-scsi instead. + config BLK_DEV_HD bool "Very old hard disk (MFM/RLL/IDE) driver" depends on HAVE_IDE diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index ec9d8610b25f..027b876370bc 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -396,8 +396,8 @@ aoeblk_gdalloc(void *vp) WARN_ON(d->gd); WARN_ON(d->flags & DEVFL_UP); blk_queue_max_hw_sectors(q, BLK_DEF_MAX_SECTORS); - q->backing_dev_info.name = "aoe"; - q->backing_dev_info.ra_pages = READ_AHEAD / PAGE_SIZE; + q->backing_dev_info->name = "aoe"; + q->backing_dev_info->ra_pages = READ_AHEAD / PAGE_SIZE; d->bufpool = mp; d->blkq = gd->queue = q; q->queuedata = d; diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e5c5b8eb14a9..27d613795653 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -52,6 +52,7 @@ #include <scsi/scsi.h> #include <scsi/sg.h> #include <scsi/scsi_ioctl.h> +#include <scsi/scsi_request.h> #include <linux/cdrom.h> #include <linux/scatterlist.h> #include <linux/kthread.h> @@ -1853,8 +1854,8 @@ static void cciss_softirq_done(struct request *rq) dev_dbg(&h->pdev->dev, "Done with %p\n", rq); /* set the residual count for pc requests */ - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) - rq->resid_len = c->err_info->ResidualCnt; + if (blk_rq_is_passthrough(rq)) + scsi_req(rq)->resid_len = c->err_info->ResidualCnt; blk_end_request_all(rq, (rq->errors == 0) ? 0 : -EIO); @@ -1941,9 +1942,16 @@ static void cciss_get_serial_no(ctlr_info_t *h, int logvol, static int cciss_add_disk(ctlr_info_t *h, struct gendisk *disk, int drv_index) { - disk->queue = blk_init_queue(do_cciss_request, &h->lock); + disk->queue = blk_alloc_queue(GFP_KERNEL); if (!disk->queue) goto init_queue_failure; + + disk->queue->cmd_size = sizeof(struct scsi_request); + disk->queue->request_fn = do_cciss_request; + disk->queue->queue_lock = &h->lock; + if (blk_init_allocated_queue(disk->queue) < 0) + goto cleanup_queue; + sprintf(disk->disk_name, "cciss/c%dd%d", h->ctlr, drv_index); disk->major = h->major; disk->first_minor = drv_index << NWD_SHIFT; @@ -3075,7 +3083,7 @@ static inline int evaluate_target_status(ctlr_info_t *h, driver_byte = DRIVER_OK; msg_byte = cmd->err_info->CommandStatus; /* correct? seems too device specific */ - if (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) + if (blk_rq_is_passthrough(cmd->rq)) host_byte = DID_PASSTHROUGH; else host_byte = DID_OK; @@ -3084,7 +3092,7 @@ static inline int evaluate_target_status(ctlr_info_t *h, host_byte, driver_byte); if (cmd->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) { - if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC) + if (!blk_rq_is_passthrough(cmd->rq)) dev_warn(&h->pdev->dev, "cmd %p " "has SCSI Status 0x%x\n", cmd, cmd->err_info->ScsiStatus); @@ -3095,31 +3103,23 @@ static inline int evaluate_target_status(ctlr_info_t *h, sense_key = 0xf & cmd->err_info->SenseInfo[2]; /* no status or recovered error */ if (((sense_key == 0x0) || (sense_key == 0x1)) && - (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC)) + !blk_rq_is_passthrough(cmd->rq)) error_value = 0; if (check_for_unit_attention(h, cmd)) { - *retry_cmd = !(cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC); + *retry_cmd = !blk_rq_is_passthrough(cmd->rq); return 0; } /* Not SG_IO or similar? */ - if (cmd->rq->cmd_type != REQ_TYPE_BLOCK_PC) { + if (!blk_rq_is_passthrough(cmd->rq)) { if (error_value != 0) dev_warn(&h->pdev->dev, "cmd %p has CHECK CONDITION" " sense key = 0x%x\n", cmd, sense_key); return error_value; } - /* SG_IO or similar, copy sense data back */ - if (cmd->rq->sense) { - if (cmd->rq->sense_len > cmd->err_info->SenseLen) - cmd->rq->sense_len = cmd->err_info->SenseLen; - memcpy(cmd->rq->sense, cmd->err_info->SenseInfo, - cmd->rq->sense_len); - } else - cmd->rq->sense_len = 0; - + scsi_req(cmd->rq)->sense_len = cmd->err_info->SenseLen; return error_value; } @@ -3146,15 +3146,14 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, rq->errors = evaluate_target_status(h, cmd, &retry_cmd); break; case CMD_DATA_UNDERRUN: - if (cmd->rq->cmd_type == REQ_TYPE_FS) { + if (!blk_rq_is_passthrough(cmd->rq)) { dev_warn(&h->pdev->dev, "cmd %p has" " completed with data underrun " "reported\n", cmd); - cmd->rq->resid_len = cmd->err_info->ResidualCnt; } break; case CMD_DATA_OVERRUN: - if (cmd->rq->cmd_type == REQ_TYPE_FS) + if (!blk_rq_is_passthrough(cmd->rq)) dev_warn(&h->pdev->dev, "cciss: cmd %p has" " completed with data overrun " "reported\n", cmd); @@ -3164,7 +3163,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "reported invalid\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_PROTOCOL_ERR: @@ -3172,7 +3171,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "protocol error\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_HARDWARE_ERR: @@ -3180,7 +3179,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, " hardware error\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_CONNECTION_LOST: @@ -3188,7 +3187,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "connection lost\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_ABORTED: @@ -3196,7 +3195,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "aborted\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); break; case CMD_ABORT_FAILED: @@ -3204,7 +3203,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "abort failed\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_UNSOLICITED_ABORT: @@ -3219,21 +3218,21 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, "%p retried too many times\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ABORT); break; case CMD_TIMEOUT: dev_warn(&h->pdev->dev, "cmd %p timedout\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; case CMD_UNABORTABLE: dev_warn(&h->pdev->dev, "cmd %p unabortable\n", cmd); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); break; default: @@ -3242,7 +3241,7 @@ static inline void complete_command(ctlr_info_t *h, CommandList_struct *cmd, cmd->err_info->CommandStatus); rq->errors = make_status_bytes(SAM_STAT_GOOD, cmd->err_info->CommandStatus, DRIVER_OK, - (cmd->rq->cmd_type == REQ_TYPE_BLOCK_PC) ? + blk_rq_is_passthrough(cmd->rq) ? DID_PASSTHROUGH : DID_ERROR); } @@ -3395,7 +3394,9 @@ static void do_cciss_request(struct request_queue *q) c->Header.SGList = h->max_cmd_sgentries; set_performant_mode(h, c); - if (likely(creq->cmd_type == REQ_TYPE_FS)) { + switch (req_op(creq)) { + case REQ_OP_READ: + case REQ_OP_WRITE: if(h->cciss_read == CCISS_READ_10) { c->Request.CDB[1] = 0; c->Request.CDB[2] = (start_blk >> 24) & 0xff; /* MSB */ @@ -3425,12 +3426,16 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[13]= blk_rq_sectors(creq) & 0xff; c->Request.CDB[14] = c->Request.CDB[15] = 0; } - } else if (creq->cmd_type == REQ_TYPE_BLOCK_PC) { - c->Request.CDBLen = creq->cmd_len; - memcpy(c->Request.CDB, creq->cmd, BLK_MAX_CDB); - } else { + break; + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: + c->Request.CDBLen = scsi_req(creq)->cmd_len; + memcpy(c->Request.CDB, scsi_req(creq)->cmd, BLK_MAX_CDB); + scsi_req(creq)->sense = c->err_info->SenseInfo; + break; + default: dev_warn(&h->pdev->dev, "bad request type %d\n", - creq->cmd_type); + creq->cmd_flags); BUG(); } @@ -4074,41 +4079,27 @@ clean_up: static void cciss_interrupt_mode(ctlr_info_t *h) { -#ifdef CONFIG_PCI_MSI - int err; - struct msix_entry cciss_msix_entries[4] = { {0, 0}, {0, 1}, - {0, 2}, {0, 3} - }; + int ret; /* Some boards advertise MSI but don't really support it */ if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) || (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) goto default_int_mode; - if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - err = pci_enable_msix_exact(h->pdev, cciss_msix_entries, 4); - if (!err) { - h->intr[0] = cciss_msix_entries[0].vector; - h->intr[1] = cciss_msix_entries[1].vector; - h->intr[2] = cciss_msix_entries[2].vector; - h->intr[3] = cciss_msix_entries[3].vector; - h->msix_vector = 1; - return; - } else { - dev_warn(&h->pdev->dev, - "MSI-X init failed %d\n", err); - } - } - if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { - if (!pci_enable_msi(h->pdev)) - h->msi_vector = 1; - else - dev_warn(&h->pdev->dev, "MSI init failed\n"); + ret = pci_alloc_irq_vectors(h->pdev, 4, 4, PCI_IRQ_MSIX); + if (ret >= 0) { + h->intr[0] = pci_irq_vector(h->pdev, 0); + h->intr[1] = pci_irq_vector(h->pdev, 1); + h->intr[2] = pci_irq_vector(h->pdev, 2); + h->intr[3] = pci_irq_vector(h->pdev, 3); + return; } + + ret = pci_alloc_irq_vectors(h->pdev, 1, 1, PCI_IRQ_MSI); + default_int_mode: -#endif /* CONFIG_PCI_MSI */ /* if we get here we're going to use the default interrupt mode */ - h->intr[h->intr_mode] = h->pdev->irq; + h->intr[h->intr_mode] = pci_irq_vector(h->pdev, 0); return; } @@ -4888,7 +4879,7 @@ static int cciss_request_irq(ctlr_info_t *h, irqreturn_t (*msixhandler)(int, void *), irqreturn_t (*intxhandler)(int, void *)) { - if (h->msix_vector || h->msi_vector) { + if (h->pdev->msi_enabled || h->pdev->msix_enabled) { if (!request_irq(h->intr[h->intr_mode], msixhandler, 0, h->devname, h)) return 0; @@ -4934,12 +4925,7 @@ static void cciss_undo_allocations_after_kdump_soft_reset(ctlr_info_t *h) int ctlr = h->ctlr; free_irq(h->intr[h->intr_mode], h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); -#endif /* CONFIG_PCI_MSI */ + pci_free_irq_vectors(h->pdev); cciss_free_sg_chain_blocks(h->cmd_sg_list, h->nr_cmds); cciss_free_scatterlists(h); cciss_free_cmd_pool(h); @@ -5295,12 +5281,7 @@ static void cciss_remove_one(struct pci_dev *pdev) cciss_shutdown(pdev); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); -#endif /* CONFIG_PCI_MSI */ + pci_free_irq_vectors(h->pdev); iounmap(h->transtable); iounmap(h->cfgtable); diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h index 428766d1ce80..24b5fd75501a 100644 --- a/drivers/block/cciss.h +++ b/drivers/block/cciss.h @@ -90,8 +90,6 @@ struct ctlr_info # define SIMPLE_MODE_INT 2 # define MEMQ_MODE_INT 3 unsigned int intr[4]; - unsigned int msix_vector; - unsigned int msi_vector; int intr_mode; int cciss_max_sectors; BYTE cciss_read; @@ -333,7 +331,7 @@ static unsigned long SA5_performant_completed(ctlr_info_t *h) */ register_value = readl(h->vaddr + SA5_OUTDB_STATUS); /* msi auto clears the interrupt pending bit. */ - if (!(h->msi_vector || h->msix_vector)) { + if (!(h->pdev->msi_enabled || h->pdev->msix_enabled)) { writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); /* Do a read in order to flush the write to the controller * (as per spec.) @@ -393,7 +391,7 @@ static bool SA5_performant_intr_pending(ctlr_info_t *h) if (!register_value) return false; - if (h->msi_vector || h->msix_vector) + if (h->pdev->msi_enabled || h->pdev->msix_enabled) return true; /* Read outbound doorbell to flush */ diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index ab62b81c2ca7..dece26f119d4 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1070,7 +1070,7 @@ static int bm_rw(struct drbd_device *device, const unsigned int flags, unsigned .done = 0, .flags = flags, .error = 0, - .kref = { ATOMIC_INIT(2) }, + .kref = KREF_INIT(2), }; if (!get_ldev_if_state(device, D_ATTACHING)) { /* put is in drbd_bm_aio_ctx_destroy() */ diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 83482721bc01..615e5b5178a0 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -2462,7 +2462,7 @@ static int drbd_congested(void *congested_data, int bdi_bits) if (get_ldev(device)) { q = bdev_get_queue(device->ldev->backing_bdev); - r = bdi_congested(&q->backing_dev_info, bdi_bits); + r = bdi_congested(q->backing_dev_info, bdi_bits); put_ldev(device); if (r) reason = 'b'; @@ -2834,8 +2834,8 @@ enum drbd_ret_code drbd_create_device(struct drbd_config_context *adm_ctx, unsig /* we have no partitions. we contain only ourselves. */ device->this_bdev->bd_contains = device->this_bdev; - q->backing_dev_info.congested_fn = drbd_congested; - q->backing_dev_info.congested_data = device; + q->backing_dev_info->congested_fn = drbd_congested; + q->backing_dev_info->congested_data = device; blk_queue_make_request(q, drbd_make_request); blk_queue_write_cache(q, true, true); @@ -2948,7 +2948,6 @@ void drbd_delete_device(struct drbd_device *device) struct drbd_resource *resource = device->resource; struct drbd_connection *connection; struct drbd_peer_device *peer_device; - int refs = 3; /* move to free_peer_device() */ for_each_peer_device(peer_device, device) @@ -2956,13 +2955,15 @@ void drbd_delete_device(struct drbd_device *device) drbd_debugfs_device_cleanup(device); for_each_connection(connection, resource) { idr_remove(&connection->peer_devices, device->vnr); - refs++; + kref_put(&device->kref, drbd_destroy_device); } idr_remove(&resource->devices, device->vnr); + kref_put(&device->kref, drbd_destroy_device); idr_remove(&drbd_devices, device_to_minor(device)); + kref_put(&device->kref, drbd_destroy_device); del_gendisk(device->vdisk); synchronize_rcu(); - kref_sub(&device->kref, refs, drbd_destroy_device); + kref_put(&device->kref, drbd_destroy_device); } static int __init drbd_init(void) diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index f35db29cac76..908c704e20aa 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1328,11 +1328,13 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi if (b) { blk_queue_stack_limits(q, b); - if (q->backing_dev_info.ra_pages != b->backing_dev_info.ra_pages) { + if (q->backing_dev_info->ra_pages != + b->backing_dev_info->ra_pages) { drbd_info(device, "Adjusting my ra_pages to backing device's (%lu -> %lu)\n", - q->backing_dev_info.ra_pages, - b->backing_dev_info.ra_pages); - q->backing_dev_info.ra_pages = b->backing_dev_info.ra_pages; + q->backing_dev_info->ra_pages, + b->backing_dev_info->ra_pages); + q->backing_dev_info->ra_pages = + b->backing_dev_info->ra_pages; } } fixup_discard_if_not_supported(q); @@ -3345,7 +3347,7 @@ static void device_to_statistics(struct device_statistics *s, s->dev_disk_flags = md->flags; q = bdev_get_queue(device->ldev->backing_bdev); s->dev_lower_blocked = - bdi_congested(&q->backing_dev_info, + bdi_congested(q->backing_dev_info, (1 << WB_async_congested) | (1 << WB_sync_congested)); put_ldev(device); diff --git a/drivers/block/drbd/drbd_proc.c b/drivers/block/drbd/drbd_proc.c index be2b93fd2c11..8378142f7a55 100644 --- a/drivers/block/drbd/drbd_proc.c +++ b/drivers/block/drbd/drbd_proc.c @@ -288,7 +288,7 @@ static int drbd_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%2d: cs:Unconfigured\n", i); } else { /* reset device->congestion_reason */ - bdi_rw_congested(&device->rq_queue->backing_dev_info); + bdi_rw_congested(device->rq_queue->backing_dev_info); nc = rcu_dereference(first_peer_device(device)->connection->net_conf); wp = nc ? nc->wire_protocol - DRBD_PROT_A + 'A' : ' '; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index de279fe4e4fd..652114ae1a8a 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -421,7 +421,6 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, struct drbd_peer_device *peer_device = first_peer_device(device); unsigned s = req->rq_state; int c_put = 0; - int k_put = 0; if (drbd_suspended(device) && !((s | clear) & RQ_COMPLETION_SUSP)) set |= RQ_COMPLETION_SUSP; @@ -437,6 +436,8 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, /* intent: get references */ + kref_get(&req->kref); + if (!(s & RQ_LOCAL_PENDING) && (set & RQ_LOCAL_PENDING)) atomic_inc(&req->completion_ref); @@ -473,15 +474,12 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, if (!(s & RQ_LOCAL_ABORTED) && (set & RQ_LOCAL_ABORTED)) { D_ASSERT(device, req->rq_state & RQ_LOCAL_PENDING); - /* local completion may still come in later, - * we need to keep the req object around. */ - kref_get(&req->kref); ++c_put; } if ((s & RQ_LOCAL_PENDING) && (clear & RQ_LOCAL_PENDING)) { if (req->rq_state & RQ_LOCAL_ABORTED) - ++k_put; + kref_put(&req->kref, drbd_req_destroy); else ++c_put; list_del_init(&req->req_pending_local); @@ -503,7 +501,7 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, if (s & RQ_NET_SENT) atomic_sub(req->i.size >> 9, &device->ap_in_flight); if (s & RQ_EXP_BARR_ACK) - ++k_put; + kref_put(&req->kref, drbd_req_destroy); req->net_done_jif = jiffies; /* in ahead/behind mode, or just in case, @@ -516,25 +514,16 @@ static void mod_rq_state(struct drbd_request *req, struct bio_and_error *m, /* potentially complete and destroy */ - if (k_put || c_put) { - /* Completion does it's own kref_put. If we are going to - * kref_sub below, we need req to be still around then. */ - int at_least = k_put + !!c_put; - int refcount = atomic_read(&req->kref.refcount); - if (refcount < at_least) - drbd_err(device, - "mod_rq_state: Logic BUG: %x -> %x: refcount = %d, should be >= %d\n", - s, req->rq_state, refcount, at_least); - } - /* If we made progress, retry conflicting peer requests, if any. */ if (req->i.waiting) wake_up(&device->misc_wait); - if (c_put) - k_put += drbd_req_put_completion_ref(req, m, c_put); - if (k_put) - kref_sub(&req->kref, k_put, drbd_req_destroy); + if (c_put) { + if (drbd_req_put_completion_ref(req, m, c_put)) + kref_put(&req->kref, drbd_req_destroy); + } else { + kref_put(&req->kref, drbd_req_destroy); + } } static void drbd_report_io_error(struct drbd_device *device, struct drbd_request *req) @@ -938,7 +927,7 @@ static bool remote_due_to_read_balancing(struct drbd_device *device, sector_t se switch (rbm) { case RB_CONGESTED_REMOTE: - bdi = &device->ldev->backing_bdev->bd_disk->queue->backing_dev_info; + bdi = device->ldev->backing_bdev->bd_disk->queue->backing_dev_info; return bdi_read_congested(bdi); case RB_LEAST_PENDING: return atomic_read(&device->local_cnt) > diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index a391a3cfb3fe..45b4384f650c 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2900,8 +2900,8 @@ static void do_fd_request(struct request_queue *q) return; if (WARN(atomic_read(&usage_count) == 0, - "warning: usage count=0, current_req=%p sect=%ld type=%x flags=%llx\n", - current_req, (long)blk_rq_pos(current_req), current_req->cmd_type, + "warning: usage count=0, current_req=%p sect=%ld flags=%llx\n", + current_req, (long)blk_rq_pos(current_req), (unsigned long long) current_req->cmd_flags)) return; @@ -3119,7 +3119,7 @@ static int raw_cmd_copyin(int cmd, void __user *param, *rcmd = NULL; loop: - ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER); + ptr = kmalloc(sizeof(struct floppy_raw_cmd), GFP_KERNEL); if (!ptr) return -ENOMEM; *rcmd = ptr; diff --git a/drivers/block/hd.c b/drivers/block/hd.c index a9b48ed7a3cd..6043648da1e8 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -626,30 +626,29 @@ repeat: req_data_dir(req) == READ ? "read" : "writ", cyl, head, sec, nsect, bio_data(req->bio)); #endif - if (req->cmd_type == REQ_TYPE_FS) { - switch (rq_data_dir(req)) { - case READ: - hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ, - &read_intr); - if (reset) - goto repeat; - break; - case WRITE: - hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE, - &write_intr); - if (reset) - goto repeat; - if (wait_DRQ()) { - bad_rw_intr(); - goto repeat; - } - outsw(HD_DATA, bio_data(req->bio), 256); - break; - default: - printk("unknown hd-command\n"); - hd_end_request_cur(-EIO); - break; + + switch (req_op(req)) { + case REQ_OP_READ: + hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ, + &read_intr); + if (reset) + goto repeat; + break; + case REQ_OP_WRITE: + hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE, + &write_intr); + if (reset) + goto repeat; + if (wait_DRQ()) { + bad_rw_intr(); + goto repeat; } + outsw(HD_DATA, bio_data(req->bio), 256); + break; + default: + printk("unknown hd-command\n"); + hd_end_request_cur(-EIO); + break; } } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f347285c67ec..304377182c1a 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1097,9 +1097,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) return -EINVAL; + /* I/O need to be drained during transfer transition */ + blk_mq_freeze_queue(lo->lo_queue); + err = loop_release_xfer(lo); if (err) - return err; + goto exit; if (info->lo_encrypt_type) { unsigned int type = info->lo_encrypt_type; @@ -1114,12 +1117,14 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) err = loop_init_xfer(lo, xfer, info); if (err) - return err; + goto exit; if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) - if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) - return -EFBIG; + if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) { + err = -EFBIG; + goto exit; + } loop_config_discard(lo); @@ -1156,7 +1161,9 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) /* update dio if lo_offset or transfer is changed */ __loop_update_dio(lo, lo->use_dio); - return 0; + exit: + blk_mq_unfreeze_queue(lo->lo_queue); + return err; } static int diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index e937fcf71769..286f276f586e 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c @@ -670,15 +670,17 @@ static void mg_request_poll(struct request_queue *q) break; } - if (unlikely(host->req->cmd_type != REQ_TYPE_FS)) { - mg_end_request_cur(host, -EIO); - continue; - } - - if (rq_data_dir(host->req) == READ) + switch (req_op(host->req)) { + case REQ_OP_READ: mg_read(host->req); - else + break; + case REQ_OP_WRITE: mg_write(host->req); + break; + default: + mg_end_request_cur(host, -EIO); + break; + } } } @@ -687,13 +689,15 @@ static unsigned int mg_issue_req(struct request *req, unsigned int sect_num, unsigned int sect_cnt) { - if (rq_data_dir(req) == READ) { + switch (req_op(host->req)) { + case REQ_OP_READ: if (mg_out(host, sect_num, sect_cnt, MG_CMD_RD, &mg_read_intr) != MG_ERR_NONE) { mg_bad_rw_intr(host); return host->error; } - } else { + break; + case REQ_OP_WRITE: /* TODO : handler */ outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL); if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr) @@ -712,6 +716,10 @@ static unsigned int mg_issue_req(struct request *req, mod_timer(&host->timer, jiffies + 3 * HZ); outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND); + break; + default: + mg_end_request_cur(host, -EIO); + break; } return MG_ERR_NONE; } @@ -753,11 +761,6 @@ static void mg_request(struct request_queue *q) continue; } - if (unlikely(req->cmd_type != REQ_TYPE_FS)) { - mg_end_request_cur(host, -EIO); - continue; - } - if (!mg_issue_req(req, host, sect_num, sect_cnt)) return; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 38c576f76d36..0be84a3cb6d7 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -41,6 +41,9 @@ #include <linux/nbd.h> +static DEFINE_IDR(nbd_index_idr); +static DEFINE_MUTEX(nbd_index_mutex); + struct nbd_sock { struct socket *sock; struct mutex tx_lock; @@ -89,8 +92,9 @@ static struct dentry *nbd_dbg_dir; #define NBD_MAGIC 0x68797548 static unsigned int nbds_max = 16; -static struct nbd_device *nbd_dev; static int max_part; +static struct workqueue_struct *recv_workqueue; +static int part_shift; static inline struct device *nbd_to_dev(struct nbd_device *nbd) { @@ -193,13 +197,6 @@ static enum blk_eh_timer_return nbd_xmit_timeout(struct request *req, set_bit(NBD_TIMEDOUT, &nbd->runtime_flags); req->errors++; - /* - * If our disconnect packet times out then we're already holding the - * config_lock and could deadlock here, so just set an error and return, - * we'll handle shutting everything down later. - */ - if (req->cmd_type == REQ_TYPE_DRV_PRIV) - return BLK_EH_HANDLED; mutex_lock(&nbd->config_lock); sock_shutdown(nbd); mutex_unlock(&nbd->config_lock); @@ -271,21 +268,36 @@ static inline int sock_send_bvec(struct nbd_device *nbd, int index, static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) { struct request *req = blk_mq_rq_from_pdu(cmd); - int result, flags; + int result; struct nbd_request request; unsigned long size = blk_rq_bytes(req); struct bio *bio; u32 type; u32 tag = blk_mq_unique_tag(req); - if (req_op(req) == REQ_OP_DISCARD) + switch (req_op(req)) { + case REQ_OP_DISCARD: type = NBD_CMD_TRIM; - else if (req_op(req) == REQ_OP_FLUSH) + break; + case REQ_OP_FLUSH: type = NBD_CMD_FLUSH; - else if (rq_data_dir(req) == WRITE) + break; + case REQ_OP_WRITE: type = NBD_CMD_WRITE; - else + break; + case REQ_OP_READ: type = NBD_CMD_READ; + break; + default: + return -EIO; + } + + if (rq_data_dir(req) == WRITE && + (nbd->flags & NBD_FLAG_READ_ONLY)) { + dev_err_ratelimited(disk_to_dev(nbd->disk), + "Write on read-only\n"); + return -EIO; + } memset(&request, 0, sizeof(request)); request.magic = htonl(NBD_REQUEST_MAGIC); @@ -310,7 +322,6 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) if (type != NBD_CMD_WRITE) return 0; - flags = 0; bio = req->bio; while (bio) { struct bio *next = bio->bi_next; @@ -319,9 +330,8 @@ static int nbd_send_cmd(struct nbd_device *nbd, struct nbd_cmd *cmd, int index) bio_for_each_segment(bvec, bio, iter) { bool is_last = !next && bio_iter_last(bvec, iter); + int flags = is_last ? 0 : MSG_MORE; - if (is_last) - flags = MSG_MORE; dev_dbg(nbd_to_dev(nbd), "request %p: sending %d bytes data\n", cmd, bvec.bv_len); result = sock_send_bvec(nbd, index, &bvec, flags); @@ -512,18 +522,6 @@ static void nbd_handle_cmd(struct nbd_cmd *cmd, int index) goto error_out; } - if (req->cmd_type != REQ_TYPE_FS && - req->cmd_type != REQ_TYPE_DRV_PRIV) - goto error_out; - - if (req->cmd_type == REQ_TYPE_FS && - rq_data_dir(req) == WRITE && - (nbd->flags & NBD_FLAG_READ_ONLY)) { - dev_err_ratelimited(disk_to_dev(nbd->disk), - "Write on read-only\n"); - goto error_out; - } - req->errors = 0; nsock = nbd->socks[index]; @@ -787,7 +785,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd, INIT_WORK(&args[i].work, recv_work); args[i].nbd = nbd; args[i].index = i; - queue_work(system_long_wq, &args[i].work); + queue_work(recv_workqueue, &args[i].work); } wait_event_interruptible(nbd->recv_wq, atomic_read(&nbd->recv_threads) == 0); @@ -998,6 +996,103 @@ static struct blk_mq_ops nbd_mq_ops = { .timeout = nbd_xmit_timeout, }; +static void nbd_dev_remove(struct nbd_device *nbd) +{ + struct gendisk *disk = nbd->disk; + nbd->magic = 0; + if (disk) { + del_gendisk(disk); + blk_cleanup_queue(disk->queue); + blk_mq_free_tag_set(&nbd->tag_set); + put_disk(disk); + } + kfree(nbd); +} + +static int nbd_dev_add(int index) +{ + struct nbd_device *nbd; + struct gendisk *disk; + struct request_queue *q; + int err = -ENOMEM; + + nbd = kzalloc(sizeof(struct nbd_device), GFP_KERNEL); + if (!nbd) + goto out; + + disk = alloc_disk(1 << part_shift); + if (!disk) + goto out_free_nbd; + + if (index >= 0) { + err = idr_alloc(&nbd_index_idr, nbd, index, index + 1, + GFP_KERNEL); + if (err == -ENOSPC) + err = -EEXIST; + } else { + err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL); + if (err >= 0) + index = err; + } + if (err < 0) + goto out_free_disk; + + nbd->disk = disk; + nbd->tag_set.ops = &nbd_mq_ops; + nbd->tag_set.nr_hw_queues = 1; + nbd->tag_set.queue_depth = 128; + nbd->tag_set.numa_node = NUMA_NO_NODE; + nbd->tag_set.cmd_size = sizeof(struct nbd_cmd); + nbd->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | + BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING; + nbd->tag_set.driver_data = nbd; + + err = blk_mq_alloc_tag_set(&nbd->tag_set); + if (err) + goto out_free_idr; + + q = blk_mq_init_queue(&nbd->tag_set); + if (IS_ERR(q)) { + err = PTR_ERR(q); + goto out_free_tags; + } + disk->queue = q; + + /* + * Tell the block layer that we are not a rotational device + */ + queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); + queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue); + disk->queue->limits.discard_granularity = 512; + blk_queue_max_discard_sectors(disk->queue, UINT_MAX); + disk->queue->limits.discard_zeroes_data = 0; + blk_queue_max_hw_sectors(disk->queue, 65536); + disk->queue->limits.max_sectors = 256; + + nbd->magic = NBD_MAGIC; + mutex_init(&nbd->config_lock); + disk->major = NBD_MAJOR; + disk->first_minor = index << part_shift; + disk->fops = &nbd_fops; + disk->private_data = nbd; + sprintf(disk->disk_name, "nbd%d", index); + init_waitqueue_head(&nbd->recv_wq); + nbd_reset(nbd); + add_disk(disk); + return index; + +out_free_tags: + blk_mq_free_tag_set(&nbd->tag_set); +out_free_idr: + idr_remove(&nbd_index_idr, index); +out_free_disk: + put_disk(disk); +out_free_nbd: + kfree(nbd); +out: + return err; +} + /* * And here should be modules and kernel interface * (Just smiley confuses emacs :-) @@ -1005,9 +1100,7 @@ static struct blk_mq_ops nbd_mq_ops = { static int __init nbd_init(void) { - int err = -ENOMEM; int i; - int part_shift; BUILD_BUG_ON(sizeof(struct nbd_request) != 28); @@ -1036,109 +1129,38 @@ static int __init nbd_init(void) if (nbds_max > 1UL << (MINORBITS - part_shift)) return -EINVAL; - - nbd_dev = kcalloc(nbds_max, sizeof(*nbd_dev), GFP_KERNEL); - if (!nbd_dev) + recv_workqueue = alloc_workqueue("knbd-recv", + WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); + if (!recv_workqueue) return -ENOMEM; - for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = alloc_disk(1 << part_shift); - if (!disk) - goto out; - nbd_dev[i].disk = disk; - - nbd_dev[i].tag_set.ops = &nbd_mq_ops; - nbd_dev[i].tag_set.nr_hw_queues = 1; - nbd_dev[i].tag_set.queue_depth = 128; - nbd_dev[i].tag_set.numa_node = NUMA_NO_NODE; - nbd_dev[i].tag_set.cmd_size = sizeof(struct nbd_cmd); - nbd_dev[i].tag_set.flags = BLK_MQ_F_SHOULD_MERGE | - BLK_MQ_F_SG_MERGE | BLK_MQ_F_BLOCKING; - nbd_dev[i].tag_set.driver_data = &nbd_dev[i]; - - err = blk_mq_alloc_tag_set(&nbd_dev[i].tag_set); - if (err) { - put_disk(disk); - goto out; - } - - /* - * The new linux 2.5 block layer implementation requires - * every gendisk to have its very own request_queue struct. - * These structs are big so we dynamically allocate them. - */ - disk->queue = blk_mq_init_queue(&nbd_dev[i].tag_set); - if (!disk->queue) { - blk_mq_free_tag_set(&nbd_dev[i].tag_set); - put_disk(disk); - goto out; - } - - /* - * Tell the block layer that we are not a rotational device - */ - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); - queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue); - disk->queue->limits.discard_granularity = 512; - blk_queue_max_discard_sectors(disk->queue, UINT_MAX); - disk->queue->limits.discard_zeroes_data = 0; - blk_queue_max_hw_sectors(disk->queue, 65536); - disk->queue->limits.max_sectors = 256; - } - - if (register_blkdev(NBD_MAJOR, "nbd")) { - err = -EIO; - goto out; - } - - printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR); + if (register_blkdev(NBD_MAJOR, "nbd")) + return -EIO; nbd_dbg_init(); - for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = nbd_dev[i].disk; - nbd_dev[i].magic = NBD_MAGIC; - mutex_init(&nbd_dev[i].config_lock); - disk->major = NBD_MAJOR; - disk->first_minor = i << part_shift; - disk->fops = &nbd_fops; - disk->private_data = &nbd_dev[i]; - sprintf(disk->disk_name, "nbd%d", i); - init_waitqueue_head(&nbd_dev[i].recv_wq); - nbd_reset(&nbd_dev[i]); - add_disk(disk); - } + mutex_lock(&nbd_index_mutex); + for (i = 0; i < nbds_max; i++) + nbd_dev_add(i); + mutex_unlock(&nbd_index_mutex); + return 0; +} +static int nbd_exit_cb(int id, void *ptr, void *data) +{ + struct nbd_device *nbd = ptr; + nbd_dev_remove(nbd); return 0; -out: - while (i--) { - blk_mq_free_tag_set(&nbd_dev[i].tag_set); - blk_cleanup_queue(nbd_dev[i].disk->queue); - put_disk(nbd_dev[i].disk); - } - kfree(nbd_dev); - return err; } static void __exit nbd_cleanup(void) { - int i; - nbd_dbg_close(); - for (i = 0; i < nbds_max; i++) { - struct gendisk *disk = nbd_dev[i].disk; - nbd_dev[i].magic = 0; - if (disk) { - del_gendisk(disk); - blk_cleanup_queue(disk->queue); - blk_mq_free_tag_set(&nbd_dev[i].tag_set); - put_disk(disk); - } - } + idr_for_each(&nbd_index_idr, &nbd_exit_cb, NULL); + idr_destroy(&nbd_index_idr); + destroy_workqueue(recv_workqueue); unregister_blkdev(NBD_MAJOR, "nbd"); - kfree(nbd_dev); - printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR); } module_init(nbd_init); diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index c0e14e54909b..6f2e565bccc5 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -420,7 +420,8 @@ static void null_lnvm_end_io(struct request *rq, int error) { struct nvm_rq *rqd = rq->end_io_data; - nvm_end_io(rqd, error); + rqd->error = error; + nvm_end_io(rqd); blk_put_request(rq); } @@ -431,11 +432,11 @@ static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd) struct request *rq; struct bio *bio = rqd->bio; - rq = blk_mq_alloc_request(q, bio_data_dir(bio), 0); + rq = blk_mq_alloc_request(q, + op_is_write(bio_op(bio)) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, 0); if (IS_ERR(rq)) return -ENOMEM; - rq->cmd_type = REQ_TYPE_DRV_PRIV; rq->__sector = bio->bi_iter.bi_sector; rq->ioprio = bio_prio(bio); @@ -460,7 +461,6 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id) id->ver_id = 0x1; id->vmnt = 0; - id->cgrps = 1; id->cap = 0x2; id->dom = 0x1; @@ -479,7 +479,7 @@ static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id) sector_div(size, bs); /* convert size to pages */ size >>= 8; /* concert size to pgs pr blk */ - grp = &id->groups[0]; + grp = &id->grp; grp->mtype = 0; grp->fmtype = 0; grp->num_ch = 1; diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c index 92900f5f0b47..8127b8201a01 100644 --- a/drivers/block/osdblk.c +++ b/drivers/block/osdblk.c @@ -308,12 +308,6 @@ static void osdblk_rq_fn(struct request_queue *q) if (!rq) break; - /* filter out block requests we don't understand */ - if (rq->cmd_type != REQ_TYPE_FS) { - blk_end_request_all(rq, 0); - continue; - } - /* deduce our operation (read, write, flush) */ /* I wish the block layer simplified cmd_type/cmd_flags/cmd[] * into a clearly defined set of RPC commands: diff --git a/drivers/block/paride/Kconfig b/drivers/block/paride/Kconfig index efefb5ac3004..3a15247942e4 100644 --- a/drivers/block/paride/Kconfig +++ b/drivers/block/paride/Kconfig @@ -25,6 +25,7 @@ config PARIDE_PD config PARIDE_PCD tristate "Parallel port ATAPI CD-ROMs" depends on PARIDE + select BLK_SCSI_REQUEST # only for the generic cdrom code ---help--- This option enables the high-level driver for ATAPI CD-ROM devices connected through a parallel port. If you chose to build PARIDE diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 5fd2d0e25567..10aed84244f5 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -273,7 +273,7 @@ static const struct block_device_operations pcd_bdops = { .check_events = pcd_block_check_events, }; -static struct cdrom_device_ops pcd_dops = { +static const struct cdrom_device_ops pcd_dops = { .open = pcd_open, .release = pcd_release, .drive_status = pcd_drive_status, diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index c3ed2fc72daa..644ba0888bd4 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -439,18 +439,16 @@ static int pd_retries = 0; /* i/o error retry count */ static int pd_block; /* address of next requested block */ static int pd_count; /* number of blocks still to do */ static int pd_run; /* sectors in current cluster */ -static int pd_cmd; /* current command READ/WRITE */ static char *pd_buf; /* buffer for request in progress */ static enum action do_pd_io_start(void) { - if (pd_req->cmd_type == REQ_TYPE_DRV_PRIV) { + switch (req_op(pd_req)) { + case REQ_OP_DRV_IN: phase = pd_special; return pd_special(); - } - - pd_cmd = rq_data_dir(pd_req); - if (pd_cmd == READ || pd_cmd == WRITE) { + case REQ_OP_READ: + case REQ_OP_WRITE: pd_block = blk_rq_pos(pd_req); pd_count = blk_rq_cur_sectors(pd_req); if (pd_block + pd_count > get_capacity(pd_req->rq_disk)) @@ -458,7 +456,7 @@ static enum action do_pd_io_start(void) pd_run = blk_rq_sectors(pd_req); pd_buf = bio_data(pd_req->bio); pd_retries = 0; - if (pd_cmd == READ) + if (req_op(pd_req) == REQ_OP_READ) return do_pd_read_start(); else return do_pd_write_start(); @@ -723,11 +721,10 @@ static int pd_special_command(struct pd_unit *disk, struct request *rq; int err = 0; - rq = blk_get_request(disk->gd->queue, READ, __GFP_RECLAIM); + rq = blk_get_request(disk->gd->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); if (IS_ERR(rq)) return PTR_ERR(rq); - rq->cmd_type = REQ_TYPE_DRV_PRIV; rq->special = func; err = blk_execute_rq(disk->gd->queue, disk->gd, rq, 0); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 1b94c1ca5c5f..66d846ba85a9 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -704,10 +704,10 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * int ret = 0; rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? - WRITE : READ, __GFP_RECLAIM); + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM); if (IS_ERR(rq)) return PTR_ERR(rq); - blk_rq_set_block_pc(rq); + scsi_req_init(rq); if (cgc->buflen) { ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, @@ -716,8 +716,8 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command * goto out; } - rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]); - memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE); + scsi_req(rq)->cmd_len = COMMAND_SIZE(cgc->cmd[0]); + memcpy(scsi_req(rq)->cmd, cgc->cmd, CDROM_PACKET_SIZE); rq->timeout = 60*HZ; if (cgc->quiet) @@ -1243,7 +1243,7 @@ try_next_bio: && pd->bio_queue_size <= pd->write_congestion_off); spin_unlock(&pd->lock); if (wakeup) { - clear_bdi_congested(&pd->disk->queue->backing_dev_info, + clear_bdi_congested(pd->disk->queue->backing_dev_info, BLK_RW_ASYNC); } @@ -2370,7 +2370,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio) spin_lock(&pd->lock); if (pd->write_congestion_on > 0 && pd->bio_queue_size >= pd->write_congestion_on) { - set_bdi_congested(&q->backing_dev_info, BLK_RW_ASYNC); + set_bdi_congested(q->backing_dev_info, BLK_RW_ASYNC); do { spin_unlock(&pd->lock); congestion_wait(BLK_RW_ASYNC, HZ); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 76f33c84ce3d..a809e3e9feb8 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -196,16 +196,19 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__); while ((req = blk_fetch_request(q))) { - if (req_op(req) == REQ_OP_FLUSH) { + switch (req_op(req)) { + case REQ_OP_FLUSH: if (ps3disk_submit_flush_request(dev, req)) - break; - } else if (req->cmd_type == REQ_TYPE_FS) { + return; + break; + case REQ_OP_READ: + case REQ_OP_WRITE: if (ps3disk_submit_request_sg(dev, req)) - break; - } else { + return; + break; + default: blk_dump_rq_flags(req, DEVICE_NAME " bad request"); __blk_end_request_all(req, -EIO); - continue; } } } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 36d2b9f4e836..362cecc77130 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1535,7 +1535,7 @@ static bool obj_request_overlaps_parent(struct rbd_obj_request *obj_request) static void rbd_obj_request_get(struct rbd_obj_request *obj_request) { dout("%s: obj %p (was %d)\n", __func__, obj_request, - atomic_read(&obj_request->kref.refcount)); + kref_read(&obj_request->kref)); kref_get(&obj_request->kref); } @@ -1544,14 +1544,14 @@ static void rbd_obj_request_put(struct rbd_obj_request *obj_request) { rbd_assert(obj_request != NULL); dout("%s: obj %p (was %d)\n", __func__, obj_request, - atomic_read(&obj_request->kref.refcount)); + kref_read(&obj_request->kref)); kref_put(&obj_request->kref, rbd_obj_request_destroy); } static void rbd_img_request_get(struct rbd_img_request *img_request) { dout("%s: img %p (was %d)\n", __func__, img_request, - atomic_read(&img_request->kref.refcount)); + kref_read(&img_request->kref)); kref_get(&img_request->kref); } @@ -1562,7 +1562,7 @@ static void rbd_img_request_put(struct rbd_img_request *img_request) { rbd_assert(img_request != NULL); dout("%s: img %p (was %d)\n", __func__, img_request, - atomic_read(&img_request->kref.refcount)); + kref_read(&img_request->kref)); if (img_request_child_test(img_request)) kref_put(&img_request->kref, rbd_parent_request_destroy); else @@ -4099,19 +4099,21 @@ static void rbd_queue_workfn(struct work_struct *work) bool must_be_locked; int result; - if (rq->cmd_type != REQ_TYPE_FS) { - dout("%s: non-fs request type %d\n", __func__, - (int) rq->cmd_type); - result = -EIO; - goto err; - } - - if (req_op(rq) == REQ_OP_DISCARD) + switch (req_op(rq)) { + case REQ_OP_DISCARD: op_type = OBJ_OP_DISCARD; - else if (req_op(rq) == REQ_OP_WRITE) + break; + case REQ_OP_WRITE: op_type = OBJ_OP_WRITE; - else + break; + case REQ_OP_READ: op_type = OBJ_OP_READ; + break; + default: + dout("%s: non-fs request type %d\n", __func__, req_op(rq)); + result = -EIO; + goto err; + } /* Ignore/skip any zero-length requests */ @@ -4524,7 +4526,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) q->limits.discard_zeroes_data = 1; if (!ceph_test_opt(rbd_dev->rbd_client->client, NOCRC)) - q->backing_dev_info.capabilities |= BDI_CAP_STABLE_WRITES; + q->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; disk->queue = q; diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index abf805e332e2..27833e4dae2a 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -1204,10 +1204,11 @@ static void skd_complete_special(struct skd_device *skdev, static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode, uint cmd_in, ulong arg) { - int rc = 0; + static const int sg_version_num = 30527; + int rc = 0, timeout; struct gendisk *disk = bdev->bd_disk; struct skd_device *skdev = disk->private_data; - void __user *p = (void *)arg; + int __user *p = (int __user *)arg; pr_debug("%s:%s:%d %s: CMD[%s] ioctl mode 0x%x, cmd 0x%x arg %0lx\n", skdev->name, __func__, __LINE__, @@ -1218,12 +1219,18 @@ static int skd_bdev_ioctl(struct block_device *bdev, fmode_t mode, switch (cmd_in) { case SG_SET_TIMEOUT: + rc = get_user(timeout, p); + if (!rc) + disk->queue->sg_timeout = clock_t_to_jiffies(timeout); + break; case SG_GET_TIMEOUT: + rc = jiffies_to_clock_t(disk->queue->sg_timeout); + break; case SG_GET_VERSION_NUM: - rc = scsi_cmd_ioctl(disk->queue, disk, mode, cmd_in, p); + rc = put_user(sg_version_num, p); break; case SG_IO: - rc = skd_ioctl_sg_io(skdev, mode, p); + rc = skd_ioctl_sg_io(skdev, mode, (void __user *)arg); break; default: diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index 0e93ad7b8511..c8e072caf56f 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -567,7 +567,7 @@ static struct carm_request *carm_get_special(struct carm_host *host) if (!crq) return NULL; - rq = blk_get_request(host->oob_q, WRITE /* bogus */, GFP_KERNEL); + rq = blk_get_request(host->oob_q, REQ_OP_DRV_OUT, GFP_KERNEL); if (IS_ERR(rq)) { spin_lock_irqsave(&host->lock, flags); carm_put_request(host, crq); @@ -620,7 +620,6 @@ static int carm_array_info (struct carm_host *host, unsigned int array_idx) spin_unlock_irq(&host->lock); DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); - crq->rq->cmd_type = REQ_TYPE_DRV_PRIV; crq->rq->special = crq; blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); @@ -661,7 +660,6 @@ static int carm_send_special (struct carm_host *host, carm_sspc_t func) crq->msg_bucket = (u32) rc; DPRINTK("blk_execute_rq_nowait, tag == %u\n", idx); - crq->rq->cmd_type = REQ_TYPE_DRV_PRIV; crq->rq->special = crq; blk_execute_rq_nowait(host->oob_q, NULL, crq->rq, true, NULL); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 5545a679abd8..024b473524c0 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -52,9 +52,12 @@ struct virtio_blk { }; struct virtblk_req { - struct request *req; - struct virtio_blk_outhdr out_hdr; +#ifdef CONFIG_VIRTIO_BLK_SCSI + struct scsi_request sreq; /* for SCSI passthrough, must be first */ + u8 sense[SCSI_SENSE_BUFFERSIZE]; struct virtio_scsi_inhdr in_hdr; +#endif + struct virtio_blk_outhdr out_hdr; u8 status; struct scatterlist sg[]; }; @@ -71,28 +74,88 @@ static inline int virtblk_result(struct virtblk_req *vbr) } } -static int __virtblk_add_req(struct virtqueue *vq, - struct virtblk_req *vbr, - struct scatterlist *data_sg, - bool have_data) +/* + * If this is a packet command we need a couple of additional headers. Behind + * the normal outhdr we put a segment with the scsi command block, and before + * the normal inhdr we put the sense data and the inhdr with additional status + * information. + */ +#ifdef CONFIG_VIRTIO_BLK_SCSI +static int virtblk_add_req_scsi(struct virtqueue *vq, struct virtblk_req *vbr, + struct scatterlist *data_sg, bool have_data) { struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6]; unsigned int num_out = 0, num_in = 0; - __virtio32 type = vbr->out_hdr.type & ~cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT); sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); sgs[num_out++] = &hdr; + sg_init_one(&cmd, vbr->sreq.cmd, vbr->sreq.cmd_len); + sgs[num_out++] = &cmd; + + if (have_data) { + if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) + sgs[num_out++] = data_sg; + else + sgs[num_out + num_in++] = data_sg; + } + + sg_init_one(&sense, vbr->sense, SCSI_SENSE_BUFFERSIZE); + sgs[num_out + num_in++] = &sense; + sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr)); + sgs[num_out + num_in++] = &inhdr; + sg_init_one(&status, &vbr->status, sizeof(vbr->status)); + sgs[num_out + num_in++] = &status; + + return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); +} + +static inline void virtblk_scsi_reques_done(struct request *req) +{ + struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); + struct virtio_blk *vblk = req->q->queuedata; + struct scsi_request *sreq = &vbr->sreq; + + sreq->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual); + sreq->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len); + req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors); +} + +static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long data) +{ + struct gendisk *disk = bdev->bd_disk; + struct virtio_blk *vblk = disk->private_data; /* - * If this is a packet command we need a couple of additional headers. - * Behind the normal outhdr we put a segment with the scsi command - * block, and before the normal inhdr we put the sense data and the - * inhdr with additional status information. + * Only allow the generic SCSI ioctls if the host can support it. */ - if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) { - sg_init_one(&cmd, vbr->req->cmd, vbr->req->cmd_len); - sgs[num_out++] = &cmd; - } + if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) + return -ENOTTY; + + return scsi_cmd_blk_ioctl(bdev, mode, cmd, + (void __user *)data); +} +#else +static inline int virtblk_add_req_scsi(struct virtqueue *vq, + struct virtblk_req *vbr, struct scatterlist *data_sg, + bool have_data) +{ + return -EIO; +} +static inline void virtblk_scsi_reques_done(struct request *req) +{ +} +#define virtblk_ioctl NULL +#endif /* CONFIG_VIRTIO_BLK_SCSI */ + +static int virtblk_add_req(struct virtqueue *vq, struct virtblk_req *vbr, + struct scatterlist *data_sg, bool have_data) +{ + struct scatterlist hdr, status, *sgs[3]; + unsigned int num_out = 0, num_in = 0; + + sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); + sgs[num_out++] = &hdr; if (have_data) { if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) @@ -101,13 +164,6 @@ static int __virtblk_add_req(struct virtqueue *vq, sgs[num_out + num_in++] = data_sg; } - if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) { - sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE); - sgs[num_out + num_in++] = &sense; - sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr)); - sgs[num_out + num_in++] = &inhdr; - } - sg_init_one(&status, &vbr->status, sizeof(vbr->status)); sgs[num_out + num_in++] = &status; @@ -117,15 +173,16 @@ static int __virtblk_add_req(struct virtqueue *vq, static inline void virtblk_request_done(struct request *req) { struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); - struct virtio_blk *vblk = req->q->queuedata; int error = virtblk_result(vbr); - if (req->cmd_type == REQ_TYPE_BLOCK_PC) { - req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual); - req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len); - req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors); - } else if (req->cmd_type == REQ_TYPE_DRV_PRIV) { + switch (req_op(req)) { + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: + virtblk_scsi_reques_done(req); + break; + case REQ_OP_DRV_IN: req->errors = (error != 0); + break; } blk_mq_end_request(req, error); @@ -144,7 +201,9 @@ static void virtblk_done(struct virtqueue *vq) do { virtqueue_disable_cb(vq); while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { - blk_mq_complete_request(vbr->req, vbr->req->errors); + struct request *req = blk_mq_rq_from_pdu(vbr); + + blk_mq_complete_request(req, req->errors); req_done = true; } if (unlikely(virtqueue_is_broken(vq))) @@ -168,49 +227,50 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, int qid = hctx->queue_num; int err; bool notify = false; + u32 type; BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); - vbr->req = req; - if (req_op(req) == REQ_OP_FLUSH) { - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - } else { - switch (req->cmd_type) { - case REQ_TYPE_FS: - vbr->out_hdr.type = 0; - vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, blk_rq_pos(vbr->req)); - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - case REQ_TYPE_BLOCK_PC: - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_SCSI_CMD); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - case REQ_TYPE_DRV_PRIV: - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - default: - /* We don't put anything else in the queue. */ - BUG(); - } + switch (req_op(req)) { + case REQ_OP_READ: + case REQ_OP_WRITE: + type = 0; + break; + case REQ_OP_FLUSH: + type = VIRTIO_BLK_T_FLUSH; + break; + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: + type = VIRTIO_BLK_T_SCSI_CMD; + break; + case REQ_OP_DRV_IN: + type = VIRTIO_BLK_T_GET_ID; + break; + default: + WARN_ON_ONCE(1); + return BLK_MQ_RQ_QUEUE_ERROR; } + vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, type); + vbr->out_hdr.sector = type ? + 0 : cpu_to_virtio64(vblk->vdev, blk_rq_pos(req)); + vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(req)); + blk_mq_start_request(req); - num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg); + num = blk_rq_map_sg(hctx->queue, req, vbr->sg); if (num) { - if (rq_data_dir(vbr->req) == WRITE) + if (rq_data_dir(req) == WRITE) vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT); else vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN); } spin_lock_irqsave(&vblk->vqs[qid].lock, flags); - err = __virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); + if (req_op(req) == REQ_OP_SCSI_IN || req_op(req) == REQ_OP_SCSI_OUT) + err = virtblk_add_req_scsi(vblk->vqs[qid].vq, vbr, vbr->sg, num); + else + err = virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); if (err) { virtqueue_kick(vblk->vqs[qid].vq); blk_mq_stop_hw_queue(hctx); @@ -240,10 +300,9 @@ static int virtblk_get_id(struct gendisk *disk, char *id_str) struct request *req; int err; - req = blk_get_request(q, READ, GFP_KERNEL); + req = blk_get_request(q, REQ_OP_DRV_IN, GFP_KERNEL); if (IS_ERR(req)) return PTR_ERR(req); - req->cmd_type = REQ_TYPE_DRV_PRIV; err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); if (err) @@ -255,22 +314,6 @@ out: return err; } -static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long data) -{ - struct gendisk *disk = bdev->bd_disk; - struct virtio_blk *vblk = disk->private_data; - - /* - * Only allow the generic SCSI ioctls if the host can support it. - */ - if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) - return -ENOTTY; - - return scsi_cmd_blk_ioctl(bdev, mode, cmd, - (void __user *)data); -} - /* We provide getgeo only to please some old bootloader/partitioning tools */ static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) { @@ -536,6 +579,9 @@ static int virtblk_init_request(void *data, struct request *rq, struct virtio_blk *vblk = data; struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); +#ifdef CONFIG_VIRTIO_BLK_SCSI + vbr->sreq.sense = vbr->sense; +#endif sg_init_table(vbr->sg, vblk->sg_elems); return 0; } @@ -628,11 +674,12 @@ static int virtblk_probe(struct virtio_device *vdev) if (err) goto out_put_disk; - q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set); + q = blk_mq_init_queue(&vblk->tag_set); if (IS_ERR(q)) { err = -ENOMEM; goto out_free_tags; } + vblk->disk->queue = q; q->queuedata = vblk; @@ -767,7 +814,7 @@ static void virtblk_remove(struct virtio_device *vdev) /* Stop all the virtqueues. */ vdev->config->reset(vdev); - refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount); + refc = kref_read(&disk_to_dev(vblk->disk)->kobj.kref); put_disk(vblk->disk); vdev->config->del_vqs(vdev); kfree(vblk->vqs); @@ -818,7 +865,10 @@ static const struct virtio_device_id id_table[] = { static unsigned int features_legacy[] = { VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, - VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI, + VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, +#ifdef CONFIG_VIRTIO_BLK_SCSI + VIRTIO_BLK_F_SCSI, +#endif VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_MQ, } diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index b2bdfa81f929..5067a0a952cb 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -197,13 +197,13 @@ struct blkfront_info /* Number of pages per ring buffer. */ unsigned int nr_ring_pages; struct request_queue *rq; - unsigned int feature_flush; - unsigned int feature_fua; + unsigned int feature_flush:1; + unsigned int feature_fua:1; unsigned int feature_discard:1; unsigned int feature_secdiscard:1; + unsigned int feature_persistent:1; unsigned int discard_granularity; unsigned int discard_alignment; - unsigned int feature_persistent:1; /* Number of 4KB segments handled */ unsigned int max_indirect_segments; int is_ready; @@ -865,7 +865,7 @@ static inline void flush_requests(struct blkfront_ring_info *rinfo) static inline bool blkif_request_flush_invalid(struct request *req, struct blkfront_info *info) { - return ((req->cmd_type != REQ_TYPE_FS) || + return (blk_rq_is_passthrough(req) || ((req_op(req) == REQ_OP_FLUSH) && !info->feature_flush) || ((req->cmd_flags & REQ_FUA) && @@ -2223,7 +2223,7 @@ static int blkfront_setup_indirect(struct blkfront_ring_info *rinfo) } else grants = info->max_indirect_segments; - psegs = grants / GRANTS_PER_PSEG; + psegs = DIV_ROUND_UP(grants, GRANTS_PER_PSEG); err = fill_grant_buffer(rinfo, (grants + INDIRECT_GREFS(grants)) * BLK_RING_SIZE(info)); @@ -2323,13 +2323,16 @@ static void blkfront_gather_backend_features(struct blkfront_info *info) blkfront_setup_discard(info); info->feature_persistent = - xenbus_read_unsigned(info->xbdev->otherend, - "feature-persistent", 0); + !!xenbus_read_unsigned(info->xbdev->otherend, + "feature-persistent", 0); indirect_segments = xenbus_read_unsigned(info->xbdev->otherend, "feature-max-indirect-segments", 0); - info->max_indirect_segments = min(indirect_segments, - xen_blkif_max_segments); + if (indirect_segments > xen_blkif_max_segments) + indirect_segments = xen_blkif_max_segments; + if (indirect_segments <= BLKIF_MAX_SEGMENTS_PER_REQUEST) + indirect_segments = 0; + info->max_indirect_segments = indirect_segments; } /* @@ -2652,6 +2655,9 @@ static int __init xlblk_init(void) if (!xen_domain()) return -ENODEV; + if (xen_blkif_max_segments < BLKIF_MAX_SEGMENTS_PER_REQUEST) + xen_blkif_max_segments = BLKIF_MAX_SEGMENTS_PER_REQUEST; + if (xen_blkif_max_ring_order > XENBUS_MAX_RING_GRANT_ORDER) { pr_info("Invalid max_ring_order (%d), will use default max: %d.\n", xen_blkif_max_ring_order, XENBUS_MAX_RING_GRANT_ORDER); diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index c4328d9d9981..757dce2147e0 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -468,7 +468,7 @@ static struct request *ace_get_next_request(struct request_queue *q) struct request *req; while ((req = blk_peek_request(q)) != NULL) { - if (req->cmd_type == REQ_TYPE_FS) + if (!blk_rq_is_passthrough(req)) break; blk_start_request(req); __blk_end_request_all(req, -EIO); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 15f58ab44d0b..3cd7856156b4 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -25,6 +25,7 @@ #include <linux/genhd.h> #include <linux/highmem.h> #include <linux/slab.h> +#include <linux/backing-dev.h> #include <linux/string.h> #include <linux/vmalloc.h> #include <linux/err.h> @@ -112,6 +113,14 @@ static inline bool is_partial_io(struct bio_vec *bvec) return bvec->bv_len != PAGE_SIZE; } +static void zram_revalidate_disk(struct zram *zram) +{ + revalidate_disk(zram->disk); + /* revalidate_disk reset the BDI_CAP_STABLE_WRITES so set again */ + zram->disk->queue->backing_dev_info->capabilities |= + BDI_CAP_STABLE_WRITES; +} + /* * Check if request is within bounds and aligned on zram logical blocks. */ @@ -1095,15 +1104,9 @@ static ssize_t disksize_store(struct device *dev, zram->comp = comp; zram->disksize = disksize; set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT); + zram_revalidate_disk(zram); up_write(&zram->init_lock); - /* - * Revalidate disk out of the init_lock to avoid lockdep splat. - * It's okay because disk's capacity is protected by init_lock - * so that revalidate_disk always sees up-to-date capacity. - */ - revalidate_disk(zram->disk); - return len; out_destroy_comp: @@ -1149,7 +1152,7 @@ static ssize_t reset_store(struct device *dev, /* Make sure all the pending I/O are finished */ fsync_bdev(bdev); zram_reset_device(zram); - revalidate_disk(zram->disk); + zram_revalidate_disk(zram); bdput(bdev); mutex_lock(&bdev->bd_mutex); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 59cca72647a6..87739649eac2 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -281,8 +281,8 @@ #include <linux/fcntl.h> #include <linux/blkdev.h> #include <linux/times.h> - #include <linux/uaccess.h> +#include <scsi/scsi_request.h> /* used to tell the module to turn on full debugging messages */ static bool debug; @@ -342,8 +342,8 @@ static void cdrom_sysctl_register(void); static LIST_HEAD(cdrom_list); -static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, - struct packet_command *cgc) +int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, + struct packet_command *cgc) { if (cgc->sense) { cgc->sense->sense_key = 0x05; @@ -354,6 +354,7 @@ static int cdrom_dummy_generic_packet(struct cdrom_device_info *cdi, cgc->stat = -EIO; return -EIO; } +EXPORT_SYMBOL(cdrom_dummy_generic_packet); static int cdrom_flush_cache(struct cdrom_device_info *cdi) { @@ -371,7 +372,7 @@ static int cdrom_flush_cache(struct cdrom_device_info *cdi) static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; int ret, buflen; @@ -586,7 +587,7 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) int register_cdrom(struct cdrom_device_info *cdi) { static char banner_printed; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; int *change_capability = (int *)&cdo->capability; /* hack */ cd_dbg(CD_OPEN, "entering register_cdrom\n"); @@ -610,7 +611,6 @@ int register_cdrom(struct cdrom_device_info *cdi) ENSURE(reset, CDC_RESET); ENSURE(generic_packet, CDC_GENERIC_PACKET); cdi->mc_flags = 0; - cdo->n_minors = 0; cdi->options = CDO_USE_FFLAGS; if (autoclose == 1 && CDROM_CAN(CDC_CLOSE_TRAY)) @@ -630,8 +630,7 @@ int register_cdrom(struct cdrom_device_info *cdi) else cdi->cdda_method = CDDA_OLD; - if (!cdo->generic_packet) - cdo->generic_packet = cdrom_dummy_generic_packet; + WARN_ON(!cdo->generic_packet); cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); mutex_lock(&cdrom_mutex); @@ -652,7 +651,6 @@ void unregister_cdrom(struct cdrom_device_info *cdi) if (cdi->exit) cdi->exit(cdi); - cdi->ops->n_minors--; cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); } @@ -1036,7 +1034,7 @@ static int open_for_data(struct cdrom_device_info *cdi) { int ret; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; tracktype tracks; cd_dbg(CD_OPEN, "entering open_for_data\n"); /* Check if the driver can report drive status. If it can, we @@ -1198,8 +1196,8 @@ err: /* This code is similar to that in open_for_data. The routine is called whenever an audio play operation is requested. */ -static int check_for_audio_disc(struct cdrom_device_info * cdi, - struct cdrom_device_ops * cdo) +static int check_for_audio_disc(struct cdrom_device_info *cdi, + const struct cdrom_device_ops *cdo) { int ret; tracktype tracks; @@ -1254,7 +1252,7 @@ static int check_for_audio_disc(struct cdrom_device_info * cdi, void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; int opened_for_data; cd_dbg(CD_CLOSE, "entering cdrom_release\n"); @@ -1294,7 +1292,7 @@ static int cdrom_read_mech_status(struct cdrom_device_info *cdi, struct cdrom_changer_info *buf) { struct packet_command cgc; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; int length; /* @@ -1643,7 +1641,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) int ret; u_char buf[20]; struct packet_command cgc; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; rpc_state_t rpc_state; memset(buf, 0, sizeof(buf)); @@ -1791,7 +1789,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s, { unsigned char buf[21], *base; struct dvd_layer *layer; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; int ret, layer_num = s->physical.layer_num; if (layer_num >= DVD_LAYERS) @@ -1842,7 +1840,7 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s, { int ret; u_char buf[8]; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; init_cdrom_command(cgc, buf, sizeof(buf), CGC_DATA_READ); cgc->cmd[0] = GPCMD_READ_DVD_STRUCTURE; @@ -1866,7 +1864,7 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s, { int ret, size; u_char *buf; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; size = sizeof(s->disckey.value) + 4; @@ -1894,7 +1892,7 @@ static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s, { int ret, size = 4 + 188; u_char *buf; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; buf = kmalloc(size, GFP_KERNEL); if (!buf) @@ -1928,7 +1926,7 @@ static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s, { int ret = 0, size; u_char *buf; - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; size = sizeof(s->manufact.value) + 4; @@ -1995,7 +1993,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi, struct packet_command *cgc, int page_code, int page_control) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; memset(cgc->cmd, 0, sizeof(cgc->cmd)); @@ -2010,7 +2008,7 @@ int cdrom_mode_sense(struct cdrom_device_info *cdi, int cdrom_mode_select(struct cdrom_device_info *cdi, struct packet_command *cgc) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; memset(cgc->cmd, 0, sizeof(cgc->cmd)); memset(cgc->buffer, 0, 2); @@ -2025,7 +2023,7 @@ int cdrom_mode_select(struct cdrom_device_info *cdi, static int cdrom_read_subchannel(struct cdrom_device_info *cdi, struct cdrom_subchnl *subchnl, int mcn) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; char buffer[32]; int ret; @@ -2073,7 +2071,7 @@ static int cdrom_read_cd(struct cdrom_device_info *cdi, struct packet_command *cgc, int lba, int blocksize, int nblocks) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; memset(&cgc->cmd, 0, sizeof(cgc->cmd)); cgc->cmd[0] = GPCMD_READ_10; @@ -2093,7 +2091,7 @@ static int cdrom_read_block(struct cdrom_device_info *cdi, struct packet_command *cgc, int lba, int nblocks, int format, int blksize) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; memset(&cgc->cmd, 0, sizeof(cgc->cmd)); cgc->cmd[0] = GPCMD_READ_CD; @@ -2172,6 +2170,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, { struct request_queue *q = cdi->disk->queue; struct request *rq; + struct scsi_request *req; struct bio *bio; unsigned int len; int nr, ret = 0; @@ -2190,12 +2189,13 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, len = nr * CD_FRAMESIZE_RAW; - rq = blk_get_request(q, READ, GFP_KERNEL); + rq = blk_get_request(q, REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(rq)) { ret = PTR_ERR(rq); break; } - blk_rq_set_block_pc(rq); + req = scsi_req(rq); + scsi_req_init(rq); ret = blk_rq_map_user(q, rq, NULL, ubuf, len, GFP_KERNEL); if (ret) { @@ -2203,23 +2203,23 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, break; } - rq->cmd[0] = GPCMD_READ_CD; - rq->cmd[1] = 1 << 2; - rq->cmd[2] = (lba >> 24) & 0xff; - rq->cmd[3] = (lba >> 16) & 0xff; - rq->cmd[4] = (lba >> 8) & 0xff; - rq->cmd[5] = lba & 0xff; - rq->cmd[6] = (nr >> 16) & 0xff; - rq->cmd[7] = (nr >> 8) & 0xff; - rq->cmd[8] = nr & 0xff; - rq->cmd[9] = 0xf8; - - rq->cmd_len = 12; + req->cmd[0] = GPCMD_READ_CD; + req->cmd[1] = 1 << 2; + req->cmd[2] = (lba >> 24) & 0xff; + req->cmd[3] = (lba >> 16) & 0xff; + req->cmd[4] = (lba >> 8) & 0xff; + req->cmd[5] = lba & 0xff; + req->cmd[6] = (nr >> 16) & 0xff; + req->cmd[7] = (nr >> 8) & 0xff; + req->cmd[8] = nr & 0xff; + req->cmd[9] = 0xf8; + + req->cmd_len = 12; rq->timeout = 60 * HZ; bio = rq->bio; if (blk_execute_rq(q, cdi->disk, rq, 0)) { - struct request_sense *s = rq->sense; + struct request_sense *s = req->sense; ret = -EIO; cdi->last_sense = s->sense_key; } @@ -2764,7 +2764,7 @@ static int cdrom_ioctl_audioctl(struct cdrom_device_info *cdi, */ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; struct modesel_head mh; @@ -2790,7 +2790,7 @@ static int cdrom_switch_blocksize(struct cdrom_device_info *cdi, int size) static int cdrom_get_track_info(struct cdrom_device_info *cdi, __u16 track, __u8 type, track_information *ti) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; int ret, buflen; @@ -3049,7 +3049,7 @@ static noinline int mmc_ioctl_cdrom_play_msf(struct cdrom_device_info *cdi, void __user *arg, struct packet_command *cgc) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_msf msf; cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYMSF\n"); if (copy_from_user(&msf, (struct cdrom_msf __user *)arg, sizeof(msf))) @@ -3069,7 +3069,7 @@ static noinline int mmc_ioctl_cdrom_play_blk(struct cdrom_device_info *cdi, void __user *arg, struct packet_command *cgc) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; struct cdrom_blk blk; cd_dbg(CD_DO_IOCTL, "entering CDROMPLAYBLK\n"); if (copy_from_user(&blk, (struct cdrom_blk __user *)arg, sizeof(blk))) @@ -3164,7 +3164,7 @@ static noinline int mmc_ioctl_cdrom_start_stop(struct cdrom_device_info *cdi, struct packet_command *cgc, int cmd) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; cd_dbg(CD_DO_IOCTL, "entering CDROMSTART/CDROMSTOP\n"); cgc->cmd[0] = GPCMD_START_STOP_UNIT; cgc->cmd[1] = 1; @@ -3177,7 +3177,7 @@ static noinline int mmc_ioctl_cdrom_pause_resume(struct cdrom_device_info *cdi, struct packet_command *cgc, int cmd) { - struct cdrom_device_ops *cdo = cdi->ops; + const struct cdrom_device_ops *cdo = cdi->ops; cd_dbg(CD_DO_IOCTL, "entering CDROMPAUSE/CDROMRESUME\n"); cgc->cmd[0] = GPCMD_PAUSE_RESUME; cgc->cmd[8] = (cmd == CDROMRESUME) ? 1 : 0; diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index 584bc3126403..1372763a948f 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -481,7 +481,7 @@ static int gdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, return -EINVAL; } -static struct cdrom_device_ops gdrom_ops = { +static const struct cdrom_device_ops gdrom_ops = { .open = gdrom_open, .release = gdrom_release, .drive_status = gdrom_drivestatus, @@ -489,9 +489,9 @@ static struct cdrom_device_ops gdrom_ops = { .get_last_session = gdrom_get_last_session, .reset = gdrom_hardreset, .audio_ioctl = gdrom_audio_ioctl, + .generic_packet = cdrom_dummy_generic_packet, .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, - .n_minors = 1, }; static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) @@ -659,23 +659,24 @@ static void gdrom_request(struct request_queue *rq) struct request *req; while ((req = blk_fetch_request(rq)) != NULL) { - if (req->cmd_type != REQ_TYPE_FS) { - printk(KERN_DEBUG "gdrom: Non-fs request ignored\n"); - __blk_end_request_all(req, -EIO); - continue; - } - if (rq_data_dir(req) != READ) { + switch (req_op(req)) { + case REQ_OP_READ: + /* + * Add to list of deferred work and then schedule + * workqueue. + */ + list_add_tail(&req->queuelist, &gdrom_deferred); + schedule_work(&work); + break; + case REQ_OP_WRITE: pr_notice("Read only device - write request ignored\n"); __blk_end_request_all(req, -EIO); - continue; + break; + default: + printk(KERN_DEBUG "gdrom: Non-fs request ignored\n"); + __blk_end_request_all(req, -EIO); + break; } - - /* - * Add to list of deferred work and then schedule - * workqueue. - */ - list_add_tail(&req->queuelist, &gdrom_deferred); - schedule_work(&work); } } @@ -807,16 +808,20 @@ static int probe_gdrom(struct platform_device *devptr) if (err) goto probe_fail_cmdirq_register; gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock); - if (!gd.gdrom_rq) + if (!gd.gdrom_rq) { + err = -ENOMEM; goto probe_fail_requestq; + } err = probe_gdrom_setupqueue(); if (err) goto probe_fail_toc; gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL); - if (!gd.toc) + if (!gd.toc) { + err = -ENOMEM; goto probe_fail_toc; + } add_disk(gd.disk); return 0; diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 6ce5ce8be2f2..87fba424817e 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -92,7 +92,6 @@ static void add_early_randomness(struct hwrng *rng) mutex_unlock(&reading_mutex); if (bytes_read > 0) add_device_randomness(rng_buffer, bytes_read); - memset(rng_buffer, 0, size); } static inline void cleanup_rng(struct kref *kref) @@ -288,7 +287,6 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, } } out: - memset(rng_buffer, 0, rng_buffer_size()); return ret ? : err; out_unlock_reading: @@ -427,7 +425,6 @@ static int hwrng_fillfn(void *unused) /* Outside lock, sure, but y'know: randomness. */ add_hwgenerator_randomness((void *)rng_fillbuf, rc, rc * current_quality * 8 >> 10); - memset(rng_fillbuf, 0, rng_buffer_size()); } hwrng_fill = NULL; return 0; diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 5bb1985ec484..6d9cc2d39d22 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -381,9 +381,6 @@ static ssize_t read_kmem(struct file *file, char __user *buf, char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ int err = 0; - if (!pfn_valid(PFN_DOWN(p))) - return -EIO; - read = 0; if (p < (unsigned long) high_memory) { low_count = count; @@ -412,6 +409,8 @@ static ssize_t read_kmem(struct file *file, char __user *buf, * by the kernel or data corruption may occur */ kbuf = xlate_dev_kmem_ptr((void *)p); + if (!virt_addr_valid(kbuf)) + return -ENXIO; if (copy_to_user(buf, kbuf, sz)) return -EFAULT; @@ -482,6 +481,8 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf, * corruption may occur. */ ptr = xlate_dev_kmem_ptr((void *)p); + if (!virt_addr_valid(ptr)) + return -ENXIO; copied = copy_from_user(ptr, buf, sz); if (copied) { @@ -512,9 +513,6 @@ static ssize_t write_kmem(struct file *file, const char __user *buf, char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ int err = 0; - if (!pfn_valid(PFN_DOWN(p))) - return -EIO; - if (p < (unsigned long) high_memory) { unsigned long to_write = min_t(unsigned long, count, (unsigned long)high_memory - p); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 02819e0703c8..87885d146dbb 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -290,6 +290,7 @@ static int register_device(int minor, struct pp_struct *pp) struct pardevice *pdev = NULL; char *name; struct pardev_cb ppdev_cb; + int rc = 0; name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor); if (name == NULL) @@ -298,8 +299,8 @@ static int register_device(int minor, struct pp_struct *pp) port = parport_find_number(minor); if (!port) { pr_warn("%s: no associated port!\n", name); - kfree(name); - return -ENXIO; + rc = -ENXIO; + goto err; } memset(&ppdev_cb, 0, sizeof(ppdev_cb)); @@ -308,16 +309,18 @@ static int register_device(int minor, struct pp_struct *pp) ppdev_cb.private = pp; pdev = parport_register_dev_model(port, name, &ppdev_cb, minor); parport_put_port(port); - kfree(name); if (!pdev) { pr_warn("%s: failed to register device!\n", name); - return -ENXIO; + rc = -ENXIO; + goto err; } pp->pdev = pdev; dev_dbg(&pdev->dev, "registered pardevice\n"); - return 0; +err: + kfree(name); + return rc; } static enum ieee1284_phase init_phase(int mode) diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 8b00e79c2683..17857beb4892 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1862,7 +1862,7 @@ static void config_work_handler(struct work_struct *work) { struct ports_device *portdev; - portdev = container_of(work, struct ports_device, control_work); + portdev = container_of(work, struct ports_device, config_work); if (!use_multiport(portdev)) { struct virtio_device *vdev; struct port *port; diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 5eb05dbf59b8..fc585f370549 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -768,5 +768,5 @@ fail: kfree(clks); iounmap(base); } -CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); -CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 9375777776d9..b533f99550e1 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -37,12 +37,14 @@ * @smstpcr: module stop control register * @mstpsr: module stop status register (optional) * @lock: protects writes to SMSTPCR + * @width_8bit: registers are 8-bit, not 32-bit */ struct mstp_clock_group { struct clk_onecell_data data; void __iomem *smstpcr; void __iomem *mstpsr; spinlock_t lock; + bool width_8bit; }; /** @@ -59,6 +61,18 @@ struct mstp_clock { #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) +static inline u32 cpg_mstp_read(struct mstp_clock_group *group, + u32 __iomem *reg) +{ + return group->width_8bit ? readb(reg) : clk_readl(reg); +} + +static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, + u32 __iomem *reg) +{ + group->width_8bit ? writeb(val, reg) : clk_writel(val, reg); +} + static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) { struct mstp_clock *clock = to_mstp_clock(hw); @@ -70,12 +84,12 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) spin_lock_irqsave(&group->lock, flags); - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); if (enable) value &= ~bitmask; else value |= bitmask; - clk_writel(value, group->smstpcr); + cpg_mstp_write(group, value, group->smstpcr); spin_unlock_irqrestore(&group->lock, flags); @@ -83,7 +97,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) return 0; for (i = 1000; i > 0; --i) { - if (!(clk_readl(group->mstpsr) & bitmask)) + if (!(cpg_mstp_read(group, group->mstpsr) & bitmask)) break; cpu_relax(); } @@ -114,9 +128,9 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) u32 value; if (group->mstpsr) - value = clk_readl(group->mstpsr); + value = cpg_mstp_read(group, group->mstpsr); else - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); return !(value & BIT(clock->bit_index)); } @@ -188,6 +202,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) return; } + if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) + group->width_8bit = true; + for (i = 0; i < MSTP_MAX_CLOCKS; ++i) clks[i] = ERR_PTR(-ENOENT); diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 8c8b495cbf0d..cdc092a1d9ef 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -586,7 +586,7 @@ static const struct samsung_gate_clock exynos5800_gate_clks[] __initconst = { GATE(CLK_ACLK550_CAM, "aclk550_cam", "mout_user_aclk550_cam", GATE_BUS_TOP, 24, 0, 0), GATE(CLK_ACLK432_SCALER, "aclk432_scaler", "mout_user_aclk432_scaler", - GATE_BUS_TOP, 27, 0, 0), + GATE_BUS_TOP, 27, CLK_IS_CRITICAL, 0), }; static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { @@ -956,20 +956,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk333_g2d", GATE_IP_G2D, 7, 0, 0), GATE(0, "aclk200_fsys", "mout_user_aclk200_fsys", - GATE_BUS_FSYS0, 9, CLK_IGNORE_UNUSED, 0), + GATE_BUS_FSYS0, 9, CLK_IS_CRITICAL, 0), GATE(0, "aclk200_fsys2", "mout_user_aclk200_fsys2", GATE_BUS_FSYS0, 10, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_g2d", "mout_user_aclk333_g2d", GATE_BUS_TOP, 0, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk266_g2d", "mout_user_aclk266_g2d", - GATE_BUS_TOP, 1, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 1, CLK_IS_CRITICAL, 0), GATE(0, "aclk300_jpeg", "mout_user_aclk300_jpeg", GATE_BUS_TOP, 4, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp0", "mout_user_aclk333_432_isp0", GATE_BUS_TOP, 5, 0, 0), GATE(0, "aclk300_gscl", "mout_user_aclk300_gscl", - GATE_BUS_TOP, 6, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 6, CLK_IS_CRITICAL, 0), GATE(0, "aclk333_432_gscl", "mout_user_aclk333_432_gscl", GATE_BUS_TOP, 7, CLK_IGNORE_UNUSED, 0), GATE(0, "aclk333_432_isp", "mout_user_aclk333_432_isp", @@ -983,20 +983,20 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(0, "aclk166", "mout_user_aclk166", GATE_BUS_TOP, 14, CLK_IGNORE_UNUSED, 0), GATE(CLK_ACLK333, "aclk333", "mout_user_aclk333", - GATE_BUS_TOP, 15, CLK_IGNORE_UNUSED, 0), + GATE_BUS_TOP, 15, CLK_IS_CRITICAL, 0), GATE(0, "aclk400_isp", "mout_user_aclk400_isp", GATE_BUS_TOP, 16, 0, 0), GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl", GATE_BUS_TOP, 17, 0, 0), GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1", - GATE_BUS_TOP, 18, 0, 0), + GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0), GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24", GATE_BUS_TOP, 28, 0, 0), GATE(CLK_SCLK_HSIC_12M, "sclk_hsic_12m", "ff_hsic_12m", GATE_BUS_TOP, 29, 0, 0), GATE(0, "aclk300_disp1", "mout_user_aclk300_disp1", - SRC_MASK_TOP2, 24, 0, 0), + SRC_MASK_TOP2, 24, CLK_IS_CRITICAL, 0), GATE(CLK_MAU_EPLL, "mau_epll", "mout_mau_epll_clk", SRC_MASK_TOP7, 20, 0, 0), diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index f010562534eb..2c44aeb0b97c 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -633,16 +633,12 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate) struct dev_pm_opp *opp; int i, uv; - rcu_read_lock(); - opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate); - if (IS_ERR(opp)) { - rcu_read_unlock(); + if (IS_ERR(opp)) return PTR_ERR(opp); - } - uv = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + uv = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); for (i = 0; i < td->i2c_lut_size; i++) { if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv) @@ -1440,8 +1436,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) struct dev_pm_opp *opp; int lut; - rcu_read_lock(); - rate = ULONG_MAX; opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate); if (IS_ERR(opp)) { @@ -1449,6 +1443,7 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) goto out; } v_max = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); v = td->soc->cvb->min_millivolts * 1000; lut = find_vdd_map_entry_exact(td, v); @@ -1465,6 +1460,8 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) if (v_opp <= td->soc->cvb->min_millivolts * 1000) td->dvco_rate_min = dev_pm_opp_get_freq(opp); + dev_pm_opp_put(opp); + for (;;) { v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j)); if (v >= v_opp) @@ -1496,8 +1493,6 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td) ret = 0; out: - rcu_read_unlock(); - return ret; } diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4866f7aa32e6..3356ab821624 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -5,6 +5,10 @@ config CLKSRC_OF bool select CLKSRC_PROBE +config CLKEVT_OF + bool + select CLKEVT_PROBE + config CLKSRC_ACPI bool select CLKSRC_PROBE @@ -12,6 +16,9 @@ config CLKSRC_ACPI config CLKSRC_PROBE bool +config CLKEVT_PROBE + bool + config CLKSRC_I8253 bool @@ -60,6 +67,16 @@ config DW_APB_TIMER_OF select DW_APB_TIMER select CLKSRC_OF +config GEMINI_TIMER + bool "Cortina Gemini timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on HAS_IOMEM + select CLKSRC_MMIO + select CLKSRC_OF + select MFD_SYSCON + help + Enables support for the Gemini timer + config ROCKCHIP_TIMER bool "Rockchip timer driver" if COMPILE_TEST depends on ARM || ARM64 @@ -325,16 +342,30 @@ config ARM_ARCH_TIMER_EVTSTREAM This must be disabled for hardware validation purposes to detect any hardware anomalies of missing events. +config ARM_ARCH_TIMER_OOL_WORKAROUND + bool + config FSL_ERRATUM_A008585 bool "Workaround for Freescale/NXP Erratum A-008585" default y depends on ARM_ARCH_TIMER && ARM64 + select ARM_ARCH_TIMER_OOL_WORKAROUND help This option enables a workaround for Freescale/NXP Erratum A-008585 ("ARM generic timer may contain an erroneous value"). The workaround will only be active if the fsl,erratum-a008585 property is found in the timer node. +config HISILICON_ERRATUM_161010101 + bool "Workaround for Hisilicon Erratum 161010101" + default y + select ARM_ARCH_TIMER_OOL_WORKAROUND + depends on ARM_ARCH_TIMER && ARM64 + help + This option enables a workaround for Hisilicon Erratum + 161010101. The workaround will be active if the hisilicon,erratum-161010101 + property is found in the timer node. + config ARM_GLOBAL_TIMER bool "Support for the ARM global timer" if COMPILE_TEST select CLKSRC_OF if OF @@ -467,6 +498,13 @@ config SH_TIMER_MTU2 Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. This hardware comes with 16 bit-timer registers. +config RENESAS_OSTM + bool "Renesas OSTM timer driver" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_MMIO + help + Enables the support for the Renesas OSTM. + config SH_TIMER_TMU bool "Renesas TMU timer driver" if COMPILE_TEST depends on GENERIC_CLOCKEVENTS diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index a14111e1f087..d227d1314f14 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_CLKSRC_PROBE) += clksrc-probe.o +obj-$(CONFIG_CLKEVT_PROBE) += clkevt-probe.o obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o @@ -8,6 +9,7 @@ obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o +obj-$(CONFIG_RENESAS_OSTM) += renesas-ostm.o obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o obj-$(CONFIG_EM_TIMER_STI) += em_sti.o obj-$(CONFIG_CLKBLD_I8253) += i8253.o @@ -15,6 +17,7 @@ obj-$(CONFIG_CLKSRC_MMIO) += mmio.o obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o +obj-$(CONFIG_GEMINI_TIMER) += timer-gemini.o obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 4c8c3fb2e8b2..93aa1364376a 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -96,41 +96,107 @@ early_param("clocksource.arm_arch_timer.evtstrm", early_evtstrm_cfg); */ #ifdef CONFIG_FSL_ERRATUM_A008585 -DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); -EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled); - -static int fsl_a008585_enable = -1; - -static int __init early_fsl_a008585_cfg(char *buf) +/* + * The number of retries is an arbitrary value well beyond the highest number + * of iterations the loop has been observed to take. + */ +#define __fsl_a008585_read_reg(reg) ({ \ + u64 _old, _new; \ + int _retries = 200; \ + \ + do { \ + _old = read_sysreg(reg); \ + _new = read_sysreg(reg); \ + _retries--; \ + } while (unlikely(_old != _new) && _retries); \ + \ + WARN_ON_ONCE(!_retries); \ + _new; \ +}) + +static u32 notrace fsl_a008585_read_cntp_tval_el0(void) { - int ret; - bool val; + return __fsl_a008585_read_reg(cntp_tval_el0); +} - ret = strtobool(buf, &val); - if (ret) - return ret; +static u32 notrace fsl_a008585_read_cntv_tval_el0(void) +{ + return __fsl_a008585_read_reg(cntv_tval_el0); +} - fsl_a008585_enable = val; - return 0; +static u64 notrace fsl_a008585_read_cntvct_el0(void) +{ + return __fsl_a008585_read_reg(cntvct_el0); } -early_param("clocksource.arm_arch_timer.fsl-a008585", early_fsl_a008585_cfg); +#endif -u32 __fsl_a008585_read_cntp_tval_el0(void) +#ifdef CONFIG_HISILICON_ERRATUM_161010101 +/* + * Verify whether the value of the second read is larger than the first by + * less than 32 is the only way to confirm the value is correct, so clear the + * lower 5 bits to check whether the difference is greater than 32 or not. + * Theoretically the erratum should not occur more than twice in succession + * when reading the system counter, but it is possible that some interrupts + * may lead to more than twice read errors, triggering the warning, so setting + * the number of retries far beyond the number of iterations the loop has been + * observed to take. + */ +#define __hisi_161010101_read_reg(reg) ({ \ + u64 _old, _new; \ + int _retries = 50; \ + \ + do { \ + _old = read_sysreg(reg); \ + _new = read_sysreg(reg); \ + _retries--; \ + } while (unlikely((_new - _old) >> 5) && _retries); \ + \ + WARN_ON_ONCE(!_retries); \ + _new; \ +}) + +static u32 notrace hisi_161010101_read_cntp_tval_el0(void) { - return __fsl_a008585_read_reg(cntp_tval_el0); + return __hisi_161010101_read_reg(cntp_tval_el0); } -u32 __fsl_a008585_read_cntv_tval_el0(void) +static u32 notrace hisi_161010101_read_cntv_tval_el0(void) { - return __fsl_a008585_read_reg(cntv_tval_el0); + return __hisi_161010101_read_reg(cntv_tval_el0); } -u64 __fsl_a008585_read_cntvct_el0(void) +static u64 notrace hisi_161010101_read_cntvct_el0(void) { - return __fsl_a008585_read_reg(cntvct_el0); + return __hisi_161010101_read_reg(cntvct_el0); } -EXPORT_SYMBOL(__fsl_a008585_read_cntvct_el0); -#endif /* CONFIG_FSL_ERRATUM_A008585 */ +#endif + +#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND +const struct arch_timer_erratum_workaround *timer_unstable_counter_workaround = NULL; +EXPORT_SYMBOL_GPL(timer_unstable_counter_workaround); + +DEFINE_STATIC_KEY_FALSE(arch_timer_read_ool_enabled); +EXPORT_SYMBOL_GPL(arch_timer_read_ool_enabled); + +static const struct arch_timer_erratum_workaround ool_workarounds[] = { +#ifdef CONFIG_FSL_ERRATUM_A008585 + { + .id = "fsl,erratum-a008585", + .read_cntp_tval_el0 = fsl_a008585_read_cntp_tval_el0, + .read_cntv_tval_el0 = fsl_a008585_read_cntv_tval_el0, + .read_cntvct_el0 = fsl_a008585_read_cntvct_el0, + }, +#endif +#ifdef CONFIG_HISILICON_ERRATUM_161010101 + { + .id = "hisilicon,erratum-161010101", + .read_cntp_tval_el0 = hisi_161010101_read_cntp_tval_el0, + .read_cntv_tval_el0 = hisi_161010101_read_cntv_tval_el0, + .read_cntvct_el0 = hisi_161010101_read_cntvct_el0, + }, +#endif +}; +#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ static __always_inline void arch_timer_reg_write(int access, enum arch_timer_reg reg, u32 val, @@ -281,8 +347,8 @@ static __always_inline void set_next_event(const int access, unsigned long evt, arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); } -#ifdef CONFIG_FSL_ERRATUM_A008585 -static __always_inline void fsl_a008585_set_next_event(const int access, +#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND +static __always_inline void erratum_set_next_event_generic(const int access, unsigned long evt, struct clock_event_device *clk) { unsigned long ctrl; @@ -300,20 +366,20 @@ static __always_inline void fsl_a008585_set_next_event(const int access, arch_timer_reg_write(access, ARCH_TIMER_REG_CTRL, ctrl, clk); } -static int fsl_a008585_set_next_event_virt(unsigned long evt, +static int erratum_set_next_event_virt(unsigned long evt, struct clock_event_device *clk) { - fsl_a008585_set_next_event(ARCH_TIMER_VIRT_ACCESS, evt, clk); + erratum_set_next_event_generic(ARCH_TIMER_VIRT_ACCESS, evt, clk); return 0; } -static int fsl_a008585_set_next_event_phys(unsigned long evt, +static int erratum_set_next_event_phys(unsigned long evt, struct clock_event_device *clk) { - fsl_a008585_set_next_event(ARCH_TIMER_PHYS_ACCESS, evt, clk); + erratum_set_next_event_generic(ARCH_TIMER_PHYS_ACCESS, evt, clk); return 0; } -#endif /* CONFIG_FSL_ERRATUM_A008585 */ +#endif /* CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND */ static int arch_timer_set_next_event_virt(unsigned long evt, struct clock_event_device *clk) @@ -343,16 +409,16 @@ static int arch_timer_set_next_event_phys_mem(unsigned long evt, return 0; } -static void fsl_a008585_set_sne(struct clock_event_device *clk) +static void erratum_workaround_set_sne(struct clock_event_device *clk) { -#ifdef CONFIG_FSL_ERRATUM_A008585 +#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND if (!static_branch_unlikely(&arch_timer_read_ool_enabled)) return; if (arch_timer_uses_ppi == VIRT_PPI) - clk->set_next_event = fsl_a008585_set_next_event_virt; + clk->set_next_event = erratum_set_next_event_virt; else - clk->set_next_event = fsl_a008585_set_next_event_phys; + clk->set_next_event = erratum_set_next_event_phys; #endif } @@ -385,7 +451,7 @@ static void __arch_timer_setup(unsigned type, BUG(); } - fsl_a008585_set_sne(clk); + erratum_workaround_set_sne(clk); } else { clk->features |= CLOCK_EVT_FEAT_DYNIRQ; clk->name = "arch_mem_timer"; @@ -580,7 +646,7 @@ static struct clocksource clocksource_counter = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -static struct cyclecounter cyclecounter = { +static struct cyclecounter cyclecounter __ro_after_init = { .read = arch_counter_read_cc, .mask = CLOCKSOURCE_MASK(56), }; @@ -605,7 +671,7 @@ static void __init arch_counter_register(unsigned type) clocksource_counter.archdata.vdso_direct = true; -#ifdef CONFIG_FSL_ERRATUM_A008585 +#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND /* * Don't use the vdso fastpath if errata require using * the out-of-line counter accessor. @@ -893,12 +959,15 @@ static int __init arch_timer_of_init(struct device_node *np) arch_timer_c3stop = !of_property_read_bool(np, "always-on"); -#ifdef CONFIG_FSL_ERRATUM_A008585 - if (fsl_a008585_enable < 0) - fsl_a008585_enable = of_property_read_bool(np, "fsl,erratum-a008585"); - if (fsl_a008585_enable) { - static_branch_enable(&arch_timer_read_ool_enabled); - pr_info("Enabling workaround for FSL erratum A-008585\n"); +#ifdef CONFIG_ARM_ARCH_TIMER_OOL_WORKAROUND + for (i = 0; i < ARRAY_SIZE(ool_workarounds); i++) { + if (of_property_read_bool(np, ool_workarounds[i].id)) { + timer_unstable_counter_workaround = &ool_workarounds[i]; + static_branch_enable(&arch_timer_read_ool_enabled); + pr_info("arch_timer: Enabling workaround for %s\n", + timer_unstable_counter_workaround->id); + break; + } } #endif diff --git a/drivers/clocksource/clkevt-probe.c b/drivers/clocksource/clkevt-probe.c new file mode 100644 index 000000000000..8c30fec86094 --- /dev/null +++ b/drivers/clocksource/clkevt-probe.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2016, Linaro Ltd. All rights reserved. + * Daniel Lezcano <daniel.lezcano@linaro.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/init.h> +#include <linux/of.h> +#include <linux/clockchip.h> + +extern struct of_device_id __clkevt_of_table[]; + +static const struct of_device_id __clkevt_of_table_sentinel + __used __section(__clkevt_of_table_end); + +int __init clockevent_probe(void) +{ + struct device_node *np; + const struct of_device_id *match; + of_init_fn_1_ret init_func; + int ret, clockevents = 0; + + for_each_matching_node_and_match(np, __clkevt_of_table, &match) { + if (!of_device_is_available(np)) + continue; + + init_func = match->data; + + ret = init_func(np); + if (ret) { + pr_warn("Failed to initialize '%s' (%d)\n", + np->name, ret); + continue; + } + + clockevents++; + } + + if (!clockevents) { + pr_crit("%s: no matching clockevent found\n", __func__); + return -ENODEV; + } + + return 0; +} diff --git a/drivers/clocksource/exynos_mct.c b/drivers/clocksource/exynos_mct.c index 4da1dc2278bd..670ff0f25b67 100644 --- a/drivers/clocksource/exynos_mct.c +++ b/drivers/clocksource/exynos_mct.c @@ -495,6 +495,7 @@ static int exynos4_mct_dying_cpu(unsigned int cpu) if (mct_int_type == MCT_INT_SPI) { if (evt->irq != -1) disable_irq_nosync(evt->irq); + exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); } else { disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); } diff --git a/drivers/clocksource/renesas-ostm.c b/drivers/clocksource/renesas-ostm.c new file mode 100644 index 000000000000..c76f57668fb2 --- /dev/null +++ b/drivers/clocksource/renesas-ostm.c @@ -0,0 +1,265 @@ +/* + * Renesas Timer Support - OSTM + * + * Copyright (C) 2017 Renesas Electronics America, Inc. + * Copyright (C) 2017 Chris Brandt + * + * 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 + * + * 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. + * + */ + +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/clk.h> +#include <linux/clockchips.h> +#include <linux/interrupt.h> +#include <linux/sched_clock.h> +#include <linux/slab.h> + +/* + * The OSTM contains independent channels. + * The first OSTM channel probed will be set up as a free running + * clocksource. Additionally we will use this clocksource for the system + * schedule timer sched_clock(). + * + * The second (or more) channel probed will be set up as an interrupt + * driven clock event. + */ + +struct ostm_device { + void __iomem *base; + unsigned long ticks_per_jiffy; + struct clock_event_device ced; +}; + +static void __iomem *system_clock; /* For sched_clock() */ + +/* OSTM REGISTERS */ +#define OSTM_CMP 0x000 /* RW,32 */ +#define OSTM_CNT 0x004 /* R,32 */ +#define OSTM_TE 0x010 /* R,8 */ +#define OSTM_TS 0x014 /* W,8 */ +#define OSTM_TT 0x018 /* W,8 */ +#define OSTM_CTL 0x020 /* RW,8 */ + +#define TE 0x01 +#define TS 0x01 +#define TT 0x01 +#define CTL_PERIODIC 0x00 +#define CTL_ONESHOT 0x02 +#define CTL_FREERUN 0x02 + +static struct ostm_device *ced_to_ostm(struct clock_event_device *ced) +{ + return container_of(ced, struct ostm_device, ced); +} + +static void ostm_timer_stop(struct ostm_device *ostm) +{ + if (readb(ostm->base + OSTM_TE) & TE) { + writeb(TT, ostm->base + OSTM_TT); + + /* + * Read back the register simply to confirm the write operation + * has completed since I/O writes can sometimes get queued by + * the bus architecture. + */ + while (readb(ostm->base + OSTM_TE) & TE) + ; + } +} + +static int __init ostm_init_clksrc(struct ostm_device *ostm, unsigned long rate) +{ + /* + * irq not used (clock sources don't use interrupts) + */ + + ostm_timer_stop(ostm); + + writel(0, ostm->base + OSTM_CMP); + writeb(CTL_FREERUN, ostm->base + OSTM_CTL); + writeb(TS, ostm->base + OSTM_TS); + + return clocksource_mmio_init(ostm->base + OSTM_CNT, + "ostm", rate, + 300, 32, clocksource_mmio_readl_up); +} + +static u64 notrace ostm_read_sched_clock(void) +{ + return readl(system_clock); +} + +static void __init ostm_init_sched_clock(struct ostm_device *ostm, + unsigned long rate) +{ + system_clock = ostm->base + OSTM_CNT; + sched_clock_register(ostm_read_sched_clock, 32, rate); +} + +static int ostm_clock_event_next(unsigned long delta, + struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + writel(delta, ostm->base + OSTM_CMP); + writeb(CTL_ONESHOT, ostm->base + OSTM_CTL); + writeb(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_shutdown(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} +static int ostm_set_periodic(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + if (clockevent_state_oneshot(ced) || clockevent_state_periodic(ced)) + ostm_timer_stop(ostm); + + writel(ostm->ticks_per_jiffy - 1, ostm->base + OSTM_CMP); + writeb(CTL_PERIODIC, ostm->base + OSTM_CTL); + writeb(TS, ostm->base + OSTM_TS); + + return 0; +} + +static int ostm_set_oneshot(struct clock_event_device *ced) +{ + struct ostm_device *ostm = ced_to_ostm(ced); + + ostm_timer_stop(ostm); + + return 0; +} + +static irqreturn_t ostm_timer_interrupt(int irq, void *dev_id) +{ + struct ostm_device *ostm = dev_id; + + if (clockevent_state_oneshot(&ostm->ced)) + ostm_timer_stop(ostm); + + /* notify clockevent layer */ + if (ostm->ced.event_handler) + ostm->ced.event_handler(&ostm->ced); + + return IRQ_HANDLED; +} + +static int __init ostm_init_clkevt(struct ostm_device *ostm, int irq, + unsigned long rate) +{ + struct clock_event_device *ced = &ostm->ced; + int ret = -ENXIO; + + ret = request_irq(irq, ostm_timer_interrupt, + IRQF_TIMER | IRQF_IRQPOLL, + "ostm", ostm); + if (ret) { + pr_err("ostm: failed to request irq\n"); + return ret; + } + + ced->name = "ostm"; + ced->features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC; + ced->set_state_shutdown = ostm_shutdown; + ced->set_state_periodic = ostm_set_periodic; + ced->set_state_oneshot = ostm_set_oneshot; + ced->set_next_event = ostm_clock_event_next; + ced->shift = 32; + ced->rating = 300; + ced->cpumask = cpumask_of(0); + clockevents_config_and_register(ced, rate, 0xf, 0xffffffff); + + return 0; +} + +static int __init ostm_init(struct device_node *np) +{ + struct ostm_device *ostm; + int ret = -EFAULT; + struct clk *ostm_clk = NULL; + int irq; + unsigned long rate; + + ostm = kzalloc(sizeof(*ostm), GFP_KERNEL); + if (!ostm) + return -ENOMEM; + + ostm->base = of_iomap(np, 0); + if (!ostm->base) { + pr_err("ostm: failed to remap I/O memory\n"); + goto err; + } + + irq = irq_of_parse_and_map(np, 0); + if (irq < 0) { + pr_err("ostm: Failed to get irq\n"); + goto err; + } + + ostm_clk = of_clk_get(np, 0); + if (IS_ERR(ostm_clk)) { + pr_err("ostm: Failed to get clock\n"); + ostm_clk = NULL; + goto err; + } + + ret = clk_prepare_enable(ostm_clk); + if (ret) { + pr_err("ostm: Failed to enable clock\n"); + goto err; + } + + rate = clk_get_rate(ostm_clk); + ostm->ticks_per_jiffy = (rate + HZ / 2) / HZ; + + /* + * First probed device will be used as system clocksource. Any + * additional devices will be used as clock events. + */ + if (!system_clock) { + ret = ostm_init_clksrc(ostm, rate); + + if (!ret) { + ostm_init_sched_clock(ostm, rate); + pr_info("ostm: used for clocksource\n"); + } + + } else { + ret = ostm_init_clkevt(ostm, irq, rate); + + if (!ret) + pr_info("ostm: used for clock events\n"); + } + +err: + if (ret) { + clk_disable_unprepare(ostm_clk); + iounmap(ostm->base); + kfree(ostm); + return ret; + } + + return 0; +} + +CLOCKSOURCE_OF_DECLARE(ostm, "renesas,ostm", ostm_init); diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c index d4ca9962a759..745844ee973e 100644 --- a/drivers/clocksource/tcb_clksrc.c +++ b/drivers/clocksource/tcb_clksrc.c @@ -10,6 +10,7 @@ #include <linux/io.h> #include <linux/platform_device.h> #include <linux/atmel_tc.h> +#include <linux/sched_clock.h> /* @@ -56,11 +57,16 @@ static u64 tc_get_cycles(struct clocksource *cs) return (upper << 16) | lower; } -static u64 tc_get_cycles32(struct clocksource *cs) +static u32 tc_get_cv32(void) { return __raw_readl(tcaddr + ATMEL_TC_REG(0, CV)); } +static u64 tc_get_cycles32(struct clocksource *cs) +{ + return tc_get_cv32(); +} + static struct clocksource clksrc = { .name = "tcb_clksrc", .rating = 200, @@ -69,6 +75,11 @@ static struct clocksource clksrc = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; +static u64 notrace tc_read_sched_clock(void) +{ + return tc_get_cv32(); +} + #ifdef CONFIG_GENERIC_CLOCKEVENTS struct tc_clkevt_device { @@ -339,6 +350,9 @@ static int __init tcb_clksrc_init(void) clksrc.read = tc_get_cycles32; /* setup ony channel 0 */ tcb_setup_single_chan(tc, best_divisor_idx); + + /* register sched_clock on chips with single 32 bit counter */ + sched_clock_register(tc_read_sched_clock, 32, divided_rate); } else { /* tclib will give us three clocks no matter what the * underlying platform supports. diff --git a/drivers/clocksource/timer-gemini.c b/drivers/clocksource/timer-gemini.c new file mode 100644 index 000000000000..dda27b7bf1a1 --- /dev/null +++ b/drivers/clocksource/timer-gemini.c @@ -0,0 +1,277 @@ +/* + * Gemini timer driver + * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> + * + * Based on a rewrite of arch/arm/mach-gemini/timer.c: + * Copyright (C) 2001-2006 Storlink, Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + */ +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/clockchips.h> +#include <linux/clocksource.h> +#include <linux/sched_clock.h> + +/* + * Relevant registers in the global syscon + */ +#define GLOBAL_STATUS 0x04 +#define CPU_AHB_RATIO_MASK (0x3 << 18) +#define CPU_AHB_1_1 (0x0 << 18) +#define CPU_AHB_3_2 (0x1 << 18) +#define CPU_AHB_24_13 (0x2 << 18) +#define CPU_AHB_2_1 (0x3 << 18) +#define REG_TO_AHB_SPEED(reg) ((((reg) >> 15) & 0x7) * 10 + 130) + +/* + * Register definitions for the timers + */ +#define TIMER1_COUNT (0x00) +#define TIMER1_LOAD (0x04) +#define TIMER1_MATCH1 (0x08) +#define TIMER1_MATCH2 (0x0c) +#define TIMER2_COUNT (0x10) +#define TIMER2_LOAD (0x14) +#define TIMER2_MATCH1 (0x18) +#define TIMER2_MATCH2 (0x1c) +#define TIMER3_COUNT (0x20) +#define TIMER3_LOAD (0x24) +#define TIMER3_MATCH1 (0x28) +#define TIMER3_MATCH2 (0x2c) +#define TIMER_CR (0x30) +#define TIMER_INTR_STATE (0x34) +#define TIMER_INTR_MASK (0x38) + +#define TIMER_1_CR_ENABLE (1 << 0) +#define TIMER_1_CR_CLOCK (1 << 1) +#define TIMER_1_CR_INT (1 << 2) +#define TIMER_2_CR_ENABLE (1 << 3) +#define TIMER_2_CR_CLOCK (1 << 4) +#define TIMER_2_CR_INT (1 << 5) +#define TIMER_3_CR_ENABLE (1 << 6) +#define TIMER_3_CR_CLOCK (1 << 7) +#define TIMER_3_CR_INT (1 << 8) +#define TIMER_1_CR_UPDOWN (1 << 9) +#define TIMER_2_CR_UPDOWN (1 << 10) +#define TIMER_3_CR_UPDOWN (1 << 11) +#define TIMER_DEFAULT_FLAGS (TIMER_1_CR_UPDOWN | \ + TIMER_3_CR_ENABLE | \ + TIMER_3_CR_UPDOWN) + +#define TIMER_1_INT_MATCH1 (1 << 0) +#define TIMER_1_INT_MATCH2 (1 << 1) +#define TIMER_1_INT_OVERFLOW (1 << 2) +#define TIMER_2_INT_MATCH1 (1 << 3) +#define TIMER_2_INT_MATCH2 (1 << 4) +#define TIMER_2_INT_OVERFLOW (1 << 5) +#define TIMER_3_INT_MATCH1 (1 << 6) +#define TIMER_3_INT_MATCH2 (1 << 7) +#define TIMER_3_INT_OVERFLOW (1 << 8) +#define TIMER_INT_ALL_MASK 0x1ff + +static unsigned int tick_rate; +static void __iomem *base; + +static u64 notrace gemini_read_sched_clock(void) +{ + return readl(base + TIMER3_COUNT); +} + +static int gemini_timer_set_next_event(unsigned long cycles, + struct clock_event_device *evt) +{ + u32 cr; + + /* Setup the match register */ + cr = readl(base + TIMER1_COUNT); + writel(cr + cycles, base + TIMER1_MATCH1); + if (readl(base + TIMER1_COUNT) - cr > cycles) + return -ETIME; + + return 0; +} + +static int gemini_timer_shutdown(struct clock_event_device *evt) +{ + u32 cr; + + /* + * Disable also for oneshot: the set_next() call will arm the timer + * instead. + */ + /* Stop timer and interrupt. */ + cr = readl(base + TIMER_CR); + cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); + writel(cr, base + TIMER_CR); + + /* Setup counter start from 0 */ + writel(0, base + TIMER1_COUNT); + writel(0, base + TIMER1_LOAD); + + /* enable interrupt */ + cr = readl(base + TIMER_INTR_MASK); + cr &= ~(TIMER_1_INT_OVERFLOW | TIMER_1_INT_MATCH2); + cr |= TIMER_1_INT_MATCH1; + writel(cr, base + TIMER_INTR_MASK); + + /* start the timer */ + cr = readl(base + TIMER_CR); + cr |= TIMER_1_CR_ENABLE; + writel(cr, base + TIMER_CR); + + return 0; +} + +static int gemini_timer_set_periodic(struct clock_event_device *evt) +{ + u32 period = DIV_ROUND_CLOSEST(tick_rate, HZ); + u32 cr; + + /* Stop timer and interrupt */ + cr = readl(base + TIMER_CR); + cr &= ~(TIMER_1_CR_ENABLE | TIMER_1_CR_INT); + writel(cr, base + TIMER_CR); + + /* Setup timer to fire at 1/HT intervals. */ + cr = 0xffffffff - (period - 1); + writel(cr, base + TIMER1_COUNT); + writel(cr, base + TIMER1_LOAD); + + /* enable interrupt on overflow */ + cr = readl(base + TIMER_INTR_MASK); + cr &= ~(TIMER_1_INT_MATCH1 | TIMER_1_INT_MATCH2); + cr |= TIMER_1_INT_OVERFLOW; + writel(cr, base + TIMER_INTR_MASK); + + /* Start the timer */ + cr = readl(base + TIMER_CR); + cr |= TIMER_1_CR_ENABLE; + cr |= TIMER_1_CR_INT; + writel(cr, base + TIMER_CR); + + return 0; +} + +/* Use TIMER1 as clock event */ +static struct clock_event_device gemini_clockevent = { + .name = "TIMER1", + /* Reasonably fast and accurate clock event */ + .rating = 300, + .shift = 32, + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = gemini_timer_set_next_event, + .set_state_shutdown = gemini_timer_shutdown, + .set_state_periodic = gemini_timer_set_periodic, + .set_state_oneshot = gemini_timer_shutdown, + .tick_resume = gemini_timer_shutdown, +}; + +/* + * IRQ handler for the timer + */ +static irqreturn_t gemini_timer_interrupt(int irq, void *dev_id) +{ + struct clock_event_device *evt = &gemini_clockevent; + + evt->event_handler(evt); + return IRQ_HANDLED; +} + +static struct irqaction gemini_timer_irq = { + .name = "Gemini Timer Tick", + .flags = IRQF_TIMER, + .handler = gemini_timer_interrupt, +}; + +static int __init gemini_timer_of_init(struct device_node *np) +{ + static struct regmap *map; + int irq; + int ret; + u32 val; + + map = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(map)) { + pr_err("Can't get regmap for syscon handle"); + return -ENODEV; + } + ret = regmap_read(map, GLOBAL_STATUS, &val); + if (ret) { + pr_err("Can't read syscon status register"); + return -ENXIO; + } + + base = of_iomap(np, 0); + if (!base) { + pr_err("Can't remap registers"); + return -ENXIO; + } + /* IRQ for timer 1 */ + irq = irq_of_parse_and_map(np, 0); + if (irq <= 0) { + pr_err("Can't parse IRQ"); + return -EINVAL; + } + + tick_rate = REG_TO_AHB_SPEED(val) * 1000000; + printk(KERN_INFO "Bus: %dMHz", tick_rate / 1000000); + + tick_rate /= 6; /* APB bus run AHB*(1/6) */ + + switch (val & CPU_AHB_RATIO_MASK) { + case CPU_AHB_1_1: + printk(KERN_CONT "(1/1)\n"); + break; + case CPU_AHB_3_2: + printk(KERN_CONT "(3/2)\n"); + break; + case CPU_AHB_24_13: + printk(KERN_CONT "(24/13)\n"); + break; + case CPU_AHB_2_1: + printk(KERN_CONT "(2/1)\n"); + break; + } + + /* + * Reset the interrupt mask and status + */ + writel(TIMER_INT_ALL_MASK, base + TIMER_INTR_MASK); + writel(0, base + TIMER_INTR_STATE); + writel(TIMER_DEFAULT_FLAGS, base + TIMER_CR); + + /* + * Setup free-running clocksource timer (interrupts + * disabled.) + */ + writel(0, base + TIMER3_COUNT); + writel(0, base + TIMER3_LOAD); + writel(0, base + TIMER3_MATCH1); + writel(0, base + TIMER3_MATCH2); + clocksource_mmio_init(base + TIMER3_COUNT, + "gemini_clocksource", tick_rate, + 300, 32, clocksource_mmio_readl_up); + sched_clock_register(gemini_read_sched_clock, 32, tick_rate); + + /* + * Setup clockevent timer (interrupt-driven.) + */ + writel(0, base + TIMER1_COUNT); + writel(0, base + TIMER1_LOAD); + writel(0, base + TIMER1_MATCH1); + writel(0, base + TIMER1_MATCH2); + setup_irq(irq, &gemini_timer_irq); + gemini_clockevent.cpumask = cpumask_of(0); + clockevents_config_and_register(&gemini_clockevent, tick_rate, + 1, 0xffffffff); + + return 0; +} +CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "cortina,gemini-timer", + gemini_timer_of_init); diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index d8b164a7c4e5..4ebae43118ef 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -37,14 +37,6 @@ config CPU_FREQ_STAT If in doubt, say N. -config CPU_FREQ_STAT_DETAILS - bool "CPU frequency transition statistics details" - depends on CPU_FREQ_STAT - help - Show detailed CPU frequency transition table in sysfs. - - If in doubt, say N. - choice prompt "Default CPUFreq governor" default CPU_FREQ_DEFAULT_GOV_USERSPACE if ARM_SA1100_CPUFREQ || ARM_SA1110_CPUFREQ @@ -271,6 +263,16 @@ config IA64_ACPI_CPUFREQ endif if MIPS +config BMIPS_CPUFREQ + tristate "BMIPS CPUfreq Driver" + help + This option adds a CPUfreq driver for BMIPS processors with + support for configurable CPU frequency. + + For now, BMIPS5 chips are supported (such as the Broadcom 7425). + + If in doubt, say N. + config LOONGSON2_CPUFREQ tristate "Loongson2 CPUFreq Driver" help @@ -332,7 +334,7 @@ endif config QORIQ_CPUFREQ tristate "CPU frequency scaling driver for Freescale QorIQ SoCs" - depends on OF && COMMON_CLK && (PPC_E500MC || ARM) + depends on OF && COMMON_CLK && (PPC_E500MC || ARM || ARM64) depends on !CPU_THERMAL || THERMAL select CLK_QORIQ help diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 920c469f3953..74fa5c5904d3 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -247,6 +247,17 @@ config ARM_TEGRA124_CPUFREQ help This adds the CPUFreq driver support for Tegra124 SOCs. +config ARM_TI_CPUFREQ + bool "Texas Instruments CPUFreq support" + depends on ARCH_OMAP2PLUS + help + This driver enables valid OPPs on the running platform based on + values contained within the SoC in use. Enable this in order to + use the cpufreq-dt driver on all Texas Instruments platforms that + provide dt based operating-points-v2 tables with opp-supported-hw + data provided. Required for cpufreq support on AM335x, AM437x, + DRA7x, and AM57x platforms. + config ARM_PXA2xx_CPUFREQ tristate "Intel PXA2xx CPUfreq driver" depends on PXA27x || PXA25x @@ -257,7 +268,7 @@ config ARM_PXA2xx_CPUFREQ config ACPI_CPPC_CPUFREQ tristate "CPUFreq driver based on the ACPI CPPC spec" - depends on ACPI + depends on ACPI_PROCESSOR select ACPI_CPPC_LIB default n help diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 1e46c3918e7a..9f5a8045f36d 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -77,6 +77,7 @@ obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o obj-$(CONFIG_ARM_STI_CPUFREQ) += sti-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o +obj-$(CONFIG_ARM_TI_CPUFREQ) += ti-cpufreq.o obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ) += vexpress-spc-cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o @@ -98,6 +99,7 @@ obj-$(CONFIG_POWERNV_CPUFREQ) += powernv-cpufreq.o # Other platform drivers obj-$(CONFIG_AVR32_AT32AP_CPUFREQ) += at32ap-cpufreq.o obj-$(CONFIG_BFIN_CPU_FREQ) += blackfin-cpufreq.o +obj-$(CONFIG_BMIPS_CPUFREQ) += bmips-cpufreq.o obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o diff --git a/drivers/cpufreq/bmips-cpufreq.c b/drivers/cpufreq/bmips-cpufreq.c new file mode 100644 index 000000000000..1653151b77df --- /dev/null +++ b/drivers/cpufreq/bmips-cpufreq.c @@ -0,0 +1,188 @@ +/* + * CPU frequency scaling for Broadcom BMIPS SoCs + * + * Copyright (c) 2017 Broadcom + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/cpufreq.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/slab.h> + +/* for mips_hpt_frequency */ +#include <asm/time.h> + +#define BMIPS_CPUFREQ_PREFIX "bmips" +#define BMIPS_CPUFREQ_NAME BMIPS_CPUFREQ_PREFIX "-cpufreq" + +#define TRANSITION_LATENCY (25 * 1000) /* 25 us */ + +#define BMIPS5_CLK_DIV_SET_SHIFT 0x7 +#define BMIPS5_CLK_DIV_SHIFT 0x4 +#define BMIPS5_CLK_DIV_MASK 0xf + +enum bmips_type { + BMIPS5000, + BMIPS5200, +}; + +struct cpufreq_compat { + const char *compatible; + unsigned int bmips_type; + unsigned int clk_mult; + unsigned int max_freqs; +}; + +#define BMIPS(c, t, m, f) { \ + .compatible = c, \ + .bmips_type = (t), \ + .clk_mult = (m), \ + .max_freqs = (f), \ +} + +static struct cpufreq_compat bmips_cpufreq_compat[] = { + BMIPS("brcm,bmips5000", BMIPS5000, 8, 4), + BMIPS("brcm,bmips5200", BMIPS5200, 8, 4), + { } +}; + +static struct cpufreq_compat *priv; + +static int htp_freq_to_cpu_freq(unsigned int clk_mult) +{ + return mips_hpt_frequency * clk_mult / 1000; +} + +static struct cpufreq_frequency_table * +bmips_cpufreq_get_freq_table(const struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *table; + unsigned long cpu_freq; + int i; + + cpu_freq = htp_freq_to_cpu_freq(priv->clk_mult); + + table = kmalloc((priv->max_freqs + 1) * sizeof(*table), GFP_KERNEL); + if (!table) + return ERR_PTR(-ENOMEM); + + for (i = 0; i < priv->max_freqs; i++) { + table[i].frequency = cpu_freq / (1 << i); + table[i].driver_data = i; + } + table[i].frequency = CPUFREQ_TABLE_END; + + return table; +} + +static unsigned int bmips_cpufreq_get(unsigned int cpu) +{ + unsigned int div; + uint32_t mode; + + switch (priv->bmips_type) { + case BMIPS5200: + case BMIPS5000: + mode = read_c0_brcm_mode(); + div = ((mode >> BMIPS5_CLK_DIV_SHIFT) & BMIPS5_CLK_DIV_MASK); + break; + default: + div = 0; + } + + return htp_freq_to_cpu_freq(priv->clk_mult) / (1 << div); +} + +static int bmips_cpufreq_target_index(struct cpufreq_policy *policy, + unsigned int index) +{ + unsigned int div = policy->freq_table[index].driver_data; + + switch (priv->bmips_type) { + case BMIPS5200: + case BMIPS5000: + change_c0_brcm_mode(BMIPS5_CLK_DIV_MASK << BMIPS5_CLK_DIV_SHIFT, + (1 << BMIPS5_CLK_DIV_SET_SHIFT) | + (div << BMIPS5_CLK_DIV_SHIFT)); + break; + default: + return -ENOTSUPP; + } + + return 0; +} + +static int bmips_cpufreq_exit(struct cpufreq_policy *policy) +{ + kfree(policy->freq_table); + + return 0; +} + +static int bmips_cpufreq_init(struct cpufreq_policy *policy) +{ + struct cpufreq_frequency_table *freq_table; + int ret; + + freq_table = bmips_cpufreq_get_freq_table(policy); + if (IS_ERR(freq_table)) { + ret = PTR_ERR(freq_table); + pr_err("%s: couldn't determine frequency table (%d).\n", + BMIPS_CPUFREQ_NAME, ret); + return ret; + } + + ret = cpufreq_generic_init(policy, freq_table, TRANSITION_LATENCY); + if (ret) + bmips_cpufreq_exit(policy); + else + pr_info("%s: registered\n", BMIPS_CPUFREQ_NAME); + + return ret; +} + +static struct cpufreq_driver bmips_cpufreq_driver = { + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = bmips_cpufreq_target_index, + .get = bmips_cpufreq_get, + .init = bmips_cpufreq_init, + .exit = bmips_cpufreq_exit, + .attr = cpufreq_generic_attr, + .name = BMIPS_CPUFREQ_PREFIX, +}; + +static int __init bmips_cpufreq_probe(void) +{ + struct cpufreq_compat *cc; + struct device_node *np; + + for (cc = bmips_cpufreq_compat; cc->compatible; cc++) { + np = of_find_compatible_node(NULL, "cpu", cc->compatible); + if (np) { + of_node_put(np); + priv = cc; + break; + } + } + + /* We hit the guard element of the array. No compatible CPU found. */ + if (!cc->compatible) + return -ENODEV; + + return cpufreq_register_driver(&bmips_cpufreq_driver); +} +device_initcall(bmips_cpufreq_probe); + +MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>"); +MODULE_DESCRIPTION("CPUfreq driver for Broadcom BMIPS SoCs"); +MODULE_LICENSE("GPL"); diff --git a/drivers/cpufreq/brcmstb-avs-cpufreq.c b/drivers/cpufreq/brcmstb-avs-cpufreq.c index 4fda623e55bb..7281a2c19c36 100644 --- a/drivers/cpufreq/brcmstb-avs-cpufreq.c +++ b/drivers/cpufreq/brcmstb-avs-cpufreq.c @@ -784,8 +784,19 @@ static int brcm_avs_target_index(struct cpufreq_policy *policy, static int brcm_avs_suspend(struct cpufreq_policy *policy) { struct private_data *priv = policy->driver_data; + int ret; + + ret = brcm_avs_get_pmap(priv, &priv->pmap); + if (ret) + return ret; - return brcm_avs_get_pmap(priv, &priv->pmap); + /* + * We can't use the P-state returned by brcm_avs_get_pmap(), since + * that's the initial P-state from when the P-map was downloaded to the + * AVS co-processor, not necessarily the P-state we are running at now. + * So, we get the current P-state explicitly. + */ + return brcm_avs_get_pstate(priv, &priv->pmap.state); } static int brcm_avs_resume(struct cpufreq_policy *policy) @@ -867,7 +878,6 @@ unmap_intr_base: iounmap(priv->avs_intr_base); unmap_base: iounmap(priv->base); - platform_set_drvdata(pdev, NULL); return ret; } @@ -954,9 +964,9 @@ static ssize_t show_brcm_avs_pmap(struct cpufreq_policy *policy, char *buf) brcm_avs_parse_p1(pmap.p1, &mdiv_p0, &pdiv, &ndiv); brcm_avs_parse_p2(pmap.p2, &mdiv_p1, &mdiv_p2, &mdiv_p3, &mdiv_p4); - return sprintf(buf, "0x%08x 0x%08x %u %u %u %u %u %u %u\n", + return sprintf(buf, "0x%08x 0x%08x %u %u %u %u %u %u %u %u %u\n", pmap.p1, pmap.p2, ndiv, pdiv, mdiv_p0, mdiv_p1, mdiv_p2, - mdiv_p3, mdiv_p4); + mdiv_p3, mdiv_p4, pmap.mode, pmap.state); } static ssize_t show_brcm_avs_voltage(struct cpufreq_policy *policy, char *buf) @@ -1031,7 +1041,6 @@ static int brcm_avs_cpufreq_remove(struct platform_device *pdev) priv = platform_get_drvdata(pdev); iounmap(priv->base); iounmap(priv->avs_intr_base); - platform_set_drvdata(pdev, NULL); return 0; } diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index bc97b6a4b1cf..921b4a6c3d16 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -26,6 +26,8 @@ static const struct of_device_id machines[] __initconst = { { .compatible = "allwinner,sun8i-a83t", }, { .compatible = "allwinner,sun8i-h3", }, + { .compatible = "apm,xgene-shadowcat", }, + { .compatible = "arm,integrator-ap", }, { .compatible = "arm,integrator-cp", }, @@ -85,8 +87,6 @@ static const struct of_device_id machines[] __initconst = { { .compatible = "socionext,uniphier-ld11", }, { .compatible = "socionext,uniphier-ld20", }, - { .compatible = "ti,am33xx", }, - { .compatible = "ti,dra7", }, { .compatible = "ti,omap2", }, { .compatible = "ti,omap3", }, { .compatible = "ti,omap4", }, diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 269013311e79..c943787d761e 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -148,7 +148,6 @@ static int cpufreq_init(struct cpufreq_policy *policy) struct private_data *priv; struct device *cpu_dev; struct clk *cpu_clk; - struct dev_pm_opp *suspend_opp; unsigned int transition_latency; bool fallback = false; const char *name; @@ -252,11 +251,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) policy->driver_data = priv; policy->clk = cpu_clk; - rcu_read_lock(); - suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev); - if (suspend_opp) - policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000; - rcu_read_unlock(); + policy->suspend_freq = dev_pm_opp_get_suspend_opp_freq(cpu_dev) / 1000; ret = cpufreq_table_validate_and_show(policy, freq_table); if (ret) { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index cc475eff90b3..a47543281864 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -132,7 +132,7 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) u64 cur_wall_time; u64 busy_time; - cur_wall_time = jiffies64_to_cputime64(get_jiffies_64()); + cur_wall_time = jiffies64_to_nsecs(get_jiffies_64()); busy_time = kcpustat_cpu(cpu).cpustat[CPUTIME_USER]; busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM]; @@ -143,9 +143,9 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall) idle_time = cur_wall_time - busy_time; if (wall) - *wall = cputime_to_usecs(cur_wall_time); + *wall = div_u64(cur_wall_time, NSEC_PER_USEC); - return cputime_to_usecs(idle_time); + return div_u64(idle_time, NSEC_PER_USEC); } u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy) @@ -1078,15 +1078,11 @@ err_free_policy: return NULL; } -static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify) +static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy) { struct kobject *kobj; struct completion *cmp; - if (notify) - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_REMOVE_POLICY, policy); - down_write(&policy->rwsem); cpufreq_stats_free_table(policy); kobj = &policy->kobj; @@ -1104,7 +1100,7 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify) pr_debug("wait complete\n"); } -static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify) +static void cpufreq_policy_free(struct cpufreq_policy *policy) { unsigned long flags; int cpu; @@ -1117,7 +1113,7 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy, bool notify) per_cpu(cpufreq_cpu_data, cpu) = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - cpufreq_policy_put_kobj(policy, notify); + cpufreq_policy_put_kobj(policy); free_cpumask_var(policy->real_cpus); free_cpumask_var(policy->related_cpus); free_cpumask_var(policy->cpus); @@ -1170,8 +1166,6 @@ static int cpufreq_online(unsigned int cpu) if (new_policy) { /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); - /* Clear mask of registered CPUs */ - cpumask_clear(policy->real_cpus); } /* @@ -1244,17 +1238,12 @@ static int cpufreq_online(unsigned int cpu) goto out_exit_policy; cpufreq_stats_create_table(policy); - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_CREATE_POLICY, policy); write_lock_irqsave(&cpufreq_driver_lock, flags); list_add(&policy->policy_list, &cpufreq_policy_list); write_unlock_irqrestore(&cpufreq_driver_lock, flags); } - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_START, policy); - ret = cpufreq_init_policy(policy); if (ret) { pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", @@ -1282,7 +1271,7 @@ out_exit_policy: if (cpufreq_driver->exit) cpufreq_driver->exit(policy); out_free_policy: - cpufreq_policy_free(policy, !new_policy); + cpufreq_policy_free(policy); return ret; } @@ -1403,7 +1392,7 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif) remove_cpu_dev_symlink(policy, dev); if (cpumask_empty(policy->real_cpus)) - cpufreq_policy_free(policy, true); + cpufreq_policy_free(policy); } /** diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 0196467280bd..631bd2c86c5e 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -152,7 +152,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) if (ignore_nice) { u64 cur_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - idle_time += cputime_to_usecs(cur_nice - j_cdbs->prev_cpu_nice); + idle_time += div_u64(cur_nice - j_cdbs->prev_cpu_nice, NSEC_PER_USEC); j_cdbs->prev_cpu_nice = cur_nice; } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index ac284e66839c..f570ead62454 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -13,7 +13,6 @@ #include <linux/cpufreq.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/cputime.h> static DEFINE_SPINLOCK(cpufreq_stats_lock); @@ -25,9 +24,7 @@ struct cpufreq_stats { unsigned int last_index; u64 *time_in_state; unsigned int *freq_table; -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS unsigned int *trans_table; -#endif }; static int cpufreq_stats_update(struct cpufreq_stats *stats) @@ -46,9 +43,7 @@ static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) unsigned int count = stats->max_state; memset(stats->time_in_state, 0, count * sizeof(u64)); -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS memset(stats->trans_table, 0, count * count * sizeof(int)); -#endif stats->last_time = get_jiffies_64(); stats->total_trans = 0; } @@ -84,7 +79,6 @@ static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf, return count; } -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) { struct cpufreq_stats *stats = policy->stats; @@ -129,7 +123,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) return len; } cpufreq_freq_attr_ro(trans_table); -#endif cpufreq_freq_attr_ro(total_trans); cpufreq_freq_attr_ro(time_in_state); @@ -139,9 +132,7 @@ static struct attribute *default_attrs[] = { &total_trans.attr, &time_in_state.attr, &reset.attr, -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS &trans_table.attr, -#endif NULL }; static struct attribute_group stats_attr_group = { @@ -200,9 +191,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) alloc_size = count * sizeof(int) + count * sizeof(u64); -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS alloc_size += count * count * sizeof(int); -#endif /* Allocate memory for time_in_state/freq_table/trans_table in one go */ stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL); @@ -211,9 +200,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) stats->freq_table = (unsigned int *)(stats->time_in_state + count); -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS stats->trans_table = stats->freq_table + count; -#endif stats->max_state = count; @@ -259,8 +246,6 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy, cpufreq_stats_update(stats); stats->last_index = new_index; -#ifdef CONFIG_CPU_FREQ_STAT_DETAILS stats->trans_table[old_index * stats->max_state + new_index]++; -#endif stats->total_trans++; } diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c index c0f3373706f4..9180d34cc9fc 100644 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ b/drivers/cpufreq/exynos5440-cpufreq.c @@ -118,12 +118,10 @@ static int init_div_table(void) unsigned int tmp, clk_div, ema_div, freq, volt_id; struct dev_pm_opp *opp; - rcu_read_lock(); cpufreq_for_each_entry(pos, freq_tbl) { opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, pos->frequency * 1000, true); if (IS_ERR(opp)) { - rcu_read_unlock(); dev_err(dvfs_info->dev, "failed to find valid OPP for %u KHZ\n", pos->frequency); @@ -140,6 +138,7 @@ static int init_div_table(void) /* Calculate EMA */ volt_id = dev_pm_opp_get_voltage(opp); + volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP; if (volt_id < PMIC_HIGH_VOLT) { ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) | @@ -157,9 +156,9 @@ static int init_div_table(void) __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * (pos - freq_tbl)); + dev_pm_opp_put(opp); } - rcu_read_unlock(); return 0; } diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c index ef1fa8145419..7719b02e04f5 100644 --- a/drivers/cpufreq/imx6q-cpufreq.c +++ b/drivers/cpufreq/imx6q-cpufreq.c @@ -53,16 +53,15 @@ static int imx6q_set_target(struct cpufreq_policy *policy, unsigned int index) freq_hz = new_freq * 1000; old_freq = clk_get_rate(arm_clk) / 1000; - rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { - rcu_read_unlock(); dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz); return PTR_ERR(opp); } volt = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); + volt_old = regulator_get_voltage(arm_reg); dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n", @@ -321,14 +320,15 @@ soc_opp_out: * freq_table initialised from OPP is therefore sorted in the * same order. */ - rcu_read_lock(); opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[0].frequency * 1000, true); min_volt = dev_pm_opp_get_voltage(opp); + dev_pm_opp_put(opp); opp = dev_pm_opp_find_freq_exact(cpu_dev, freq_table[--num].frequency * 1000, true); max_volt = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); + ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt); if (ret > 0) transition_latency += ret * 1000; diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 6acbd4af632e..eb0f7fb71685 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -358,6 +358,8 @@ static struct pstate_funcs pstate_funcs __read_mostly; static int hwp_active __read_mostly; static bool per_cpu_limits __read_mostly; +static bool driver_registered __read_mostly; + #ifdef CONFIG_ACPI static bool acpi_ppc; #endif @@ -394,6 +396,7 @@ static struct perf_limits *limits = &performance_limits; static struct perf_limits *limits = &powersave_limits; #endif +static DEFINE_MUTEX(intel_pstate_driver_lock); static DEFINE_MUTEX(intel_pstate_limits_lock); #ifdef CONFIG_ACPI @@ -538,7 +541,6 @@ static void intel_pstate_exit_perf_limits(struct cpufreq_policy *policy) acpi_processor_unregister_performance(policy->cpu); } - #else static inline void intel_pstate_init_acpi_perf_limits(struct cpufreq_policy *policy) { @@ -857,13 +859,13 @@ static struct freq_attr *hwp_cpufreq_attrs[] = { NULL, }; -static void intel_pstate_hwp_set(const struct cpumask *cpumask) +static void intel_pstate_hwp_set(struct cpufreq_policy *policy) { int min, hw_min, max, hw_max, cpu, range, adj_range; struct perf_limits *perf_limits = limits; u64 value, cap; - for_each_cpu(cpu, cpumask) { + for_each_cpu(cpu, policy->cpus) { int max_perf_pct, min_perf_pct; struct cpudata *cpu_data = all_cpu_data[cpu]; s16 epp; @@ -873,7 +875,10 @@ static void intel_pstate_hwp_set(const struct cpumask *cpumask) rdmsrl_on_cpu(cpu, MSR_HWP_CAPABILITIES, &cap); hw_min = HWP_LOWEST_PERF(cap); - hw_max = HWP_HIGHEST_PERF(cap); + if (limits->no_turbo) + hw_max = HWP_GUARANTEED_PERF(cap); + else + hw_max = HWP_HIGHEST_PERF(cap); range = hw_max - hw_min; max_perf_pct = perf_limits->max_perf_pct; @@ -887,11 +892,6 @@ static void intel_pstate_hwp_set(const struct cpumask *cpumask) adj_range = max_perf_pct * range / 100; max = hw_min + adj_range; - if (limits->no_turbo) { - hw_max = HWP_GUARANTEED_PERF(cap); - if (hw_max < max) - max = hw_max; - } value &= ~HWP_MAX_PERF(~0L); value |= HWP_MAX_PERF(max); @@ -949,7 +949,7 @@ skip_epp: static int intel_pstate_hwp_set_policy(struct cpufreq_policy *policy) { if (hwp_active) - intel_pstate_hwp_set(policy->cpus); + intel_pstate_hwp_set(policy); return 0; } @@ -968,19 +968,28 @@ static int intel_pstate_hwp_save_state(struct cpufreq_policy *policy) static int intel_pstate_resume(struct cpufreq_policy *policy) { + int ret; + if (!hwp_active) return 0; + mutex_lock(&intel_pstate_limits_lock); + all_cpu_data[policy->cpu]->epp_policy = 0; - return intel_pstate_hwp_set_policy(policy); + ret = intel_pstate_hwp_set_policy(policy); + + mutex_unlock(&intel_pstate_limits_lock); + + return ret; } -static void intel_pstate_hwp_set_online_cpus(void) +static void intel_pstate_update_policies(void) { - get_online_cpus(); - intel_pstate_hwp_set(cpu_online_mask); - put_online_cpus(); + int cpu; + + for_each_possible_cpu(cpu) + cpufreq_update_policy(cpu); } /************************** debugfs begin ************************/ @@ -998,39 +1007,57 @@ static int pid_param_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(fops_pid_param, pid_param_get, pid_param_set, "%llu\n"); +static struct dentry *debugfs_parent; + struct pid_param { char *name; void *value; + struct dentry *dentry; }; static struct pid_param pid_files[] = { - {"sample_rate_ms", &pid_params.sample_rate_ms}, - {"d_gain_pct", &pid_params.d_gain_pct}, - {"i_gain_pct", &pid_params.i_gain_pct}, - {"deadband", &pid_params.deadband}, - {"setpoint", &pid_params.setpoint}, - {"p_gain_pct", &pid_params.p_gain_pct}, - {NULL, NULL} + {"sample_rate_ms", &pid_params.sample_rate_ms, }, + {"d_gain_pct", &pid_params.d_gain_pct, }, + {"i_gain_pct", &pid_params.i_gain_pct, }, + {"deadband", &pid_params.deadband, }, + {"setpoint", &pid_params.setpoint, }, + {"p_gain_pct", &pid_params.p_gain_pct, }, + {NULL, NULL, } }; -static void __init intel_pstate_debug_expose_params(void) +static void intel_pstate_debug_expose_params(void) { - struct dentry *debugfs_parent; - int i = 0; + int i; - if (hwp_active || - pstate_funcs.get_target_pstate == get_target_pstate_use_cpu_load) + debugfs_parent = debugfs_create_dir("pstate_snb", NULL); + if (IS_ERR_OR_NULL(debugfs_parent)) return; - debugfs_parent = debugfs_create_dir("pstate_snb", NULL); + for (i = 0; pid_files[i].name; i++) { + struct dentry *dentry; + + dentry = debugfs_create_file(pid_files[i].name, 0660, + debugfs_parent, pid_files[i].value, + &fops_pid_param); + if (!IS_ERR(dentry)) + pid_files[i].dentry = dentry; + } +} + +static void intel_pstate_debug_hide_params(void) +{ + int i; + if (IS_ERR_OR_NULL(debugfs_parent)) return; - while (pid_files[i].name) { - debugfs_create_file(pid_files[i].name, 0660, - debugfs_parent, pid_files[i].value, - &fops_pid_param); - i++; + + for (i = 0; pid_files[i].name; i++) { + debugfs_remove(pid_files[i].dentry); + pid_files[i].dentry = NULL; } + + debugfs_remove(debugfs_parent); + debugfs_parent = NULL; } /************************** debugfs end ************************/ @@ -1043,6 +1070,34 @@ static void __init intel_pstate_debug_expose_params(void) return sprintf(buf, "%u\n", limits->object); \ } +static ssize_t intel_pstate_show_status(char *buf); +static int intel_pstate_update_status(const char *buf, size_t size); + +static ssize_t show_status(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + ssize_t ret; + + mutex_lock(&intel_pstate_driver_lock); + ret = intel_pstate_show_status(buf); + mutex_unlock(&intel_pstate_driver_lock); + + return ret; +} + +static ssize_t store_status(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + char *p = memchr(buf, '\n', count); + int ret; + + mutex_lock(&intel_pstate_driver_lock); + ret = intel_pstate_update_status(buf, p ? p - buf : count); + mutex_unlock(&intel_pstate_driver_lock); + + return ret < 0 ? ret : count; +} + static ssize_t show_turbo_pct(struct kobject *kobj, struct attribute *attr, char *buf) { @@ -1050,12 +1105,22 @@ static ssize_t show_turbo_pct(struct kobject *kobj, int total, no_turbo, turbo_pct; uint32_t turbo_fp; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + cpu = all_cpu_data[0]; total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1; turbo_fp = div_fp(no_turbo, total); turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100))); + + mutex_unlock(&intel_pstate_driver_lock); + return sprintf(buf, "%u\n", turbo_pct); } @@ -1065,8 +1130,18 @@ static ssize_t show_num_pstates(struct kobject *kobj, struct cpudata *cpu; int total; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + cpu = all_cpu_data[0]; total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1; + + mutex_unlock(&intel_pstate_driver_lock); + return sprintf(buf, "%u\n", total); } @@ -1075,12 +1150,21 @@ static ssize_t show_no_turbo(struct kobject *kobj, { ssize_t ret; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + update_turbo_state(); if (limits->turbo_disabled) ret = sprintf(buf, "%u\n", limits->turbo_disabled); else ret = sprintf(buf, "%u\n", limits->no_turbo); + mutex_unlock(&intel_pstate_driver_lock); + return ret; } @@ -1094,22 +1178,31 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + mutex_lock(&intel_pstate_limits_lock); update_turbo_state(); if (limits->turbo_disabled) { pr_warn("Turbo disabled by BIOS or unavailable on processor\n"); mutex_unlock(&intel_pstate_limits_lock); + mutex_unlock(&intel_pstate_driver_lock); return -EPERM; } limits->no_turbo = clamp_t(int, input, 0, 1); - if (hwp_active) - intel_pstate_hwp_set_online_cpus(); - mutex_unlock(&intel_pstate_limits_lock); + intel_pstate_update_policies(); + + mutex_unlock(&intel_pstate_driver_lock); + return count; } @@ -1123,6 +1216,13 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + mutex_lock(&intel_pstate_limits_lock); limits->max_sysfs_pct = clamp_t(int, input, 0 , 100); @@ -1134,11 +1234,12 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, limits->max_perf_pct); limits->max_perf = div_ext_fp(limits->max_perf_pct, 100); - if (hwp_active) - intel_pstate_hwp_set_online_cpus(); - mutex_unlock(&intel_pstate_limits_lock); + intel_pstate_update_policies(); + + mutex_unlock(&intel_pstate_driver_lock); + return count; } @@ -1152,6 +1253,13 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, if (ret != 1) return -EINVAL; + mutex_lock(&intel_pstate_driver_lock); + + if (!driver_registered) { + mutex_unlock(&intel_pstate_driver_lock); + return -EAGAIN; + } + mutex_lock(&intel_pstate_limits_lock); limits->min_sysfs_pct = clamp_t(int, input, 0 , 100); @@ -1163,17 +1271,19 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, limits->min_perf_pct); limits->min_perf = div_ext_fp(limits->min_perf_pct, 100); - if (hwp_active) - intel_pstate_hwp_set_online_cpus(); - mutex_unlock(&intel_pstate_limits_lock); + intel_pstate_update_policies(); + + mutex_unlock(&intel_pstate_driver_lock); + return count; } show_one(max_perf_pct, max_perf_pct); show_one(min_perf_pct, min_perf_pct); +define_one_global_rw(status); define_one_global_rw(no_turbo); define_one_global_rw(max_perf_pct); define_one_global_rw(min_perf_pct); @@ -1181,6 +1291,7 @@ define_one_global_ro(turbo_pct); define_one_global_ro(num_pstates); static struct attribute *intel_pstate_attributes[] = { + &status.attr, &no_turbo.attr, &turbo_pct.attr, &num_pstates.attr, @@ -1233,6 +1344,25 @@ static void intel_pstate_hwp_enable(struct cpudata *cpudata) cpudata->epp_default = intel_pstate_get_epp(cpudata, 0); } +#define MSR_IA32_POWER_CTL_BIT_EE 19 + +/* Disable energy efficiency optimization */ +static void intel_pstate_disable_ee(int cpu) +{ + u64 power_ctl; + int ret; + + ret = rdmsrl_on_cpu(cpu, MSR_IA32_POWER_CTL, &power_ctl); + if (ret) + return; + + if (!(power_ctl & BIT(MSR_IA32_POWER_CTL_BIT_EE))) { + pr_info("Disabling energy efficiency optimization\n"); + power_ctl |= BIT(MSR_IA32_POWER_CTL_BIT_EE); + wrmsrl_on_cpu(cpu, MSR_IA32_POWER_CTL, power_ctl); + } +} + static int atom_get_min_pstate(void) { u64 value; @@ -1343,48 +1473,71 @@ static int core_get_max_pstate_physical(void) return (value >> 8) & 0xFF; } +static int core_get_tdp_ratio(u64 plat_info) +{ + /* Check how many TDP levels present */ + if (plat_info & 0x600000000) { + u64 tdp_ctrl; + u64 tdp_ratio; + int tdp_msr; + int err; + + /* Get the TDP level (0, 1, 2) to get ratios */ + err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl); + if (err) + return err; + + /* TDP MSR are continuous starting at 0x648 */ + tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x03); + err = rdmsrl_safe(tdp_msr, &tdp_ratio); + if (err) + return err; + + /* For level 1 and 2, bits[23:16] contain the ratio */ + if (tdp_ctrl & 0x03) + tdp_ratio >>= 16; + + tdp_ratio &= 0xff; /* ratios are only 8 bits long */ + pr_debug("tdp_ratio %x\n", (int)tdp_ratio); + + return (int)tdp_ratio; + } + + return -ENXIO; +} + static int core_get_max_pstate(void) { u64 tar; u64 plat_info; int max_pstate; + int tdp_ratio; int err; rdmsrl(MSR_PLATFORM_INFO, plat_info); max_pstate = (plat_info >> 8) & 0xFF; + tdp_ratio = core_get_tdp_ratio(plat_info); + if (tdp_ratio <= 0) + return max_pstate; + + if (hwp_active) { + /* Turbo activation ratio is not used on HWP platforms */ + return tdp_ratio; + } + err = rdmsrl_safe(MSR_TURBO_ACTIVATION_RATIO, &tar); if (!err) { + int tar_levels; + /* Do some sanity checking for safety */ - if (plat_info & 0x600000000) { - u64 tdp_ctrl; - u64 tdp_ratio; - int tdp_msr; - - err = rdmsrl_safe(MSR_CONFIG_TDP_CONTROL, &tdp_ctrl); - if (err) - goto skip_tar; - - tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x3); - err = rdmsrl_safe(tdp_msr, &tdp_ratio); - if (err) - goto skip_tar; - - /* For level 1 and 2, bits[23:16] contain the ratio */ - if (tdp_ctrl) - tdp_ratio >>= 16; - - tdp_ratio &= 0xff; /* ratios are only 8 bits long */ - if (tdp_ratio - 1 == tar) { - max_pstate = tar; - pr_debug("max_pstate=TAC %x\n", max_pstate); - } else { - goto skip_tar; - } + tar_levels = tar & 0xff; + if (tdp_ratio - 1 == tar_levels) { + max_pstate = tar_levels; + pr_debug("max_pstate=TAC %x\n", max_pstate); } } -skip_tar: return max_pstate; } @@ -1843,6 +1996,11 @@ static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = { {} }; +static const struct x86_cpu_id intel_pstate_cpu_ee_disable_ids[] = { + ICPU(INTEL_FAM6_KABYLAKE_DESKTOP, core_params), + {} +}; + static int intel_pstate_init_cpu(unsigned int cpunum) { struct cpudata *cpu; @@ -1873,6 +2031,12 @@ static int intel_pstate_init_cpu(unsigned int cpunum) cpu->cpu = cpunum; if (hwp_active) { + const struct x86_cpu_id *id; + + id = x86_match_cpu(intel_pstate_cpu_ee_disable_ids); + if (id) + intel_pstate_disable_ee(cpunum); + intel_pstate_hwp_enable(cpu); pid_params.sample_rate_ms = 50; pid_params.sample_rate_ns = 50 * NSEC_PER_MSEC; @@ -2003,7 +2167,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits = &performance_limits; perf_limits = limits; } - if (policy->max >= policy->cpuinfo.max_freq) { + if (policy->max >= policy->cpuinfo.max_freq && + !limits->no_turbo) { pr_debug("set performance\n"); intel_pstate_set_performance_limits(perf_limits); goto out; @@ -2039,12 +2204,37 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) static int intel_pstate_verify_policy(struct cpufreq_policy *policy) { + struct cpudata *cpu = all_cpu_data[policy->cpu]; + struct perf_limits *perf_limits; + + if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) + perf_limits = &performance_limits; + else + perf_limits = &powersave_limits; + + update_turbo_state(); + policy->cpuinfo.max_freq = perf_limits->turbo_disabled || + perf_limits->no_turbo ? + cpu->pstate.max_freq : + cpu->pstate.turbo_freq; + cpufreq_verify_within_cpu_limits(policy); if (policy->policy != CPUFREQ_POLICY_POWERSAVE && policy->policy != CPUFREQ_POLICY_PERFORMANCE) return -EINVAL; + /* When per-CPU limits are used, sysfs limits are not used */ + if (!per_cpu_limits) { + unsigned int max_freq, min_freq; + + max_freq = policy->cpuinfo.max_freq * + limits->max_sysfs_pct / 100; + min_freq = policy->cpuinfo.max_freq * + limits->min_sysfs_pct / 100; + cpufreq_verify_within_limits(policy, min_freq, max_freq); + } + return 0; } @@ -2153,8 +2343,12 @@ static int intel_cpufreq_verify_policy(struct cpufreq_policy *policy) if (per_cpu_limits) perf_limits = cpu->perf_limits; + mutex_lock(&intel_pstate_limits_lock); + intel_pstate_update_perf_limits(policy, perf_limits); + mutex_unlock(&intel_pstate_limits_lock); + return 0; } @@ -2251,6 +2445,111 @@ static struct cpufreq_driver intel_cpufreq = { static struct cpufreq_driver *intel_pstate_driver = &intel_pstate; +static void intel_pstate_driver_cleanup(void) +{ + unsigned int cpu; + + get_online_cpus(); + for_each_online_cpu(cpu) { + if (all_cpu_data[cpu]) { + if (intel_pstate_driver == &intel_pstate) + intel_pstate_clear_update_util_hook(cpu); + + kfree(all_cpu_data[cpu]); + all_cpu_data[cpu] = NULL; + } + } + put_online_cpus(); +} + +static int intel_pstate_register_driver(void) +{ + int ret; + + ret = cpufreq_register_driver(intel_pstate_driver); + if (ret) { + intel_pstate_driver_cleanup(); + return ret; + } + + mutex_lock(&intel_pstate_limits_lock); + driver_registered = true; + mutex_unlock(&intel_pstate_limits_lock); + + if (intel_pstate_driver == &intel_pstate && !hwp_active && + pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load) + intel_pstate_debug_expose_params(); + + return 0; +} + +static int intel_pstate_unregister_driver(void) +{ + if (hwp_active) + return -EBUSY; + + if (intel_pstate_driver == &intel_pstate && !hwp_active && + pstate_funcs.get_target_pstate != get_target_pstate_use_cpu_load) + intel_pstate_debug_hide_params(); + + mutex_lock(&intel_pstate_limits_lock); + driver_registered = false; + mutex_unlock(&intel_pstate_limits_lock); + + cpufreq_unregister_driver(intel_pstate_driver); + intel_pstate_driver_cleanup(); + + return 0; +} + +static ssize_t intel_pstate_show_status(char *buf) +{ + if (!driver_registered) + return sprintf(buf, "off\n"); + + return sprintf(buf, "%s\n", intel_pstate_driver == &intel_pstate ? + "active" : "passive"); +} + +static int intel_pstate_update_status(const char *buf, size_t size) +{ + int ret; + + if (size == 3 && !strncmp(buf, "off", size)) + return driver_registered ? + intel_pstate_unregister_driver() : -EINVAL; + + if (size == 6 && !strncmp(buf, "active", size)) { + if (driver_registered) { + if (intel_pstate_driver == &intel_pstate) + return 0; + + ret = intel_pstate_unregister_driver(); + if (ret) + return ret; + } + + intel_pstate_driver = &intel_pstate; + return intel_pstate_register_driver(); + } + + if (size == 7 && !strncmp(buf, "passive", size)) { + if (driver_registered) { + if (intel_pstate_driver != &intel_pstate) + return 0; + + ret = intel_pstate_unregister_driver(); + if (ret) + return ret; + } + + intel_pstate_driver = &intel_cpufreq; + return intel_pstate_register_driver(); + } + + return -EINVAL; +} + static int no_load __initdata; static int no_hwp __initdata; static int hwp_only __initdata; @@ -2438,9 +2737,9 @@ static const struct x86_cpu_id hwp_support_ids[] __initconst = { static int __init intel_pstate_init(void) { - int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_def; + int rc = 0; if (no_load) return -ENODEV; @@ -2472,42 +2771,29 @@ hwp_cpu_matched: if (intel_pstate_platform_pwr_mgmt_exists()) return -ENODEV; + if (!hwp_active && hwp_only) + return -ENOTSUPP; + pr_info("Intel P-state driver initializing\n"); all_cpu_data = vzalloc(sizeof(void *) * num_possible_cpus()); if (!all_cpu_data) return -ENOMEM; - if (!hwp_active && hwp_only) - goto out; - intel_pstate_request_control_from_smm(); - rc = cpufreq_register_driver(intel_pstate_driver); - if (rc) - goto out; - - intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); + mutex_lock(&intel_pstate_driver_lock); + rc = intel_pstate_register_driver(); + mutex_unlock(&intel_pstate_driver_lock); + if (rc) + return rc; + if (hwp_active) pr_info("HWP enabled\n"); - return rc; -out: - get_online_cpus(); - for_each_online_cpu(cpu) { - if (all_cpu_data[cpu]) { - if (intel_pstate_driver == &intel_pstate) - intel_pstate_clear_update_util_hook(cpu); - - kfree(all_cpu_data[cpu]); - } - } - - put_online_cpus(); - vfree(all_cpu_data); - return -ENODEV; + return 0; } device_initcall(intel_pstate_init); diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c index 643f43179df1..ab25b1235a5e 100644 --- a/drivers/cpufreq/mt8173-cpufreq.c +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -232,16 +232,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, freq_hz = freq_table[index].frequency * 1000; - rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); if (IS_ERR(opp)) { - rcu_read_unlock(); pr_err("cpu%d: failed to find OPP for %ld\n", policy->cpu, freq_hz); return PTR_ERR(opp); } vproc = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); /* * If the new voltage or the intermediate voltage is higher than the @@ -411,16 +409,14 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) /* Search a safe voltage for intermediate frequency. */ rate = clk_get_rate(inter_clk); - rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); if (IS_ERR(opp)) { - rcu_read_unlock(); pr_err("failed to get intermediate opp for cpu%d\n", cpu); ret = PTR_ERR(opp); goto out_free_opp_table; } info->intermediate_voltage = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); info->cpu_dev = cpu_dev; info->proc_reg = proc_reg; diff --git a/drivers/cpufreq/omap-cpufreq.c b/drivers/cpufreq/omap-cpufreq.c index 376e63ca94e8..71e81bbf031b 100644 --- a/drivers/cpufreq/omap-cpufreq.c +++ b/drivers/cpufreq/omap-cpufreq.c @@ -63,16 +63,14 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int index) freq = ret; if (mpu_reg) { - rcu_read_lock(); opp = dev_pm_opp_find_freq_ceil(mpu_dev, &freq); if (IS_ERR(opp)) { - rcu_read_unlock(); dev_err(mpu_dev, "%s: unable to find MPU OPP for %d\n", __func__, new_freq); return -EINVAL; } volt = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); tol = volt * OPP_TOLERANCE / 100; volt_old = regulator_get_voltage(mpu_reg); } diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 37671b545880..3ff5160451b4 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -144,6 +144,7 @@ static struct powernv_pstate_info { unsigned int max; unsigned int nominal; unsigned int nr_pstates; + bool wof_enabled; } powernv_pstate_info; /* Use following macros for conversions between pstate_id and index */ @@ -203,6 +204,7 @@ static int init_powernv_pstates(void) const __be32 *pstate_ids, *pstate_freqs; u32 len_ids, len_freqs; u32 pstate_min, pstate_max, pstate_nominal; + u32 pstate_turbo, pstate_ultra_turbo; power_mgt = of_find_node_by_path("/ibm,opal/power-mgt"); if (!power_mgt) { @@ -225,8 +227,29 @@ static int init_powernv_pstates(void) pr_warn("ibm,pstate-nominal not found\n"); return -ENODEV; } + + if (of_property_read_u32(power_mgt, "ibm,pstate-ultra-turbo", + &pstate_ultra_turbo)) { + powernv_pstate_info.wof_enabled = false; + goto next; + } + + if (of_property_read_u32(power_mgt, "ibm,pstate-turbo", + &pstate_turbo)) { + powernv_pstate_info.wof_enabled = false; + goto next; + } + + if (pstate_turbo == pstate_ultra_turbo) + powernv_pstate_info.wof_enabled = false; + else + powernv_pstate_info.wof_enabled = true; + +next: pr_info("cpufreq pstate min %d nominal %d max %d\n", pstate_min, pstate_nominal, pstate_max); + pr_info("Workload Optimized Frequency is %s in the platform\n", + (powernv_pstate_info.wof_enabled) ? "enabled" : "disabled"); pstate_ids = of_get_property(power_mgt, "ibm,pstate-ids", &len_ids); if (!pstate_ids) { @@ -268,6 +291,13 @@ static int init_powernv_pstates(void) powernv_pstate_info.nominal = i; else if (id == pstate_min) powernv_pstate_info.min = i; + + if (powernv_pstate_info.wof_enabled && id == pstate_turbo) { + int j; + + for (j = i - 1; j >= (int)powernv_pstate_info.max; j--) + powernv_freqs[j].flags = CPUFREQ_BOOST_FREQ; + } } /* End of list marker entry */ @@ -305,9 +335,12 @@ static ssize_t cpuinfo_nominal_freq_show(struct cpufreq_policy *policy, struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq = __ATTR_RO(cpuinfo_nominal_freq); +#define SCALING_BOOST_FREQS_ATTR_INDEX 2 + static struct freq_attr *powernv_cpu_freq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, &cpufreq_freq_attr_cpuinfo_nominal_freq, + &cpufreq_freq_attr_scaling_boost_freqs, NULL, }; @@ -1013,11 +1046,22 @@ static int __init powernv_cpufreq_init(void) register_reboot_notifier(&powernv_cpufreq_reboot_nb); opal_message_notifier_register(OPAL_MSG_OCC, &powernv_cpufreq_opal_nb); + if (powernv_pstate_info.wof_enabled) + powernv_cpufreq_driver.boost_enabled = true; + else + powernv_cpu_freq_attr[SCALING_BOOST_FREQS_ATTR_INDEX] = NULL; + rc = cpufreq_register_driver(&powernv_cpufreq_driver); - if (!rc) - return 0; + if (rc) { + pr_info("Failed to register the cpufreq driver (%d)\n", rc); + goto cleanup_notifiers; + } - pr_info("Failed to register the cpufreq driver (%d)\n", rc); + if (powernv_pstate_info.wof_enabled) + cpufreq_enable_boost_support(); + + return 0; +cleanup_notifiers: unregister_all_notifiers(); clean_chip_info(); out: diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index dc112481a408..eeaa92251512 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -100,9 +100,6 @@ static int pmi_notifier(struct notifier_block *nb, /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY * policy events?) */ - if (event == CPUFREQ_START) - return 0; - node = cbe_cpu_to_node(policy->cpu); pr_debug("got notified, event=%lu, node=%u\n", event, node); diff --git a/drivers/cpufreq/qoriq-cpufreq.c b/drivers/cpufreq/qoriq-cpufreq.c index 53d8c3fb16f6..a6fefac8afe4 100644 --- a/drivers/cpufreq/qoriq-cpufreq.c +++ b/drivers/cpufreq/qoriq-cpufreq.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/cpufreq.h> #include <linux/cpu_cooling.h> #include <linux/errno.h> @@ -37,53 +38,20 @@ struct cpu_data { struct thermal_cooling_device *cdev; }; +/* + * Don't use cpufreq on this SoC -- used when the SoC would have otherwise + * matched a more generic compatible. + */ +#define SOC_BLACKLIST 1 + /** * struct soc_data - SoC specific data - * @freq_mask: mask the disallowed frequencies - * @flag: unique flags + * @flags: SOC_xxx */ struct soc_data { - u32 freq_mask[4]; - u32 flag; -}; - -#define FREQ_MASK 1 -/* see hardware specification for the allowed frqeuencies */ -static const struct soc_data sdata[] = { - { /* used by p2041 and p3041 */ - .freq_mask = {0x8, 0x8, 0x2, 0x2}, - .flag = FREQ_MASK, - }, - { /* used by p5020 */ - .freq_mask = {0x8, 0x2}, - .flag = FREQ_MASK, - }, - { /* used by p4080, p5040 */ - .freq_mask = {0}, - .flag = 0, - }, + u32 flags; }; -/* - * the minimum allowed core frequency, in Hz - * for chassis v1.0, >= platform frequency - * for chassis v2.0, >= platform frequency / 2 - */ -static u32 min_cpufreq; -static const u32 *fmask; - -#if defined(CONFIG_ARM) -static int get_cpu_physical_id(int cpu) -{ - return topology_core_id(cpu); -} -#else -static int get_cpu_physical_id(int cpu) -{ - return get_hard_smp_processor_id(cpu); -} -#endif - static u32 get_bus_freq(void) { struct device_node *soc; @@ -101,9 +69,10 @@ static u32 get_bus_freq(void) return sysfreq; } -static struct device_node *cpu_to_clk_node(int cpu) +static struct clk *cpu_to_clk(int cpu) { - struct device_node *np, *clk_np; + struct device_node *np; + struct clk *clk; if (!cpu_present(cpu)) return NULL; @@ -112,37 +81,28 @@ static struct device_node *cpu_to_clk_node(int cpu) if (!np) return NULL; - clk_np = of_parse_phandle(np, "clocks", 0); - if (!clk_np) - return NULL; - + clk = of_clk_get(np, 0); of_node_put(np); - - return clk_np; + return clk; } /* traverse cpu nodes to get cpu mask of sharing clock wire */ static void set_affected_cpus(struct cpufreq_policy *policy) { - struct device_node *np, *clk_np; struct cpumask *dstp = policy->cpus; + struct clk *clk; int i; - np = cpu_to_clk_node(policy->cpu); - if (!np) - return; - for_each_present_cpu(i) { - clk_np = cpu_to_clk_node(i); - if (!clk_np) + clk = cpu_to_clk(i); + if (IS_ERR(clk)) { + pr_err("%s: no clock for cpu %d\n", __func__, i); continue; + } - if (clk_np == np) + if (clk_is_match(policy->clk, clk)) cpumask_set_cpu(i, dstp); - - of_node_put(clk_np); } - of_node_put(np); } /* reduce the duplicated frequencies in frequency table */ @@ -198,10 +158,11 @@ static void freq_table_sort(struct cpufreq_frequency_table *freq_table, static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) { - struct device_node *np, *pnode; + struct device_node *np; int i, count, ret; - u32 freq, mask; + u32 freq; struct clk *clk; + const struct clk_hw *hwclk; struct cpufreq_frequency_table *table; struct cpu_data *data; unsigned int cpu = policy->cpu; @@ -221,17 +182,13 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_nomem2; } - pnode = of_parse_phandle(np, "clocks", 0); - if (!pnode) { - pr_err("%s: could not get clock information\n", __func__); - goto err_nomem2; - } + hwclk = __clk_get_hw(policy->clk); + count = clk_hw_get_num_parents(hwclk); - count = of_property_count_strings(pnode, "clock-names"); data->pclk = kcalloc(count, sizeof(struct clk *), GFP_KERNEL); if (!data->pclk) { pr_err("%s: no memory\n", __func__); - goto err_node; + goto err_nomem2; } table = kcalloc(count + 1, sizeof(*table), GFP_KERNEL); @@ -240,23 +197,11 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_pclk; } - if (fmask) - mask = fmask[get_cpu_physical_id(cpu)]; - else - mask = 0x0; - for (i = 0; i < count; i++) { - clk = of_clk_get(pnode, i); + clk = clk_hw_get_parent_by_index(hwclk, i)->clk; data->pclk[i] = clk; freq = clk_get_rate(clk); - /* - * the clock is valid if its frequency is not masked - * and large than minimum allowed frequency. - */ - if (freq < min_cpufreq || (mask & (1 << i))) - table[i].frequency = CPUFREQ_ENTRY_INVALID; - else - table[i].frequency = freq / 1000; + table[i].frequency = freq / 1000; table[i].driver_data = i; } freq_table_redup(table, count); @@ -282,7 +227,6 @@ static int qoriq_cpufreq_cpu_init(struct cpufreq_policy *policy) policy->cpuinfo.transition_latency = u64temp + 1; of_node_put(np); - of_node_put(pnode); return 0; @@ -290,10 +234,7 @@ err_nomem1: kfree(table); err_pclk: kfree(data->pclk); -err_node: - of_node_put(pnode); err_nomem2: - policy->driver_data = NULL; kfree(data); err_np: of_node_put(np); @@ -357,12 +298,25 @@ static struct cpufreq_driver qoriq_cpufreq_driver = { .attr = cpufreq_generic_attr, }; +static const struct soc_data blacklist = { + .flags = SOC_BLACKLIST, +}; + static const struct of_device_id node_matches[] __initconst = { - { .compatible = "fsl,p2041-clockgen", .data = &sdata[0], }, - { .compatible = "fsl,p3041-clockgen", .data = &sdata[0], }, - { .compatible = "fsl,p5020-clockgen", .data = &sdata[1], }, - { .compatible = "fsl,p4080-clockgen", .data = &sdata[2], }, - { .compatible = "fsl,p5040-clockgen", .data = &sdata[2], }, + /* e6500 cannot use cpufreq due to erratum A-008083 */ + { .compatible = "fsl,b4420-clockgen", &blacklist }, + { .compatible = "fsl,b4860-clockgen", &blacklist }, + { .compatible = "fsl,t2080-clockgen", &blacklist }, + { .compatible = "fsl,t4240-clockgen", &blacklist }, + + { .compatible = "fsl,ls1012a-clockgen", }, + { .compatible = "fsl,ls1021a-clockgen", }, + { .compatible = "fsl,ls1043a-clockgen", }, + { .compatible = "fsl,ls1046a-clockgen", }, + { .compatible = "fsl,ls1088a-clockgen", }, + { .compatible = "fsl,ls2080a-clockgen", }, + { .compatible = "fsl,p4080-clockgen", }, + { .compatible = "fsl,qoriq-clockgen-1.0", }, { .compatible = "fsl,qoriq-clockgen-2.0", }, {} }; @@ -380,16 +334,12 @@ static int __init qoriq_cpufreq_init(void) match = of_match_node(node_matches, np); data = match->data; - if (data) { - if (data->flag) - fmask = data->freq_mask; - min_cpufreq = get_bus_freq(); - } else { - min_cpufreq = get_bus_freq() / 2; - } of_node_put(np); + if (data && data->flags & SOC_BLACKLIST) + return -ENODEV; + ret = cpufreq_register_driver(&qoriq_cpufreq_driver); if (!ret) pr_info("Freescale QorIQ CPU frequency scaling driver\n"); diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c index d6d425773fa4..5b2db3c6568f 100644 --- a/drivers/cpufreq/s3c2416-cpufreq.c +++ b/drivers/cpufreq/s3c2416-cpufreq.c @@ -400,7 +400,6 @@ static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy) rate = clk_get_rate(s3c_freq->hclk); if (rate < 133 * 1000 * 1000) { pr_err("cpufreq: HCLK not at 133MHz\n"); - clk_put(s3c_freq->hclk); ret = -EINVAL; goto err_armclk; } diff --git a/drivers/cpufreq/sti-cpufreq.c b/drivers/cpufreq/sti-cpufreq.c index b366e6d830ea..a7db9011d5fe 100644 --- a/drivers/cpufreq/sti-cpufreq.c +++ b/drivers/cpufreq/sti-cpufreq.c @@ -160,6 +160,7 @@ static int sti_cpufreq_set_opp_info(void) int pcode, substrate, major, minor; int ret; char name[MAX_PCODE_NAME_LEN]; + struct opp_table *opp_table; reg_fields = sti_cpufreq_match(); if (!reg_fields) { @@ -211,20 +212,20 @@ use_defaults: snprintf(name, MAX_PCODE_NAME_LEN, "pcode%d", pcode); - ret = dev_pm_opp_set_prop_name(dev, name); - if (ret) { + opp_table = dev_pm_opp_set_prop_name(dev, name); + if (IS_ERR(opp_table)) { dev_err(dev, "Failed to set prop name\n"); - return ret; + return PTR_ERR(opp_table); } version[0] = BIT(major); version[1] = BIT(minor); version[2] = BIT(substrate); - ret = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS); - if (ret) { + opp_table = dev_pm_opp_set_supported_hw(dev, version, VERSION_ELEMENTS); + if (IS_ERR(opp_table)) { dev_err(dev, "Failed to set supported hardware\n"); - return ret; + return PTR_ERR(opp_table); } dev_dbg(dev, "pcode: %d major: %d minor: %d substrate: %d\n", diff --git a/drivers/cpufreq/ti-cpufreq.c b/drivers/cpufreq/ti-cpufreq.c new file mode 100644 index 000000000000..a7b5658c0460 --- /dev/null +++ b/drivers/cpufreq/ti-cpufreq.c @@ -0,0 +1,268 @@ +/* + * TI CPUFreq/OPP hw-supported driver + * + * Copyright (C) 2016-2017 Texas Instruments, Inc. + * Dave Gerlach <d-gerlach@ti.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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. + */ + +#include <linux/cpu.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/init.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/pm_opp.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +#define REVISION_MASK 0xF +#define REVISION_SHIFT 28 + +#define AM33XX_800M_ARM_MPU_MAX_FREQ 0x1E2F +#define AM43XX_600M_ARM_MPU_MAX_FREQ 0xFFA + +#define DRA7_EFUSE_HAS_OD_MPU_OPP 11 +#define DRA7_EFUSE_HAS_HIGH_MPU_OPP 15 +#define DRA7_EFUSE_HAS_ALL_MPU_OPP 23 + +#define DRA7_EFUSE_NOM_MPU_OPP BIT(0) +#define DRA7_EFUSE_OD_MPU_OPP BIT(1) +#define DRA7_EFUSE_HIGH_MPU_OPP BIT(2) + +#define VERSION_COUNT 2 + +struct ti_cpufreq_data; + +struct ti_cpufreq_soc_data { + unsigned long (*efuse_xlate)(struct ti_cpufreq_data *opp_data, + unsigned long efuse); + unsigned long efuse_fallback; + unsigned long efuse_offset; + unsigned long efuse_mask; + unsigned long efuse_shift; + unsigned long rev_offset; +}; + +struct ti_cpufreq_data { + struct device *cpu_dev; + struct device_node *opp_node; + struct regmap *syscon; + const struct ti_cpufreq_soc_data *soc_data; +}; + +static unsigned long amx3_efuse_xlate(struct ti_cpufreq_data *opp_data, + unsigned long efuse) +{ + if (!efuse) + efuse = opp_data->soc_data->efuse_fallback; + /* AM335x and AM437x use "OPP disable" bits, so invert */ + return ~efuse; +} + +static unsigned long dra7_efuse_xlate(struct ti_cpufreq_data *opp_data, + unsigned long efuse) +{ + unsigned long calculated_efuse = DRA7_EFUSE_NOM_MPU_OPP; + + /* + * The efuse on dra7 and am57 parts contains a specific + * value indicating the highest available OPP. + */ + + switch (efuse) { + case DRA7_EFUSE_HAS_ALL_MPU_OPP: + case DRA7_EFUSE_HAS_HIGH_MPU_OPP: + calculated_efuse |= DRA7_EFUSE_HIGH_MPU_OPP; + case DRA7_EFUSE_HAS_OD_MPU_OPP: + calculated_efuse |= DRA7_EFUSE_OD_MPU_OPP; + } + + return calculated_efuse; +} + +static struct ti_cpufreq_soc_data am3x_soc_data = { + .efuse_xlate = amx3_efuse_xlate, + .efuse_fallback = AM33XX_800M_ARM_MPU_MAX_FREQ, + .efuse_offset = 0x07fc, + .efuse_mask = 0x1fff, + .rev_offset = 0x600, +}; + +static struct ti_cpufreq_soc_data am4x_soc_data = { + .efuse_xlate = amx3_efuse_xlate, + .efuse_fallback = AM43XX_600M_ARM_MPU_MAX_FREQ, + .efuse_offset = 0x0610, + .efuse_mask = 0x3f, + .rev_offset = 0x600, +}; + +static struct ti_cpufreq_soc_data dra7_soc_data = { + .efuse_xlate = dra7_efuse_xlate, + .efuse_offset = 0x020c, + .efuse_mask = 0xf80000, + .efuse_shift = 19, + .rev_offset = 0x204, +}; + +/** + * ti_cpufreq_get_efuse() - Parse and return efuse value present on SoC + * @opp_data: pointer to ti_cpufreq_data context + * @efuse_value: Set to the value parsed from efuse + * + * Returns error code if efuse not read properly. + */ +static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data, + u32 *efuse_value) +{ + struct device *dev = opp_data->cpu_dev; + u32 efuse; + int ret; + + ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset, + &efuse); + if (ret) { + dev_err(dev, + "Failed to read the efuse value from syscon: %d\n", + ret); + return ret; + } + + efuse = (efuse & opp_data->soc_data->efuse_mask); + efuse >>= opp_data->soc_data->efuse_shift; + + *efuse_value = opp_data->soc_data->efuse_xlate(opp_data, efuse); + + return 0; +} + +/** + * ti_cpufreq_get_rev() - Parse and return rev value present on SoC + * @opp_data: pointer to ti_cpufreq_data context + * @revision_value: Set to the value parsed from revision register + * + * Returns error code if revision not read properly. + */ +static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data, + u32 *revision_value) +{ + struct device *dev = opp_data->cpu_dev; + u32 revision; + int ret; + + ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset, + &revision); + if (ret) { + dev_err(dev, + "Failed to read the revision number from syscon: %d\n", + ret); + return ret; + } + + *revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK); + + return 0; +} + +static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data) +{ + struct device *dev = opp_data->cpu_dev; + struct device_node *np = opp_data->opp_node; + + opp_data->syscon = syscon_regmap_lookup_by_phandle(np, + "syscon"); + if (IS_ERR(opp_data->syscon)) { + dev_err(dev, + "\"syscon\" is missing, cannot use OPPv2 table.\n"); + return PTR_ERR(opp_data->syscon); + } + + return 0; +} + +static const struct of_device_id ti_cpufreq_of_match[] = { + { .compatible = "ti,am33xx", .data = &am3x_soc_data, }, + { .compatible = "ti,am4372", .data = &am4x_soc_data, }, + { .compatible = "ti,dra7", .data = &dra7_soc_data }, + {}, +}; + +static int ti_cpufreq_init(void) +{ + u32 version[VERSION_COUNT]; + struct device_node *np; + const struct of_device_id *match; + struct ti_cpufreq_data *opp_data; + int ret; + + np = of_find_node_by_path("/"); + match = of_match_node(ti_cpufreq_of_match, np); + if (!match) + return -ENODEV; + + opp_data = kzalloc(sizeof(*opp_data), GFP_KERNEL); + if (!opp_data) + return -ENOMEM; + + opp_data->soc_data = match->data; + + opp_data->cpu_dev = get_cpu_device(0); + if (!opp_data->cpu_dev) { + pr_err("%s: Failed to get device for CPU0\n", __func__); + return -ENODEV; + } + + opp_data->opp_node = dev_pm_opp_of_get_opp_desc_node(opp_data->cpu_dev); + if (!opp_data->opp_node) { + dev_info(opp_data->cpu_dev, + "OPP-v2 not supported, cpufreq-dt will attempt to use legacy tables.\n"); + goto register_cpufreq_dt; + } + + ret = ti_cpufreq_setup_syscon_register(opp_data); + if (ret) + goto fail_put_node; + + /* + * OPPs determine whether or not they are supported based on + * two metrics: + * 0 - SoC Revision + * 1 - eFuse value + */ + ret = ti_cpufreq_get_rev(opp_data, &version[0]); + if (ret) + goto fail_put_node; + + ret = ti_cpufreq_get_efuse(opp_data, &version[1]); + if (ret) + goto fail_put_node; + + of_node_put(opp_data->opp_node); + + ret = PTR_ERR_OR_ZERO(dev_pm_opp_set_supported_hw(opp_data->cpu_dev, + version, VERSION_COUNT)); + if (ret) { + dev_err(opp_data->cpu_dev, + "Failed to set supported hardware\n"); + goto fail_put_node; + } + +register_cpufreq_dt: + platform_device_register_simple("cpufreq-dt", -1, NULL, 0); + + return 0; + +fail_put_node: + of_node_put(opp_data->opp_node); + + return ret; +} +device_initcall(ti_cpufreq_init); diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c index d9b5b9398a0f..8d6d25c38c02 100644 --- a/drivers/cpuidle/governors/menu.c +++ b/drivers/cpuidle/governors/menu.c @@ -19,6 +19,7 @@ #include <linux/tick.h> #include <linux/sched.h> #include <linux/math64.h> +#include <linux/cpu.h> /* * Please note when changing the tuning values: @@ -280,17 +281,23 @@ again: static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) { struct menu_device *data = this_cpu_ptr(&menu_devices); + struct device *device = get_cpu_device(dev->cpu); int latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); int i; unsigned int interactivity_req; unsigned int expected_interval; unsigned long nr_iowaiters, cpu_load; + int resume_latency = dev_pm_qos_read_value(device); if (data->needs_update) { menu_update(drv, dev); data->needs_update = 0; } + /* resume_latency is 0 means no restriction */ + if (resume_latency && resume_latency < latency_req) + latency_req = resume_latency; + /* Special case when user has set very strict latency requirement */ if (unlikely(latency_req == 0)) return 0; @@ -357,9 +364,9 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) if (s->disabled || su->disable) continue; if (s->target_residency > data->predicted_us) - continue; + break; if (s->exit_latency > latency_req) - continue; + break; data->last_state_idx = i; } diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index e2ce8190ecc9..612898b4aaad 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -959,7 +959,7 @@ static irqreturn_t ccp5_irq_handler(int irq, void *data) static void ccp5_config(struct ccp_device *ccp) { /* Public side */ - iowrite32(0x00001249, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET); + iowrite32(0x0, ccp->io_regs + CMD5_REQID_CONFIG_OFFSET); } static void ccp5other_config(struct ccp_device *ccp) diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 830f35e6005f..649e5610a5ce 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -238,6 +238,7 @@ struct ccp_dma_chan { struct ccp_device *ccp; spinlock_t lock; + struct list_head created; struct list_head pending; struct list_head active; struct list_head complete; diff --git a/drivers/crypto/ccp/ccp-dmaengine.c b/drivers/crypto/ccp/ccp-dmaengine.c index 6553912804f7..e5d9278f4019 100644 --- a/drivers/crypto/ccp/ccp-dmaengine.c +++ b/drivers/crypto/ccp/ccp-dmaengine.c @@ -63,6 +63,7 @@ static void ccp_free_chan_resources(struct dma_chan *dma_chan) ccp_free_desc_resources(chan->ccp, &chan->complete); ccp_free_desc_resources(chan->ccp, &chan->active); ccp_free_desc_resources(chan->ccp, &chan->pending); + ccp_free_desc_resources(chan->ccp, &chan->created); spin_unlock_irqrestore(&chan->lock, flags); } @@ -273,6 +274,7 @@ static dma_cookie_t ccp_tx_submit(struct dma_async_tx_descriptor *tx_desc) spin_lock_irqsave(&chan->lock, flags); cookie = dma_cookie_assign(tx_desc); + list_del(&desc->entry); list_add_tail(&desc->entry, &chan->pending); spin_unlock_irqrestore(&chan->lock, flags); @@ -426,7 +428,7 @@ static struct ccp_dma_desc *ccp_create_desc(struct dma_chan *dma_chan, spin_lock_irqsave(&chan->lock, sflags); - list_add_tail(&desc->entry, &chan->pending); + list_add_tail(&desc->entry, &chan->created); spin_unlock_irqrestore(&chan->lock, sflags); @@ -610,6 +612,7 @@ static int ccp_terminate_all(struct dma_chan *dma_chan) /*TODO: Purge the complete list? */ ccp_free_desc_resources(chan->ccp, &chan->active); ccp_free_desc_resources(chan->ccp, &chan->pending); + ccp_free_desc_resources(chan->ccp, &chan->created); spin_unlock_irqrestore(&chan->lock, flags); @@ -679,6 +682,7 @@ int ccp_dmaengine_register(struct ccp_device *ccp) chan->ccp = ccp; spin_lock_init(&chan->lock); + INIT_LIST_HEAD(&chan->created); INIT_LIST_HEAD(&chan->pending); INIT_LIST_HEAD(&chan->active); INIT_LIST_HEAD(&chan->complete); diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 2ed1e24b44a8..b4b78b37f8a6 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -158,7 +158,7 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, case CRYPTO_ALG_TYPE_AEAD: ctx_req.req.aead_req = (struct aead_request *)req; ctx_req.ctx.reqctx = aead_request_ctx(ctx_req.req.aead_req); - dma_unmap_sg(&u_ctx->lldi.pdev->dev, ctx_req.req.aead_req->dst, + dma_unmap_sg(&u_ctx->lldi.pdev->dev, ctx_req.ctx.reqctx->dst, ctx_req.ctx.reqctx->dst_nents, DMA_FROM_DEVICE); if (ctx_req.ctx.reqctx->skb) { kfree_skb(ctx_req.ctx.reqctx->skb); @@ -1362,8 +1362,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, struct chcr_wr *chcr_req; struct cpl_rx_phys_dsgl *phys_cpl; struct phys_sge_parm sg_param; - struct scatterlist *src, *dst; - struct scatterlist src_sg[2], dst_sg[2]; + struct scatterlist *src; unsigned int frags = 0, transhdr_len; unsigned int ivsize = crypto_aead_ivsize(tfm), dst_size = 0; unsigned int kctx_len = 0; @@ -1383,19 +1382,21 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) goto err; - src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); - dst = src; + src = scatterwalk_ffwd(reqctx->srcffwd, req->src, req->assoclen); + reqctx->dst = src; + if (req->src != req->dst) { err = chcr_copy_assoc(req, aeadctx); if (err) return ERR_PTR(err); - dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + reqctx->dst = scatterwalk_ffwd(reqctx->dstffwd, req->dst, + req->assoclen); } if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_NULL) { null = 1; assoclen = 0; } - reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + reqctx->dst_nents = sg_nents_for_len(reqctx->dst, req->cryptlen + (op_type ? -authsize : authsize)); if (reqctx->dst_nents <= 0) { pr_err("AUTHENC:Invalid Destination sg entries\n"); @@ -1460,7 +1461,7 @@ static struct sk_buff *create_authenc_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; sg_param.align = 0; - if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, reqctx->dst, &sg_param)) goto dstmap_fail; @@ -1711,8 +1712,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, struct chcr_wr *chcr_req; struct cpl_rx_phys_dsgl *phys_cpl; struct phys_sge_parm sg_param; - struct scatterlist *src, *dst; - struct scatterlist src_sg[2], dst_sg[2]; + struct scatterlist *src; unsigned int frags = 0, transhdr_len, ivsize = AES_BLOCK_SIZE; unsigned int dst_size = 0, kctx_len; unsigned int sub_type; @@ -1728,17 +1728,19 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) goto err; sub_type = get_aead_subtype(tfm); - src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); - dst = src; + src = scatterwalk_ffwd(reqctx->srcffwd, req->src, req->assoclen); + reqctx->dst = src; + if (req->src != req->dst) { err = chcr_copy_assoc(req, aeadctx); if (err) { pr_err("AAD copy to destination buffer fails\n"); return ERR_PTR(err); } - dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + reqctx->dst = scatterwalk_ffwd(reqctx->dstffwd, req->dst, + req->assoclen); } - reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + reqctx->dst_nents = sg_nents_for_len(reqctx->dst, req->cryptlen + (op_type ? -authsize : authsize)); if (reqctx->dst_nents <= 0) { pr_err("CCM:Invalid Destination sg entries\n"); @@ -1777,7 +1779,7 @@ static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; sg_param.align = 0; - if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, reqctx->dst, &sg_param)) goto dstmap_fail; @@ -1809,8 +1811,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, struct chcr_wr *chcr_req; struct cpl_rx_phys_dsgl *phys_cpl; struct phys_sge_parm sg_param; - struct scatterlist *src, *dst; - struct scatterlist src_sg[2], dst_sg[2]; + struct scatterlist *src; unsigned int frags = 0, transhdr_len; unsigned int ivsize = AES_BLOCK_SIZE; unsigned int dst_size = 0, kctx_len; @@ -1832,13 +1833,14 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) goto err; - src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); - dst = src; + src = scatterwalk_ffwd(reqctx->srcffwd, req->src, req->assoclen); + reqctx->dst = src; if (req->src != req->dst) { err = chcr_copy_assoc(req, aeadctx); if (err) return ERR_PTR(err); - dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + reqctx->dst = scatterwalk_ffwd(reqctx->dstffwd, req->dst, + req->assoclen); } if (!req->cryptlen) @@ -1848,7 +1850,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, crypt_len = AES_BLOCK_SIZE; else crypt_len = req->cryptlen; - reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + reqctx->dst_nents = sg_nents_for_len(reqctx->dst, req->cryptlen + (op_type ? -authsize : authsize)); if (reqctx->dst_nents <= 0) { pr_err("GCM:Invalid Destination sg entries\n"); @@ -1923,7 +1925,7 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); sg_param.qid = qid; sg_param.align = 0; - if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, reqctx->dst, &sg_param)) goto dstmap_fail; @@ -1937,7 +1939,8 @@ static struct sk_buff *create_gcm_wr(struct aead_request *req, write_sg_to_skb(skb, &frags, src, req->cryptlen); } else { aes_gcm_empty_pld_pad(req->dst, authsize - 1); - write_sg_to_skb(skb, &frags, dst, crypt_len); + write_sg_to_skb(skb, &frags, reqctx->dst, crypt_len); + } create_wreq(ctx, chcr_req, req, skb, kctx_len, size, 1, @@ -2189,8 +2192,8 @@ static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, unsigned int ck_size; int ret = 0, key_ctx_size = 0; - if (get_aead_subtype(aead) == - CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) { + if (get_aead_subtype(aead) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106 && + keylen > 3) { keylen -= 4; /* nonce/salt is present in the last 4 bytes */ memcpy(aeadctx->salt, key + keylen, 4); } diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c index 918da8e6e2d8..1c65f07e1cc9 100644 --- a/drivers/crypto/chelsio/chcr_core.c +++ b/drivers/crypto/chelsio/chcr_core.c @@ -52,6 +52,7 @@ static struct cxgb4_uld_info chcr_uld_info = { int assign_chcr_device(struct chcr_dev **dev) { struct uld_ctx *u_ctx; + int ret = -ENXIO; /* * Which device to use if multiple devices are available TODO @@ -59,15 +60,14 @@ int assign_chcr_device(struct chcr_dev **dev) * must go to the same device to maintain the ordering. */ mutex_lock(&dev_mutex); /* TODO ? */ - u_ctx = list_first_entry(&uld_ctx_list, struct uld_ctx, entry); - if (!u_ctx) { - mutex_unlock(&dev_mutex); - return -ENXIO; + list_for_each_entry(u_ctx, &uld_ctx_list, entry) + if (u_ctx && u_ctx->dev) { + *dev = u_ctx->dev; + ret = 0; + break; } - - *dev = u_ctx->dev; mutex_unlock(&dev_mutex); - return 0; + return ret; } static int chcr_dev_add(struct uld_ctx *u_ctx) @@ -202,10 +202,8 @@ static int chcr_uld_state_change(void *handle, enum cxgb4_state state) static int __init chcr_crypto_init(void) { - if (cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info)) { + if (cxgb4_register_uld(CXGB4_ULD_CRYPTO, &chcr_uld_info)) pr_err("ULD register fail: No chcr crypto support in cxgb4"); - return -1; - } return 0; } diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index d5af7d64a763..7ec0a8f12475 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -158,6 +158,9 @@ struct ablk_ctx { }; struct chcr_aead_reqctx { struct sk_buff *skb; + struct scatterlist *dst; + struct scatterlist srcffwd[2]; + struct scatterlist dstffwd[2]; short int dst_nents; u16 verify; u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c index bc5cbc193aae..5b2d78a5b5aa 100644 --- a/drivers/crypto/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/qat/qat_c62x/adf_drv.c @@ -233,7 +233,7 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) &hw_data->accel_capabilities_mask); /* Find and map all the device's BARS */ - i = 0; + i = (hw_data->fuses & ADF_DEVICE_FUSECTL_MASK) ? 1 : 0; bar_mask = pci_select_bars(pdev, IORESOURCE_MEM); for_each_set_bit(bar_nr, (const unsigned long *)&bar_mask, ADF_PCI_MAX_BARS * 2) { diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index e8822536530b..33f0a6251e38 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -69,6 +69,7 @@ #define ADF_ERRSOU5 (0x3A000 + 0xD8) #define ADF_DEVICE_FUSECTL_OFFSET 0x40 #define ADF_DEVICE_LEGFUSE_OFFSET 0x4C +#define ADF_DEVICE_FUSECTL_MASK 0x80000000 #define ADF_PCI_MAX_BARS 3 #define ADF_DEVICE_NAME_LENGTH 32 #define ADF_ETR_MAX_RINGS_PER_BANK 16 diff --git a/drivers/crypto/qat/qat_common/qat_hal.c b/drivers/crypto/qat/qat_common/qat_hal.c index 1e480f140663..8c4fd255a601 100644 --- a/drivers/crypto/qat/qat_common/qat_hal.c +++ b/drivers/crypto/qat/qat_common/qat_hal.c @@ -456,7 +456,7 @@ static int qat_hal_init_esram(struct icp_qat_fw_loader_handle *handle) unsigned int csr_val; int times = 30; - if (handle->pci_dev->device == ADF_C3XXX_PCI_DEVICE_ID) + if (handle->pci_dev->device != ADF_DH895XCC_PCI_DEVICE_ID) return 0; csr_val = ADF_CSR_RD(csr_addr, 0); @@ -716,7 +716,7 @@ int qat_hal_init(struct adf_accel_dev *accel_dev) (void __iomem *)((uintptr_t)handle->hal_cap_ae_xfer_csr_addr_v + LOCAL_TO_XFER_REG_OFFSET); handle->pci_dev = pci_info->pci_dev; - if (handle->pci_dev->device != ADF_C3XXX_PCI_DEVICE_ID) { + if (handle->pci_dev->device == ADF_DH895XCC_PCI_DEVICE_ID) { sram_bar = &pci_info->pci_bars[hw_data->get_sram_bar_id(hw_data)]; handle->hal_sram_addr_v = sram_bar->virt_addr; diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c index 9aea2c7ecbe6..8648b32ebc89 100644 --- a/drivers/devfreq/devfreq-event.c +++ b/drivers/devfreq/devfreq-event.c @@ -306,7 +306,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, struct devfreq_event_desc *desc) { struct devfreq_event_dev *edev; - static atomic_t event_no = ATOMIC_INIT(0); + static atomic_t event_no = ATOMIC_INIT(-1); int ret; if (!dev || !desc) @@ -329,7 +329,7 @@ struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev, edev->dev.class = devfreq_event_class; edev->dev.release = devfreq_event_release_edev; - dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1); + dev_set_name(&edev->dev, "event%d", atomic_inc_return(&event_no)); ret = device_register(&edev->dev); if (ret < 0) { put_device(&edev->dev); diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c index a324801d6a66..551a271353d2 100644 --- a/drivers/devfreq/devfreq.c +++ b/drivers/devfreq/devfreq.c @@ -111,18 +111,16 @@ static void devfreq_set_freq_table(struct devfreq *devfreq) return; } - rcu_read_lock(); for (i = 0, freq = 0; i < profile->max_state; i++, freq++) { opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq); if (IS_ERR(opp)) { devm_kfree(devfreq->dev.parent, profile->freq_table); profile->max_state = 0; - rcu_read_unlock(); return; } + dev_pm_opp_put(opp); profile->freq_table[i] = freq; } - rcu_read_unlock(); } /** @@ -130,7 +128,7 @@ static void devfreq_set_freq_table(struct devfreq *devfreq) * @devfreq: the devfreq instance * @freq: the update target frequency */ -static int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) +int devfreq_update_status(struct devfreq *devfreq, unsigned long freq) { int lev, prev_lev, ret = 0; unsigned long cur_time; @@ -166,6 +164,7 @@ out: devfreq->last_stat_updated = cur_time; return ret; } +EXPORT_SYMBOL(devfreq_update_status); /** * find_devfreq_governor() - find devfreq governor from name @@ -474,11 +473,15 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type, } /** - * _remove_devfreq() - Remove devfreq from the list and release its resources. - * @devfreq: the devfreq struct + * devfreq_dev_release() - Callback for struct device to release the device. + * @dev: the devfreq device + * + * Remove devfreq from the list and release its resources. */ -static void _remove_devfreq(struct devfreq *devfreq) +static void devfreq_dev_release(struct device *dev) { + struct devfreq *devfreq = to_devfreq(dev); + mutex_lock(&devfreq_list_lock); if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) { mutex_unlock(&devfreq_list_lock); @@ -500,19 +503,6 @@ static void _remove_devfreq(struct devfreq *devfreq) } /** - * devfreq_dev_release() - Callback for struct device to release the device. - * @dev: the devfreq device - * - * This calls _remove_devfreq() if _remove_devfreq() is not called. - */ -static void devfreq_dev_release(struct device *dev) -{ - struct devfreq *devfreq = to_devfreq(dev); - - _remove_devfreq(devfreq); -} - -/** * devfreq_add_device() - Add devfreq feature to the device * @dev: the device to add devfreq feature. * @profile: device-specific profile to run devfreq. @@ -527,6 +517,7 @@ struct devfreq *devfreq_add_device(struct device *dev, { struct devfreq *devfreq; struct devfreq_governor *governor; + static atomic_t devfreq_no = ATOMIC_INIT(-1); int err = 0; if (!dev || !profile || !governor_name) { @@ -538,15 +529,14 @@ struct devfreq *devfreq_add_device(struct device *dev, devfreq = find_device_devfreq(dev); mutex_unlock(&devfreq_list_lock); if (!IS_ERR(devfreq)) { - dev_err(dev, "%s: Unable to create devfreq for the device. It already has one.\n", __func__); + dev_err(dev, "%s: Unable to create devfreq for the device.\n", + __func__); err = -EINVAL; goto err_out; } devfreq = kzalloc(sizeof(struct devfreq), GFP_KERNEL); if (!devfreq) { - dev_err(dev, "%s: Unable to create devfreq for the device\n", - __func__); err = -ENOMEM; goto err_out; } @@ -569,18 +559,21 @@ struct devfreq *devfreq_add_device(struct device *dev, mutex_lock(&devfreq->lock); } - dev_set_name(&devfreq->dev, "%s", dev_name(dev)); + dev_set_name(&devfreq->dev, "devfreq%d", + atomic_inc_return(&devfreq_no)); err = device_register(&devfreq->dev); if (err) { mutex_unlock(&devfreq->lock); goto err_out; } - devfreq->trans_table = devm_kzalloc(&devfreq->dev, sizeof(unsigned int) * + devfreq->trans_table = devm_kzalloc(&devfreq->dev, + sizeof(unsigned int) * devfreq->profile->max_state * devfreq->profile->max_state, GFP_KERNEL); - devfreq->time_in_state = devm_kzalloc(&devfreq->dev, sizeof(unsigned long) * + devfreq->time_in_state = devm_kzalloc(&devfreq->dev, + sizeof(unsigned long) * devfreq->profile->max_state, GFP_KERNEL); devfreq->last_stat_updated = jiffies; @@ -593,11 +586,16 @@ struct devfreq *devfreq_add_device(struct device *dev, list_add(&devfreq->node, &devfreq_list); governor = find_devfreq_governor(devfreq->governor_name); - if (!IS_ERR(governor)) - devfreq->governor = governor; - if (devfreq->governor) - err = devfreq->governor->event_handler(devfreq, - DEVFREQ_GOV_START, NULL); + if (IS_ERR(governor)) { + dev_err(dev, "%s: Unable to find governor for the device\n", + __func__); + err = PTR_ERR(governor); + goto err_init; + } + + devfreq->governor = governor; + err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START, + NULL); if (err) { dev_err(dev, "%s: Unable to start governor for the device\n", __func__); @@ -934,6 +932,9 @@ static ssize_t governor_store(struct device *dev, struct device_attribute *attr, if (df->governor == governor) { ret = 0; goto out; + } else if (df->governor->immutable || governor->immutable) { + ret = -EINVAL; + goto out; } if (df->governor) { @@ -963,13 +964,33 @@ static ssize_t available_governors_show(struct device *d, struct device_attribute *attr, char *buf) { - struct devfreq_governor *tmp_governor; + struct devfreq *df = to_devfreq(d); ssize_t count = 0; mutex_lock(&devfreq_list_lock); - list_for_each_entry(tmp_governor, &devfreq_governor_list, node) - count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), - "%s ", tmp_governor->name); + + /* + * The devfreq with immutable governor (e.g., passive) shows + * only own governor. + */ + if (df->governor->immutable) { + count = scnprintf(&buf[count], DEVFREQ_NAME_LEN, + "%s ", df->governor_name); + /* + * The devfreq device shows the registered governor except for + * immutable governors such as passive governor . + */ + } else { + struct devfreq_governor *governor; + + list_for_each_entry(governor, &devfreq_governor_list, node) { + if (governor->immutable) + continue; + count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), + "%s ", governor->name); + } + } + mutex_unlock(&devfreq_list_lock); /* Truncate the trailing space */ @@ -990,7 +1011,7 @@ static ssize_t cur_freq_show(struct device *dev, struct device_attribute *attr, if (devfreq->profile->get_cur_freq && !devfreq->profile->get_cur_freq(devfreq->dev.parent, &freq)) - return sprintf(buf, "%lu\n", freq); + return sprintf(buf, "%lu\n", freq); return sprintf(buf, "%lu\n", devfreq->previous_freq); } @@ -1107,17 +1128,16 @@ static ssize_t available_frequencies_show(struct device *d, ssize_t count = 0; unsigned long freq = 0; - rcu_read_lock(); do { opp = dev_pm_opp_find_freq_ceil(dev, &freq); if (IS_ERR(opp)) break; + dev_pm_opp_put(opp); count += scnprintf(&buf[count], (PAGE_SIZE - count - 2), "%lu ", freq); freq++; } while (1); - rcu_read_unlock(); /* Truncate the trailing space */ if (count) @@ -1219,11 +1239,8 @@ subsys_initcall(devfreq_init); * @freq: The frequency given to target function * @flags: Flags handed from devfreq framework. * - * Locking: This function must be called under rcu_read_lock(). opp is a rcu - * protected pointer. The reason for the same is that the opp pointer which is - * returned will remain valid for use with opp_get_{voltage, freq} only while - * under the locked area. The pointer returned must be used prior to unlocking - * with rcu_read_unlock() to maintain the integrity of the pointer. + * The callers are required to call dev_pm_opp_put() for the returned OPP after + * use. */ struct dev_pm_opp *devfreq_recommended_opp(struct device *dev, unsigned long *freq, @@ -1260,18 +1277,7 @@ EXPORT_SYMBOL(devfreq_recommended_opp); */ int devfreq_register_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh; - int ret = 0; - - rcu_read_lock(); - nh = dev_pm_opp_get_notifier(dev); - if (IS_ERR(nh)) - ret = PTR_ERR(nh); - rcu_read_unlock(); - if (!ret) - ret = srcu_notifier_chain_register(nh, &devfreq->nb); - - return ret; + return dev_pm_opp_register_notifier(dev, &devfreq->nb); } EXPORT_SYMBOL(devfreq_register_opp_notifier); @@ -1287,18 +1293,7 @@ EXPORT_SYMBOL(devfreq_register_opp_notifier); */ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq) { - struct srcu_notifier_head *nh; - int ret = 0; - - rcu_read_lock(); - nh = dev_pm_opp_get_notifier(dev); - if (IS_ERR(nh)) - ret = PTR_ERR(nh); - rcu_read_unlock(); - if (!ret) - ret = srcu_notifier_chain_unregister(nh, &devfreq->nb); - - return ret; + return dev_pm_opp_unregister_notifier(dev, &devfreq->nb); } EXPORT_SYMBOL(devfreq_unregister_opp_notifier); diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c index 107eb91a9415..9b7350935b73 100644 --- a/drivers/devfreq/event/exynos-ppmu.c +++ b/drivers/devfreq/event/exynos-ppmu.c @@ -17,13 +17,13 @@ #include <linux/module.h> #include <linux/of_address.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/suspend.h> #include <linux/devfreq-event.h> #include "exynos-ppmu.h" struct exynos_ppmu_data { - void __iomem *base; struct clk *clk; }; @@ -33,6 +33,7 @@ struct exynos_ppmu { unsigned int num_events; struct device *dev; + struct regmap *regmap; struct exynos_ppmu_data ppmu; }; @@ -107,20 +108,28 @@ static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev) static int exynos_ppmu_disable(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int ret; u32 pmnc; /* Disable all counters */ - __raw_writel(PPMU_CCNT_MASK | - PPMU_PMCNT0_MASK | - PPMU_PMCNT1_MASK | - PPMU_PMCNT2_MASK | - PPMU_PMCNT3_MASK, - info->ppmu.base + PPMU_CNTENC); + ret = regmap_write(info->regmap, PPMU_CNTENC, + PPMU_CCNT_MASK | + PPMU_PMCNT0_MASK | + PPMU_PMCNT1_MASK | + PPMU_PMCNT2_MASK | + PPMU_PMCNT3_MASK); + if (ret < 0) + return ret; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -129,29 +138,42 @@ static int exynos_ppmu_set_event(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); + int ret; u32 pmnc, cntens; if (id < 0) return id; /* Enable specific counter */ - cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS); + ret = regmap_read(info->regmap, PPMU_CNTENS, &cntens); + if (ret < 0) + return ret; + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS); + ret = regmap_write(info->regmap, PPMU_CNTENS, cntens); + if (ret < 0) + return ret; /* Set the event of Read/Write data count */ - __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT, - info->ppmu.base + PPMU_BEVTxSEL(id)); + ret = regmap_write(info->regmap, PPMU_BEVTxSEL(id), + PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT); + if (ret < 0) + return ret; /* Reset cycle counter/performance counter and enable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~(PPMU_PMNC_ENABLE_MASK | PPMU_PMNC_COUNTER_RESET_MASK | PPMU_PMNC_CC_RESET_MASK); pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -161,40 +183,64 @@ static int exynos_ppmu_get_event(struct devfreq_event_dev *edev, { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntenc; + unsigned int total_count, load_count; + unsigned int pmcnt3_high, pmcnt3_low; + unsigned int pmnc, cntenc; + int ret; if (id < 0) return -EINVAL; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC); + ret = regmap_read(info->regmap, PPMU_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC); + ret = regmap_write(info->regmap, PPMU_PMNC, pmnc); + if (ret < 0) + return ret; /* Read cycle count */ - edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT); + ret = regmap_read(info->regmap, PPMU_CCNT, &total_count); + if (ret < 0) + return ret; + edata->total_count = total_count; /* Read performance count */ switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - edata->load_count - = __raw_readl(info->ppmu.base + PPMU_PMNCT(id)); + ret = regmap_read(info->regmap, PPMU_PMNCT(id), &load_count); + if (ret < 0) + return ret; + edata->load_count = load_count; break; case PPMU_PMNCNT3: - edata->load_count = - ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8) - | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW)); + ret = regmap_read(info->regmap, PPMU_PMCNT3_HIGH, &pmcnt3_high); + if (ret < 0) + return ret; + + ret = regmap_read(info->regmap, PPMU_PMCNT3_LOW, &pmcnt3_low); + if (ret < 0) + return ret; + + edata->load_count = ((pmcnt3_high << 8) | pmcnt3_low); break; default: return -EINVAL; } /* Disable specific counter */ - cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC); + ret = regmap_read(info->regmap, PPMU_CNTENC, &cntenc); + if (ret < 0) + return ret; + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC); + ret = regmap_write(info->regmap, PPMU_CNTENC, cntenc); + if (ret < 0) + return ret; dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name, edata->load_count, edata->total_count); @@ -214,36 +260,93 @@ static const struct devfreq_event_ops exynos_ppmu_ops = { static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + int ret; u32 pmnc, clear; /* Disable all counters */ clear = (PPMU_CCNT_MASK | PPMU_PMCNT0_MASK | PPMU_PMCNT1_MASK | PPMU_PMCNT2_MASK | PPMU_PMCNT3_MASK); + ret = regmap_write(info->regmap, PPMU_V2_FLAG, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_INTENC, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNTENC, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNT_RESET, clear); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG0, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG1, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_CFG2, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CIG_RESULT, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CNT_AUTO, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV0_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV1_TYPE, 0x0); + if (ret < 0) + return ret; - __raw_writel(clear, info->ppmu.base + PPMU_V2_FLAG); - __raw_writel(clear, info->ppmu.base + PPMU_V2_INTENC); - __raw_writel(clear, info->ppmu.base + PPMU_V2_CNTENC); - __raw_writel(clear, info->ppmu.base + PPMU_V2_CNT_RESET); - - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG0); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG1); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_CFG2); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CIG_RESULT); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CNT_AUTO); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV0_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV1_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV2_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_CH_EV3_TYPE); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_V); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_ID_A); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_V); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_SM_OTHERS_A); - __raw_writel(0x0, info->ppmu.base + PPMU_V2_INTERRUPT_RESET); + ret = regmap_write(info->regmap, PPMU_V2_CH_EV2_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_CH_EV3_TYPE, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_ID_V, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_ID_A, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_V, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_SM_OTHERS_A, 0x0); + if (ret < 0) + return ret; + + ret = regmap_write(info->regmap, PPMU_V2_INTERRUPT_RESET, 0x0); + if (ret < 0) + return ret; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -251,30 +354,43 @@ static int exynos_ppmu_v2_disable(struct devfreq_event_dev *edev) static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); + unsigned int pmnc, cntens; int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntens; + int ret; /* Enable all counters */ - cntens = __raw_readl(info->ppmu.base + PPMU_V2_CNTENS); + ret = regmap_read(info->regmap, PPMU_V2_CNTENS, &cntens); + if (ret < 0) + return ret; + cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntens, info->ppmu.base + PPMU_V2_CNTENS); + ret = regmap_write(info->regmap, PPMU_V2_CNTENS, cntens); + if (ret < 0) + return ret; /* Set the event of Read/Write data count */ switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - __raw_writel(PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT, - info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), + PPMU_V2_RO_DATA_CNT | PPMU_V2_WO_DATA_CNT); + if (ret < 0) + return ret; break; case PPMU_PMNCNT3: - __raw_writel(PPMU_V2_EVT3_RW_DATA_CNT, - info->ppmu.base + PPMU_V2_CH_EVx_TYPE(id)); + ret = regmap_write(info->regmap, PPMU_V2_CH_EVx_TYPE(id), + PPMU_V2_EVT3_RW_DATA_CNT); + if (ret < 0) + return ret; break; } /* Reset cycle counter/performance counter and enable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~(PPMU_PMNC_ENABLE_MASK | PPMU_PMNC_COUNTER_RESET_MASK | PPMU_PMNC_CC_RESET_MASK @@ -284,7 +400,10 @@ static int exynos_ppmu_v2_set_event(struct devfreq_event_dev *edev) pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT); pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT); pmnc |= (PPMU_V2_MODE_MANUAL << PPMU_V2_PMNC_START_MODE_SHIFT); - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; return 0; } @@ -294,37 +413,61 @@ static int exynos_ppmu_v2_get_event(struct devfreq_event_dev *edev, { struct exynos_ppmu *info = devfreq_event_get_drvdata(edev); int id = exynos_ppmu_find_ppmu_id(edev); - u32 pmnc, cntenc; - u32 pmcnt_high, pmcnt_low; - u64 load_count = 0; + int ret; + unsigned int pmnc, cntenc; + unsigned int pmcnt_high, pmcnt_low; + unsigned int total_count, count; + unsigned long load_count = 0; /* Disable PPMU */ - pmnc = __raw_readl(info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_read(info->regmap, PPMU_V2_PMNC, &pmnc); + if (ret < 0) + return ret; + pmnc &= ~PPMU_PMNC_ENABLE_MASK; - __raw_writel(pmnc, info->ppmu.base + PPMU_V2_PMNC); + ret = regmap_write(info->regmap, PPMU_V2_PMNC, pmnc); + if (ret < 0) + return ret; /* Read cycle count and performance count */ - edata->total_count = __raw_readl(info->ppmu.base + PPMU_V2_CCNT); + ret = regmap_read(info->regmap, PPMU_V2_CCNT, &total_count); + if (ret < 0) + return ret; + edata->total_count = total_count; switch (id) { case PPMU_PMNCNT0: case PPMU_PMNCNT1: case PPMU_PMNCNT2: - load_count = __raw_readl(info->ppmu.base + PPMU_V2_PMNCT(id)); + ret = regmap_read(info->regmap, PPMU_V2_PMNCT(id), &count); + if (ret < 0) + return ret; + load_count = count; break; case PPMU_PMNCNT3: - pmcnt_high = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_HIGH); - pmcnt_low = __raw_readl(info->ppmu.base + PPMU_V2_PMCNT3_LOW); - load_count = ((u64)((pmcnt_high & 0xff)) << 32) - + (u64)pmcnt_low; + ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_HIGH, + &pmcnt_high); + if (ret < 0) + return ret; + + ret = regmap_read(info->regmap, PPMU_V2_PMCNT3_LOW, &pmcnt_low); + if (ret < 0) + return ret; + + load_count = ((u64)((pmcnt_high & 0xff)) << 32)+ (u64)pmcnt_low; break; } edata->load_count = load_count; /* Disable all counters */ - cntenc = __raw_readl(info->ppmu.base + PPMU_V2_CNTENC); + ret = regmap_read(info->regmap, PPMU_V2_CNTENC, &cntenc); + if (ret < 0) + return 0; + cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id)); - __raw_writel(cntenc, info->ppmu.base + PPMU_V2_CNTENC); + ret = regmap_write(info->regmap, PPMU_V2_CNTENC, cntenc); + if (ret < 0) + return ret; dev_dbg(&edev->dev, "%25s (load: %ld / %ld)\n", edev->desc->name, edata->load_count, edata->total_count); @@ -411,10 +554,19 @@ static int of_get_devfreq_events(struct device_node *np, return 0; } -static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) +static struct regmap_config exynos_ppmu_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int exynos_ppmu_parse_dt(struct platform_device *pdev, + struct exynos_ppmu *info) { struct device *dev = info->dev; struct device_node *np = dev->of_node; + struct resource *res; + void __iomem *base; int ret = 0; if (!np) { @@ -423,10 +575,17 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) } /* Maps the memory mapped IO to control PPMU register */ - info->ppmu.base = of_iomap(np, 0); - if (IS_ERR_OR_NULL(info->ppmu.base)) { - dev_err(dev, "failed to map memory region\n"); - return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + exynos_ppmu_regmap_config.max_register = resource_size(res) - 4; + info->regmap = devm_regmap_init_mmio(dev, base, + &exynos_ppmu_regmap_config); + if (IS_ERR(info->regmap)) { + dev_err(dev, "failed to initialize regmap\n"); + return PTR_ERR(info->regmap); } info->ppmu.clk = devm_clk_get(dev, "ppmu"); @@ -438,15 +597,10 @@ static int exynos_ppmu_parse_dt(struct exynos_ppmu *info) ret = of_get_devfreq_events(np, info); if (ret < 0) { dev_err(dev, "failed to parse exynos ppmu dt node\n"); - goto err; + return ret; } return 0; - -err: - iounmap(info->ppmu.base); - - return ret; } static int exynos_ppmu_probe(struct platform_device *pdev) @@ -463,7 +617,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) info->dev = &pdev->dev; /* Parse dt data to get resource */ - ret = exynos_ppmu_parse_dt(info); + ret = exynos_ppmu_parse_dt(pdev, info); if (ret < 0) { dev_err(&pdev->dev, "failed to parse devicetree for resource\n"); @@ -476,8 +630,7 @@ static int exynos_ppmu_probe(struct platform_device *pdev) if (!info->edev) { dev_err(&pdev->dev, "failed to allocate memory devfreq-event devices\n"); - ret = -ENOMEM; - goto err; + return -ENOMEM; } edev = info->edev; platform_set_drvdata(pdev, info); @@ -488,17 +641,16 @@ static int exynos_ppmu_probe(struct platform_device *pdev) ret = PTR_ERR(edev[i]); dev_err(&pdev->dev, "failed to add devfreq-event device\n"); - goto err; + return PTR_ERR(edev[i]); } + + pr_info("exynos-ppmu: new PPMU device registered %s (%s)\n", + dev_name(&pdev->dev), desc[i].name); } clk_prepare_enable(info->ppmu.clk); return 0; -err: - iounmap(info->ppmu.base); - - return ret; } static int exynos_ppmu_remove(struct platform_device *pdev) @@ -506,7 +658,6 @@ static int exynos_ppmu_remove(struct platform_device *pdev) struct exynos_ppmu *info = platform_get_drvdata(pdev); clk_disable_unprepare(info->ppmu.clk); - iounmap(info->ppmu.base); return 0; } diff --git a/drivers/devfreq/exynos-bus.c b/drivers/devfreq/exynos-bus.c index a8ed7792ece2..49f68929e024 100644 --- a/drivers/devfreq/exynos-bus.c +++ b/drivers/devfreq/exynos-bus.c @@ -103,18 +103,17 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) int ret = 0; /* Get new opp-bus instance according to new bus clock */ - rcu_read_lock(); new_opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(new_opp)) { dev_err(dev, "failed to get recommended opp instance\n"); - rcu_read_unlock(); return PTR_ERR(new_opp); } new_freq = dev_pm_opp_get_freq(new_opp); new_volt = dev_pm_opp_get_voltage(new_opp); + dev_pm_opp_put(new_opp); + old_freq = bus->curr_freq; - rcu_read_unlock(); if (old_freq == new_freq) return 0; @@ -147,8 +146,8 @@ static int exynos_bus_target(struct device *dev, unsigned long *freq, u32 flags) } bus->curr_freq = new_freq; - dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", - old_freq/1000, new_freq/1000); + dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", + old_freq, new_freq, clk_get_rate(bus->clk)); out: mutex_unlock(&bus->lock); @@ -214,17 +213,16 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq, int ret = 0; /* Get new opp-bus instance according to new bus clock */ - rcu_read_lock(); new_opp = devfreq_recommended_opp(dev, freq, flags); if (IS_ERR(new_opp)) { dev_err(dev, "failed to get recommended opp instance\n"); - rcu_read_unlock(); return PTR_ERR(new_opp); } new_freq = dev_pm_opp_get_freq(new_opp); + dev_pm_opp_put(new_opp); + old_freq = bus->curr_freq; - rcu_read_unlock(); if (old_freq == new_freq) return 0; @@ -241,8 +239,8 @@ static int exynos_bus_passive_target(struct device *dev, unsigned long *freq, *freq = new_freq; bus->curr_freq = new_freq; - dev_dbg(dev, "Set the frequency of bus (%lukHz -> %lukHz)\n", - old_freq/1000, new_freq/1000); + dev_dbg(dev, "Set the frequency of bus (%luHz -> %luHz, %luHz)\n", + old_freq, new_freq, clk_get_rate(bus->clk)); out: mutex_unlock(&bus->lock); @@ -358,16 +356,14 @@ static int exynos_bus_parse_of(struct device_node *np, rate = clk_get_rate(bus->clk); - rcu_read_lock(); opp = devfreq_recommended_opp(dev, &rate, 0); if (IS_ERR(opp)) { dev_err(dev, "failed to find dev_pm_opp\n"); - rcu_read_unlock(); ret = PTR_ERR(opp); goto err_opp; } bus->curr_freq = dev_pm_opp_get_freq(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); return 0; @@ -497,7 +493,7 @@ passive: if (IS_ERR(bus->devfreq)) { dev_err(dev, "failed to add devfreq dev with passive governor\n"); - ret = -EPROBE_DEFER; + ret = PTR_ERR(bus->devfreq); goto err; } diff --git a/drivers/devfreq/governor.h b/drivers/devfreq/governor.h index fad7d6321978..71576b8bdfef 100644 --- a/drivers/devfreq/governor.h +++ b/drivers/devfreq/governor.h @@ -38,4 +38,6 @@ extern void devfreq_interval_update(struct devfreq *devfreq, extern int devfreq_add_governor(struct devfreq_governor *governor); extern int devfreq_remove_governor(struct devfreq_governor *governor); +extern int devfreq_update_status(struct devfreq *devfreq, unsigned long freq); + #endif /* _GOVERNOR_H */ diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c index 9ef46e2592c4..673ad8cc9a1d 100644 --- a/drivers/devfreq/governor_passive.c +++ b/drivers/devfreq/governor_passive.c @@ -59,14 +59,14 @@ static int devfreq_passive_get_target_freq(struct devfreq *devfreq, * list of parent device. Because in this case, *freq is temporary * value which is decided by ondemand governor. */ - rcu_read_lock(); opp = devfreq_recommended_opp(parent_devfreq->dev.parent, freq, 0); - rcu_read_unlock(); if (IS_ERR(opp)) { ret = PTR_ERR(opp); goto out; } + dev_pm_opp_put(opp); + /* * Get the OPP table's index of decided freqeuncy by governor * of parent device. @@ -112,6 +112,11 @@ static int update_devfreq_passive(struct devfreq *devfreq, unsigned long freq) if (ret < 0) goto out; + if (devfreq->profile->freq_table + && (devfreq_update_status(devfreq, freq))) + dev_err(&devfreq->dev, + "Couldn't update frequency transition information.\n"); + devfreq->previous_freq = freq; out: @@ -179,6 +184,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq, static struct devfreq_governor devfreq_passive = { .name = "passive", + .immutable = 1, .get_target_freq = devfreq_passive_get_target_freq, .event_handler = devfreq_passive_event_handler, }; diff --git a/drivers/devfreq/governor_userspace.c b/drivers/devfreq/governor_userspace.c index 35de6e83c1fe..176976068bcd 100644 --- a/drivers/devfreq/governor_userspace.c +++ b/drivers/devfreq/governor_userspace.c @@ -1,5 +1,5 @@ /* - * linux/drivers/devfreq/governor_simpleondemand.c + * linux/drivers/devfreq/governor_userspace.c * * Copyright (C) 2011 Samsung Electronics * MyungJoo Ham <myungjoo.ham@samsung.com> @@ -50,7 +50,6 @@ static ssize_t store_freq(struct device *dev, struct device_attribute *attr, unsigned long wanted; int err = 0; - mutex_lock(&devfreq->lock); data = devfreq->data; @@ -112,7 +111,13 @@ out: static void userspace_exit(struct devfreq *devfreq) { - sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); + /* + * Remove the sysfs entry, unless this is being called after + * device_del(), which should have done this already via kobject_del(). + */ + if (devfreq->dev.kobj.sd) + sysfs_remove_group(&devfreq->dev.kobj, &dev_attr_group); + kfree(devfreq->data); devfreq->data = NULL; } diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c index 27d2f349b53c..40a2499730fc 100644 --- a/drivers/devfreq/rk3399_dmc.c +++ b/drivers/devfreq/rk3399_dmc.c @@ -91,17 +91,13 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq, unsigned long target_volt, target_rate; int err; - rcu_read_lock(); opp = devfreq_recommended_opp(dev, freq, flags); - if (IS_ERR(opp)) { - rcu_read_unlock(); + if (IS_ERR(opp)) return PTR_ERR(opp); - } target_rate = dev_pm_opp_get_freq(opp); target_volt = dev_pm_opp_get_voltage(opp); - - rcu_read_unlock(); + dev_pm_opp_put(opp); if (dmcfreq->rate == target_rate) return 0; @@ -422,15 +418,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev) data->rate = clk_get_rate(data->dmc_clk); - rcu_read_lock(); opp = devfreq_recommended_opp(dev, &data->rate, 0); - if (IS_ERR(opp)) { - rcu_read_unlock(); + if (IS_ERR(opp)) return PTR_ERR(opp); - } + data->rate = dev_pm_opp_get_freq(opp); data->volt = dev_pm_opp_get_voltage(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); rk3399_devfreq_dmc_profile.initial_freq = data->rate; diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c index fe9dce0245bf..214fff96fa4a 100644 --- a/drivers/devfreq/tegra-devfreq.c +++ b/drivers/devfreq/tegra-devfreq.c @@ -487,15 +487,13 @@ static int tegra_devfreq_target(struct device *dev, unsigned long *freq, struct dev_pm_opp *opp; unsigned long rate = *freq * KHZ; - rcu_read_lock(); opp = devfreq_recommended_opp(dev, &rate, flags); if (IS_ERR(opp)) { - rcu_read_unlock(); dev_err(dev, "Failed to find opp for %lu KHz\n", *freq); return PTR_ERR(opp); } rate = dev_pm_opp_get_freq(opp); - rcu_read_unlock(); + dev_pm_opp_put(opp); clk_set_min_rate(tegra->emc_clock, rate); clk_set_rate(tegra->emc_clock, 0); diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index d5ba43a87a68..200828c60db9 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -153,6 +153,8 @@ struct cppi41_dd { /* context for suspend/resume */ unsigned int dma_tdfdq; + + bool is_suspended; }; #define FIST_COMPLETION_QUEUE 93 @@ -257,6 +259,10 @@ static struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) BUG_ON(desc_num >= ALLOC_DECS_NUM); c = cdd->chan_busy[desc_num]; cdd->chan_busy[desc_num] = NULL; + + /* Usecount for chan_busy[], paired with push_desc_queue() */ + pm_runtime_put(cdd->ddev.dev); + return c; } @@ -317,12 +323,12 @@ static irqreturn_t cppi41_irq(int irq, void *data) while (val) { u32 desc, len; - int error; - error = pm_runtime_get(cdd->ddev.dev); - if (error < 0) - dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n", - __func__, error); + /* + * This should never trigger, see the comments in + * push_desc_queue() + */ + WARN_ON(cdd->is_suspended); q_num = __fls(val); val &= ~(1 << q_num); @@ -343,9 +349,6 @@ static irqreturn_t cppi41_irq(int irq, void *data) c->residue = pd_trans_len(c->desc->pd6) - len; dma_cookie_complete(&c->txd); dmaengine_desc_get_callback_invoke(&c->txd, NULL); - - pm_runtime_mark_last_busy(cdd->ddev.dev); - pm_runtime_put_autosuspend(cdd->ddev.dev); } } return IRQ_HANDLED; @@ -447,6 +450,15 @@ static void push_desc_queue(struct cppi41_channel *c) */ __iowmb(); + /* + * DMA transfers can take at least 200ms to complete with USB mass + * storage connected. To prevent autosuspend timeouts, we must use + * pm_runtime_get/put() when chan_busy[] is modified. This will get + * cleared in desc_to_chan() or cppi41_stop_chan() depending on the + * outcome of the transfer. + */ + pm_runtime_get(cdd->ddev.dev); + desc_phys = lower_32_bits(c->desc_phys); desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); WARN_ON(cdd->chan_busy[desc_num]); @@ -457,20 +469,26 @@ static void push_desc_queue(struct cppi41_channel *c) cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); } -static void pending_desc(struct cppi41_channel *c) +/* + * Caller must hold cdd->lock to prevent push_desc_queue() + * getting called out of order. We have both cppi41_dma_issue_pending() + * and cppi41_runtime_resume() call this function. + */ +static void cppi41_run_queue(struct cppi41_dd *cdd) { - struct cppi41_dd *cdd = c->cdd; - unsigned long flags; + struct cppi41_channel *c, *_c; - spin_lock_irqsave(&cdd->lock, flags); - list_add_tail(&c->node, &cdd->pending); - spin_unlock_irqrestore(&cdd->lock, flags); + list_for_each_entry_safe(c, _c, &cdd->pending, node) { + push_desc_queue(c); + list_del(&c->node); + } } static void cppi41_dma_issue_pending(struct dma_chan *chan) { struct cppi41_channel *c = to_cpp41_chan(chan); struct cppi41_dd *cdd = c->cdd; + unsigned long flags; int error; error = pm_runtime_get(cdd->ddev.dev); @@ -482,10 +500,11 @@ static void cppi41_dma_issue_pending(struct dma_chan *chan) return; } - if (likely(pm_runtime_active(cdd->ddev.dev))) - push_desc_queue(c); - else - pending_desc(c); + spin_lock_irqsave(&cdd->lock, flags); + list_add_tail(&c->node, &cdd->pending); + if (!cdd->is_suspended) + cppi41_run_queue(cdd); + spin_unlock_irqrestore(&cdd->lock, flags); pm_runtime_mark_last_busy(cdd->ddev.dev); pm_runtime_put_autosuspend(cdd->ddev.dev); @@ -705,6 +724,9 @@ static int cppi41_stop_chan(struct dma_chan *chan) WARN_ON(!cdd->chan_busy[desc_num]); cdd->chan_busy[desc_num] = NULL; + /* Usecount for chan_busy[], paired with push_desc_queue() */ + pm_runtime_put(cdd->ddev.dev); + return 0; } @@ -1150,8 +1172,12 @@ static int __maybe_unused cppi41_resume(struct device *dev) static int __maybe_unused cppi41_runtime_suspend(struct device *dev) { struct cppi41_dd *cdd = dev_get_drvdata(dev); + unsigned long flags; + spin_lock_irqsave(&cdd->lock, flags); + cdd->is_suspended = true; WARN_ON(!list_empty(&cdd->pending)); + spin_unlock_irqrestore(&cdd->lock, flags); return 0; } @@ -1159,14 +1185,11 @@ static int __maybe_unused cppi41_runtime_suspend(struct device *dev) static int __maybe_unused cppi41_runtime_resume(struct device *dev) { struct cppi41_dd *cdd = dev_get_drvdata(dev); - struct cppi41_channel *c, *_c; unsigned long flags; spin_lock_irqsave(&cdd->lock, flags); - list_for_each_entry_safe(c, _c, &cdd->pending, node) { - push_desc_queue(c); - list_del(&c->node); - } + cdd->is_suspended = false; + cppi41_run_queue(cdd); spin_unlock_irqrestore(&cdd->lock, flags); return 0; diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig index e00c9b022964..5a37b9fcf40d 100644 --- a/drivers/dma/dw/Kconfig +++ b/drivers/dma/dw/Kconfig @@ -24,5 +24,5 @@ config DW_DMAC_PCI select DW_DMAC_CORE help Support the Synopsys DesignWare AHB DMA controller on the - platfroms that enumerate it as a PCI device. For example, + platforms that enumerate it as a PCI device. For example, Intel Medfield has integrated this GPDMA controller. diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index 8e67895bcca3..abcc51b343ce 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h @@ -64,6 +64,8 @@ #define PCI_DEVICE_ID_INTEL_IOAT_BDX8 0x6f2e #define PCI_DEVICE_ID_INTEL_IOAT_BDX9 0x6f2f +#define PCI_DEVICE_ID_INTEL_IOAT_SKX 0x2021 + #define IOAT_VER_1_2 0x12 /* Version 1.2 */ #define IOAT_VER_2_0 0x20 /* Version 2.0 */ #define IOAT_VER_3_0 0x30 /* Version 3.0 */ diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 90eddd9f07e4..cc5259b881d4 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -106,6 +106,8 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_SKX) }, + /* I/OAT v3.3 platforms */ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) }, @@ -243,10 +245,15 @@ static bool is_bdx_ioat(struct pci_dev *pdev) } } +static inline bool is_skx_ioat(struct pci_dev *pdev) +{ + return (pdev->device == PCI_DEVICE_ID_INTEL_IOAT_SKX) ? true : false; +} + static bool is_xeon_cb32(struct pci_dev *pdev) { return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) || - is_hsw_ioat(pdev) || is_bdx_ioat(pdev); + is_hsw_ioat(pdev) || is_bdx_ioat(pdev) || is_skx_ioat(pdev); } bool is_bwd_ioat(struct pci_dev *pdev) @@ -693,7 +700,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c) /* doing 2 32bit writes to mmio since 1 64b write doesn't work */ ioat_chan->completion = dma_pool_zalloc(ioat_chan->ioat_dma->completion_pool, - GFP_KERNEL, &ioat_chan->completion_dma); + GFP_NOWAIT, &ioat_chan->completion_dma); if (!ioat_chan->completion) return -ENOMEM; @@ -703,7 +710,7 @@ static int ioat_alloc_chan_resources(struct dma_chan *c) ioat_chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); order = IOAT_MAX_ORDER; - ring = ioat_alloc_ring(c, order, GFP_KERNEL); + ring = ioat_alloc_ring(c, order, GFP_NOWAIT); if (!ring) return -ENOMEM; @@ -1357,6 +1364,8 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) device->version = readb(device->reg_base + IOAT_VER_OFFSET); if (device->version >= IOAT_VER_3_0) { + if (is_skx_ioat(pdev)) + device->version = IOAT_VER_3_2; err = ioat3_dma_probe(device, ioat_dca_enabled); if (device->version >= IOAT_VER_3_3) diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index ac68666cd3f4..daf479cce691 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -938,21 +938,14 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr |= CCR_DST_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_SRC_AMODE_DBLIDX; - d->ei = 1; - /* - * One frame covers the port_window and by configure - * the source frame index to be -1 * (port_window - 1) - * we instruct the sDMA that after a frame is processed - * it should move back to the start of the window. - */ - d->fi = -(port_window_bytes - 1); if (port_window_bytes >= 64) - d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; + d->csdp |= CSDP_SRC_BURST_64; else if (port_window_bytes >= 32) - d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED; + d->csdp |= CSDP_SRC_BURST_32; else if (port_window_bytes >= 16) - d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED; + d->csdp |= CSDP_SRC_BURST_16; + } else { d->ccr |= CCR_SRC_AMODE_CONSTANT; } @@ -962,13 +955,21 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr |= CCR_SRC_AMODE_POSTINC; if (port_window) { d->ccr |= CCR_DST_AMODE_DBLIDX; + d->ei = 1; + /* + * One frame covers the port_window and by configure + * the source frame index to be -1 * (port_window - 1) + * we instruct the sDMA that after a frame is processed + * it should move back to the start of the window. + */ + d->fi = -(port_window_bytes - 1); if (port_window_bytes >= 64) - d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; + d->csdp |= CSDP_DST_BURST_64; else if (port_window_bytes >= 32) - d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED; + d->csdp |= CSDP_DST_BURST_32; else if (port_window_bytes >= 16) - d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED; + d->csdp |= CSDP_DST_BURST_16; } else { d->ccr |= CCR_DST_AMODE_CONSTANT; } @@ -1017,7 +1018,7 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( osg->addr = sg_dma_address(sgent); osg->en = en; osg->fn = sg_dma_len(sgent) / frame_bytes; - if (port_window && dir == DMA_MEM_TO_DEV) { + if (port_window && dir == DMA_DEV_TO_MEM) { osg->ei = 1; /* * One frame covers the port_window and by configure @@ -1452,6 +1453,7 @@ static int omap_dma_probe(struct platform_device *pdev) struct omap_dmadev *od; struct resource *res; int rc, i, irq; + u32 lch_count; od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL); if (!od) @@ -1494,20 +1496,31 @@ static int omap_dma_probe(struct platform_device *pdev) spin_lock_init(&od->lock); spin_lock_init(&od->irq_lock); - if (!pdev->dev.of_node) { - od->dma_requests = od->plat->dma_attr->lch_count; - if (unlikely(!od->dma_requests)) - od->dma_requests = OMAP_SDMA_REQUESTS; - } else if (of_property_read_u32(pdev->dev.of_node, "dma-requests", - &od->dma_requests)) { + /* Number of DMA requests */ + od->dma_requests = OMAP_SDMA_REQUESTS; + if (pdev->dev.of_node && of_property_read_u32(pdev->dev.of_node, + "dma-requests", + &od->dma_requests)) { dev_info(&pdev->dev, "Missing dma-requests property, using %u.\n", OMAP_SDMA_REQUESTS); - od->dma_requests = OMAP_SDMA_REQUESTS; } - od->lch_map = devm_kcalloc(&pdev->dev, od->dma_requests, - sizeof(*od->lch_map), GFP_KERNEL); + /* Number of available logical channels */ + if (!pdev->dev.of_node) { + lch_count = od->plat->dma_attr->lch_count; + if (unlikely(!lch_count)) + lch_count = OMAP_SDMA_CHANNELS; + } else if (of_property_read_u32(pdev->dev.of_node, "dma-channels", + &lch_count)) { + dev_info(&pdev->dev, + "Missing dma-channels property, using %u.\n", + OMAP_SDMA_CHANNELS); + lch_count = OMAP_SDMA_CHANNELS; + } + + od->lch_map = devm_kcalloc(&pdev->dev, lch_count, sizeof(*od->lch_map), + GFP_KERNEL); if (!od->lch_map) return -ENOMEM; diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 87fd01539fcb..f37f4978dabb 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -448,6 +448,9 @@ struct dma_pl330_chan { /* for cyclic capability */ bool cyclic; + + /* for runtime pm tracking */ + bool active; }; struct pl330_dmac { @@ -1696,7 +1699,6 @@ static bool _chan_ns(const struct pl330_dmac *pl330, int i) static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) { struct pl330_thread *thrd = NULL; - unsigned long flags; int chans, i; if (pl330->state == DYING) @@ -1704,8 +1706,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) chans = pl330->pcfg.num_chan; - spin_lock_irqsave(&pl330->lock, flags); - for (i = 0; i < chans; i++) { thrd = &pl330->channels[i]; if ((thrd->free) && (!_manager_ns(thrd) || @@ -1723,8 +1723,6 @@ static struct pl330_thread *pl330_request_channel(struct pl330_dmac *pl330) thrd = NULL; } - spin_unlock_irqrestore(&pl330->lock, flags); - return thrd; } @@ -1742,7 +1740,6 @@ static inline void _free_event(struct pl330_thread *thrd, int ev) static void pl330_release_channel(struct pl330_thread *thrd) { struct pl330_dmac *pl330; - unsigned long flags; if (!thrd || thrd->free) return; @@ -1754,10 +1751,8 @@ static void pl330_release_channel(struct pl330_thread *thrd) pl330 = thrd->dmac; - spin_lock_irqsave(&pl330->lock, flags); _free_event(thrd, thrd->ev); thrd->free = true; - spin_unlock_irqrestore(&pl330->lock, flags); } /* Initialize the structure for PL330 configuration, that can be used @@ -1864,9 +1859,10 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) * Alloc MicroCode buffer for 'chans' Channel threads. * A channel's buffer offset is (Channel_Id * MCODE_BUFF_PERCHAN) */ - pl330->mcode_cpu = dma_alloc_coherent(pl330->ddma.dev, + pl330->mcode_cpu = dma_alloc_attrs(pl330->ddma.dev, chans * pl330->mcbufsz, - &pl330->mcode_bus, GFP_KERNEL); + &pl330->mcode_bus, GFP_KERNEL, + DMA_ATTR_PRIVILEGED); if (!pl330->mcode_cpu) { dev_err(pl330->ddma.dev, "%s:%d Can't allocate memory!\n", __func__, __LINE__); @@ -2033,6 +2029,7 @@ static void pl330_tasklet(unsigned long data) _stop(pch->thread); spin_unlock(&pch->thread->dmac->lock); power_down = true; + pch->active = false; } else { /* Make sure the PL330 Channel thread is active */ spin_lock(&pch->thread->dmac->lock); @@ -2052,6 +2049,7 @@ static void pl330_tasklet(unsigned long data) desc->status = PREP; list_move_tail(&desc->node, &pch->work_list); if (power_down) { + pch->active = true; spin_lock(&pch->thread->dmac->lock); _start(pch->thread); spin_unlock(&pch->thread->dmac->lock); @@ -2117,20 +2115,20 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan) struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; - spin_lock_irqsave(&pch->lock, flags); + spin_lock_irqsave(&pl330->lock, flags); dma_cookie_init(chan); pch->cyclic = false; pch->thread = pl330_request_channel(pl330); if (!pch->thread) { - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); return -ENOMEM; } tasklet_init(&pch->task, pl330_tasklet, (unsigned long) pch); - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); return 1; } @@ -2166,6 +2164,7 @@ static int pl330_terminate_all(struct dma_chan *chan) unsigned long flags; struct pl330_dmac *pl330 = pch->dmac; LIST_HEAD(list); + bool power_down = false; pm_runtime_get_sync(pl330->ddma.dev); spin_lock_irqsave(&pch->lock, flags); @@ -2176,6 +2175,8 @@ static int pl330_terminate_all(struct dma_chan *chan) pch->thread->req[0].desc = NULL; pch->thread->req[1].desc = NULL; pch->thread->req_running = -1; + power_down = pch->active; + pch->active = false; /* Mark all desc done */ list_for_each_entry(desc, &pch->submitted_list, node) { @@ -2193,6 +2194,8 @@ static int pl330_terminate_all(struct dma_chan *chan) list_splice_tail_init(&pch->completed_list, &pl330->desc_pool); spin_unlock_irqrestore(&pch->lock, flags); pm_runtime_mark_last_busy(pl330->ddma.dev); + if (power_down) + pm_runtime_put_autosuspend(pl330->ddma.dev); pm_runtime_put_autosuspend(pl330->ddma.dev); return 0; @@ -2228,12 +2231,13 @@ static int pl330_pause(struct dma_chan *chan) static void pl330_free_chan_resources(struct dma_chan *chan) { struct dma_pl330_chan *pch = to_pchan(chan); + struct pl330_dmac *pl330 = pch->dmac; unsigned long flags; tasklet_kill(&pch->task); pm_runtime_get_sync(pch->dmac->ddma.dev); - spin_lock_irqsave(&pch->lock, flags); + spin_lock_irqsave(&pl330->lock, flags); pl330_release_channel(pch->thread); pch->thread = NULL; @@ -2241,7 +2245,7 @@ static void pl330_free_chan_resources(struct dma_chan *chan) if (pch->cyclic) list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool); - spin_unlock_irqrestore(&pch->lock, flags); + spin_unlock_irqrestore(&pl330->lock, flags); pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pch->dmac->ddma.dev); } @@ -2357,6 +2361,7 @@ static void pl330_issue_pending(struct dma_chan *chan) * updated on work_list emptiness status. */ WARN_ON(list_empty(&pch->submitted_list)); + pch->active = true; pm_runtime_get_sync(pch->dmac->ddma.dev); } list_splice_tail_init(&pch->submitted_list, &pch->work_list); diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c index 2e441d0ccd79..4c357d475465 100644 --- a/drivers/dma/sh/rcar-dmac.c +++ b/drivers/dma/sh/rcar-dmac.c @@ -986,6 +986,7 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan) { struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan); struct rcar_dmac *dmac = to_rcar_dmac(chan->device); + struct rcar_dmac_chan_map *map = &rchan->map; struct rcar_dmac_desc_page *page, *_page; struct rcar_dmac_desc *desc; LIST_HEAD(list); @@ -1019,6 +1020,13 @@ static void rcar_dmac_free_chan_resources(struct dma_chan *chan) free_page((unsigned long)page); } + /* Remove slave mapping if present. */ + if (map->slave.xfer_size) { + dma_unmap_resource(chan->device->dev, map->addr, + map->slave.xfer_size, map->dir, 0); + map->slave.xfer_size = 0; + } + pm_runtime_put(chan->device->dev); } diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 3688d0873a3e..3056ce7f8c69 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -880,7 +880,7 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, struct virt_dma_desc *vdesc; enum dma_status status; unsigned long flags; - u32 residue; + u32 residue = 0; status = dma_cookie_status(c, cookie, state); if ((status == DMA_COMPLETE) || (!state)) @@ -888,16 +888,12 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, spin_lock_irqsave(&chan->vchan.lock, flags); vdesc = vchan_find_desc(&chan->vchan, cookie); - if (cookie == chan->desc->vdesc.tx.cookie) { + if (chan->desc && cookie == chan->desc->vdesc.tx.cookie) residue = stm32_dma_desc_residue(chan, chan->desc, chan->next_sg); - } else if (vdesc) { + else if (vdesc) residue = stm32_dma_desc_residue(chan, to_stm32_dma_desc(vdesc), 0); - } else { - residue = 0; - } - dma_set_residue(state, residue); spin_unlock_irqrestore(&chan->vchan.lock, flags); @@ -972,21 +968,18 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, struct stm32_dma_chan *chan; struct dma_chan *c; - if (dma_spec->args_count < 3) + if (dma_spec->args_count < 4) return NULL; cfg.channel_id = dma_spec->args[0]; cfg.request_line = dma_spec->args[1]; cfg.stream_config = dma_spec->args[2]; - cfg.threshold = 0; + cfg.threshold = dma_spec->args[3]; if ((cfg.channel_id >= STM32_DMA_MAX_CHANNELS) || (cfg.request_line >= STM32_DMA_MAX_REQUEST_ID)) return NULL; - if (dma_spec->args_count > 3) - cfg.threshold = dma_spec->args[3]; - chan = &dmadev->chan[cfg.channel_id]; c = dma_get_slave_channel(&chan->vchan.chan); diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 3f24aeb48c0e..2403475a37cf 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -149,6 +149,7 @@ static int ti_am335x_xbar_probe(struct platform_device *pdev) match = of_match_node(ti_am335x_master_match, dma_node); if (!match) { dev_err(&pdev->dev, "DMA master is not supported\n"); + of_node_put(dma_node); return -EINVAL; } @@ -339,6 +340,7 @@ static int ti_dra7_xbar_probe(struct platform_device *pdev) match = of_match_node(ti_dra7_master_match, dma_node); if (!match) { dev_err(&pdev->dev, "DMA master is not supported\n"); + of_node_put(dma_node); return -EINVAL; } diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 260251177830..82dab1692264 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -3065,6 +3065,8 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) /* Check whether at least one UMC is enabled: */ if (umc_en_mask) ecc_en = umc_en_mask == ecc_en_mask; + else + edac_dbg(0, "Node %d: No enabled UMCs.\n", nid); /* Assume UMC MCA banks are enabled. */ nb_mce_en = true; @@ -3075,14 +3077,15 @@ static bool ecc_enabled(struct pci_dev *F3, u16 nid) nb_mce_en = nb_mce_bank_enabled_on_node(nid); if (!nb_mce_en) - amd64_notice("NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n", + edac_dbg(0, "NB MCE bank disabled, set MSR 0x%08x[4] on node %d to enable.\n", MSR_IA32_MCG_CTL, nid); } - amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled")); + amd64_info("Node %d: DRAM ECC %s.\n", + nid, (ecc_en ? "enabled" : "disabled")); if (!ecc_en || !nb_mce_en) { - amd64_notice("%s", ecc_msg); + amd64_info("%s", ecc_msg); return false; } return true; @@ -3300,15 +3303,6 @@ static int init_one_instance(unsigned int nid) goto err_add_mc; } - /* register stuff with EDAC MCE */ - if (report_gart_errors) - amd_report_gart_errors(true); - - if (pvt->umc) - amd_register_ecc_decoder(decode_umc_error); - else - amd_register_ecc_decoder(decode_bus_error); - return 0; err_add_mc: @@ -3342,7 +3336,7 @@ static int probe_one_instance(unsigned int nid) ecc_stngs[nid] = s; if (!ecc_enabled(F3, nid)) { - ret = -ENODEV; + ret = 0; if (!ecc_enable_override) goto err_enable; @@ -3363,6 +3357,8 @@ static int probe_one_instance(unsigned int nid) if (boot_cpu_data.x86 < 0x17) restore_ecc_error_reporting(s, nid, F3); + + goto err_enable; } return ret; @@ -3396,14 +3392,6 @@ static void remove_one_instance(unsigned int nid) free_mc_sibling_devs(pvt); - /* unregister from EDAC MCE */ - amd_report_gart_errors(false); - - if (pvt->umc) - amd_unregister_ecc_decoder(decode_umc_error); - else - amd_unregister_ecc_decoder(decode_bus_error); - kfree(ecc_stngs[nid]); ecc_stngs[nid] = NULL; @@ -3452,8 +3440,11 @@ static int __init amd64_edac_init(void) int err = -ENODEV; int i; + if (!x86_match_cpu(amd64_cpuids)) + return -ENODEV; + if (amd_cache_northbridges() < 0) - goto err_ret; + return -ENODEV; opstate_init(); @@ -3466,14 +3457,30 @@ static int __init amd64_edac_init(void) if (!msrs) goto err_free; - for (i = 0; i < amd_nb_num(); i++) - if (probe_one_instance(i)) { + for (i = 0; i < amd_nb_num(); i++) { + err = probe_one_instance(i); + if (err) { /* unwind properly */ while (--i >= 0) remove_one_instance(i); goto err_pci; } + } + + if (!edac_has_mcs()) { + err = -ENODEV; + goto err_pci; + } + + /* register stuff with EDAC MCE */ + if (report_gart_errors) + amd_report_gart_errors(true); + + if (boot_cpu_data.x86 >= 0x17) + amd_register_ecc_decoder(decode_umc_error); + else + amd_register_ecc_decoder(decode_bus_error); setup_pci_device(); @@ -3493,7 +3500,6 @@ err_free: kfree(ecc_stngs); ecc_stngs = NULL; -err_ret: return err; } @@ -3504,6 +3510,14 @@ static void __exit amd64_edac_exit(void) if (pci_ctl) edac_pci_release_generic_ctl(pci_ctl); + /* unregister from EDAC MCE */ + amd_report_gart_errors(false); + + if (boot_cpu_data.x86 >= 0x17) + amd_unregister_ecc_decoder(decode_umc_error); + else + amd_unregister_ecc_decoder(decode_bus_error); + for (i = 0; i < amd_nb_num(); i++) remove_one_instance(i); diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 496603d8f3d2..1d4b74e9a037 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -16,19 +16,14 @@ #include <linux/slab.h> #include <linux/mmzone.h> #include <linux/edac.h> +#include <asm/cpu_device_id.h> #include <asm/msr.h> #include "edac_module.h" #include "mce_amd.h" -#define amd64_debug(fmt, arg...) \ - edac_printk(KERN_DEBUG, "amd64", fmt, ##arg) - #define amd64_info(fmt, arg...) \ edac_printk(KERN_INFO, "amd64", fmt, ##arg) -#define amd64_notice(fmt, arg...) \ - edac_printk(KERN_NOTICE, "amd64", fmt, ##arg) - #define amd64_warn(fmt, arg...) \ edac_printk(KERN_WARNING, "amd64", "Warning: " fmt, ##arg) @@ -90,7 +85,7 @@ * sections 3.5.4 and 3.5.5 for more information. */ -#define EDAC_AMD64_VERSION "3.4.0" +#define EDAC_AMD64_VERSION "3.5.0" #define EDAC_MOD_STR "amd64_edac" /* Extended Model from CPUID, for CPU Revision numbers */ diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 750891ea07de..e5573c56b15e 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -453,6 +453,20 @@ void edac_mc_free(struct mem_ctl_info *mci) } EXPORT_SYMBOL_GPL(edac_mc_free); +bool edac_has_mcs(void) +{ + bool ret; + + mutex_lock(&mem_ctls_mutex); + + ret = list_empty(&mc_devices); + + mutex_unlock(&mem_ctls_mutex); + + return !ret; +} +EXPORT_SYMBOL_GPL(edac_has_mcs); + /* Caller must hold mem_ctls_mutex */ static struct mem_ctl_info *__find_mci_by_dev(struct device *dev) { diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 50fc1dc9c0d8..5357800e418d 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -149,6 +149,15 @@ extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, extern void edac_mc_free(struct mem_ctl_info *mci); /** + * edac_has_mcs() - Check if any MCs have been allocated. + * + * Returns: + * True if MC instances have been registered successfully. + * False otherwise. + */ +extern bool edac_has_mcs(void); + +/** * edac_mc_find() - Search for a mem_ctl_info structure whose index is @idx. * * @idx: index to be seek diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 39dbab7d62f1..445862dac273 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -569,6 +569,40 @@ static ssize_t dimmdev_edac_mode_show(struct device *dev, return sprintf(data, "%s\n", edac_caps[dimm->edac_mode]); } +static ssize_t dimmdev_ce_count_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct dimm_info *dimm = to_dimm(dev); + u32 count; + int off; + + off = EDAC_DIMM_OFF(dimm->mci->layers, + dimm->mci->n_layers, + dimm->location[0], + dimm->location[1], + dimm->location[2]); + count = dimm->mci->ce_per_layer[dimm->mci->n_layers-1][off]; + return sprintf(data, "%u\n", count); +} + +static ssize_t dimmdev_ue_count_show(struct device *dev, + struct device_attribute *mattr, + char *data) +{ + struct dimm_info *dimm = to_dimm(dev); + u32 count; + int off; + + off = EDAC_DIMM_OFF(dimm->mci->layers, + dimm->mci->n_layers, + dimm->location[0], + dimm->location[1], + dimm->location[2]); + count = dimm->mci->ue_per_layer[dimm->mci->n_layers-1][off]; + return sprintf(data, "%u\n", count); +} + /* dimm/rank attribute files */ static DEVICE_ATTR(dimm_label, S_IRUGO | S_IWUSR, dimmdev_label_show, dimmdev_label_store); @@ -577,6 +611,8 @@ static DEVICE_ATTR(size, S_IRUGO, dimmdev_size_show, NULL); static DEVICE_ATTR(dimm_mem_type, S_IRUGO, dimmdev_mem_type_show, NULL); static DEVICE_ATTR(dimm_dev_type, S_IRUGO, dimmdev_dev_type_show, NULL); static DEVICE_ATTR(dimm_edac_mode, S_IRUGO, dimmdev_edac_mode_show, NULL); +static DEVICE_ATTR(dimm_ce_count, S_IRUGO, dimmdev_ce_count_show, NULL); +static DEVICE_ATTR(dimm_ue_count, S_IRUGO, dimmdev_ue_count_show, NULL); /* attributes of the dimm<id>/rank<id> object */ static struct attribute *dimm_attrs[] = { @@ -586,6 +622,8 @@ static struct attribute *dimm_attrs[] = { &dev_attr_dimm_mem_type.attr, &dev_attr_dimm_dev_type.attr, &dev_attr_dimm_edac_mode.attr, + &dev_attr_dimm_ce_count.attr, + &dev_attr_dimm_ue_count.attr, NULL, }; @@ -831,7 +869,7 @@ static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL); static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL); /* memory scrubber attribute file */ -DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show, +static DEVICE_ATTR(sdram_scrub_rate, 0, mci_sdram_scrub_rate_show, mci_sdram_scrub_rate_store); /* umode set later in is_visible */ static struct attribute *mci_attrs[] = { diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 4e9608a958e7..efc8276d1d9c 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -145,12 +145,12 @@ static ssize_t fsl_mc_inject_ctrl_store(struct device *dev, return 0; } -DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, - fsl_mc_inject_data_hi_show, fsl_mc_inject_data_hi_store); -DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, - fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); -DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, - fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); +static DEVICE_ATTR(inject_data_hi, S_IRUGO | S_IWUSR, + fsl_mc_inject_data_hi_show, fsl_mc_inject_data_hi_store); +static DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, + fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); +static DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, + fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); static struct attribute *fsl_ddr_dev_attrs[] = { &dev_attr_inject_data_hi.attr, diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 0a912bf6de00..e391f5a716be 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -304,7 +304,6 @@ static const char *ferr_global_lo_name[] = { #define REDMEMA 0xdc #define REDMEMB 0x7c - #define IS_SECOND_CH(v) ((v) * (1 << 17)) #define RECMEMA 0xe0 #define RECMEMA_BANK(v) (((v) >> 12) & 7) @@ -483,8 +482,9 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) pci_read_config_dword(pvt->pci_dev_16_1_fsb_addr_map, REDMEMB, &value); channel = (branch << 1); - if (IS_SECOND_CH(value)) - channel++; + + /* Second channel ? */ + channel += !!(value & BIT(17)); /* Clear the error bit */ pci_write_config_dword(pvt->pci_dev_16_1_fsb_addr_map, diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 69b5adead0ad..75ad847593b7 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1835,6 +1835,7 @@ static int i7core_mce_check_error(struct notifier_block *nb, unsigned long val, static struct notifier_block i7_mce_dec = { .notifier_call = i7core_mce_check_error, + .priority = MCE_PRIO_EDAC, }; struct memdev_dmi_entry { diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 7baa8ace267b..9dcdab28f665 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -494,6 +494,10 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx) } mchbar &= 0xffffc000; /* bits 31:14 used for 16K window */ mch_window = ioremap_nocache(mchbar, 0x1000); + if (!mch_window) { + edac_dbg(3, "error ioremapping MCHBAR!\n"); + goto fail0; + } #ifdef i82975x_DEBUG_IOMEM i82975x_printk(KERN_INFO, "MCHBAR real = %0x, remapped = %p\n", diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 34208f38c5b1..ba35b7ea3686 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -937,12 +937,13 @@ static const char *decode_error_status(struct mce *m) } if (m->status & MCI_STATUS_DEFERRED) - return "Deferred error."; + return "Deferred error, no action required."; return "Corrected error, no action required."; } -int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) +static int +amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) { struct mce *m = (struct mce *)data; struct cpuinfo_x86 *c = &cpu_data(m->extcpu); @@ -991,20 +992,22 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) pr_cont("]: 0x%016llx\n", m->status); if (m->status & MCI_STATUS_ADDRV) - pr_emerg(HW_ERR "Error Addr: 0x%016llx", m->addr); + pr_emerg(HW_ERR "Error Addr: 0x%016llx\n", m->addr); if (boot_cpu_has(X86_FEATURE_SMCA)) { + pr_emerg(HW_ERR "IPID: 0x%016llx", m->ipid); + if (m->status & MCI_STATUS_SYNDV) pr_cont(", Syndrome: 0x%016llx", m->synd); - pr_cont(", IPID: 0x%016llx", m->ipid); - pr_cont("\n"); decode_smca_errors(m); goto err_code; - } else - pr_cont("\n"); + } + + if (m->tsc) + pr_emerg(HW_ERR "TSC: %llu\n", m->tsc); if (!fam_ops) goto err_code; @@ -1047,10 +1050,10 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) return NOTIFY_STOP; } -EXPORT_SYMBOL_GPL(amd_decode_mce); static struct notifier_block amd_mce_dec_nb = { .notifier_call = amd_decode_mce, + .priority = MCE_PRIO_EDAC, }; static int __init mce_amd_init(void) diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h index c2359a1ea6b3..0b6a68673e0e 100644 --- a/drivers/edac/mce_amd.h +++ b/drivers/edac/mce_amd.h @@ -79,6 +79,5 @@ struct amd_decoder_ops { void amd_report_gart_errors(bool); void amd_register_ecc_decoder(void (*f)(int, struct mce *)); void amd_unregister_ecc_decoder(void (*f)(int, struct mce *)); -int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data); #endif /* _EDAC_MCE_AMD_H */ diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index 8f66cbed70b7..67f7bc3fe5b3 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -629,6 +629,7 @@ static const struct of_device_id mpc85xx_l2_err_of_match[] = { { .compatible = "fsl,p1020-l2-cache-controller", }, { .compatible = "fsl,p1021-l2-cache-controller", }, { .compatible = "fsl,p2020-l2-cache-controller", }, + { .compatible = "fsl,t2080-l2-cache-controller", }, {}, }; MODULE_DEVICE_TABLE(of, mpc85xx_l2_err_of_match); diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 54ae6dc45ab2..a65ea44e3b0b 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -304,7 +304,6 @@ struct sbridge_info { u64 (*rir_limit)(u32 reg); u64 (*sad_limit)(u32 reg); u32 (*interleave_mode)(u32 reg); - char* (*show_interleave_mode)(u32 reg); u32 (*dram_attr)(u32 reg); const u32 *dram_rule; const u32 *interleave_list; @@ -811,11 +810,6 @@ static u32 interleave_mode(u32 reg) return GET_BITFIELD(reg, 1, 1); } -char *show_interleave_mode(u32 reg) -{ - return interleave_mode(reg) ? "8:6" : "[8:6]XOR[18:16]"; -} - static u32 dram_attr(u32 reg) { return GET_BITFIELD(reg, 2, 3); @@ -831,29 +825,16 @@ static u32 knl_interleave_mode(u32 reg) return GET_BITFIELD(reg, 1, 2); } -static char *knl_show_interleave_mode(u32 reg) -{ - char *s; - - switch (knl_interleave_mode(reg)) { - case 0: - s = "use address bits [8:6]"; - break; - case 1: - s = "use address bits [10:8]"; - break; - case 2: - s = "use address bits [14:12]"; - break; - case 3: - s = "use address bits [32:30]"; - break; - default: - WARN_ON(1); - break; - } +static const char * const knl_intlv_mode[] = { + "[8:6]", "[10:8]", "[14:12]", "[32:30]" +}; - return s; +static const char *get_intlv_mode_str(u32 reg, enum type t) +{ + if (t == KNIGHTS_LANDING) + return knl_intlv_mode[knl_interleave_mode(reg)]; + else + return interleave_mode(reg) ? "[8:6]" : "[8:6]XOR[18:16]"; } static u32 dram_attr_knl(u32 reg) @@ -1810,7 +1791,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) show_dram_attr(pvt->info.dram_attr(reg)), gb, (mb*1000)/1024, ((u64)tmp_mb) << 20L, - pvt->info.show_interleave_mode(reg), + get_intlv_mode_str(reg, pvt->info.type), reg); prv = limit; @@ -3136,7 +3117,8 @@ static int sbridge_mce_check_error(struct notifier_block *nb, unsigned long val, } static struct notifier_block sbridge_mce_dec = { - .notifier_call = sbridge_mce_check_error, + .notifier_call = sbridge_mce_check_error, + .priority = MCE_PRIO_EDAC, }; /**************************************************************************** @@ -3227,7 +3209,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.rir_limit = rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; - pvt->info.show_interleave_mode = show_interleave_mode; pvt->info.dram_attr = dram_attr; pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); pvt->info.interleave_list = ibridge_interleave_list; @@ -3251,7 +3232,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.rir_limit = rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; - pvt->info.show_interleave_mode = show_interleave_mode; pvt->info.dram_attr = dram_attr; pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); pvt->info.interleave_list = sbridge_interleave_list; @@ -3275,7 +3255,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.rir_limit = haswell_rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; - pvt->info.show_interleave_mode = show_interleave_mode; pvt->info.dram_attr = dram_attr; pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); pvt->info.interleave_list = ibridge_interleave_list; @@ -3299,7 +3278,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.rir_limit = haswell_rir_limit; pvt->info.sad_limit = sad_limit; pvt->info.interleave_mode = interleave_mode; - pvt->info.show_interleave_mode = show_interleave_mode; pvt->info.dram_attr = dram_attr; pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); pvt->info.interleave_list = ibridge_interleave_list; @@ -3323,7 +3301,6 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.rir_limit = NULL; pvt->info.sad_limit = knl_sad_limit; pvt->info.interleave_mode = knl_interleave_mode; - pvt->info.show_interleave_mode = knl_show_interleave_mode; pvt->info.dram_attr = dram_attr_knl; pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule); pvt->info.interleave_list = knl_interleave_list; diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c index 79ef675e4d6f..1159dba4671f 100644 --- a/drivers/edac/skx_edac.c +++ b/drivers/edac/skx_edac.c @@ -1007,7 +1007,8 @@ static int skx_mce_check_error(struct notifier_block *nb, unsigned long val, } static struct notifier_block skx_mce_dec = { - .notifier_call = skx_mce_check_error, + .notifier_call = skx_mce_check_error, + .priority = MCE_PRIO_EDAC, }; static void skx_remove(void) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index 78298460d168..7c1e3a7b14e0 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -453,7 +453,7 @@ int extcon_sync(struct extcon_dev *edev, unsigned int id) dev_err(&edev->dev, "out of memory in extcon_set_state\n"); kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); - return 0; + return -ENOMEM; } length = name_show(&edev->dev, NULL, prop_buf); diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 70e13230d8db..9ad0b1934be9 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -721,11 +721,17 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val) ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id), &buf, sizeof(buf)); - if (!ret) + if (ret) + return ret; + + if (scpi_info->is_legacy) + /* only 32-bits supported, hi_val can be junk */ + *val = le32_to_cpu(buf.lo_val); + else *val = (u64)le32_to_cpu(buf.hi_val) << 32 | le32_to_cpu(buf.lo_val); - return ret; + return 0; } static int scpi_device_get_power_state(u16 dev_id) diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c index f853ad2c4ca0..1027d7b44358 100644 --- a/drivers/firmware/efi/arm-init.c +++ b/drivers/firmware/efi/arm-init.c @@ -250,7 +250,6 @@ void __init efi_init(void) } reserve_regions(); - efi_memattr_init(); efi_esrt_init(); efi_memmap_unmap(); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 92914801e388..e7d404059b73 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -529,6 +529,8 @@ int __init efi_config_parse_tables(void *config_tables, int count, int sz, } } + efi_memattr_init(); + /* Parse the EFI Properties table if it exists */ if (efi.properties_table != EFI_INVALID_TABLE_ADDR) { efi_properties_table_t *tbl; diff --git a/drivers/firmware/efi/esrt.c b/drivers/firmware/efi/esrt.c index 14914074f716..08b026864d4e 100644 --- a/drivers/firmware/efi/esrt.c +++ b/drivers/firmware/efi/esrt.c @@ -269,7 +269,7 @@ void __init efi_esrt_init(void) max -= efi.esrt; if (max < size) { - pr_err("ESRT header doen't fit on single memory map entry. (size: %zu max: %zu)\n", + pr_err("ESRT header doesn't fit on single memory map entry. (size: %zu max: %zu)\n", size, max); return; } diff --git a/drivers/firmware/efi/fake_mem.c b/drivers/firmware/efi/fake_mem.c index 520a40e5e0e4..6c7d60c239b5 100644 --- a/drivers/firmware/efi/fake_mem.c +++ b/drivers/firmware/efi/fake_mem.c @@ -71,8 +71,7 @@ void __init efi_fake_memmap(void) } /* allocate memory for new EFI memmap */ - new_memmap_phy = memblock_alloc(efi.memmap.desc_size * new_nr_map, - PAGE_SIZE); + new_memmap_phy = efi_memmap_alloc(new_nr_map); if (!new_memmap_phy) return; diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index d564d25df8ab..f7425960f6a5 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -11,7 +11,7 @@ cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -mno-mmx -mno-sse cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS)) -cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) -g0 \ +cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \ -fno-builtin -fpic -mno-single-pic-base cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt @@ -28,7 +28,7 @@ OBJECT_FILES_NON_STANDARD := y # Prevents link failures: __sanitizer_cov_trace_pc() is not linked in. KCOV_INSTRUMENT := n -lib-y := efi-stub-helper.o gop.o +lib-y := efi-stub-helper.o gop.o secureboot.o # include the stub's generic dependencies from lib/ when building for ARM/arm64 arm-deps := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c fdt_empty_tree.c fdt_sw.c sort.c @@ -60,7 +60,7 @@ CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) extra-$(CONFIG_EFI_ARMSTUB) := $(lib-y) lib-$(CONFIG_EFI_ARMSTUB) := $(patsubst %.o,%.stub.o,$(lib-y)) -STUBCOPY_FLAGS-y := -R .debug* -R *ksymtab* -R *kcrctab* +STUBCOPY_RM-y := -R *ksymtab* -R *kcrctab* STUBCOPY_FLAGS-$(CONFIG_ARM64) += --prefix-alloc-sections=.init \ --prefix-symbols=__efistub_ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS @@ -68,17 +68,25 @@ STUBCOPY_RELOC-$(CONFIG_ARM64) := R_AARCH64_ABS $(obj)/%.stub.o: $(obj)/%.o FORCE $(call if_changed,stubcopy) +# +# Strip debug sections and some other sections that may legally contain +# absolute relocations, so that we can inspect the remaining sections for +# such relocations. If none are found, regenerate the output object, but +# this time, use objcopy and leave all sections in place. +# quiet_cmd_stubcopy = STUBCPY $@ - cmd_stubcopy = if $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; then \ - $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \ - && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ - rm -f $@; /bin/false); else /bin/false; fi + cmd_stubcopy = if $(STRIP) --strip-debug $(STUBCOPY_RM-y) -o $@ $<; \ + then if $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y); \ + then (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ + rm -f $@; /bin/false); \ + else $(OBJCOPY) $(STUBCOPY_FLAGS-y) $< $@; fi \ + else /bin/false; fi # # ARM discards the .data section because it disallows r/w data in the # decompressor. So move our .data to .data.efistub, which is preserved # explicitly by the decompressor linker script. # -STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub \ - -R ___ksymtab+sort -R ___kcrctab+sort +STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub +STUBCOPY_RM-$(CONFIG_ARM) += -R ___ksymtab+sort -R ___kcrctab+sort STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index b4f7d78f9e8b..d4056c6be1ec 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c @@ -20,52 +20,6 @@ bool __nokaslr; -static int efi_get_secureboot(efi_system_table_t *sys_table_arg) -{ - static efi_char16_t const sb_var_name[] = { - 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 }; - static efi_char16_t const sm_var_name[] = { - 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 }; - - efi_guid_t var_guid = EFI_GLOBAL_VARIABLE_GUID; - efi_get_variable_t *f_getvar = sys_table_arg->runtime->get_variable; - u8 val; - unsigned long size = sizeof(val); - efi_status_t status; - - status = f_getvar((efi_char16_t *)sb_var_name, (efi_guid_t *)&var_guid, - NULL, &size, &val); - - if (status != EFI_SUCCESS) - goto out_efi_err; - - if (val == 0) - return 0; - - status = f_getvar((efi_char16_t *)sm_var_name, (efi_guid_t *)&var_guid, - NULL, &size, &val); - - if (status != EFI_SUCCESS) - goto out_efi_err; - - if (val == 1) - return 0; - - return 1; - -out_efi_err: - switch (status) { - case EFI_NOT_FOUND: - return 0; - case EFI_DEVICE_ERROR: - return -EIO; - case EFI_SECURITY_VIOLATION: - return -EACCES; - default: - return -EINVAL; - } -} - efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh) { @@ -91,75 +45,6 @@ efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, return status; } -efi_status_t efi_file_close(void *handle) -{ - efi_file_handle_t *fh = handle; - - return fh->close(handle); -} - -efi_status_t -efi_file_read(void *handle, unsigned long *size, void *addr) -{ - efi_file_handle_t *fh = handle; - - return fh->read(handle, size, addr); -} - - -efi_status_t -efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, - efi_char16_t *filename_16, void **handle, u64 *file_sz) -{ - efi_file_handle_t *h, *fh = __fh; - efi_file_info_t *info; - efi_status_t status; - efi_guid_t info_guid = EFI_FILE_INFO_ID; - unsigned long info_sz; - - status = fh->open(fh, &h, filename_16, EFI_FILE_MODE_READ, (u64)0); - if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to open file: "); - efi_char16_printk(sys_table_arg, filename_16); - efi_printk(sys_table_arg, "\n"); - return status; - } - - *handle = h; - - info_sz = 0; - status = h->get_info(h, &info_guid, &info_sz, NULL); - if (status != EFI_BUFFER_TOO_SMALL) { - efi_printk(sys_table_arg, "Failed to get file info size\n"); - return status; - } - -grow: - status = sys_table_arg->boottime->allocate_pool(EFI_LOADER_DATA, - info_sz, (void **)&info); - if (status != EFI_SUCCESS) { - efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); - return status; - } - - status = h->get_info(h, &info_guid, &info_sz, - info); - if (status == EFI_BUFFER_TOO_SMALL) { - sys_table_arg->boottime->free_pool(info); - goto grow; - } - - *file_sz = info->file_size; - sys_table_arg->boottime->free_pool(info); - - if (status != EFI_SUCCESS) - efi_printk(sys_table_arg, "Failed to get initrd info\n"); - - return status; -} - - - void efi_char16_printk(efi_system_table_t *sys_table_arg, efi_char16_t *str) { @@ -226,7 +111,7 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, efi_guid_t loaded_image_proto = LOADED_IMAGE_PROTOCOL_GUID; unsigned long reserve_addr = 0; unsigned long reserve_size = 0; - int secure_boot = 0; + enum efi_secureboot_mode secure_boot; struct screen_info *si; /* Check if we were booted by the EFI firmware */ @@ -296,19 +181,14 @@ unsigned long efi_entry(void *handle, efi_system_table_t *sys_table, pr_efi_err(sys_table, "Failed to parse EFI cmdline options\n"); secure_boot = efi_get_secureboot(sys_table); - if (secure_boot > 0) - pr_efi(sys_table, "UEFI Secure Boot is enabled.\n"); - - if (secure_boot < 0) { - pr_efi_err(sys_table, - "could not determine UEFI Secure Boot status.\n"); - } /* - * Unauthenticated device tree data is a security hazard, so - * ignore 'dtb=' unless UEFI Secure Boot is disabled. + * Unauthenticated device tree data is a security hazard, so ignore + * 'dtb=' unless UEFI Secure Boot is disabled. We assume that secure + * boot is enabled if we can't determine its state. */ - if (secure_boot != 0 && strstr(cmdline_ptr, "dtb=")) { + if (secure_boot != efi_secureboot_mode_disabled && + strstr(cmdline_ptr, "dtb=")) { pr_efi(sys_table, "Ignoring DTB from command line.\n"); } else { status = handle_cmdline_files(sys_table, image, cmdline_ptr, diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 757badc1debb..919822b7773d 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -338,6 +338,69 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, efi_call_early(free_pages, addr, nr_pages); } +static efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, + efi_char16_t *filename_16, void **handle, + u64 *file_sz) +{ + efi_file_handle_t *h, *fh = __fh; + efi_file_info_t *info; + efi_status_t status; + efi_guid_t info_guid = EFI_FILE_INFO_ID; + unsigned long info_sz; + + status = efi_call_proto(efi_file_handle, open, fh, &h, filename_16, + EFI_FILE_MODE_READ, (u64)0); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to open file: "); + efi_char16_printk(sys_table_arg, filename_16); + efi_printk(sys_table_arg, "\n"); + return status; + } + + *handle = h; + + info_sz = 0; + status = efi_call_proto(efi_file_handle, get_info, h, &info_guid, + &info_sz, NULL); + if (status != EFI_BUFFER_TOO_SMALL) { + efi_printk(sys_table_arg, "Failed to get file info size\n"); + return status; + } + +grow: + status = efi_call_early(allocate_pool, EFI_LOADER_DATA, + info_sz, (void **)&info); + if (status != EFI_SUCCESS) { + efi_printk(sys_table_arg, "Failed to alloc mem for file info\n"); + return status; + } + + status = efi_call_proto(efi_file_handle, get_info, h, &info_guid, + &info_sz, info); + if (status == EFI_BUFFER_TOO_SMALL) { + efi_call_early(free_pool, info); + goto grow; + } + + *file_sz = info->file_size; + efi_call_early(free_pool, info); + + if (status != EFI_SUCCESS) + efi_printk(sys_table_arg, "Failed to get initrd info\n"); + + return status; +} + +static efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr) +{ + return efi_call_proto(efi_file_handle, read, handle, size, addr); +} + +static efi_status_t efi_file_close(void *handle) +{ + return efi_call_proto(efi_file_handle, close, handle); +} + /* * Parse the ASCII string 'cmdline' for EFI options, denoted by the efi= * option, e.g. efi=nochunk. @@ -351,6 +414,14 @@ efi_status_t efi_parse_options(char *cmdline) char *str; /* + * Currently, the only efi= option we look for is 'nochunk', which + * is intended to work around known issues on certain x86 UEFI + * versions. So ignore for now on other architectures. + */ + if (!IS_ENABLED(CONFIG_X86)) + return EFI_SUCCESS; + + /* * If no EFI parameters were specified on the cmdline we've got * nothing to do. */ @@ -523,7 +594,8 @@ efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, size = files[j].size; while (size) { unsigned long chunksize; - if (size > __chunk_size) + + if (IS_ENABLED(CONFIG_X86) && size > __chunk_size) chunksize = __chunk_size; else chunksize = size; diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h index b98824e3800a..71c4d0e3c4ed 100644 --- a/drivers/firmware/efi/libstub/efistub.h +++ b/drivers/firmware/efi/libstub/efistub.h @@ -29,24 +29,8 @@ void efi_char16_printk(efi_system_table_t *, efi_char16_t *); efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image, void **__fh); -efi_status_t efi_file_size(efi_system_table_t *sys_table_arg, void *__fh, - efi_char16_t *filename_16, void **handle, - u64 *file_sz); - -efi_status_t efi_file_read(void *handle, unsigned long *size, void *addr); - -efi_status_t efi_file_close(void *handle); - unsigned long get_dram_base(efi_system_table_t *sys_table_arg); -efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, - unsigned long orig_fdt_size, - void *fdt, int new_fdt_size, char *cmdline_ptr, - u64 initrd_addr, u64 initrd_size, - efi_memory_desc_t *memory_map, - unsigned long map_size, unsigned long desc_size, - u32 desc_ver); - efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, void *handle, unsigned long *new_fdt_addr, diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c index a6a93116a8f0..260c4b4b492e 100644 --- a/drivers/firmware/efi/libstub/fdt.c +++ b/drivers/firmware/efi/libstub/fdt.c @@ -16,13 +16,10 @@ #include "efistub.h" -efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, - unsigned long orig_fdt_size, - void *fdt, int new_fdt_size, char *cmdline_ptr, - u64 initrd_addr, u64 initrd_size, - efi_memory_desc_t *memory_map, - unsigned long map_size, unsigned long desc_size, - u32 desc_ver) +static efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, + unsigned long orig_fdt_size, + void *fdt, int new_fdt_size, char *cmdline_ptr, + u64 initrd_addr, u64 initrd_size) { int node, num_rsv; int status; @@ -101,25 +98,23 @@ efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, if (status) goto fdt_set_fail; - fdt_val64 = cpu_to_fdt64((u64)(unsigned long)memory_map); + fdt_val64 = U64_MAX; /* placeholder */ status = fdt_setprop(fdt, node, "linux,uefi-mmap-start", &fdt_val64, sizeof(fdt_val64)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(map_size); + fdt_val32 = U32_MAX; /* placeholder */ status = fdt_setprop(fdt, node, "linux,uefi-mmap-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(desc_size); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-size", &fdt_val32, sizeof(fdt_val32)); if (status) goto fdt_set_fail; - fdt_val32 = cpu_to_fdt32(desc_ver); status = fdt_setprop(fdt, node, "linux,uefi-mmap-desc-ver", &fdt_val32, sizeof(fdt_val32)); if (status) @@ -148,6 +143,43 @@ fdt_set_fail: return EFI_LOAD_ERROR; } +static efi_status_t update_fdt_memmap(void *fdt, struct efi_boot_memmap *map) +{ + int node = fdt_path_offset(fdt, "/chosen"); + u64 fdt_val64; + u32 fdt_val32; + int err; + + if (node < 0) + return EFI_LOAD_ERROR; + + fdt_val64 = cpu_to_fdt64((unsigned long)*map->map); + err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-start", + &fdt_val64, sizeof(fdt_val64)); + if (err) + return EFI_LOAD_ERROR; + + fdt_val32 = cpu_to_fdt32(*map->map_size); + err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-size", + &fdt_val32, sizeof(fdt_val32)); + if (err) + return EFI_LOAD_ERROR; + + fdt_val32 = cpu_to_fdt32(*map->desc_size); + err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-size", + &fdt_val32, sizeof(fdt_val32)); + if (err) + return EFI_LOAD_ERROR; + + fdt_val32 = cpu_to_fdt32(*map->desc_ver); + err = fdt_setprop_inplace(fdt, node, "linux,uefi-mmap-desc-ver", + &fdt_val32, sizeof(fdt_val32)); + if (err) + return EFI_LOAD_ERROR; + + return EFI_SUCCESS; +} + #ifndef EFI_FDT_ALIGN #define EFI_FDT_ALIGN EFI_PAGE_SIZE #endif @@ -155,6 +187,7 @@ fdt_set_fail: struct exit_boot_struct { efi_memory_desc_t *runtime_map; int *runtime_entry_count; + void *new_fdt_addr; }; static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, @@ -170,7 +203,7 @@ static efi_status_t exit_boot_func(efi_system_table_t *sys_table_arg, efi_get_virtmap(*map->map, *map->map_size, *map->desc_size, p->runtime_map, p->runtime_entry_count); - return EFI_SUCCESS; + return update_fdt_memmap(p->new_fdt_addr, map); } /* @@ -243,20 +276,10 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, goto fail; } - /* - * Now that we have done our final memory allocation (and free) - * we can get the memory map key needed for - * exit_boot_services(). - */ - status = efi_get_memory_map(sys_table, &map); - if (status != EFI_SUCCESS) - goto fail_free_new_fdt; - status = update_fdt(sys_table, (void *)fdt_addr, fdt_size, (void *)*new_fdt_addr, new_fdt_size, - cmdline_ptr, initrd_addr, initrd_size, - memory_map, map_size, desc_size, desc_ver); + cmdline_ptr, initrd_addr, initrd_size); /* Succeeding the first time is the expected case. */ if (status == EFI_SUCCESS) @@ -266,22 +289,19 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, /* * We need to allocate more space for the new * device tree, so free existing buffer that is - * too small. Also free memory map, as we will need - * to get new one that reflects the free/alloc we do - * on the device tree buffer. + * too small. */ efi_free(sys_table, new_fdt_size, *new_fdt_addr); - sys_table->boottime->free_pool(memory_map); new_fdt_size += EFI_PAGE_SIZE; } else { pr_efi_err(sys_table, "Unable to construct new device tree.\n"); - goto fail_free_mmap; + goto fail_free_new_fdt; } } - sys_table->boottime->free_pool(memory_map); priv.runtime_map = runtime_map; priv.runtime_entry_count = &runtime_entry_count; + priv.new_fdt_addr = (void *)*new_fdt_addr; status = efi_exit_boot_services(sys_table, handle, &map, &priv, exit_boot_func); @@ -319,9 +339,6 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table, pr_efi_err(sys_table, "Exit boot services failed.\n"); -fail_free_mmap: - sys_table->boottime->free_pool(memory_map); - fail_free_new_fdt: efi_free(sys_table, new_fdt_size, *new_fdt_addr); diff --git a/drivers/firmware/efi/libstub/secureboot.c b/drivers/firmware/efi/libstub/secureboot.c new file mode 100644 index 000000000000..6def402bf569 --- /dev/null +++ b/drivers/firmware/efi/libstub/secureboot.c @@ -0,0 +1,84 @@ +/* + * Secure boot handling. + * + * Copyright (C) 2013,2014 Linaro Limited + * Roy Franz <roy.franz@linaro.org + * Copyright (C) 2013 Red Hat, Inc. + * Mark Salter <msalter@redhat.com> + * + * This file is part of the Linux kernel, and is made available under the + * terms of the GNU General Public License version 2. + */ +#include <linux/efi.h> +#include <asm/efi.h> + +/* BIOS variables */ +static const efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID; +static const efi_char16_t const efi_SecureBoot_name[] = { + 'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', 0 +}; +static const efi_char16_t const efi_SetupMode_name[] = { + 'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', 0 +}; + +/* SHIM variables */ +static const efi_guid_t shim_guid = EFI_SHIM_LOCK_GUID; +static efi_char16_t const shim_MokSBState_name[] = { + 'M', 'o', 'k', 'S', 'B', 'S', 't', 'a', 't', 'e', 0 +}; + +#define get_efi_var(name, vendor, ...) \ + efi_call_runtime(get_variable, \ + (efi_char16_t *)(name), (efi_guid_t *)(vendor), \ + __VA_ARGS__); + +/* + * Determine whether we're in secure boot mode. + */ +enum efi_secureboot_mode efi_get_secureboot(efi_system_table_t *sys_table_arg) +{ + u32 attr; + u8 secboot, setupmode, moksbstate; + unsigned long size; + efi_status_t status; + + size = sizeof(secboot); + status = get_efi_var(efi_SecureBoot_name, &efi_variable_guid, + NULL, &size, &secboot); + if (status != EFI_SUCCESS) + goto out_efi_err; + + size = sizeof(setupmode); + status = get_efi_var(efi_SetupMode_name, &efi_variable_guid, + NULL, &size, &setupmode); + if (status != EFI_SUCCESS) + goto out_efi_err; + + if (secboot == 0 || setupmode == 1) + return efi_secureboot_mode_disabled; + + /* + * See if a user has put the shim into insecure mode. If so, and if the + * variable doesn't have the runtime attribute set, we might as well + * honor that. + */ + size = sizeof(moksbstate); + status = get_efi_var(shim_MokSBState_name, &shim_guid, + &attr, &size, &moksbstate); + + /* If it fails, we don't care why. Default to secure */ + if (status != EFI_SUCCESS) + goto secure_boot_enabled; + if (!(attr & EFI_VARIABLE_RUNTIME_ACCESS) && moksbstate == 1) + return efi_secureboot_mode_disabled; + +secure_boot_enabled: + pr_efi(sys_table_arg, "UEFI Secure Boot is enabled.\n"); + return efi_secureboot_mode_enabled; + +out_efi_err: + pr_efi_err(sys_table_arg, "Could not determine UEFI Secure Boot status.\n"); + if (status == EFI_NOT_FOUND) + return efi_secureboot_mode_disabled; + return efi_secureboot_mode_unknown; +} diff --git a/drivers/firmware/efi/memattr.c b/drivers/firmware/efi/memattr.c index 236004b9a50d..8986757eafaf 100644 --- a/drivers/firmware/efi/memattr.c +++ b/drivers/firmware/efi/memattr.c @@ -43,6 +43,7 @@ int __init efi_memattr_init(void) tbl_size = sizeof(*tbl) + tbl->num_entries * tbl->desc_size; memblock_reserve(efi.mem_attr_table, tbl_size); + set_bit(EFI_MEM_ATTR, &efi.flags); unmap: early_memunmap(tbl, sizeof(*tbl)); @@ -174,8 +175,11 @@ int __init efi_memattr_apply_permissions(struct mm_struct *mm, md.phys_addr + size - 1, efi_md_typeattr_format(buf, sizeof(buf), &md)); - if (valid) + if (valid) { ret = fn(mm, &md); + if (ret) + pr_err("Error updating mappings, skipping subsequent md's\n"); + } } memunmap(tbl); return ret; diff --git a/drivers/firmware/efi/memmap.c b/drivers/firmware/efi/memmap.c index f03ddecd232b..78686443cb37 100644 --- a/drivers/firmware/efi/memmap.c +++ b/drivers/firmware/efi/memmap.c @@ -9,6 +9,44 @@ #include <linux/efi.h> #include <linux/io.h> #include <asm/early_ioremap.h> +#include <linux/memblock.h> +#include <linux/slab.h> + +static phys_addr_t __init __efi_memmap_alloc_early(unsigned long size) +{ + return memblock_alloc(size, 0); +} + +static phys_addr_t __init __efi_memmap_alloc_late(unsigned long size) +{ + unsigned int order = get_order(size); + struct page *p = alloc_pages(GFP_KERNEL, order); + + if (!p) + return 0; + + return PFN_PHYS(page_to_pfn(p)); +} + +/** + * efi_memmap_alloc - Allocate memory for the EFI memory map + * @num_entries: Number of entries in the allocated map. + * + * Depending on whether mm_init() has already been invoked or not, + * either memblock or "normal" page allocation is used. + * + * Returns the physical address of the allocated memory map on + * success, zero on failure. + */ +phys_addr_t __init efi_memmap_alloc(unsigned int num_entries) +{ + unsigned long size = num_entries * efi.memmap.desc_size; + + if (slab_is_available()) + return __efi_memmap_alloc_late(size); + + return __efi_memmap_alloc_early(size); +} /** * __efi_memmap_init - Common code for mapping the EFI memory map diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c index 44bdb78f837b..29d58feaf675 100644 --- a/drivers/firmware/psci_checker.c +++ b/drivers/firmware/psci_checker.c @@ -270,8 +270,7 @@ static int suspend_test_thread(void *arg) struct cpuidle_device *dev; struct cpuidle_driver *drv; /* No need for an actual callback, we just want to wake up the CPU. */ - struct timer_list wakeup_timer = - TIMER_INITIALIZER(dummy_callback, 0, 0); + struct timer_list wakeup_timer; /* Wait for the main thread to give the start signal. */ wait_for_completion(&suspend_threads_started); @@ -287,6 +286,7 @@ static int suspend_test_thread(void *arg) pr_info("CPU %d entering suspend cycles, states 1 through %d\n", cpu, drv->state_count - 1); + setup_timer_on_stack(&wakeup_timer, dummy_callback, 0); for (i = 0; i < NUM_SUSPEND_CYCLE; ++i) { int index; /* diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 1e8fde8cb803..2292742eac8f 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -205,7 +205,7 @@ static int mxs_gpio_set_wake_irq(struct irq_data *d, unsigned int enable) return 0; } -static int __init mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) +static int mxs_gpio_init_gc(struct mxs_gpio_port *port, int irq_base) { struct irq_chip_generic *gc; struct irq_chip_type *ct; diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index f4c26c7826cd..a07ae9e37930 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1317,12 +1317,12 @@ void gpiochip_remove(struct gpio_chip *chip) /* FIXME: should the legacy sysfs handling be moved to gpio_device? */ gpiochip_sysfs_unregister(gdev); + gpiochip_free_hogs(chip); /* Numb the device, cancelling all outstanding operations */ gdev->chip = NULL; gpiochip_irqchip_remove(chip); acpi_gpiochip_remove(chip); gpiochip_remove_pin_ranges(chip); - gpiochip_free_hogs(chip); of_gpiochip_remove(chip); /* * We accept no more calls into the driver from this point, so @@ -1723,7 +1723,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) } /** - * _gpiochip_irqchip_add() - adds an irqchip to a gpiochip + * gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip * @gpiochip: the gpiochip to add the irqchip to * @irqchip: the irqchip to add to the gpiochip * @first_irq: if not dynamically assigned, the base (first) IRQ to @@ -1749,13 +1749,13 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) * the pins on the gpiochip can generate a unique IRQ. Everything else * need to be open coded. */ -int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, - struct irq_chip *irqchip, - unsigned int first_irq, - irq_flow_handler_t handler, - unsigned int type, - bool nested, - struct lock_class_key *lock_key) +int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip, + struct irq_chip *irqchip, + unsigned int first_irq, + irq_flow_handler_t handler, + unsigned int type, + bool nested, + struct lock_class_key *lock_key) { struct device_node *of_node; bool irq_base_set = false; @@ -1840,7 +1840,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip, return 0; } -EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add); +EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key); #else /* CONFIG_GPIOLIB_IRQCHIP */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c index 9ada56c16a58..4c851fde1e82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c @@ -840,6 +840,9 @@ static int amdgpu_cgs_get_firmware_info(struct cgs_device *cgs_device, else if (type == CGS_UCODE_ID_SMU_SK) strcpy(fw_name, "amdgpu/polaris10_smc_sk.bin"); break; + case CHIP_POLARIS12: + strcpy(fw_name, "amdgpu/polaris12_smc.bin"); + break; default: DRM_ERROR("SMC firmware not supported\n"); return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 29d6d84d1c28..41e41f90265d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -83,6 +83,13 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type, } break; } + + if (!(*out_ring && (*out_ring)->adev)) { + DRM_ERROR("Ring %d is not initialized on IP %d\n", + ring, ip_type); + return -EINVAL; + } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 60bd4afe45c8..fe3bb94fe58d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -73,6 +73,7 @@ static const char *amdgpu_asic_name[] = { "STONEY", "POLARIS10", "POLARIS11", + "POLARIS12", "LAST", }; @@ -1277,6 +1278,7 @@ static int amdgpu_early_init(struct amdgpu_device *adev) case CHIP_FIJI: case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: case CHIP_CARRIZO: case CHIP_STONEY: if (adev->asic_type == CHIP_CARRIZO || adev->asic_type == CHIP_STONEY) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 8cb937b2bfcc..2534adaebe30 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -418,6 +418,13 @@ static const struct pci_device_id pciidlist[] = { {0x1002, 0x67CA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67CC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, {0x1002, 0x67CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS10}, + /* Polaris12 */ + {0x1002, 0x6980, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x6981, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x6985, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x6986, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x6987, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, + {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12}, {0, 0, 0} }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c index fc592c2b0e16..95a568df8551 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_powerplay.c @@ -98,6 +98,7 @@ static int amdgpu_pp_early_init(void *handle) switch (adev->asic_type) { case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: case CHIP_TONGA: case CHIP_FIJI: case CHIP_TOPAZ: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index a81dfaeeb8c0..1d564beb0fde 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -65,6 +65,7 @@ #define FIRMWARE_STONEY "amdgpu/stoney_uvd.bin" #define FIRMWARE_POLARIS10 "amdgpu/polaris10_uvd.bin" #define FIRMWARE_POLARIS11 "amdgpu/polaris11_uvd.bin" +#define FIRMWARE_POLARIS12 "amdgpu/polaris12_uvd.bin" /** * amdgpu_uvd_cs_ctx - Command submission parser context @@ -98,6 +99,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); MODULE_FIRMWARE(FIRMWARE_STONEY); MODULE_FIRMWARE(FIRMWARE_POLARIS10); MODULE_FIRMWARE(FIRMWARE_POLARIS11); +MODULE_FIRMWARE(FIRMWARE_POLARIS12); static void amdgpu_uvd_idle_work_handler(struct work_struct *work); @@ -149,6 +151,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) case CHIP_POLARIS11: fw_name = FIRMWARE_POLARIS11; break; + case CHIP_POLARIS12: + fw_name = FIRMWARE_POLARIS12; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 69b66b9e7f57..8fec802d3908 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -52,6 +52,7 @@ #define FIRMWARE_STONEY "amdgpu/stoney_vce.bin" #define FIRMWARE_POLARIS10 "amdgpu/polaris10_vce.bin" #define FIRMWARE_POLARIS11 "amdgpu/polaris11_vce.bin" +#define FIRMWARE_POLARIS12 "amdgpu/polaris12_vce.bin" #ifdef CONFIG_DRM_AMDGPU_CIK MODULE_FIRMWARE(FIRMWARE_BONAIRE); @@ -66,6 +67,7 @@ MODULE_FIRMWARE(FIRMWARE_FIJI); MODULE_FIRMWARE(FIRMWARE_STONEY); MODULE_FIRMWARE(FIRMWARE_POLARIS10); MODULE_FIRMWARE(FIRMWARE_POLARIS11); +MODULE_FIRMWARE(FIRMWARE_POLARIS12); static void amdgpu_vce_idle_work_handler(struct work_struct *work); @@ -121,6 +123,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) case CHIP_POLARIS11: fw_name = FIRMWARE_POLARIS11; break; + case CHIP_POLARIS12: + fw_name = FIRMWARE_POLARIS12; + break; default: return -EINVAL; diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 9999dc71b998..ccb5e02e7b20 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -2512,6 +2512,8 @@ static int dce_v10_0_cursor_move_locked(struct drm_crtc *crtc, WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, + ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); return 0; } @@ -2537,7 +2539,6 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; struct drm_gem_object *obj; struct amdgpu_bo *aobj; int ret; @@ -2578,7 +2579,9 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v10_0_lock_cursor(crtc, true); - if (hot_x != amdgpu_crtc->cursor_hot_x || + if (width != amdgpu_crtc->cursor_width || + height != amdgpu_crtc->cursor_height || + hot_x != amdgpu_crtc->cursor_hot_x || hot_y != amdgpu_crtc->cursor_hot_y) { int x, y; @@ -2587,16 +2590,10 @@ static int dce_v10_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v10_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_hot_x = hot_x; - amdgpu_crtc->cursor_hot_y = hot_y; - } - - if (width != amdgpu_crtc->cursor_width || - height != amdgpu_crtc->cursor_height) { - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (width - 1) << 16 | (height - 1)); amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; } dce_v10_0_show_cursor(crtc); @@ -2620,7 +2617,6 @@ unpin: static void dce_v10_0_cursor_reset(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; if (amdgpu_crtc->cursor_bo) { dce_v10_0_lock_cursor(crtc, true); @@ -2628,10 +2624,6 @@ static void dce_v10_0_cursor_reset(struct drm_crtc *crtc) dce_v10_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, amdgpu_crtc->cursor_y); - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (amdgpu_crtc->cursor_width - 1) << 16 | - (amdgpu_crtc->cursor_height - 1)); - dce_v10_0_show_cursor(crtc); dce_v10_0_lock_cursor(crtc, false); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index b3d62b909f43..a7af5b33a5e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -167,6 +167,7 @@ static void dce_v11_0_init_golden_registers(struct amdgpu_device *adev) (const u32)ARRAY_SIZE(stoney_golden_settings_a11)); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: amdgpu_program_register_sequence(adev, polaris11_golden_settings_a11, (const u32)ARRAY_SIZE(polaris11_golden_settings_a11)); @@ -608,6 +609,7 @@ static int dce_v11_0_get_num_crtc (struct amdgpu_device *adev) num_crtc = 6; break; case CHIP_POLARIS11: + case CHIP_POLARIS12: num_crtc = 5; break; default: @@ -1589,6 +1591,7 @@ static int dce_v11_0_audio_init(struct amdgpu_device *adev) adev->mode_info.audio.num_pins = 8; break; case CHIP_POLARIS11: + case CHIP_POLARIS12: adev->mode_info.audio.num_pins = 6; break; default: @@ -2388,7 +2391,8 @@ static u32 dce_v11_0_pick_pll(struct drm_crtc *crtc) int pll; if ((adev->asic_type == CHIP_POLARIS10) || - (adev->asic_type == CHIP_POLARIS11)) { + (adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) { struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(amdgpu_crtc->encoder); struct amdgpu_encoder_atom_dig *dig = amdgpu_encoder->enc_priv; @@ -2528,6 +2532,8 @@ static int dce_v11_0_cursor_move_locked(struct drm_crtc *crtc, WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, + ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); return 0; } @@ -2553,7 +2559,6 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; struct drm_gem_object *obj; struct amdgpu_bo *aobj; int ret; @@ -2594,7 +2599,9 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v11_0_lock_cursor(crtc, true); - if (hot_x != amdgpu_crtc->cursor_hot_x || + if (width != amdgpu_crtc->cursor_width || + height != amdgpu_crtc->cursor_height || + hot_x != amdgpu_crtc->cursor_hot_x || hot_y != amdgpu_crtc->cursor_hot_y) { int x, y; @@ -2603,16 +2610,10 @@ static int dce_v11_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v11_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_hot_x = hot_x; - amdgpu_crtc->cursor_hot_y = hot_y; - } - - if (width != amdgpu_crtc->cursor_width || - height != amdgpu_crtc->cursor_height) { - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (width - 1) << 16 | (height - 1)); amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; } dce_v11_0_show_cursor(crtc); @@ -2636,7 +2637,6 @@ unpin: static void dce_v11_0_cursor_reset(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; if (amdgpu_crtc->cursor_bo) { dce_v11_0_lock_cursor(crtc, true); @@ -2644,10 +2644,6 @@ static void dce_v11_0_cursor_reset(struct drm_crtc *crtc) dce_v11_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, amdgpu_crtc->cursor_y); - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (amdgpu_crtc->cursor_width - 1) << 16 | - (amdgpu_crtc->cursor_height - 1)); - dce_v11_0_show_cursor(crtc); dce_v11_0_lock_cursor(crtc, false); @@ -2822,7 +2818,8 @@ static int dce_v11_0_crtc_mode_set(struct drm_crtc *crtc, return -EINVAL; if ((adev->asic_type == CHIP_POLARIS10) || - (adev->asic_type == CHIP_POLARIS11)) { + (adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) { struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(amdgpu_crtc->encoder); int encoder_mode = @@ -2992,6 +2989,7 @@ static int dce_v11_0_early_init(void *handle) adev->mode_info.num_dig = 6; break; case CHIP_POLARIS11: + case CHIP_POLARIS12: adev->mode_info.num_hpd = 5; adev->mode_info.num_dig = 5; break; @@ -3101,7 +3099,8 @@ static int dce_v11_0_hw_init(void *handle) amdgpu_atombios_crtc_powergate_init(adev); amdgpu_atombios_encoder_init_dig(adev); if ((adev->asic_type == CHIP_POLARIS10) || - (adev->asic_type == CHIP_POLARIS11)) { + (adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) { amdgpu_atombios_crtc_set_dce_clock(adev, adev->clock.default_dispclk, DCE_CLOCK_TYPE_DISPCLK, ATOM_GCK_DFS); amdgpu_atombios_crtc_set_dce_clock(adev, 0, diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index b4e4ec630e8c..39df6a50637f 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1859,6 +1859,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc, struct amdgpu_device *adev = crtc->dev->dev_private; int xorigin = 0, yorigin = 0; + int w = amdgpu_crtc->cursor_width; + amdgpu_crtc->cursor_x = x; amdgpu_crtc->cursor_y = y; @@ -1878,6 +1880,8 @@ static int dce_v6_0_cursor_move_locked(struct drm_crtc *crtc, WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, + ((w - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); return 0; } @@ -1903,7 +1907,6 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; struct drm_gem_object *obj; struct amdgpu_bo *aobj; int ret; @@ -1944,7 +1947,9 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v6_0_lock_cursor(crtc, true); - if (hot_x != amdgpu_crtc->cursor_hot_x || + if (width != amdgpu_crtc->cursor_width || + height != amdgpu_crtc->cursor_height || + hot_x != amdgpu_crtc->cursor_hot_x || hot_y != amdgpu_crtc->cursor_hot_y) { int x, y; @@ -1953,16 +1958,10 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v6_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_hot_x = hot_x; - amdgpu_crtc->cursor_hot_y = hot_y; - } - - if (width != amdgpu_crtc->cursor_width || - height != amdgpu_crtc->cursor_height) { - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (width - 1) << 16 | (height - 1)); amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; } dce_v6_0_show_cursor(crtc); @@ -1986,7 +1985,6 @@ unpin: static void dce_v6_0_cursor_reset(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; if (amdgpu_crtc->cursor_bo) { dce_v6_0_lock_cursor(crtc, true); @@ -1994,10 +1992,6 @@ static void dce_v6_0_cursor_reset(struct drm_crtc *crtc) dce_v6_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, amdgpu_crtc->cursor_y); - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (amdgpu_crtc->cursor_width - 1) << 16 | - (amdgpu_crtc->cursor_height - 1)); - dce_v6_0_show_cursor(crtc); dce_v6_0_lock_cursor(crtc, false); } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 584abe834a3c..28102bb1704d 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2363,6 +2363,8 @@ static int dce_v8_0_cursor_move_locked(struct drm_crtc *crtc, WREG32(mmCUR_POSITION + amdgpu_crtc->crtc_offset, (x << 16) | y); WREG32(mmCUR_HOT_SPOT + amdgpu_crtc->crtc_offset, (xorigin << 16) | yorigin); + WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, + ((amdgpu_crtc->cursor_width - 1) << 16) | (amdgpu_crtc->cursor_height - 1)); return 0; } @@ -2388,7 +2390,6 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, int32_t hot_y) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; struct drm_gem_object *obj; struct amdgpu_bo *aobj; int ret; @@ -2429,7 +2430,9 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v8_0_lock_cursor(crtc, true); - if (hot_x != amdgpu_crtc->cursor_hot_x || + if (width != amdgpu_crtc->cursor_width || + height != amdgpu_crtc->cursor_height || + hot_x != amdgpu_crtc->cursor_hot_x || hot_y != amdgpu_crtc->cursor_hot_y) { int x, y; @@ -2438,16 +2441,10 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v8_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_hot_x = hot_x; - amdgpu_crtc->cursor_hot_y = hot_y; - } - - if (width != amdgpu_crtc->cursor_width || - height != amdgpu_crtc->cursor_height) { - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (width - 1) << 16 | (height - 1)); amdgpu_crtc->cursor_width = width; amdgpu_crtc->cursor_height = height; + amdgpu_crtc->cursor_hot_x = hot_x; + amdgpu_crtc->cursor_hot_y = hot_y; } dce_v8_0_show_cursor(crtc); @@ -2471,7 +2468,6 @@ unpin: static void dce_v8_0_cursor_reset(struct drm_crtc *crtc) { struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc); - struct amdgpu_device *adev = crtc->dev->dev_private; if (amdgpu_crtc->cursor_bo) { dce_v8_0_lock_cursor(crtc, true); @@ -2479,10 +2475,6 @@ static void dce_v8_0_cursor_reset(struct drm_crtc *crtc) dce_v8_0_cursor_move_locked(crtc, amdgpu_crtc->cursor_x, amdgpu_crtc->cursor_y); - WREG32(mmCUR_SIZE + amdgpu_crtc->crtc_offset, - (amdgpu_crtc->cursor_width - 1) << 16 | - (amdgpu_crtc->cursor_height - 1)); - dce_v8_0_show_cursor(crtc); dce_v8_0_lock_cursor(crtc, false); diff --git a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c index 762f8e82ceb7..e9a176891e13 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_virtual.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_virtual.c @@ -627,11 +627,8 @@ static const struct drm_encoder_helper_funcs dce_virtual_encoder_helper_funcs = static void dce_virtual_encoder_destroy(struct drm_encoder *encoder) { - struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder); - - kfree(amdgpu_encoder->enc_priv); drm_encoder_cleanup(encoder); - kfree(amdgpu_encoder); + kfree(encoder); } static const struct drm_encoder_funcs dce_virtual_encoder_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index d0ec00986f38..373374164bd5 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -139,6 +139,13 @@ MODULE_FIRMWARE("amdgpu/polaris10_mec.bin"); MODULE_FIRMWARE("amdgpu/polaris10_mec2.bin"); MODULE_FIRMWARE("amdgpu/polaris10_rlc.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_ce.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_pfp.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_me.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_mec.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_mec2.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_rlc.bin"); + static const struct amdgpu_gds_reg_offset amdgpu_gds_reg_offset[] = { {mmGDS_VMID0_BASE, mmGDS_VMID0_SIZE, mmGDS_GWS_VMID0, mmGDS_OA_VMID0}, @@ -689,6 +696,7 @@ static void gfx_v8_0_init_golden_registers(struct amdgpu_device *adev) (const u32)ARRAY_SIZE(tonga_golden_common_all)); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: amdgpu_program_register_sequence(adev, golden_settings_polaris11_a11, (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); @@ -903,6 +911,9 @@ static int gfx_v8_0_init_microcode(struct amdgpu_device *adev) case CHIP_POLARIS10: chip_name = "polaris10"; break; + case CHIP_POLARIS12: + chip_name = "polaris12"; + break; case CHIP_STONEY: chip_name = "stoney"; break; @@ -1768,6 +1779,7 @@ static int gfx_v8_0_gpu_early_init(struct amdgpu_device *adev) gb_addr_config = TONGA_GB_ADDR_CONFIG_GOLDEN; break; case CHIP_POLARIS11: + case CHIP_POLARIS12: ret = amdgpu_atombios_get_gfx_info(adev); if (ret) return ret; @@ -2682,6 +2694,7 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev) break; case CHIP_POLARIS11: + case CHIP_POLARIS12: modearray[0] = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P4_16x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | @@ -3503,6 +3516,7 @@ gfx_v8_0_raster_config(struct amdgpu_device *adev, u32 *rconf, u32 *rconf1) *rconf1 |= 0x0; break; case CHIP_POLARIS11: + case CHIP_POLARIS12: *rconf |= RB_MAP_PKR0(2) | RB_XSEL2(1) | SE_MAP(2) | SE_XSEL(1) | SE_YSEL(1); *rconf1 |= 0x0; @@ -4021,7 +4035,8 @@ static void gfx_v8_0_init_pg(struct amdgpu_device *adev) cz_enable_cp_power_gating(adev, true); else cz_enable_cp_power_gating(adev, false); - } else if (adev->asic_type == CHIP_POLARIS11) { + } else if ((adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) { gfx_v8_0_init_csb(adev); gfx_v8_0_init_save_restore_list(adev); gfx_v8_0_enable_save_restore_machine(adev); @@ -4095,7 +4110,8 @@ static int gfx_v8_0_rlc_resume(struct amdgpu_device *adev) RLC_CGCG_CGLS_CTRL__CGLS_EN_MASK); WREG32(mmRLC_CGCG_CGLS_CTRL, tmp); if (adev->asic_type == CHIP_POLARIS11 || - adev->asic_type == CHIP_POLARIS10) { + adev->asic_type == CHIP_POLARIS10 || + adev->asic_type == CHIP_POLARIS12) { tmp = RREG32(mmRLC_CGCG_CGLS_CTRL_3D); tmp &= ~0x3; WREG32(mmRLC_CGCG_CGLS_CTRL_3D, tmp); @@ -4283,6 +4299,7 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev) amdgpu_ring_write(ring, 0x0000002A); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: amdgpu_ring_write(ring, 0x16000012); amdgpu_ring_write(ring, 0x00000000); break; @@ -4664,7 +4681,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) (adev->asic_type == CHIP_FIJI) || (adev->asic_type == CHIP_STONEY) || (adev->asic_type == CHIP_POLARIS11) || - (adev->asic_type == CHIP_POLARIS10)) { + (adev->asic_type == CHIP_POLARIS10) || + (adev->asic_type == CHIP_POLARIS12)) { WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2); WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, @@ -4700,7 +4718,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) mqd->cp_hqd_persistent_state = tmp; if (adev->asic_type == CHIP_STONEY || adev->asic_type == CHIP_POLARIS11 || - adev->asic_type == CHIP_POLARIS10) { + adev->asic_type == CHIP_POLARIS10 || + adev->asic_type == CHIP_POLARIS12) { tmp = RREG32(mmCP_ME1_PIPE3_INT_CNTL); tmp = REG_SET_FIELD(tmp, CP_ME1_PIPE3_INT_CNTL, GENERIC2_INT_ENABLE, 1); WREG32(mmCP_ME1_PIPE3_INT_CNTL, tmp); @@ -5279,7 +5298,8 @@ static int gfx_v8_0_late_init(void *handle) static void gfx_v8_0_enable_gfx_static_mg_power_gating(struct amdgpu_device *adev, bool enable) { - if (adev->asic_type == CHIP_POLARIS11) + if ((adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) /* Send msg to SMU via Powerplay */ amdgpu_set_powergating_state(adev, AMD_IP_BLOCK_TYPE_SMC, @@ -5353,6 +5373,7 @@ static int gfx_v8_0_set_powergating_state(void *handle, gfx_v8_0_enable_gfx_dynamic_mg_power_gating(adev, false); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable) gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true); else diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c index 45a573e63d4a..0635829b18cf 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v6_0.c @@ -44,6 +44,7 @@ MODULE_FIRMWARE("radeon/tahiti_mc.bin"); MODULE_FIRMWARE("radeon/pitcairn_mc.bin"); MODULE_FIRMWARE("radeon/verde_mc.bin"); MODULE_FIRMWARE("radeon/oland_mc.bin"); +MODULE_FIRMWARE("radeon/si58_mc.bin"); #define MC_SEQ_MISC0__MT__MASK 0xf0000000 #define MC_SEQ_MISC0__MT__GDDR1 0x10000000 @@ -113,6 +114,7 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) const char *chip_name; char fw_name[30]; int err; + bool is_58_fw = false; DRM_DEBUG("\n"); @@ -135,7 +137,14 @@ static int gmc_v6_0_init_microcode(struct amdgpu_device *adev) default: BUG(); } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); + /* this memory configuration requires special firmware */ + if (((RREG32(mmMC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58) + is_58_fw = true; + + if (is_58_fw) + snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin"); + else + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", chip_name); err = request_firmware(&adev->mc.fw, fw_name, adev->dev); if (err) goto out; @@ -245,6 +254,9 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) } WREG32(mmHDP_REG_COHERENCY_FLUSH_CNTL, 0); + if (adev->mode_info.num_crtc) + amdgpu_display_set_vga_render_state(adev, false); + gmc_v6_0_mc_stop(adev, &save); if (gmc_v6_0_wait_for_idle((void *)adev)) { @@ -274,7 +286,6 @@ static void gmc_v6_0_mc_program(struct amdgpu_device *adev) dev_warn(adev->dev, "Wait for MC idle timedout !\n"); } gmc_v6_0_mc_resume(adev, &save); - amdgpu_display_set_vga_render_state(adev, false); } static int gmc_v6_0_mc_init(struct amdgpu_device *adev) @@ -463,19 +474,11 @@ static int gmc_v6_0_gart_enable(struct amdgpu_device *adev) WREG32(mmVM_CONTEXT1_CNTL, VM_CONTEXT1_CNTL__ENABLE_CONTEXT_MASK | (1UL << VM_CONTEXT1_CNTL__PAGE_TABLE_DEPTH__SHIFT) | - ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT) | - VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__RANGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK | - VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK | - VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__PDE0_PROTECTION_FAULT_ENABLE_DEFAULT_MASK | - VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__VALID_PROTECTION_FAULT_ENABLE_DEFAULT_MASK | - VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__READ_PROTECTION_FAULT_ENABLE_DEFAULT_MASK | - VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT_MASK | - VM_CONTEXT1_CNTL__WRITE_PROTECTION_FAULT_ENABLE_DEFAULT_MASK); + ((amdgpu_vm_block_size - 9) << VM_CONTEXT1_CNTL__PAGE_TABLE_BLOCK_SIZE__SHIFT)); + if (amdgpu_vm_fault_stop == AMDGPU_VM_FAULT_STOP_ALWAYS) + gmc_v6_0_set_fault_enable_default(adev, false); + else + gmc_v6_0_set_fault_enable_default(adev, true); gmc_v6_0_gart_flush_gpu_tlb(adev, 0); dev_info(adev->dev, "PCIE GART of %uM enabled (table at 0x%016llX).\n", @@ -754,7 +757,10 @@ static int gmc_v6_0_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + if (amdgpu_vm_fault_stop != AMDGPU_VM_FAULT_STOP_ALWAYS) + return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); + else + return 0; } static int gmc_v6_0_sw_init(void *handle) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 0daac3a5be79..476bc9f1954b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -46,6 +46,7 @@ static int gmc_v8_0_wait_for_idle(void *handle); MODULE_FIRMWARE("amdgpu/tonga_mc.bin"); MODULE_FIRMWARE("amdgpu/polaris11_mc.bin"); MODULE_FIRMWARE("amdgpu/polaris10_mc.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_mc.bin"); static const u32 golden_settings_tonga_a11[] = { @@ -130,6 +131,7 @@ static void gmc_v8_0_init_golden_registers(struct amdgpu_device *adev) (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: amdgpu_program_register_sequence(adev, golden_settings_polaris11_a11, (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); @@ -225,6 +227,9 @@ static int gmc_v8_0_init_microcode(struct amdgpu_device *adev) case CHIP_POLARIS10: chip_name = "polaris10"; break; + case CHIP_POLARIS12: + chip_name = "polaris12"; + break; case CHIP_FIJI: case CHIP_CARRIZO: case CHIP_STONEY: diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 1170a64a3184..034ace79ed49 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -60,6 +60,8 @@ MODULE_FIRMWARE("amdgpu/polaris10_sdma.bin"); MODULE_FIRMWARE("amdgpu/polaris10_sdma1.bin"); MODULE_FIRMWARE("amdgpu/polaris11_sdma.bin"); MODULE_FIRMWARE("amdgpu/polaris11_sdma1.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_sdma.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_sdma1.bin"); static const u32 sdma_offsets[SDMA_MAX_INSTANCE] = @@ -206,6 +208,7 @@ static void sdma_v3_0_init_golden_registers(struct amdgpu_device *adev) (const u32)ARRAY_SIZE(golden_settings_tonga_a11)); break; case CHIP_POLARIS11: + case CHIP_POLARIS12: amdgpu_program_register_sequence(adev, golden_settings_polaris11_a11, (const u32)ARRAY_SIZE(golden_settings_polaris11_a11)); @@ -278,6 +281,9 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) case CHIP_POLARIS10: chip_name = "polaris10"; break; + case CHIP_POLARIS12: + chip_name = "polaris12"; + break; case CHIP_CARRIZO: chip_name = "carrizo"; break; diff --git a/drivers/gpu/drm/amd/amdgpu/si_dpm.c b/drivers/gpu/drm/amd/amdgpu/si_dpm.c index 6c65a1a2de79..6e150db8f380 100644 --- a/drivers/gpu/drm/amd/amdgpu/si_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/si_dpm.c @@ -56,7 +56,6 @@ #define BIOS_SCRATCH_4 0x5cd MODULE_FIRMWARE("radeon/tahiti_smc.bin"); -MODULE_FIRMWARE("radeon/tahiti_k_smc.bin"); MODULE_FIRMWARE("radeon/pitcairn_smc.bin"); MODULE_FIRMWARE("radeon/pitcairn_k_smc.bin"); MODULE_FIRMWARE("radeon/verde_smc.bin"); @@ -65,6 +64,7 @@ MODULE_FIRMWARE("radeon/oland_smc.bin"); MODULE_FIRMWARE("radeon/oland_k_smc.bin"); MODULE_FIRMWARE("radeon/hainan_smc.bin"); MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); +MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); union power_info { struct _ATOM_POWERPLAY_INFO info; @@ -3488,30 +3488,6 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, (adev->pdev->device == 0x6817) || (adev->pdev->device == 0x6806)) max_mclk = 120000; - } else if (adev->asic_type == CHIP_VERDE) { - if ((adev->pdev->revision == 0x81) || - (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0x87) || - (adev->pdev->device == 0x6820) || - (adev->pdev->device == 0x6821) || - (adev->pdev->device == 0x6822) || - (adev->pdev->device == 0x6823) || - (adev->pdev->device == 0x682A) || - (adev->pdev->device == 0x682B)) { - max_sclk = 75000; - max_mclk = 80000; - } - } else if (adev->asic_type == CHIP_OLAND) { - if ((adev->pdev->revision == 0xC7) || - (adev->pdev->revision == 0x80) || - (adev->pdev->revision == 0x81) || - (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0x87) || - (adev->pdev->device == 0x6604) || - (adev->pdev->device == 0x6605)) { - max_sclk = 75000; - max_mclk = 80000; - } } else if (adev->asic_type == CHIP_HAINAN) { if ((adev->pdev->revision == 0x81) || (adev->pdev->revision == 0x83) || @@ -3520,7 +3496,6 @@ static void si_apply_state_adjust_rules(struct amdgpu_device *adev, (adev->pdev->device == 0x6665) || (adev->pdev->device == 0x6667)) { max_sclk = 75000; - max_mclk = 80000; } } /* Apply dpm quirks */ @@ -7687,50 +7662,51 @@ static int si_dpm_init_microcode(struct amdgpu_device *adev) chip_name = "tahiti"; break; case CHIP_PITCAIRN: - if ((adev->pdev->revision == 0x81) || - (adev->pdev->device == 0x6810) || - (adev->pdev->device == 0x6811) || - (adev->pdev->device == 0x6816) || - (adev->pdev->device == 0x6817) || - (adev->pdev->device == 0x6806)) + if ((adev->pdev->revision == 0x81) && + ((adev->pdev->device == 0x6810) || + (adev->pdev->device == 0x6811))) chip_name = "pitcairn_k"; else chip_name = "pitcairn"; break; case CHIP_VERDE: - if ((adev->pdev->revision == 0x81) || - (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0x87) || - (adev->pdev->device == 0x6820) || - (adev->pdev->device == 0x6821) || - (adev->pdev->device == 0x6822) || - (adev->pdev->device == 0x6823) || - (adev->pdev->device == 0x682A) || - (adev->pdev->device == 0x682B)) + if (((adev->pdev->device == 0x6820) && + ((adev->pdev->revision == 0x81) || + (adev->pdev->revision == 0x83))) || + ((adev->pdev->device == 0x6821) && + ((adev->pdev->revision == 0x83) || + (adev->pdev->revision == 0x87))) || + ((adev->pdev->revision == 0x87) && + ((adev->pdev->device == 0x6823) || + (adev->pdev->device == 0x682b)))) chip_name = "verde_k"; else chip_name = "verde"; break; case CHIP_OLAND: - if ((adev->pdev->revision == 0xC7) || - (adev->pdev->revision == 0x80) || - (adev->pdev->revision == 0x81) || - (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0x87) || - (adev->pdev->device == 0x6604) || - (adev->pdev->device == 0x6605)) + if (((adev->pdev->revision == 0x81) && + ((adev->pdev->device == 0x6600) || + (adev->pdev->device == 0x6604) || + (adev->pdev->device == 0x6605) || + (adev->pdev->device == 0x6610))) || + ((adev->pdev->revision == 0x83) && + (adev->pdev->device == 0x6610))) chip_name = "oland_k"; else chip_name = "oland"; break; case CHIP_HAINAN: - if ((adev->pdev->revision == 0x81) || - (adev->pdev->revision == 0x83) || - (adev->pdev->revision == 0xC3) || - (adev->pdev->device == 0x6664) || - (adev->pdev->device == 0x6665) || - (adev->pdev->device == 0x6667)) + if (((adev->pdev->revision == 0x81) && + (adev->pdev->device == 0x6660)) || + ((adev->pdev->revision == 0x83) && + ((adev->pdev->device == 0x6660) || + (adev->pdev->device == 0x6663) || + (adev->pdev->device == 0x6665) || + (adev->pdev->device == 0x6667)))) chip_name = "hainan_k"; + else if ((adev->pdev->revision == 0xc3) && + (adev->pdev->device == 0x6665)) + chip_name = "banks_k_2"; else chip_name = "hainan"; break; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 96444e4d862a..7fb9137dd89b 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -40,13 +40,14 @@ #include "smu/smu_7_0_1_sh_mask.h" static void uvd_v4_2_mc_resume(struct amdgpu_device *adev); -static void uvd_v4_2_init_cg(struct amdgpu_device *adev); static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev); static void uvd_v4_2_set_irq_funcs(struct amdgpu_device *adev); static int uvd_v4_2_start(struct amdgpu_device *adev); static void uvd_v4_2_stop(struct amdgpu_device *adev); static int uvd_v4_2_set_clockgating_state(void *handle, enum amd_clockgating_state state); +static void uvd_v4_2_set_dcm(struct amdgpu_device *adev, + bool sw_mode); /** * uvd_v4_2_ring_get_rptr - get read pointer * @@ -140,7 +141,8 @@ static int uvd_v4_2_sw_fini(void *handle) return r; } - +static void uvd_v4_2_enable_mgcg(struct amdgpu_device *adev, + bool enable); /** * uvd_v4_2_hw_init - start and test UVD block * @@ -155,8 +157,7 @@ static int uvd_v4_2_hw_init(void *handle) uint32_t tmp; int r; - uvd_v4_2_init_cg(adev); - uvd_v4_2_set_clockgating_state(adev, AMD_CG_STATE_GATE); + uvd_v4_2_enable_mgcg(adev, true); amdgpu_asic_set_uvd_clocks(adev, 10000, 10000); r = uvd_v4_2_start(adev); if (r) @@ -266,11 +267,13 @@ static int uvd_v4_2_start(struct amdgpu_device *adev) struct amdgpu_ring *ring = &adev->uvd.ring; uint32_t rb_bufsz; int i, j, r; - /* disable byte swapping */ u32 lmi_swap_cntl = 0; u32 mp_swap_cntl = 0; + WREG32(mmUVD_CGC_GATE, 0); + uvd_v4_2_set_dcm(adev, true); + uvd_v4_2_mc_resume(adev); /* disable interupt */ @@ -406,6 +409,8 @@ static void uvd_v4_2_stop(struct amdgpu_device *adev) /* Unstall UMC and register bus */ WREG32_P(mmUVD_LMI_CTRL2, 0, ~(1 << 8)); + + uvd_v4_2_set_dcm(adev, false); } /** @@ -619,19 +624,6 @@ static void uvd_v4_2_set_dcm(struct amdgpu_device *adev, WREG32_UVD_CTX(ixUVD_CGC_CTRL2, tmp2); } -static void uvd_v4_2_init_cg(struct amdgpu_device *adev) -{ - bool hw_mode = true; - - if (hw_mode) { - uvd_v4_2_set_dcm(adev, false); - } else { - u32 tmp = RREG32(mmUVD_CGC_CTRL); - tmp &= ~UVD_CGC_CTRL__DYN_CLOCK_MODE_MASK; - WREG32(mmUVD_CGC_CTRL, tmp); - } -} - static bool uvd_v4_2_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -685,17 +677,6 @@ static int uvd_v4_2_process_interrupt(struct amdgpu_device *adev, static int uvd_v4_2_set_clockgating_state(void *handle, enum amd_clockgating_state state) { - bool gate = false; - struct amdgpu_device *adev = (struct amdgpu_device *)handle; - - if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) - return 0; - - if (state == AMD_CG_STATE_GATE) - gate = true; - - uvd_v4_2_enable_mgcg(adev, gate); - return 0; } @@ -711,9 +692,6 @@ static int uvd_v4_2_set_powergating_state(void *handle, */ struct amdgpu_device *adev = (struct amdgpu_device *)handle; - if (!(adev->pg_flags & AMD_PG_SUPPORT_UVD)) - return 0; - if (state == AMD_PG_STATE_GATE) { uvd_v4_2_stop(adev); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index a79e283590fb..6de6becce745 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -791,15 +791,10 @@ static int uvd_v5_0_set_clockgating_state(void *handle, { struct amdgpu_device *adev = (struct amdgpu_device *)handle; bool enable = (state == AMD_CG_STATE_GATE) ? true : false; - static int curstate = -1; if (!(adev->cg_flags & AMD_CG_SUPPORT_UVD_MGCG)) return 0; - if (curstate == state) - return 0; - - curstate = state; if (enable) { /* wait for STATUS to clear */ if (uvd_v5_0_wait_for_idle(handle)) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 6b3293a1c7b8..37ca685e5a9a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -43,9 +43,13 @@ #define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04 #define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10 +#define GRBM_GFX_INDEX__VCE_ALL_PIPE 0x07 + #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616 #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617 #define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618 +#define mmGRBM_GFX_INDEX_DEFAULT 0xE0000000 + #define VCE_STATUS_VCPU_REPORT_FW_LOADED_MASK 0x02 #define VCE_V3_0_FW_SIZE (384 * 1024) @@ -54,6 +58,9 @@ #define FW_52_8_3 ((52 << 24) | (8 << 16) | (3 << 8)) +#define GET_VCE_INSTANCE(i) ((i) << GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT \ + | GRBM_GFX_INDEX__VCE_ALL_PIPE) + static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx); static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev); static void vce_v3_0_set_irq_funcs(struct amdgpu_device *adev); @@ -175,7 +182,7 @@ static void vce_v3_0_set_vce_sw_clock_gating(struct amdgpu_device *adev, WREG32(mmVCE_UENC_CLOCK_GATING_2, data); data = RREG32(mmVCE_UENC_REG_CLOCK_GATING); - data &= ~0xffc00000; + data &= ~0x3ff; WREG32(mmVCE_UENC_REG_CLOCK_GATING, data); data = RREG32(mmVCE_UENC_DMA_DCLK_CTRL); @@ -249,7 +256,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev) if (adev->vce.harvest_config & (1 << idx)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); vce_v3_0_mc_resume(adev, idx); WREG32_FIELD(VCE_STATUS, JOB_BUSY, 1); @@ -273,7 +280,7 @@ static int vce_v3_0_start(struct amdgpu_device *adev) } } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; @@ -288,7 +295,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev) if (adev->vce.harvest_config & (1 << idx)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, idx); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(idx)); if (adev->asic_type >= CHIP_STONEY) WREG32_P(mmVCE_VCPU_CNTL, 0, ~0x200001); @@ -306,7 +313,7 @@ static int vce_v3_0_stop(struct amdgpu_device *adev) vce_v3_0_set_vce_sw_clock_gating(adev, false); } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; @@ -320,11 +327,12 @@ static unsigned vce_v3_0_get_harvest_config(struct amdgpu_device *adev) { u32 tmp; - /* Fiji, Stoney, Polaris10, Polaris11 are single pipe */ + /* Fiji, Stoney, Polaris10, Polaris11, Polaris12 are single pipe */ if ((adev->asic_type == CHIP_FIJI) || (adev->asic_type == CHIP_STONEY) || (adev->asic_type == CHIP_POLARIS10) || - (adev->asic_type == CHIP_POLARIS11)) + (adev->asic_type == CHIP_POLARIS11) || + (adev->asic_type == CHIP_POLARIS12)) return AMDGPU_VCE_HARVEST_VCE1; /* Tonga and CZ are dual or single pipe */ @@ -585,17 +593,17 @@ static bool vce_v3_0_check_soft_reset(void *handle) * VCE team suggest use bit 3--bit 6 for busy status check */ mutex_lock(&adev->grbm_idx_mutex); - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0x10); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(1)); if (RREG32(mmVCE_STATUS) & AMDGPU_VCE_STATUS_BUSY_MASK) { srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE0, 1); srbm_soft_reset = REG_SET_FIELD(srbm_soft_reset, SRBM_SOFT_RESET, SOFT_RESET_VCE1, 1); } - WREG32_FIELD(GRBM_GFX_INDEX, INSTANCE_INDEX, 0); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(0)); mutex_unlock(&adev->grbm_idx_mutex); if (srbm_soft_reset) { @@ -733,7 +741,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, if (adev->vce.harvest_config & (1 << i)) continue; - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, i); + WREG32(mmGRBM_GFX_INDEX, GET_VCE_INSTANCE(i)); if (enable) { /* initialize VCE_CLOCK_GATING_A: Clock ON/OFF delay */ @@ -752,7 +760,7 @@ static int vce_v3_0_set_clockgating_state(void *handle, vce_v3_0_set_vce_sw_clock_gating(adev, enable); } - WREG32_FIELD(GRBM_GFX_INDEX, VCE_INSTANCE, 0); + WREG32(mmGRBM_GFX_INDEX, mmGRBM_GFX_INDEX_DEFAULT); mutex_unlock(&adev->grbm_idx_mutex); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index bf088d6d9bf1..c2ac54f11341 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -88,6 +88,7 @@ MODULE_FIRMWARE("amdgpu/polaris10_smc.bin"); MODULE_FIRMWARE("amdgpu/polaris10_smc_sk.bin"); MODULE_FIRMWARE("amdgpu/polaris11_smc.bin"); MODULE_FIRMWARE("amdgpu/polaris11_smc_sk.bin"); +MODULE_FIRMWARE("amdgpu/polaris12_smc.bin"); /* * Indirect registers accessor @@ -312,6 +313,7 @@ static void vi_init_golden_registers(struct amdgpu_device *adev) break; case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: default: break; } @@ -671,6 +673,7 @@ static int vi_read_register(struct amdgpu_device *adev, u32 se_num, case CHIP_TONGA: case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: case CHIP_CARRIZO: case CHIP_STONEY: asic_register_table = cz_allowed_read_registers; @@ -994,6 +997,11 @@ static int vi_common_early_init(void *handle) adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x50; break; + case CHIP_POLARIS12: + adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG; + adev->pg_flags = 0; + adev->external_rev_id = adev->rev_id + 0x64; + break; case CHIP_CARRIZO: adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG | AMD_CG_SUPPORT_GFX_MGCG | @@ -1346,6 +1354,7 @@ static int vi_common_set_clockgating_state(void *handle, case CHIP_TONGA: case CHIP_POLARIS10: case CHIP_POLARIS11: + case CHIP_POLARIS12: vi_common_set_clockgating_state_by_smu(adev, state); default: break; @@ -1429,6 +1438,7 @@ int vi_set_ip_blocks(struct amdgpu_device *adev) break; case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: amdgpu_ip_block_add(adev, &vi_common_ip_block); amdgpu_ip_block_add(adev, &gmc_v8_1_ip_block); amdgpu_ip_block_add(adev, &tonga_ih_ip_block); diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index c02469ada9f1..85f358764bbc 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -23,7 +23,7 @@ #ifndef __AMD_SHARED_H__ #define __AMD_SHARED_H__ -#define AMD_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +#define AMD_MAX_USEC_TIMEOUT 200000 /* 200 ms */ /* * Supported ASIC types @@ -46,6 +46,7 @@ enum amd_asic_type { CHIP_STONEY, CHIP_POLARIS10, CHIP_POLARIS11, + CHIP_POLARIS12, CHIP_LAST, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c index b0c63c5f54c9..6bb79c94cb9f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_clockpowergating.c @@ -200,7 +200,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_CG_STATE_UNGATE); + AMD_CG_STATE_GATE); cgs_set_powergating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, @@ -218,7 +218,7 @@ int cz_dpm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate) cgs_set_clockgating_state( hwmgr->device, AMD_IP_BLOCK_TYPE_VCE, - AMD_PG_STATE_GATE); + AMD_PG_STATE_UNGATE); cz_dpm_update_vce_dpm(hwmgr); cz_enable_disable_vce_dpm(hwmgr, true); return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c index 4b14f259a147..0fb4e8c8f5e1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/cz_hwmgr.c @@ -1402,14 +1402,22 @@ int cz_dpm_update_vce_dpm(struct pp_hwmgr *hwmgr) cz_hwmgr->vce_dpm.hard_min_clk, PPSMC_MSG_SetEclkHardMin)); } else { - /*EPR# 419220 -HW limitation to to */ - cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk; - smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, - PPSMC_MSG_SetEclkHardMin, - cz_get_eclk_level(hwmgr, - cz_hwmgr->vce_dpm.hard_min_clk, - PPSMC_MSG_SetEclkHardMin)); - + /*Program HardMin based on the vce_arbiter.ecclk */ + if (hwmgr->vce_arbiter.ecclk == 0) { + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkHardMin, 0); + /* disable ECLK DPM 0. Otherwise VCE could hang if + * switching SCLK from DPM 0 to 6/7 */ + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkSoftMin, 1); + } else { + cz_hwmgr->vce_dpm.hard_min_clk = hwmgr->vce_arbiter.ecclk; + smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, + PPSMC_MSG_SetEclkHardMin, + cz_get_eclk_level(hwmgr, + cz_hwmgr->vce_dpm.hard_min_clk, + PPSMC_MSG_SetEclkHardMin)); + } } return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index dc6700aee18f..b03606405a53 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -95,6 +95,7 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle) break; case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: polaris_set_asic_special_caps(hwmgr); hwmgr->feature_mask &= ~(PP_UVD_HANDSHAKE_MASK); break; @@ -745,7 +746,7 @@ int polaris_set_asic_special_caps(struct pp_hwmgr *hwmgr) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TablelessHardwareInterface); - if (hwmgr->chip_id == CHIP_POLARIS11) + if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SPLLShutdownSupport); return 0; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c index 26477f0f09dc..6cd1287a7a8f 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_powertune.c @@ -521,7 +521,7 @@ int smu7_enable_didt_config(struct pp_hwmgr *hwmgr) PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10); PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); - } else if (hwmgr->chip_id == CHIP_POLARIS11) { + } else if ((hwmgr->chip_id == CHIP_POLARIS11) || (hwmgr->chip_id == CHIP_POLARIS12)) { result = smu7_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11); PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result); result = smu7_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c index e5812aa456f3..6e618aa20719 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smumgr.c @@ -65,6 +65,7 @@ int smum_init(struct amd_pp_init *pp_init, struct pp_instance *handle) break; case CHIP_POLARIS11: case CHIP_POLARIS10: + case CHIP_POLARIS12: polaris10_smum_init(smumgr); break; default: diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 908011d2c8f5..7abda94fc2cf 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -113,6 +113,7 @@ struct ast_private { struct ttm_bo_kmap_obj cache_kmap; int next_cursor; bool support_wide_screen; + bool DisableP2A; enum ast_tx_chip tx_chip_type; u8 dp501_maxclk; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index f75c6421db62..533e762d036d 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -124,6 +124,12 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) } else *need_post = false; + /* Check P2A Access */ + ast->DisableP2A = true; + data = ast_read32(ast, 0xf004); + if (data != 0xFFFFFFFF) + ast->DisableP2A = false; + /* Check if we support wide screen */ switch (ast->chip) { case AST1180: @@ -140,15 +146,17 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) ast->support_wide_screen = true; else { ast->support_wide_screen = false; - /* Read SCU7c (silicon revision register) */ - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - data = ast_read32(ast, 0x1207c); - data &= 0x300; - if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ - ast->support_wide_screen = true; - if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ - ast->support_wide_screen = true; + if (ast->DisableP2A == false) { + /* Read SCU7c (silicon revision register) */ + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + data = ast_read32(ast, 0x1207c); + data &= 0x300; + if (ast->chip == AST2300 && data == 0x0) /* ast1300 */ + ast->support_wide_screen = true; + if (ast->chip == AST2400 && data == 0x100) /* ast1400 */ + ast->support_wide_screen = true; + } } break; } @@ -216,80 +224,81 @@ static int ast_get_dram_info(struct drm_device *dev) uint32_t data, data2; uint32_t denum, num, div, ref_pll; - ast_write32(ast, 0xf004, 0x1e6e0000); - ast_write32(ast, 0xf000, 0x1); - - - ast_write32(ast, 0x10000, 0xfc600309); - - do { - if (pci_channel_offline(dev->pdev)) - return -EIO; - } while (ast_read32(ast, 0x10000) != 0x01); - data = ast_read32(ast, 0x10004); - - if (data & 0x40) + if (ast->DisableP2A) + { ast->dram_bus_width = 16; + ast->dram_type = AST_DRAM_1Gx16; + ast->mclk = 396; + } else - ast->dram_bus_width = 32; + { + ast_write32(ast, 0xf004, 0x1e6e0000); + ast_write32(ast, 0xf000, 0x1); + data = ast_read32(ast, 0x10004); + + if (data & 0x40) + ast->dram_bus_width = 16; + else + ast->dram_bus_width = 32; + + if (ast->chip == AST2300 || ast->chip == AST2400) { + switch (data & 0x03) { + case 0: + ast->dram_type = AST_DRAM_512Mx16; + break; + default: + case 1: + ast->dram_type = AST_DRAM_1Gx16; + break; + case 2: + ast->dram_type = AST_DRAM_2Gx16; + break; + case 3: + ast->dram_type = AST_DRAM_4Gx16; + break; + } + } else { + switch (data & 0x0c) { + case 0: + case 4: + ast->dram_type = AST_DRAM_512Mx16; + break; + case 8: + if (data & 0x40) + ast->dram_type = AST_DRAM_1Gx16; + else + ast->dram_type = AST_DRAM_512Mx32; + break; + case 0xc: + ast->dram_type = AST_DRAM_1Gx32; + break; + } + } - if (ast->chip == AST2300 || ast->chip == AST2400) { - switch (data & 0x03) { - case 0: - ast->dram_type = AST_DRAM_512Mx16; - break; - default: - case 1: - ast->dram_type = AST_DRAM_1Gx16; - break; - case 2: - ast->dram_type = AST_DRAM_2Gx16; - break; + data = ast_read32(ast, 0x10120); + data2 = ast_read32(ast, 0x10170); + if (data2 & 0x2000) + ref_pll = 14318; + else + ref_pll = 12000; + + denum = data & 0x1f; + num = (data & 0x3fe0) >> 5; + data = (data & 0xc000) >> 14; + switch (data) { case 3: - ast->dram_type = AST_DRAM_4Gx16; - break; - } - } else { - switch (data & 0x0c) { - case 0: - case 4: - ast->dram_type = AST_DRAM_512Mx16; + div = 0x4; break; - case 8: - if (data & 0x40) - ast->dram_type = AST_DRAM_1Gx16; - else - ast->dram_type = AST_DRAM_512Mx32; + case 2: + case 1: + div = 0x2; break; - case 0xc: - ast->dram_type = AST_DRAM_1Gx32; + default: + div = 0x1; break; } + ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); } - - data = ast_read32(ast, 0x10120); - data2 = ast_read32(ast, 0x10170); - if (data2 & 0x2000) - ref_pll = 14318; - else - ref_pll = 12000; - - denum = data & 0x1f; - num = (data & 0x3fe0) >> 5; - data = (data & 0xc000) >> 14; - switch (data) { - case 3: - div = 0x4; - break; - case 2: - case 1: - div = 0x2; - break; - default: - div = 0x1; - break; - } - ast->mclk = ref_pll * (num + 2) / (denum + 2) * (div * 1000); return 0; } diff --git a/drivers/gpu/drm/ast/ast_post.c b/drivers/gpu/drm/ast/ast_post.c index 810c51d92b99..5331ee1df086 100644 --- a/drivers/gpu/drm/ast/ast_post.c +++ b/drivers/gpu/drm/ast/ast_post.c @@ -379,12 +379,20 @@ void ast_post_gpu(struct drm_device *dev) ast_open_key(ast); ast_set_def_ext_reg(dev); - if (ast->chip == AST2300 || ast->chip == AST2400) - ast_init_dram_2300(dev); - else - ast_init_dram_reg(dev); + if (ast->DisableP2A == false) + { + if (ast->chip == AST2300 || ast->chip == AST2400) + ast_init_dram_2300(dev); + else + ast_init_dram_reg(dev); - ast_init_3rdtx(dev); + ast_init_3rdtx(dev); + } + else + { + if (ast->tx_chip_type != AST_TX_NONE) + ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xa3, 0xcf, 0x80); /* Enable DVO */ + } } /* AST 2300 DRAM settings */ diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c index eb9bf8786c24..18eefdcbf1ba 100644 --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c @@ -1382,6 +1382,7 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, pm_runtime_enable(dev); + pm_runtime_get_sync(dev); phy_power_on(dp->phy); analogix_dp_init_dp(dp); @@ -1414,9 +1415,15 @@ int analogix_dp_bind(struct device *dev, struct drm_device *drm_dev, goto err_disable_pm_runtime; } + phy_power_off(dp->phy); + pm_runtime_put(dev); + return 0; err_disable_pm_runtime: + + phy_power_off(dp->phy); + pm_runtime_put(dev); pm_runtime_disable(dev); return ret; diff --git a/drivers/gpu/drm/cirrus/Kconfig b/drivers/gpu/drm/cirrus/Kconfig index 04b3c161dfae..7f4cc6e172ab 100644 --- a/drivers/gpu/drm/cirrus/Kconfig +++ b/drivers/gpu/drm/cirrus/Kconfig @@ -7,3 +7,12 @@ config DRM_CIRRUS_QEMU This is a KMS driver for emulated cirrus device in qemu. It is *NOT* intended for real cirrus devices. This requires the modesetting userspace X.org driver. + + Cirrus is obsolete, the hardware was designed in the 90ies + and can't keep up with todays needs. More background: + https://www.kraxel.org/blog/2014/10/qemu-using-cirrus-considered-harmful/ + + Better alternatives are: + - stdvga (DRM_BOCHS, qemu -vga std, default in qemu 2.2+) + - qxl (DRM_QXL, qemu -vga qxl, works best with spice) + - virtio (DRM_VIRTIO_GPU), qemu -vga virtio) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 60697482b94c..fdfb1ec17e66 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -291,15 +291,15 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, EXPORT_SYMBOL(drm_atomic_get_crtc_state); static void set_out_fence_for_crtc(struct drm_atomic_state *state, - struct drm_crtc *crtc, s64 __user *fence_ptr) + struct drm_crtc *crtc, s32 __user *fence_ptr) { state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = fence_ptr; } -static s64 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, +static s32 __user *get_out_fence_for_crtc(struct drm_atomic_state *state, struct drm_crtc *crtc) { - s64 __user *fence_ptr; + s32 __user *fence_ptr; fence_ptr = state->crtcs[drm_crtc_index(crtc)].out_fence_ptr; state->crtcs[drm_crtc_index(crtc)].out_fence_ptr = NULL; @@ -512,7 +512,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, state->color_mgmt_changed |= replaced; return ret; } else if (property == config->prop_out_fence_ptr) { - s64 __user *fence_ptr = u64_to_user_ptr(val); + s32 __user *fence_ptr = u64_to_user_ptr(val); if (!fence_ptr) return 0; @@ -1915,7 +1915,7 @@ EXPORT_SYMBOL(drm_atomic_clean_old_fb); */ struct drm_out_fence_state { - s64 __user *out_fence_ptr; + s32 __user *out_fence_ptr; struct sync_file *sync_file; int fd; }; @@ -1952,7 +1952,7 @@ static int prepare_crtc_signaling(struct drm_device *dev, return 0; for_each_crtc_in_state(state, crtc, crtc_state, i) { - u64 __user *fence_ptr; + s32 __user *fence_ptr; fence_ptr = get_out_fence_for_crtc(crtc_state->state, crtc); @@ -2032,13 +2032,16 @@ static void complete_crtc_signaling(struct drm_device *dev, } for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct drm_pending_vblank_event *event = crtc_state->event; /* - * TEST_ONLY and PAGE_FLIP_EVENT are mutually - * exclusive, if they weren't, this code should be - * called on success for TEST_ONLY too. + * Free the allocated event. drm_atomic_helper_setup_commit + * can allocate an event too, so only free it if it's ours + * to prevent a double free in drm_atomic_state_clear. */ - if (crtc_state->event) - drm_event_cancel_free(dev, &crtc_state->event->base); + if (event && (event->base.fence || event->base.file_priv)) { + drm_event_cancel_free(dev, &event->base); + crtc_state->event = NULL; + } } if (!fence_state) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 583f47f27b36..4594477dee00 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1259,8 +1259,10 @@ int drm_atomic_helper_commit(struct drm_device *dev, if (!nonblock) { ret = drm_atomic_helper_wait_for_fences(dev, state, true); - if (ret) + if (ret) { + drm_atomic_helper_cleanup_planes(dev, state); return ret; + } } /* @@ -1664,9 +1666,6 @@ int drm_atomic_helper_prepare_planes(struct drm_device *dev, funcs = plane->helper_private; - if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc)) - continue; - if (funcs->prepare_fb) { ret = funcs->prepare_fb(plane, plane_state); if (ret) @@ -1683,9 +1682,6 @@ fail: if (j >= i) continue; - if (!drm_atomic_helper_framebuffer_changed(dev, state, plane_state->crtc)) - continue; - funcs = plane->helper_private; if (funcs->cleanup_fb) @@ -1952,9 +1948,6 @@ void drm_atomic_helper_cleanup_planes(struct drm_device *dev, for_each_plane_in_state(old_state, plane, plane_state, i) { const struct drm_plane_helper_funcs *funcs; - if (!drm_atomic_helper_framebuffer_changed(dev, old_state, plane_state->crtc)) - continue; - funcs = plane->helper_private; if (funcs->cleanup_fb) diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index 5a4526289392..7a7019ac9388 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -225,6 +225,7 @@ int drm_connector_init(struct drm_device *dev, INIT_LIST_HEAD(&connector->probed_modes); INIT_LIST_HEAD(&connector->modes); + mutex_init(&connector->mutex); connector->edid_blob_ptr = NULL; connector->status = connector_status_unknown; @@ -359,6 +360,8 @@ void drm_connector_cleanup(struct drm_connector *connector) connector->funcs->atomic_destroy_state(connector, connector->state); + mutex_destroy(&connector->mutex); + memset(connector, 0, sizeof(*connector)); } EXPORT_SYMBOL(drm_connector_cleanup); @@ -374,14 +377,18 @@ EXPORT_SYMBOL(drm_connector_cleanup); */ int drm_connector_register(struct drm_connector *connector) { - int ret; + int ret = 0; - if (connector->registered) + if (!connector->dev->registered) return 0; + mutex_lock(&connector->mutex); + if (connector->registered) + goto unlock; + ret = drm_sysfs_connector_add(connector); if (ret) - return ret; + goto unlock; ret = drm_debugfs_connector_add(connector); if (ret) { @@ -397,12 +404,14 @@ int drm_connector_register(struct drm_connector *connector) drm_mode_object_register(connector->dev, &connector->base); connector->registered = true; - return 0; + goto unlock; err_debugfs: drm_debugfs_connector_remove(connector); err_sysfs: drm_sysfs_connector_remove(connector); +unlock: + mutex_unlock(&connector->mutex); return ret; } EXPORT_SYMBOL(drm_connector_register); @@ -415,8 +424,11 @@ EXPORT_SYMBOL(drm_connector_register); */ void drm_connector_unregister(struct drm_connector *connector) { - if (!connector->registered) + mutex_lock(&connector->mutex); + if (!connector->registered) { + mutex_unlock(&connector->mutex); return; + } if (connector->funcs->early_unregister) connector->funcs->early_unregister(connector); @@ -425,6 +437,7 @@ void drm_connector_unregister(struct drm_connector *connector) drm_debugfs_connector_remove(connector); connector->registered = false; + mutex_unlock(&connector->mutex); } EXPORT_SYMBOL(drm_connector_unregister); diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index aa644487749c..f59771da52ee 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c @@ -1817,7 +1817,7 @@ int drm_dp_update_payload_part1(struct drm_dp_mst_topology_mgr *mgr) mgr->payloads[i].vcpi = req_payload.vcpi; } else if (mgr->payloads[i].num_slots) { mgr->payloads[i].num_slots = 0; - drm_dp_destroy_payload_step1(mgr, port, port->vcpi.vcpi, &mgr->payloads[i]); + drm_dp_destroy_payload_step1(mgr, port, mgr->payloads[i].vcpi, &mgr->payloads[i]); req_payload.payload_state = mgr->payloads[i].payload_state; mgr->payloads[i].start_slot = 0; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index a525751b4559..6594b4088f11 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -745,6 +745,8 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) if (ret) goto err_minors; + dev->registered = true; + if (dev->driver->load) { ret = dev->driver->load(dev, flags); if (ret) @@ -785,6 +787,8 @@ void drm_dev_unregister(struct drm_device *dev) drm_lastclose(dev); + dev->registered = false; + if (drm_core_check_feature(dev, DRIVER_MODESET)) drm_modeset_unregister_all(dev); diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 1d6c335584ec..33cd51632721 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -376,7 +376,7 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, off = drm_vma_node_start(&obj->vma_node); seq_printf(m, "%2d (%2d) %08llx %pad %p %zu", - obj->name, obj->refcount.refcount.counter, + obj->name, kref_read(&obj->refcount), off, &cma_obj->paddr, cma_obj->vaddr, obj->size); seq_printf(m, "\n"); diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c index ffb2ab389d1d..6b68e9088436 100644 --- a/drivers/gpu/drm/drm_info.c +++ b/drivers/gpu/drm/drm_info.c @@ -118,7 +118,7 @@ static int drm_gem_one_name_info(int id, void *ptr, void *data) seq_printf(m, "%6d %8zd %7d %8d\n", obj->name, obj->size, obj->handle_count, - atomic_read(&obj->refcount.refcount)); + kref_read(&obj->refcount)); return 0; } diff --git a/drivers/gpu/drm/drm_mode_object.c b/drivers/gpu/drm/drm_mode_object.c index 9f17085b1fdd..c6885a4911c0 100644 --- a/drivers/gpu/drm/drm_mode_object.c +++ b/drivers/gpu/drm/drm_mode_object.c @@ -159,7 +159,7 @@ EXPORT_SYMBOL(drm_mode_object_find); void drm_mode_object_unreference(struct drm_mode_object *obj) { if (obj->free_cb) { - DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); + DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); kref_put(&obj->refcount, obj->free_cb); } } @@ -176,7 +176,7 @@ EXPORT_SYMBOL(drm_mode_object_unreference); void drm_mode_object_reference(struct drm_mode_object *obj) { if (obj->free_cb) { - DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, atomic_read(&obj->refcount.refcount)); + DRM_DEBUG("OBJ ID: %d (%d)\n", obj->id, kref_read(&obj->refcount)); kref_get(&obj->refcount); } } diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index ac6a35212501..e6b19bc9021a 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -1460,6 +1460,13 @@ drm_mode_create_from_cmdline_mode(struct drm_device *dev, return NULL; mode->type |= DRM_MODE_TYPE_USERDEF; + /* fix up 1368x768: GFT/CVT can't express 1366 width due to alignment */ + if (cmd->xres == 1366 && mode->hdisplay == 1368) { + mode->hdisplay = 1366; + mode->hsync_start--; + mode->hsync_end--; + drm_mode_set_name(mode); + } drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V); return mode; } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index ac953f037be7..cf8f0128c161 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -143,8 +143,18 @@ void drm_kms_helper_poll_enable_locked(struct drm_device *dev) } if (dev->mode_config.delayed_event) { + /* + * FIXME: + * + * Use short (1s) delay to handle the initial delayed event. + * This delay should not be needed, but Optimus/nouveau will + * fail in a mysterious way if the delayed event is handled as + * soon as possible like it is done in + * drm_helper_probe_single_connector_modes() in case the poll + * was enabled before. + */ poll = true; - delay = 0; + delay = HZ; } if (poll) diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 114dddbd297b..aa6e35ddc87f 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -486,7 +486,7 @@ static void etnaviv_gem_describe(struct drm_gem_object *obj, struct seq_file *m) seq_printf(m, "%08x: %c %2d (%2d) %08lx %p %zd\n", etnaviv_obj->flags, is_active(etnaviv_obj) ? 'A' : 'I', - obj->name, obj->refcount.refcount.counter, + obj->name, kref_read(&obj->refcount), off, etnaviv_obj->vaddr, obj->size); rcu_read_lock(); diff --git a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c index 169ac96e8f08..fe0e85b41310 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_mmu.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_mmu.c @@ -116,9 +116,14 @@ static int etnaviv_iommu_find_iova(struct etnaviv_iommu *mmu, struct list_head list; bool found; + /* + * XXX: The DRM_MM_SEARCH_BELOW is really a hack to trick + * drm_mm into giving out a low IOVA after address space + * rollover. This needs a proper fix. + */ ret = drm_mm_insert_node_in_range(&mmu->mm, node, size, 0, mmu->last_iova, ~0UL, - DRM_MM_SEARCH_DEFAULT); + mmu->last_iova ? DRM_MM_SEARCH_DEFAULT : DRM_MM_SEARCH_BELOW); if (ret != -ENOSPC) break; diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 6ca1f3117fe8..75eeb831ed6a 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -46,7 +46,8 @@ enum decon_flag_bits { BIT_CLKS_ENABLED, BIT_IRQS_ENABLED, BIT_WIN_UPDATED, - BIT_SUSPENDED + BIT_SUSPENDED, + BIT_REQUEST_UPDATE }; struct decon_context { @@ -141,12 +142,6 @@ static void decon_commit(struct exynos_drm_crtc *crtc) m->crtc_vsync_end = m->crtc_vsync_start + 1; } - decon_set_bits(ctx, DECON_VIDCON0, VIDCON0_ENVID, 0); - - /* enable clock gate */ - val = CMU_CLKGAGE_MODE_SFR_F | CMU_CLKGAGE_MODE_MEM_F; - writel(val, ctx->addr + DECON_CMU); - if (ctx->out_type & (IFTYPE_I80 | I80_HW_TRG)) decon_setup_trigger(ctx); @@ -315,6 +310,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); + set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_disable_plane(struct exynos_drm_crtc *crtc, @@ -327,6 +323,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, return; decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); + set_bit(BIT_REQUEST_UPDATE, &ctx->flags); } static void decon_atomic_flush(struct exynos_drm_crtc *crtc) @@ -340,8 +337,8 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) for (i = ctx->first_win; i < WINDOWS_NR; i++) decon_shadow_protect_win(ctx, i, false); - /* standalone update */ - decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); + if (test_and_clear_bit(BIT_REQUEST_UPDATE, &ctx->flags)) + decon_set_bits(ctx, DECON_UPDATE, STANDALONE_UPDATE_F, ~0); if (ctx->out_type & IFTYPE_I80) set_bit(BIT_WIN_UPDATED, &ctx->flags); diff --git a/drivers/gpu/drm/i915/gvt/aperture_gm.c b/drivers/gpu/drm/i915/gvt/aperture_gm.c index 0d41ebc4aea6..f7bce8603958 100644 --- a/drivers/gpu/drm/i915/gvt/aperture_gm.c +++ b/drivers/gpu/drm/i915/gvt/aperture_gm.c @@ -37,13 +37,6 @@ #include "i915_drv.h" #include "gvt.h" -#define MB_TO_BYTES(mb) ((mb) << 20ULL) -#define BYTES_TO_MB(b) ((b) >> 20ULL) - -#define HOST_LOW_GM_SIZE MB_TO_BYTES(128) -#define HOST_HIGH_GM_SIZE MB_TO_BYTES(384) -#define HOST_FENCE 4 - static int alloc_gm(struct intel_vgpu *vgpu, bool high_gm) { struct intel_gvt *gvt = vgpu->gvt; @@ -165,6 +158,14 @@ void intel_vgpu_write_fence(struct intel_vgpu *vgpu, POSTING_READ(fence_reg_lo); } +static void _clear_vgpu_fence(struct intel_vgpu *vgpu) +{ + int i; + + for (i = 0; i < vgpu_fence_sz(vgpu); i++) + intel_vgpu_write_fence(vgpu, i, 0); +} + static void free_vgpu_fence(struct intel_vgpu *vgpu) { struct intel_gvt *gvt = vgpu->gvt; @@ -178,9 +179,9 @@ static void free_vgpu_fence(struct intel_vgpu *vgpu) intel_runtime_pm_get(dev_priv); mutex_lock(&dev_priv->drm.struct_mutex); + _clear_vgpu_fence(vgpu); for (i = 0; i < vgpu_fence_sz(vgpu); i++) { reg = vgpu->fence.regs[i]; - intel_vgpu_write_fence(vgpu, i, 0); list_add_tail(®->link, &dev_priv->mm.fence_list); } @@ -208,13 +209,14 @@ static int alloc_vgpu_fence(struct intel_vgpu *vgpu) continue; list_del(pos); vgpu->fence.regs[i] = reg; - intel_vgpu_write_fence(vgpu, i, 0); if (++i == vgpu_fence_sz(vgpu)) break; } if (i != vgpu_fence_sz(vgpu)) goto out_free_fence; + _clear_vgpu_fence(vgpu); + mutex_unlock(&dev_priv->drm.struct_mutex); intel_runtime_pm_put(dev_priv); return 0; @@ -314,6 +316,22 @@ void intel_vgpu_free_resource(struct intel_vgpu *vgpu) } /** + * intel_vgpu_reset_resource - reset resource state owned by a vGPU + * @vgpu: a vGPU + * + * This function is used to reset resource state owned by a vGPU. + * + */ +void intel_vgpu_reset_resource(struct intel_vgpu *vgpu) +{ + struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; + + intel_runtime_pm_get(dev_priv); + _clear_vgpu_fence(vgpu); + intel_runtime_pm_put(dev_priv); +} + +/** * intel_alloc_vgpu_resource - allocate HW resource for a vGPU * @vgpu: vGPU * @param: vGPU creation params diff --git a/drivers/gpu/drm/i915/gvt/cfg_space.c b/drivers/gpu/drm/i915/gvt/cfg_space.c index db516382a4d4..4a6a2ed65732 100644 --- a/drivers/gpu/drm/i915/gvt/cfg_space.c +++ b/drivers/gpu/drm/i915/gvt/cfg_space.c @@ -123,6 +123,7 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu, u8 changed = old ^ new; int ret; + memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); if (!(changed & PCI_COMMAND_MEMORY)) return 0; @@ -142,7 +143,6 @@ static int emulate_pci_command_write(struct intel_vgpu *vgpu, return ret; } - memcpy(vgpu_cfg_space(vgpu) + offset, p_data, bytes); return 0; } @@ -240,7 +240,7 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset, if (WARN_ON(bytes > 4)) return -EINVAL; - if (WARN_ON(offset + bytes >= INTEL_GVT_MAX_CFG_SPACE_SZ)) + if (WARN_ON(offset + bytes > INTEL_GVT_MAX_CFG_SPACE_SZ)) return -EINVAL; /* First check if it's PCI_COMMAND */ @@ -282,3 +282,77 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset, } return 0; } + +/** + * intel_vgpu_init_cfg_space - init vGPU configuration space when create vGPU + * + * @vgpu: a vGPU + * @primary: is the vGPU presented as primary + * + */ +void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, + bool primary) +{ + struct intel_gvt *gvt = vgpu->gvt; + const struct intel_gvt_device_info *info = &gvt->device_info; + u16 *gmch_ctl; + int i; + + memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space, + info->cfg_space_size); + + if (!primary) { + vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] = + INTEL_GVT_PCI_CLASS_VGA_OTHER; + vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] = + INTEL_GVT_PCI_CLASS_VGA_OTHER; + } + + /* Show guest that there isn't any stolen memory.*/ + gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL); + *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT); + + intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2, + gvt_aperture_pa_base(gvt), true); + + vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO + | PCI_COMMAND_MEMORY + | PCI_COMMAND_MASTER); + /* + * Clear the bar upper 32bit and let guest to assign the new value + */ + memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4); + memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4); + memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4); + + for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) { + vgpu->cfg_space.bar[i].size = pci_resource_len( + gvt->dev_priv->drm.pdev, i * 2); + vgpu->cfg_space.bar[i].tracked = false; + } +} + +/** + * intel_vgpu_reset_cfg_space - reset vGPU configuration space + * + * @vgpu: a vGPU + * + */ +void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu) +{ + u8 cmd = vgpu_cfg_space(vgpu)[PCI_COMMAND]; + bool primary = vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] != + INTEL_GVT_PCI_CLASS_VGA_OTHER; + + if (cmd & PCI_COMMAND_MEMORY) { + trap_gttmmio(vgpu, false); + map_aperture(vgpu, false); + } + + /** + * Currently we only do such reset when vGPU is not + * owned by any VM, so we simply restore entire cfg + * space to default value. + */ + intel_vgpu_init_cfg_space(vgpu, primary); +} diff --git a/drivers/gpu/drm/i915/gvt/cmd_parser.c b/drivers/gpu/drm/i915/gvt/cmd_parser.c index d26a092c70e8..e4563984cb1e 100644 --- a/drivers/gpu/drm/i915/gvt/cmd_parser.c +++ b/drivers/gpu/drm/i915/gvt/cmd_parser.c @@ -481,7 +481,6 @@ struct parser_exec_state { (s->vgpu->gvt->device_info.gmadr_bytes_in_cmd >> 2) static unsigned long bypass_scan_mask = 0; -static bool bypass_batch_buffer_scan = true; /* ring ALL, type = 0 */ static struct sub_op_bits sub_op_mi[] = { @@ -1525,9 +1524,6 @@ static int batch_buffer_needs_scan(struct parser_exec_state *s) { struct intel_gvt *gvt = s->vgpu->gvt; - if (bypass_batch_buffer_scan) - return 0; - if (IS_BROADWELL(gvt->dev_priv) || IS_SKYLAKE(gvt->dev_priv)) { /* BDW decides privilege based on address space */ if (cmd_val(s, 0) & (1 << 8)) diff --git a/drivers/gpu/drm/i915/gvt/execlist.c b/drivers/gpu/drm/i915/gvt/execlist.c index f32bb6f6495c..34083731669d 100644 --- a/drivers/gpu/drm/i915/gvt/execlist.c +++ b/drivers/gpu/drm/i915/gvt/execlist.c @@ -364,58 +364,30 @@ static void free_workload(struct intel_vgpu_workload *workload) #define get_desc_from_elsp_dwords(ed, i) \ ((struct execlist_ctx_descriptor_format *)&((ed)->data[i * 2])) - -#define BATCH_BUFFER_ADDR_MASK ((1UL << 32) - (1U << 2)) -#define BATCH_BUFFER_ADDR_HIGH_MASK ((1UL << 16) - (1U)) -static int set_gma_to_bb_cmd(struct intel_shadow_bb_entry *entry_obj, - unsigned long add, int gmadr_bytes) -{ - if (WARN_ON(gmadr_bytes != 4 && gmadr_bytes != 8)) - return -1; - - *((u32 *)(entry_obj->bb_start_cmd_va + (1 << 2))) = add & - BATCH_BUFFER_ADDR_MASK; - if (gmadr_bytes == 8) { - *((u32 *)(entry_obj->bb_start_cmd_va + (2 << 2))) = - add & BATCH_BUFFER_ADDR_HIGH_MASK; - } - - return 0; -} - static void prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload) { - int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd; + const int gmadr_bytes = workload->vgpu->gvt->device_info.gmadr_bytes_in_cmd; + struct intel_shadow_bb_entry *entry_obj; /* pin the gem object to ggtt */ - if (!list_empty(&workload->shadow_bb)) { - struct intel_shadow_bb_entry *entry_obj = - list_first_entry(&workload->shadow_bb, - struct intel_shadow_bb_entry, - list); - struct intel_shadow_bb_entry *temp; + list_for_each_entry(entry_obj, &workload->shadow_bb, list) { + struct i915_vma *vma; - list_for_each_entry_safe(entry_obj, temp, &workload->shadow_bb, - list) { - struct i915_vma *vma; - - vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0, - 4, 0); - if (IS_ERR(vma)) { - gvt_err("Cannot pin\n"); - return; - } - - /* FIXME: we are not tracking our pinned VMA leaving it - * up to the core to fix up the stray pin_count upon - * free. - */ - - /* update the relocate gma with shadow batch buffer*/ - set_gma_to_bb_cmd(entry_obj, - i915_ggtt_offset(vma), - gmadr_bytes); + vma = i915_gem_object_ggtt_pin(entry_obj->obj, NULL, 0, 4, 0); + if (IS_ERR(vma)) { + gvt_err("Cannot pin\n"); + return; } + + /* FIXME: we are not tracking our pinned VMA leaving it + * up to the core to fix up the stray pin_count upon + * free. + */ + + /* update the relocate gma with shadow batch buffer*/ + entry_obj->bb_start_cmd_va[1] = i915_ggtt_offset(vma); + if (gmadr_bytes == 8) + entry_obj->bb_start_cmd_va[2] = 0; } } @@ -826,7 +798,7 @@ int intel_vgpu_init_execlist(struct intel_vgpu *vgpu) INIT_LIST_HEAD(&vgpu->workload_q_head[i]); } - vgpu->workloads = kmem_cache_create("gvt-g vgpu workload", + vgpu->workloads = kmem_cache_create("gvt-g_vgpu_workload", sizeof(struct intel_vgpu_workload), 0, SLAB_HWCACHE_ALIGN, NULL); diff --git a/drivers/gpu/drm/i915/gvt/gtt.c b/drivers/gpu/drm/i915/gvt/gtt.c index 7eaaf1c9ed2b..47dec4acf7ff 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.c +++ b/drivers/gpu/drm/i915/gvt/gtt.c @@ -240,15 +240,8 @@ static inline int get_pse_type(int type) static u64 read_pte64(struct drm_i915_private *dev_priv, unsigned long index) { void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index; - u64 pte; -#ifdef readq - pte = readq(addr); -#else - pte = ioread32(addr); - pte |= (u64)ioread32(addr + 4) << 32; -#endif - return pte; + return readq(addr); } static void write_pte64(struct drm_i915_private *dev_priv, @@ -256,12 +249,8 @@ static void write_pte64(struct drm_i915_private *dev_priv, { void __iomem *addr = (gen8_pte_t __iomem *)dev_priv->ggtt.gsm + index; -#ifdef writeq writeq(pte, addr); -#else - iowrite32((u32)pte, addr); - iowrite32(pte >> 32, addr + 4); -#endif + I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); POSTING_READ(GFX_FLSH_CNTL_GEN6); } @@ -1380,8 +1369,7 @@ static int gen8_mm_alloc_page_table(struct intel_vgpu_mm *mm) info->gtt_entry_size; mem = kzalloc(mm->has_shadow_page_table ? mm->page_table_entry_size * 2 - : mm->page_table_entry_size, - GFP_ATOMIC); + : mm->page_table_entry_size, GFP_KERNEL); if (!mem) return -ENOMEM; mm->virtual_page_table = mem; @@ -1532,7 +1520,7 @@ struct intel_vgpu_mm *intel_vgpu_create_mm(struct intel_vgpu *vgpu, struct intel_vgpu_mm *mm; int ret; - mm = kzalloc(sizeof(*mm), GFP_ATOMIC); + mm = kzalloc(sizeof(*mm), GFP_KERNEL); if (!mm) { ret = -ENOMEM; goto fail; @@ -1886,30 +1874,27 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; int page_entry_num = GTT_PAGE_SIZE >> vgpu->gvt->device_info.gtt_entry_size_shift; - struct page *scratch_pt; + void *scratch_pt; unsigned long mfn; int i; - void *p; if (WARN_ON(type < GTT_TYPE_PPGTT_PTE_PT || type >= GTT_TYPE_MAX)) return -EINVAL; - scratch_pt = alloc_page(GFP_KERNEL | GFP_ATOMIC | __GFP_ZERO); + scratch_pt = (void *)get_zeroed_page(GFP_KERNEL); if (!scratch_pt) { gvt_err("fail to allocate scratch page\n"); return -ENOMEM; } - p = kmap_atomic(scratch_pt); - mfn = intel_gvt_hypervisor_virt_to_mfn(p); + mfn = intel_gvt_hypervisor_virt_to_mfn(scratch_pt); if (mfn == INTEL_GVT_INVALID_ADDR) { - gvt_err("fail to translate vaddr:0x%llx\n", (u64)p); - kunmap_atomic(p); - __free_page(scratch_pt); + gvt_err("fail to translate vaddr:0x%lx\n", (unsigned long)scratch_pt); + free_page((unsigned long)scratch_pt); return -EFAULT; } gtt->scratch_pt[type].page_mfn = mfn; - gtt->scratch_pt[type].page = scratch_pt; + gtt->scratch_pt[type].page = virt_to_page(scratch_pt); gvt_dbg_mm("vgpu%d create scratch_pt: type %d mfn=0x%lx\n", vgpu->id, type, mfn); @@ -1918,7 +1903,7 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, * scratch_pt[type] indicate the scratch pt/scratch page used by the * 'type' pt. * e.g. scratch_pt[GTT_TYPE_PPGTT_PDE_PT] is used by - * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scatch_pt it self + * GTT_TYPE_PPGTT_PDE_PT level pt, that means this scratch_pt it self * is GTT_TYPE_PPGTT_PTE_PT, and full filled by scratch page mfn. */ if (type > GTT_TYPE_PPGTT_PTE_PT && type < GTT_TYPE_MAX) { @@ -1936,11 +1921,9 @@ static int alloc_scratch_pages(struct intel_vgpu *vgpu, se.val64 |= PPAT_CACHED_INDEX; for (i = 0; i < page_entry_num; i++) - ops->set_entry(p, &se, i, false, 0, vgpu); + ops->set_entry(scratch_pt, &se, i, false, 0, vgpu); } - kunmap_atomic(p); - return 0; } @@ -1998,6 +1981,8 @@ int intel_vgpu_init_gtt(struct intel_vgpu *vgpu) INIT_LIST_HEAD(>t->oos_page_list_head); INIT_LIST_HEAD(>t->post_shadow_list_head); + intel_vgpu_reset_ggtt(vgpu); + ggtt_mm = intel_vgpu_create_mm(vgpu, INTEL_GVT_MM_GGTT, NULL, 1, 0); if (IS_ERR(ggtt_mm)) { @@ -2206,6 +2191,7 @@ int intel_vgpu_g2v_destroy_ppgtt_mm(struct intel_vgpu *vgpu, int intel_gvt_init_gtt(struct intel_gvt *gvt) { int ret; + void *page; gvt_dbg_core("init gtt\n"); @@ -2218,6 +2204,20 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) return -ENODEV; } + page = (void *)get_zeroed_page(GFP_KERNEL); + if (!page) { + gvt_err("fail to allocate scratch ggtt page\n"); + return -ENOMEM; + } + gvt->gtt.scratch_ggtt_page = virt_to_page(page); + + gvt->gtt.scratch_ggtt_mfn = intel_gvt_hypervisor_virt_to_mfn(page); + if (gvt->gtt.scratch_ggtt_mfn == INTEL_GVT_INVALID_ADDR) { + gvt_err("fail to translate scratch ggtt page\n"); + __free_page(gvt->gtt.scratch_ggtt_page); + return -EFAULT; + } + if (enable_out_of_sync) { ret = setup_spt_oos(gvt); if (ret) { @@ -2239,6 +2239,68 @@ int intel_gvt_init_gtt(struct intel_gvt *gvt) */ void intel_gvt_clean_gtt(struct intel_gvt *gvt) { + __free_page(gvt->gtt.scratch_ggtt_page); + if (enable_out_of_sync) clean_spt_oos(gvt); } + +/** + * intel_vgpu_reset_ggtt - reset the GGTT entry + * @vgpu: a vGPU + * + * This function is called at the vGPU create stage + * to reset all the GGTT entries. + * + */ +void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu) +{ + struct intel_gvt *gvt = vgpu->gvt; + struct intel_gvt_gtt_pte_ops *ops = vgpu->gvt->gtt.pte_ops; + u32 index; + u32 offset; + u32 num_entries; + struct intel_gvt_gtt_entry e; + + memset(&e, 0, sizeof(struct intel_gvt_gtt_entry)); + e.type = GTT_TYPE_GGTT_PTE; + ops->set_pfn(&e, gvt->gtt.scratch_ggtt_mfn); + e.val64 |= _PAGE_PRESENT; + + index = vgpu_aperture_gmadr_base(vgpu) >> PAGE_SHIFT; + num_entries = vgpu_aperture_sz(vgpu) >> PAGE_SHIFT; + for (offset = 0; offset < num_entries; offset++) + ops->set_entry(NULL, &e, index + offset, false, 0, vgpu); + + index = vgpu_hidden_gmadr_base(vgpu) >> PAGE_SHIFT; + num_entries = vgpu_hidden_sz(vgpu) >> PAGE_SHIFT; + for (offset = 0; offset < num_entries; offset++) + ops->set_entry(NULL, &e, index + offset, false, 0, vgpu); +} + +/** + * intel_vgpu_reset_gtt - reset the all GTT related status + * @vgpu: a vGPU + * @dmlr: true for vGPU Device Model Level Reset, false for GT Reset + * + * This function is called from vfio core to reset reset all + * GTT related status, including GGTT, PPGTT, scratch page. + * + */ +void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr) +{ + int i; + + ppgtt_free_all_shadow_page(vgpu); + if (!dmlr) + return; + + intel_vgpu_reset_ggtt(vgpu); + + /* clear scratch page for security */ + for (i = GTT_TYPE_PPGTT_PTE_PT; i < GTT_TYPE_MAX; i++) { + if (vgpu->gtt.scratch_pt[i].page != NULL) + memset(page_address(vgpu->gtt.scratch_pt[i].page), + 0, PAGE_SIZE); + } +} diff --git a/drivers/gpu/drm/i915/gvt/gtt.h b/drivers/gpu/drm/i915/gvt/gtt.h index d250013bc37b..f88eb5e89bea 100644 --- a/drivers/gpu/drm/i915/gvt/gtt.h +++ b/drivers/gpu/drm/i915/gvt/gtt.h @@ -81,6 +81,9 @@ struct intel_gvt_gtt { struct list_head oos_page_use_list_head; struct list_head oos_page_free_list_head; struct list_head mm_lru_list_head; + + struct page *scratch_ggtt_page; + unsigned long scratch_ggtt_mfn; }; enum { @@ -202,8 +205,10 @@ struct intel_vgpu_gtt { extern int intel_vgpu_init_gtt(struct intel_vgpu *vgpu); extern void intel_vgpu_clean_gtt(struct intel_vgpu *vgpu); +void intel_vgpu_reset_ggtt(struct intel_vgpu *vgpu); extern int intel_gvt_init_gtt(struct intel_gvt *gvt); +extern void intel_vgpu_reset_gtt(struct intel_vgpu *vgpu, bool dmlr); extern void intel_gvt_clean_gtt(struct intel_gvt *gvt); extern struct intel_vgpu_mm *intel_gvt_find_ppgtt_mm(struct intel_vgpu *vgpu, diff --git a/drivers/gpu/drm/i915/gvt/gvt.c b/drivers/gpu/drm/i915/gvt/gvt.c index 398877c3d2fd..e6bf5c533fbe 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.c +++ b/drivers/gpu/drm/i915/gvt/gvt.c @@ -201,6 +201,8 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv) intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev, gvt); intel_gvt_clean_vgpu_types(gvt); + idr_destroy(&gvt->vgpu_idr); + kfree(dev_priv->gvt); dev_priv->gvt = NULL; } @@ -237,6 +239,8 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv) gvt_dbg_core("init gvt device\n"); + idr_init(&gvt->vgpu_idr); + mutex_init(&gvt->lock); gvt->dev_priv = dev_priv; @@ -244,7 +248,7 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv) ret = intel_gvt_setup_mmio_info(gvt); if (ret) - return ret; + goto out_clean_idr; ret = intel_gvt_load_firmware(gvt); if (ret) @@ -313,6 +317,8 @@ out_free_firmware: intel_gvt_free_firmware(gvt); out_clean_mmio_info: intel_gvt_clean_mmio_info(gvt); +out_clean_idr: + idr_destroy(&gvt->vgpu_idr); kfree(gvt); return ret; } diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index ad0e9364ee70..e227caf5859e 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -175,6 +175,7 @@ struct intel_vgpu { struct notifier_block group_notifier; struct kvm *kvm; struct work_struct release_work; + atomic_t released; } vdev; #endif }; @@ -322,6 +323,7 @@ struct intel_vgpu_creation_params { int intel_vgpu_alloc_resource(struct intel_vgpu *vgpu, struct intel_vgpu_creation_params *param); +void intel_vgpu_reset_resource(struct intel_vgpu *vgpu); void intel_vgpu_free_resource(struct intel_vgpu *vgpu); void intel_vgpu_write_fence(struct intel_vgpu *vgpu, u32 fence, u64 value); @@ -374,6 +376,8 @@ void intel_gvt_clean_vgpu_types(struct intel_gvt *gvt); struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, struct intel_vgpu_type *type); void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu); +void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, + unsigned int engine_mask); void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu); @@ -410,6 +414,10 @@ int intel_gvt_ggtt_index_g2h(struct intel_vgpu *vgpu, unsigned long g_index, int intel_gvt_ggtt_h2g_index(struct intel_vgpu *vgpu, unsigned long h_index, unsigned long *g_index); +void intel_vgpu_init_cfg_space(struct intel_vgpu *vgpu, + bool primary); +void intel_vgpu_reset_cfg_space(struct intel_vgpu *vgpu); + int intel_vgpu_emulate_cfg_read(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes); @@ -423,7 +431,6 @@ void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu); int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa); int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci); -int setup_vgpu_mmio(struct intel_vgpu *vgpu); void populate_pvinfo_page(struct intel_vgpu *vgpu); struct intel_gvt_ops { diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c index 522809710312..ab2ea157da4c 100644 --- a/drivers/gpu/drm/i915/gvt/handlers.c +++ b/drivers/gpu/drm/i915/gvt/handlers.c @@ -93,7 +93,8 @@ static void write_vreg(struct intel_vgpu *vgpu, unsigned int offset, static int new_mmio_info(struct intel_gvt *gvt, u32 offset, u32 flags, u32 size, u32 addr_mask, u32 ro_mask, u32 device, - void *read, void *write) + int (*read)(struct intel_vgpu *, unsigned int, void *, unsigned int), + int (*write)(struct intel_vgpu *, unsigned int, void *, unsigned int)) { struct intel_gvt_mmio_info *info, *p; u32 start, end, i; @@ -219,7 +220,7 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu, default: /*should not hit here*/ gvt_err("invalid forcewake offset 0x%x\n", offset); - return 1; + return -EINVAL; } } else { ack_reg_offset = FORCEWAKE_ACK_HSW_REG; @@ -230,77 +231,45 @@ static int mul_force_wake_write(struct intel_vgpu *vgpu, return 0; } -static int handle_device_reset(struct intel_vgpu *vgpu, unsigned int offset, - void *p_data, unsigned int bytes, unsigned long bitmap) -{ - struct intel_gvt_workload_scheduler *scheduler = - &vgpu->gvt->scheduler; - - vgpu->resetting = true; - - intel_vgpu_stop_schedule(vgpu); - /* - * The current_vgpu will set to NULL after stopping the - * scheduler when the reset is triggered by current vgpu. - */ - if (scheduler->current_vgpu == NULL) { - mutex_unlock(&vgpu->gvt->lock); - intel_gvt_wait_vgpu_idle(vgpu); - mutex_lock(&vgpu->gvt->lock); - } - - intel_vgpu_reset_execlist(vgpu, bitmap); - - /* full GPU reset */ - if (bitmap == 0xff) { - mutex_unlock(&vgpu->gvt->lock); - intel_vgpu_clean_gtt(vgpu); - mutex_lock(&vgpu->gvt->lock); - setup_vgpu_mmio(vgpu); - populate_pvinfo_page(vgpu); - intel_vgpu_init_gtt(vgpu); - } - - vgpu->resetting = false; - - return 0; -} - static int gdrst_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, - void *p_data, unsigned int bytes) + void *p_data, unsigned int bytes) { + unsigned int engine_mask = 0; u32 data; - u64 bitmap = 0; write_vreg(vgpu, offset, p_data, bytes); data = vgpu_vreg(vgpu, offset); if (data & GEN6_GRDOM_FULL) { gvt_dbg_mmio("vgpu%d: request full GPU reset\n", vgpu->id); - bitmap = 0xff; - } - if (data & GEN6_GRDOM_RENDER) { - gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id); - bitmap |= (1 << RCS); - } - if (data & GEN6_GRDOM_MEDIA) { - gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id); - bitmap |= (1 << VCS); - } - if (data & GEN6_GRDOM_BLT) { - gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id); - bitmap |= (1 << BCS); - } - if (data & GEN6_GRDOM_VECS) { - gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id); - bitmap |= (1 << VECS); - } - if (data & GEN8_GRDOM_MEDIA2) { - gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id); - if (HAS_BSD2(vgpu->gvt->dev_priv)) - bitmap |= (1 << VCS2); + engine_mask = ALL_ENGINES; + } else { + if (data & GEN6_GRDOM_RENDER) { + gvt_dbg_mmio("vgpu%d: request RCS reset\n", vgpu->id); + engine_mask |= (1 << RCS); + } + if (data & GEN6_GRDOM_MEDIA) { + gvt_dbg_mmio("vgpu%d: request VCS reset\n", vgpu->id); + engine_mask |= (1 << VCS); + } + if (data & GEN6_GRDOM_BLT) { + gvt_dbg_mmio("vgpu%d: request BCS Reset\n", vgpu->id); + engine_mask |= (1 << BCS); + } + if (data & GEN6_GRDOM_VECS) { + gvt_dbg_mmio("vgpu%d: request VECS Reset\n", vgpu->id); + engine_mask |= (1 << VECS); + } + if (data & GEN8_GRDOM_MEDIA2) { + gvt_dbg_mmio("vgpu%d: request VCS2 Reset\n", vgpu->id); + if (HAS_BSD2(vgpu->gvt->dev_priv)) + engine_mask |= (1 << VCS2); + } } - return handle_device_reset(vgpu, offset, p_data, bytes, bitmap); + + intel_gvt_reset_vgpu_locked(vgpu, false, engine_mask); + + return 0; } static int gmbus_mmio_read(struct intel_vgpu *vgpu, unsigned int offset, @@ -974,7 +943,7 @@ static int sbi_data_mmio_read(struct intel_vgpu *vgpu, unsigned int offset, return 0; } -static bool sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, +static int sbi_ctl_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { u32 data; @@ -1366,7 +1335,6 @@ static int ring_mode_mmio_write(struct intel_vgpu *vgpu, unsigned int offset, static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu, unsigned int offset, void *p_data, unsigned int bytes) { - int rc = 0; unsigned int id = 0; write_vreg(vgpu, offset, p_data, bytes); @@ -1389,12 +1357,11 @@ static int gvt_reg_tlb_control_handler(struct intel_vgpu *vgpu, id = VECS; break; default: - rc = -EINVAL; - break; + return -EINVAL; } set_bit(id, (void *)vgpu->tlb_handle_pending); - return rc; + return 0; } static int ring_reset_ctl_write(struct intel_vgpu *vgpu, diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 4dd6722a7339..3f656e3a6e5a 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -114,12 +114,15 @@ out: static kvm_pfn_t gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn) { struct gvt_dma *entry; + kvm_pfn_t pfn; mutex_lock(&vgpu->vdev.cache_lock); + entry = __gvt_cache_find(vgpu, gfn); - mutex_unlock(&vgpu->vdev.cache_lock); + pfn = (entry == NULL) ? 0 : entry->pfn; - return entry == NULL ? 0 : entry->pfn; + mutex_unlock(&vgpu->vdev.cache_lock); + return pfn; } static void gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn, kvm_pfn_t pfn) @@ -166,7 +169,7 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu, static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) { - struct device *dev = &vgpu->vdev.mdev->dev; + struct device *dev = mdev_dev(vgpu->vdev.mdev); struct gvt_dma *this; unsigned long g1; int rc; @@ -195,7 +198,7 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu) { struct gvt_dma *dma; struct rb_node *node = NULL; - struct device *dev = &vgpu->vdev.mdev->dev; + struct device *dev = mdev_dev(vgpu->vdev.mdev); unsigned long gfn; mutex_lock(&vgpu->vdev.cache_lock); @@ -227,8 +230,8 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt, return NULL; } -static ssize_t available_instance_show(struct kobject *kobj, struct device *dev, - char *buf) +static ssize_t available_instances_show(struct kobject *kobj, + struct device *dev, char *buf) { struct intel_vgpu_type *type; unsigned int num = 0; @@ -266,12 +269,12 @@ static ssize_t description_show(struct kobject *kobj, struct device *dev, type->fence); } -static MDEV_TYPE_ATTR_RO(available_instance); +static MDEV_TYPE_ATTR_RO(available_instances); static MDEV_TYPE_ATTR_RO(device_api); static MDEV_TYPE_ATTR_RO(description); static struct attribute *type_attrs[] = { - &mdev_type_attr_available_instance.attr, + &mdev_type_attr_available_instances.attr, &mdev_type_attr_device_api.attr, &mdev_type_attr_description.attr, NULL, @@ -395,21 +398,24 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) struct intel_vgpu_type *type; struct device *pdev; void *gvt; + int ret; - pdev = mdev->parent->dev; + pdev = mdev_parent_dev(mdev); gvt = kdev_to_i915(pdev)->gvt; type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); if (!type) { gvt_err("failed to find type %s to create\n", kobject_name(kobj)); - return -EINVAL; + ret = -EINVAL; + goto out; } vgpu = intel_gvt_ops->vgpu_create(gvt, type); if (IS_ERR_OR_NULL(vgpu)) { - gvt_err("create intel vgpu failed\n"); - return -EINVAL; + ret = vgpu == NULL ? -EFAULT : PTR_ERR(vgpu); + gvt_err("failed to create intel vgpu: %d\n", ret); + goto out; } INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work); @@ -418,8 +424,11 @@ static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) mdev_set_drvdata(mdev, vgpu); gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n", - dev_name(&mdev->dev)); - return 0; + dev_name(mdev_dev(mdev))); + ret = 0; + +out: + return ret; } static int intel_vgpu_remove(struct mdev_device *mdev) @@ -482,7 +491,7 @@ static int intel_vgpu_open(struct mdev_device *mdev) vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier; events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; - ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events, + ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, &events, &vgpu->vdev.iommu_notifier); if (ret != 0) { gvt_err("vfio_register_notifier for iommu failed: %d\n", ret); @@ -490,17 +499,26 @@ static int intel_vgpu_open(struct mdev_device *mdev) } events = VFIO_GROUP_NOTIFY_SET_KVM; - ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events, + ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &events, &vgpu->vdev.group_notifier); if (ret != 0) { gvt_err("vfio_register_notifier for group failed: %d\n", ret); goto undo_iommu; } - return kvmgt_guest_init(mdev); + ret = kvmgt_guest_init(mdev); + if (ret) + goto undo_group; + + atomic_set(&vgpu->vdev.released, 0); + return ret; + +undo_group: + vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, + &vgpu->vdev.group_notifier); undo_iommu: - vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, + vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, &vgpu->vdev.iommu_notifier); out: return ret; @@ -509,17 +527,26 @@ out: static void __intel_vgpu_release(struct intel_vgpu *vgpu) { struct kvmgt_guest_info *info; + int ret; if (!handle_valid(vgpu->handle)) return; - vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY, + if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1)) + return; + + ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY, &vgpu->vdev.iommu_notifier); - vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY, + WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret); + + ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_GROUP_NOTIFY, &vgpu->vdev.group_notifier); + WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret); info = (struct kvmgt_guest_info *)vgpu->handle; kvmgt_guest_exit(info); + + vgpu->vdev.kvm = NULL; vgpu->handle = 0; } @@ -534,6 +561,7 @@ static void intel_vgpu_release_work(struct work_struct *work) { struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu, vdev.release_work); + __intel_vgpu_release(vgpu); } @@ -1089,7 +1117,7 @@ static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, return 0; } -static const struct parent_ops intel_vgpu_ops = { +static const struct mdev_parent_ops intel_vgpu_ops = { .supported_type_groups = intel_vgpu_type_groups, .create = intel_vgpu_create, .remove = intel_vgpu_remove, @@ -1134,6 +1162,10 @@ static int kvmgt_write_protect_add(unsigned long handle, u64 gfn) idx = srcu_read_lock(&kvm->srcu); slot = gfn_to_memslot(kvm, gfn); + if (!slot) { + srcu_read_unlock(&kvm->srcu, idx); + return -EINVAL; + } spin_lock(&kvm->mmu_lock); @@ -1164,6 +1196,10 @@ static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn) idx = srcu_read_lock(&kvm->srcu); slot = gfn_to_memslot(kvm, gfn); + if (!slot) { + srcu_read_unlock(&kvm->srcu, idx); + return -EINVAL; + } spin_lock(&kvm->mmu_lock); @@ -1311,18 +1347,14 @@ static int kvmgt_guest_init(struct mdev_device *mdev) static bool kvmgt_guest_exit(struct kvmgt_guest_info *info) { - struct intel_vgpu *vgpu; - if (!info) { gvt_err("kvmgt_guest_info invalid\n"); return false; } - vgpu = info->vgpu; - kvm_page_track_unregister_notifier(info->kvm, &info->track_node); kvmgt_protect_table_destroy(info); - gvt_cache_destroy(vgpu); + gvt_cache_destroy(info->vgpu); vfree(info); return true; @@ -1372,7 +1404,7 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) return pfn; pfn = INTEL_GVT_INVALID_ADDR; - dev = &info->vgpu->vdev.mdev->dev; + dev = mdev_dev(info->vgpu->vdev.mdev); rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn); if (rc != 1) { gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc); diff --git a/drivers/gpu/drm/i915/gvt/mmio.c b/drivers/gpu/drm/i915/gvt/mmio.c index 09c9450a1946..4df078bc5d04 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.c +++ b/drivers/gpu/drm/i915/gvt/mmio.c @@ -125,25 +125,12 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, if (WARN_ON(!reg_is_mmio(gvt, offset + bytes - 1))) goto err; - mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4)); - if (!mmio && !vgpu->mmio.disable_warn_untrack) { - gvt_err("vgpu%d: read untracked MMIO %x len %d val %x\n", - vgpu->id, offset, bytes, *(u32 *)p_data); - - if (offset == 0x206c) { - gvt_err("------------------------------------------\n"); - gvt_err("vgpu%d: likely triggers a gfx reset\n", - vgpu->id); - gvt_err("------------------------------------------\n"); - vgpu->mmio.disable_warn_untrack = true; - } - } - if (!intel_gvt_mmio_is_unalign(gvt, offset)) { if (WARN_ON(!IS_ALIGNED(offset, bytes))) goto err; } + mmio = intel_gvt_find_mmio_info(gvt, rounddown(offset, 4)); if (mmio) { if (!intel_gvt_mmio_is_unalign(gvt, mmio->offset)) { if (WARN_ON(offset + bytes > mmio->offset + mmio->size)) @@ -152,9 +139,23 @@ int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, uint64_t pa, goto err; } ret = mmio->read(vgpu, offset, p_data, bytes); - } else + } else { ret = intel_vgpu_default_mmio_read(vgpu, offset, p_data, bytes); + if (!vgpu->mmio.disable_warn_untrack) { + gvt_err("vgpu%d: read untracked MMIO %x(%dB) val %x\n", + vgpu->id, offset, bytes, *(u32 *)p_data); + + if (offset == 0x206c) { + gvt_err("------------------------------------------\n"); + gvt_err("vgpu%d: likely triggers a gfx reset\n", + vgpu->id); + gvt_err("------------------------------------------\n"); + vgpu->mmio.disable_warn_untrack = true; + } + } + } + if (ret) goto err; @@ -302,3 +303,56 @@ err: mutex_unlock(&gvt->lock); return ret; } + + +/** + * intel_vgpu_reset_mmio - reset virtual MMIO space + * @vgpu: a vGPU + * + */ +void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu) +{ + struct intel_gvt *gvt = vgpu->gvt; + const struct intel_gvt_device_info *info = &gvt->device_info; + + memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size); + memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size); + + vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; + + /* set the bit 0:2(Core C-State ) to C0 */ + vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0; +} + +/** + * intel_vgpu_init_mmio - init MMIO space + * @vgpu: a vGPU + * + * Returns: + * Zero on success, negative error code if failed + */ +int intel_vgpu_init_mmio(struct intel_vgpu *vgpu) +{ + const struct intel_gvt_device_info *info = &vgpu->gvt->device_info; + + vgpu->mmio.vreg = vzalloc(info->mmio_size * 2); + if (!vgpu->mmio.vreg) + return -ENOMEM; + + vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size; + + intel_vgpu_reset_mmio(vgpu); + + return 0; +} + +/** + * intel_vgpu_clean_mmio - clean MMIO space + * @vgpu: a vGPU + * + */ +void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu) +{ + vfree(vgpu->mmio.vreg); + vgpu->mmio.vreg = vgpu->mmio.sreg = NULL; +} diff --git a/drivers/gpu/drm/i915/gvt/mmio.h b/drivers/gpu/drm/i915/gvt/mmio.h index 87d5b5e366a3..3bc620f56f35 100644 --- a/drivers/gpu/drm/i915/gvt/mmio.h +++ b/drivers/gpu/drm/i915/gvt/mmio.h @@ -86,6 +86,10 @@ struct intel_gvt_mmio_info *intel_gvt_find_mmio_info(struct intel_gvt *gvt, *offset; \ }) +int intel_vgpu_init_mmio(struct intel_vgpu *vgpu); +void intel_vgpu_reset_mmio(struct intel_vgpu *vgpu); +void intel_vgpu_clean_mmio(struct intel_vgpu *vgpu); + int intel_vgpu_gpa_to_mmio_offset(struct intel_vgpu *vgpu, u64 gpa); int intel_vgpu_emulate_mmio_read(struct intel_vgpu *vgpu, u64 pa, diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c index d2a0fbc896c3..d9fb41ab7119 100644 --- a/drivers/gpu/drm/i915/gvt/opregion.c +++ b/drivers/gpu/drm/i915/gvt/opregion.c @@ -36,9 +36,9 @@ static int init_vgpu_opregion(struct intel_vgpu *vgpu, u32 gpa) vgpu->id)) return -EINVAL; - vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_ATOMIC | - GFP_DMA32 | __GFP_ZERO, - INTEL_GVT_OPREGION_PORDER); + vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL | + __GFP_ZERO, + get_order(INTEL_GVT_OPREGION_SIZE)); if (!vgpu_opregion(vgpu)->va) return -ENOMEM; @@ -65,7 +65,7 @@ static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map) int i, ret; for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++) { - mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu) + mfn = intel_gvt_hypervisor_virt_to_mfn(vgpu_opregion(vgpu)->va + i * PAGE_SIZE); if (mfn == INTEL_GVT_INVALID_ADDR) { gvt_err("fail to get MFN from VA\n"); @@ -97,7 +97,7 @@ void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu) if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) { map_vgpu_opregion(vgpu, false); free_pages((unsigned long)vgpu_opregion(vgpu)->va, - INTEL_GVT_OPREGION_PORDER); + get_order(INTEL_GVT_OPREGION_SIZE)); vgpu_opregion(vgpu)->va = NULL; } diff --git a/drivers/gpu/drm/i915/gvt/reg.h b/drivers/gpu/drm/i915/gvt/reg.h index 0dfe789d8f02..fbd023a16f18 100644 --- a/drivers/gpu/drm/i915/gvt/reg.h +++ b/drivers/gpu/drm/i915/gvt/reg.h @@ -50,8 +50,7 @@ #define INTEL_GVT_OPREGION_PARM 0x204 #define INTEL_GVT_OPREGION_PAGES 2 -#define INTEL_GVT_OPREGION_PORDER 1 -#define INTEL_GVT_OPREGION_SIZE (2 * 4096) +#define INTEL_GVT_OPREGION_SIZE (INTEL_GVT_OPREGION_PAGES * PAGE_SIZE) #define VGT_SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _PLANE_STRIDE_2_B) diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index 4db242250235..e91885dffeff 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -350,13 +350,15 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) { struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; struct intel_vgpu_workload *workload; + struct intel_vgpu *vgpu; int event; mutex_lock(&gvt->lock); workload = scheduler->current_workload[ring_id]; + vgpu = workload->vgpu; - if (!workload->status && !workload->vgpu->resetting) { + if (!workload->status && !vgpu->resetting) { wait_event(workload->shadow_ctx_status_wq, !atomic_read(&workload->shadow_ctx_active)); @@ -364,8 +366,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) for_each_set_bit(event, workload->pending_events, INTEL_GVT_EVENT_MAX) - intel_vgpu_trigger_virtual_event(workload->vgpu, - event); + intel_vgpu_trigger_virtual_event(vgpu, event); } gvt_dbg_sched("ring id %d complete workload %p status %d\n", @@ -373,11 +374,10 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) scheduler->current_workload[ring_id] = NULL; - atomic_dec(&workload->vgpu->running_workload_num); - list_del_init(&workload->list); workload->complete(workload); + atomic_dec(&vgpu->running_workload_num); wake_up(&scheduler->workload_complete_wq); mutex_unlock(&gvt->lock); } @@ -459,11 +459,11 @@ complete: gvt_dbg_sched("will complete workload %p\n, status: %d\n", workload, workload->status); - complete_current_workload(gvt, ring_id); - if (workload->req) i915_gem_request_put(fetch_and_zero(&workload->req)); + complete_current_workload(gvt, ring_id); + if (need_force_wake) intel_uncore_forcewake_put(gvt->dev_priv, FORCEWAKE_ALL); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h index 3b30c28bff51..2833dfa8c9ae 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.h +++ b/drivers/gpu/drm/i915/gvt/scheduler.h @@ -113,7 +113,7 @@ struct intel_shadow_bb_entry { struct drm_i915_gem_object *obj; void *va; unsigned long len; - void *bb_start_cmd_va; + u32 *bb_start_cmd_va; }; #define workload_q_head(vgpu, ring_id) \ diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c index 536d2b9d5777..7295bc8e12fb 100644 --- a/drivers/gpu/drm/i915/gvt/vgpu.c +++ b/drivers/gpu/drm/i915/gvt/vgpu.c @@ -35,79 +35,6 @@ #include "gvt.h" #include "i915_pvinfo.h" -static void clean_vgpu_mmio(struct intel_vgpu *vgpu) -{ - vfree(vgpu->mmio.vreg); - vgpu->mmio.vreg = vgpu->mmio.sreg = NULL; -} - -int setup_vgpu_mmio(struct intel_vgpu *vgpu) -{ - struct intel_gvt *gvt = vgpu->gvt; - const struct intel_gvt_device_info *info = &gvt->device_info; - - if (vgpu->mmio.vreg) - memset(vgpu->mmio.vreg, 0, info->mmio_size * 2); - else { - vgpu->mmio.vreg = vzalloc(info->mmio_size * 2); - if (!vgpu->mmio.vreg) - return -ENOMEM; - } - - vgpu->mmio.sreg = vgpu->mmio.vreg + info->mmio_size; - - memcpy(vgpu->mmio.vreg, gvt->firmware.mmio, info->mmio_size); - memcpy(vgpu->mmio.sreg, gvt->firmware.mmio, info->mmio_size); - - vgpu_vreg(vgpu, GEN6_GT_THREAD_STATUS_REG) = 0; - - /* set the bit 0:2(Core C-State ) to C0 */ - vgpu_vreg(vgpu, GEN6_GT_CORE_STATUS) = 0; - return 0; -} - -static void setup_vgpu_cfg_space(struct intel_vgpu *vgpu, - struct intel_vgpu_creation_params *param) -{ - struct intel_gvt *gvt = vgpu->gvt; - const struct intel_gvt_device_info *info = &gvt->device_info; - u16 *gmch_ctl; - int i; - - memcpy(vgpu_cfg_space(vgpu), gvt->firmware.cfg_space, - info->cfg_space_size); - - if (!param->primary) { - vgpu_cfg_space(vgpu)[PCI_CLASS_DEVICE] = - INTEL_GVT_PCI_CLASS_VGA_OTHER; - vgpu_cfg_space(vgpu)[PCI_CLASS_PROG] = - INTEL_GVT_PCI_CLASS_VGA_OTHER; - } - - /* Show guest that there isn't any stolen memory.*/ - gmch_ctl = (u16 *)(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_GMCH_CONTROL); - *gmch_ctl &= ~(BDW_GMCH_GMS_MASK << BDW_GMCH_GMS_SHIFT); - - intel_vgpu_write_pci_bar(vgpu, PCI_BASE_ADDRESS_2, - gvt_aperture_pa_base(gvt), true); - - vgpu_cfg_space(vgpu)[PCI_COMMAND] &= ~(PCI_COMMAND_IO - | PCI_COMMAND_MEMORY - | PCI_COMMAND_MASTER); - /* - * Clear the bar upper 32bit and let guest to assign the new value - */ - memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_1, 0, 4); - memset(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_3, 0, 4); - memset(vgpu_cfg_space(vgpu) + INTEL_GVT_PCI_OPREGION, 0, 4); - - for (i = 0; i < INTEL_GVT_MAX_BAR_NUM; i++) { - vgpu->cfg_space.bar[i].size = pci_resource_len( - gvt->dev_priv->drm.pdev, i * 2); - vgpu->cfg_space.bar[i].tracked = false; - } -} - void populate_pvinfo_page(struct intel_vgpu *vgpu) { /* setup the ballooning information */ @@ -177,7 +104,7 @@ int intel_gvt_init_vgpu_types(struct intel_gvt *gvt) if (low_avail / min_low == 0) break; gvt->types[i].low_gm_size = min_low; - gvt->types[i].high_gm_size = 3 * gvt->types[i].low_gm_size; + gvt->types[i].high_gm_size = max((min_low<<3), MB_TO_BYTES(384U)); gvt->types[i].fence = 4; gvt->types[i].max_instance = low_avail / min_low; gvt->types[i].avail_instance = gvt->types[i].max_instance; @@ -217,7 +144,7 @@ static void intel_gvt_update_vgpu_types(struct intel_gvt *gvt) */ low_gm_avail = MB_TO_BYTES(256) - HOST_LOW_GM_SIZE - gvt->gm.vgpu_allocated_low_gm_size; - high_gm_avail = MB_TO_BYTES(256) * 3 - HOST_HIGH_GM_SIZE - + high_gm_avail = MB_TO_BYTES(256) * 8UL - HOST_HIGH_GM_SIZE - gvt->gm.vgpu_allocated_high_gm_size; fence_avail = gvt_fence_sz(gvt) - HOST_FENCE - gvt->fence.vgpu_allocated_fence_num; @@ -268,7 +195,7 @@ void intel_gvt_destroy_vgpu(struct intel_vgpu *vgpu) intel_vgpu_clean_gtt(vgpu); intel_gvt_hypervisor_detach_vgpu(vgpu); intel_vgpu_free_resource(vgpu); - clean_vgpu_mmio(vgpu); + intel_vgpu_clean_mmio(vgpu); vfree(vgpu); intel_gvt_update_vgpu_types(gvt); @@ -300,11 +227,11 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt, vgpu->gvt = gvt; bitmap_zero(vgpu->tlb_handle_pending, I915_NUM_ENGINES); - setup_vgpu_cfg_space(vgpu, param); + intel_vgpu_init_cfg_space(vgpu, param->primary); - ret = setup_vgpu_mmio(vgpu); + ret = intel_vgpu_init_mmio(vgpu); if (ret) - goto out_free_vgpu; + goto out_clean_idr; ret = intel_vgpu_alloc_resource(vgpu, param); if (ret) @@ -354,7 +281,9 @@ out_detach_hypervisor_vgpu: out_clean_vgpu_resource: intel_vgpu_free_resource(vgpu); out_clean_vgpu_mmio: - clean_vgpu_mmio(vgpu); + intel_vgpu_clean_mmio(vgpu); +out_clean_idr: + idr_remove(&gvt->vgpu_idr, vgpu->id); out_free_vgpu: vfree(vgpu); mutex_unlock(&gvt->lock); @@ -398,7 +327,75 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, } /** - * intel_gvt_reset_vgpu - reset a virtual GPU + * intel_gvt_reset_vgpu_locked - reset a virtual GPU by DMLR or GT reset + * @vgpu: virtual GPU + * @dmlr: vGPU Device Model Level Reset or GT Reset + * @engine_mask: engines to reset for GT reset + * + * This function is called when user wants to reset a virtual GPU through + * device model reset or GT reset. The caller should hold the gvt lock. + * + * vGPU Device Model Level Reset (DMLR) simulates the PCI level reset to reset + * the whole vGPU to default state as when it is created. This vGPU function + * is required both for functionary and security concerns.The ultimate goal + * of vGPU FLR is that reuse a vGPU instance by virtual machines. When we + * assign a vGPU to a virtual machine we must isse such reset first. + * + * Full GT Reset and Per-Engine GT Reset are soft reset flow for GPU engines + * (Render, Blitter, Video, Video Enhancement). It is defined by GPU Spec. + * Unlike the FLR, GT reset only reset particular resource of a vGPU per + * the reset request. Guest driver can issue a GT reset by programming the + * virtual GDRST register to reset specific virtual GPU engine or all + * engines. + * + * The parameter dev_level is to identify if we will do DMLR or GT reset. + * The parameter engine_mask is to specific the engines that need to be + * resetted. If value ALL_ENGINES is given for engine_mask, it means + * the caller requests a full GT reset that we will reset all virtual + * GPU engines. For FLR, engine_mask is ignored. + */ +void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr, + unsigned int engine_mask) +{ + struct intel_gvt *gvt = vgpu->gvt; + struct intel_gvt_workload_scheduler *scheduler = &gvt->scheduler; + + gvt_dbg_core("------------------------------------------\n"); + gvt_dbg_core("resseting vgpu%d, dmlr %d, engine_mask %08x\n", + vgpu->id, dmlr, engine_mask); + vgpu->resetting = true; + + intel_vgpu_stop_schedule(vgpu); + /* + * The current_vgpu will set to NULL after stopping the + * scheduler when the reset is triggered by current vgpu. + */ + if (scheduler->current_vgpu == NULL) { + mutex_unlock(&gvt->lock); + intel_gvt_wait_vgpu_idle(vgpu); + mutex_lock(&gvt->lock); + } + + intel_vgpu_reset_execlist(vgpu, dmlr ? ALL_ENGINES : engine_mask); + + /* full GPU reset or device model level reset */ + if (engine_mask == ALL_ENGINES || dmlr) { + intel_vgpu_reset_gtt(vgpu, dmlr); + intel_vgpu_reset_resource(vgpu); + intel_vgpu_reset_mmio(vgpu); + populate_pvinfo_page(vgpu); + + if (dmlr) + intel_vgpu_reset_cfg_space(vgpu); + } + + vgpu->resetting = false; + gvt_dbg_core("reset vgpu%d done\n", vgpu->id); + gvt_dbg_core("------------------------------------------\n"); +} + +/** + * intel_gvt_reset_vgpu - reset a virtual GPU (Function Level) * @vgpu: virtual GPU * * This function is called when user wants to reset a virtual GPU. @@ -406,4 +403,7 @@ struct intel_vgpu *intel_gvt_create_vgpu(struct intel_gvt *gvt, */ void intel_gvt_reset_vgpu(struct intel_vgpu *vgpu) { + mutex_lock(&vgpu->gvt->lock); + intel_gvt_reset_vgpu_locked(vgpu, true, 0); + mutex_unlock(&vgpu->gvt->lock); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 445fec9c2841..728ca3ea74d2 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -213,7 +213,8 @@ static void intel_detect_pch(struct drm_device *dev) } else if (id == INTEL_PCH_KBP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_KBP; DRM_DEBUG_KMS("Found KabyPoint PCH\n"); - WARN_ON(!IS_KABYLAKE(dev_priv)); + WARN_ON(!IS_SKYLAKE(dev_priv) && + !IS_KABYLAKE(dev_priv)); } else if ((id == INTEL_PCH_P2X_DEVICE_ID_TYPE) || (id == INTEL_PCH_P3X_DEVICE_ID_TYPE) || ((id == INTEL_PCH_QEMU_DEVICE_ID_TYPE) && @@ -2378,7 +2379,7 @@ static int intel_runtime_suspend(struct device *kdev) assert_forcewakes_inactive(dev_priv); - if (!IS_VALLEYVIEW(dev_priv) || !IS_CHERRYVIEW(dev_priv)) + if (!IS_VALLEYVIEW(dev_priv) && !IS_CHERRYVIEW(dev_priv)) intel_hpd_poll_init(dev_priv); DRM_DEBUG_KMS("Device suspended\n"); @@ -2427,6 +2428,7 @@ static int intel_runtime_resume(struct device *kdev) * we can do is to hope that things will still work (and disable RPM). */ i915_gem_init_swizzling(dev_priv); + i915_gem_restore_fences(dev_priv); intel_runtime_pm_enable_interrupts(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 243224aeabf8..8493e19b563a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1012,6 +1012,8 @@ struct intel_fbc { struct work_struct underrun_work; struct intel_fbc_state_cache { + struct i915_vma *vma; + struct { unsigned int mode_flags; uint32_t hsw_bdw_pixel_rate; @@ -1025,15 +1027,14 @@ struct intel_fbc { } plane; struct { - u64 ilk_ggtt_offset; uint32_t pixel_format; unsigned int stride; - int fence_reg; - unsigned int tiling_mode; } fb; } state_cache; struct intel_fbc_reg_params { + struct i915_vma *vma; + struct { enum pipe pipe; enum plane plane; @@ -1041,10 +1042,8 @@ struct intel_fbc { } crtc; struct { - u64 ggtt_offset; uint32_t pixel_format; unsigned int stride; - int fence_reg; } fb; int cfb_size; @@ -1977,6 +1976,11 @@ struct drm_i915_private { struct i915_frontbuffer_tracking fb_tracking; + struct intel_atomic_helper { + struct llist_head free_list; + struct work_struct free_work; + } atomic_helper; + u16 orig_clock; bool mchbar_need_disable; @@ -3163,13 +3167,6 @@ i915_gem_object_to_ggtt(struct drm_i915_gem_object *obj, return i915_gem_obj_to_vma(obj, &to_i915(obj->base.dev)->ggtt.base, view); } -static inline unsigned long -i915_gem_object_ggtt_offset(struct drm_i915_gem_object *o, - const struct i915_ggtt_view *view) -{ - return i915_ggtt_offset(i915_gem_object_to_ggtt(o, view)); -} - /* i915_gem_fence_reg.c */ int __must_check i915_vma_get_fence(struct i915_vma *vma); int __must_check i915_vma_put_fence(struct i915_vma *vma); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4a31b7a891ec..24b5b046754b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -244,14 +244,16 @@ err_phys: static void __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, - struct sg_table *pages) + struct sg_table *pages, + bool needs_clflush) { GEM_BUG_ON(obj->mm.madv == __I915_MADV_PURGED); if (obj->mm.madv == I915_MADV_DONTNEED) obj->mm.dirty = false; - if ((obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0 && + if (needs_clflush && + (obj->base.read_domains & I915_GEM_DOMAIN_CPU) == 0 && !cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) drm_clflush_sg(pages); @@ -263,7 +265,7 @@ static void i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, struct sg_table *pages) { - __i915_gem_object_release_shmem(obj, pages); + __i915_gem_object_release_shmem(obj, pages, false); if (obj->mm.dirty) { struct address_space *mapping = obj->base.filp->f_mapping; @@ -593,47 +595,21 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, struct drm_i915_gem_pwrite *args, struct drm_file *file) { - struct drm_device *dev = obj->base.dev; void *vaddr = obj->phys_handle->vaddr + args->offset; char __user *user_data = u64_to_user_ptr(args->data_ptr); - int ret; /* We manually control the domain here and pretend that it * remains coherent i.e. in the GTT domain, like shmem_pwrite. */ - lockdep_assert_held(&obj->base.dev->struct_mutex); - ret = i915_gem_object_wait(obj, - I915_WAIT_INTERRUPTIBLE | - I915_WAIT_LOCKED | - I915_WAIT_ALL, - MAX_SCHEDULE_TIMEOUT, - to_rps_client(file)); - if (ret) - return ret; - intel_fb_obj_invalidate(obj, ORIGIN_CPU); - if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { - unsigned long unwritten; - - /* The physical object once assigned is fixed for the lifetime - * of the obj, so we can safely drop the lock and continue - * to access vaddr. - */ - mutex_unlock(&dev->struct_mutex); - unwritten = copy_from_user(vaddr, user_data, args->size); - mutex_lock(&dev->struct_mutex); - if (unwritten) { - ret = -EFAULT; - goto out; - } - } + if (copy_from_user(vaddr, user_data, args->size)) + return -EFAULT; drm_clflush_virt_range(vaddr, args->size); - i915_gem_chipset_flush(to_i915(dev)); + i915_gem_chipset_flush(to_i915(obj->base.dev)); -out: intel_fb_obj_flush(obj, false, ORIGIN_CPU); - return ret; + return 0; } void *i915_gem_object_alloc(struct drm_device *dev) @@ -2034,8 +2010,16 @@ void i915_gem_runtime_suspend(struct drm_i915_private *dev_priv) for (i = 0; i < dev_priv->num_fence_regs; i++) { struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - if (WARN_ON(reg->pin_count)) - continue; + /* Ideally we want to assert that the fence register is not + * live at this point (i.e. that no piece of code will be + * trying to write through fence + GTT, as that both violates + * our tracking of activity and associated locking/barriers, + * but also is illegal given that the hw is powered down). + * + * Previously we used reg->pin_count as a "liveness" indicator. + * That is not sufficient, and we need a more fine-grained + * tool if we want to have a sanity check here. + */ if (!reg->vma) continue; @@ -2231,7 +2215,7 @@ i915_gem_object_put_pages_gtt(struct drm_i915_gem_object *obj, struct sgt_iter sgt_iter; struct page *page; - __i915_gem_object_release_shmem(obj, pages); + __i915_gem_object_release_shmem(obj, pages, true); i915_gem_gtt_finish_pages(obj, pages); @@ -2304,15 +2288,6 @@ unlock: mutex_unlock(&obj->mm.lock); } -static unsigned int swiotlb_max_size(void) -{ -#if IS_ENABLED(CONFIG_SWIOTLB) - return rounddown(swiotlb_nr_tbl() << IO_TLB_SHIFT, PAGE_SIZE); -#else - return 0; -#endif -} - static void i915_sg_trim(struct sg_table *orig_st) { struct sg_table new_st; @@ -2322,7 +2297,7 @@ static void i915_sg_trim(struct sg_table *orig_st) if (orig_st->nents == orig_st->orig_nents) return; - if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL)) + if (sg_alloc_table(&new_st, orig_st->nents, GFP_KERNEL | __GFP_NOWARN)) return; new_sg = new_st.sgl; @@ -2360,7 +2335,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) GEM_BUG_ON(obj->base.read_domains & I915_GEM_GPU_DOMAINS); GEM_BUG_ON(obj->base.write_domain & I915_GEM_GPU_DOMAINS); - max_segment = swiotlb_max_size(); + max_segment = swiotlb_max_segment(); if (!max_segment) max_segment = rounddown(UINT_MAX, PAGE_SIZE); @@ -2728,6 +2703,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine) struct drm_i915_gem_request *request; struct i915_gem_context *incomplete_ctx; struct intel_timeline *timeline; + unsigned long flags; bool ring_hung; if (engine->irq_seqno_barrier) @@ -2763,13 +2739,20 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine) if (i915_gem_context_is_default(incomplete_ctx)) return; + timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine); + + spin_lock_irqsave(&engine->timeline->lock, flags); + spin_lock(&timeline->lock); + list_for_each_entry_continue(request, &engine->timeline->requests, link) if (request->ctx == incomplete_ctx) reset_request(request); - timeline = i915_gem_context_lookup_timeline(incomplete_ctx, engine); list_for_each_entry(request, &timeline->requests, link) reset_request(request); + + spin_unlock(&timeline->lock); + spin_unlock_irqrestore(&engine->timeline->lock, flags); } void i915_gem_reset(struct drm_i915_private *dev_priv) @@ -3503,7 +3486,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, vma->display_alignment = max_t(u64, vma->display_alignment, alignment); /* Treat this as an end-of-frame, like intel_user_framebuffer_dirty() */ - if (obj->cache_dirty) { + if (obj->cache_dirty || obj->base.write_domain == I915_GEM_DOMAIN_CPU) { i915_gem_clflush_object(obj, true); intel_fb_obj_flush(obj, false, ORIGIN_DIRTYFB); } diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c index bd08814b015c..d534a316a16e 100644 --- a/drivers/gpu/drm/i915/i915_gem_evict.c +++ b/drivers/gpu/drm/i915/i915_gem_evict.c @@ -199,6 +199,7 @@ found: } /* Unbinding will emit any required flushes */ + ret = 0; while (!list_empty(&eviction_list)) { vma = list_first_entry(&eviction_list, struct i915_vma, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 097d9d8c2315..b8b877c91b0a 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1181,14 +1181,14 @@ validate_exec_list(struct drm_device *dev, if (exec[i].offset != gen8_canonical_addr(exec[i].offset & PAGE_MASK)) return -EINVAL; - - /* From drm_mm perspective address space is continuous, - * so from this point we're always using non-canonical - * form internally. - */ - exec[i].offset = gen8_noncanonical_addr(exec[i].offset); } + /* From drm_mm perspective address space is continuous, + * so from this point we're always using non-canonical + * form internally. + */ + exec[i].offset = gen8_noncanonical_addr(exec[i].offset); + if (exec[i].alignment && !is_power_of_2(exec[i].alignment)) return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_gem_internal.c b/drivers/gpu/drm/i915/i915_gem_internal.c index 4b3ff3e5b911..d09c74973cb3 100644 --- a/drivers/gpu/drm/i915/i915_gem_internal.c +++ b/drivers/gpu/drm/i915/i915_gem_internal.c @@ -66,8 +66,16 @@ i915_gem_object_get_pages_internal(struct drm_i915_gem_object *obj) max_order = MAX_ORDER; #ifdef CONFIG_SWIOTLB - if (swiotlb_nr_tbl()) /* minimum max swiotlb size is IO_TLB_SEGSIZE */ - max_order = min(max_order, ilog2(IO_TLB_SEGPAGES)); + if (swiotlb_nr_tbl()) { + unsigned int max_segment; + + max_segment = swiotlb_max_segment(); + if (max_segment) { + max_segment = max_t(unsigned int, max_segment, + PAGE_SIZE) >> PAGE_SHIFT; + max_order = min(max_order, ilog2(max_segment)); + } + } #endif gfp = GFP_KERNEL | __GFP_HIGHMEM | __GFP_RECLAIMABLE; diff --git a/drivers/gpu/drm/i915/i915_gem_object.h b/drivers/gpu/drm/i915/i915_gem_object.h index 6a368de9d81e..ecfefb9d42e4 100644 --- a/drivers/gpu/drm/i915/i915_gem_object.h +++ b/drivers/gpu/drm/i915/i915_gem_object.h @@ -256,7 +256,7 @@ extern void drm_gem_object_unreference_unlocked(struct drm_gem_object *); static inline bool i915_gem_object_is_dead(const struct drm_i915_gem_object *obj) { - return atomic_read(&obj->base.refcount.refcount) == 0; + return kref_read(&obj->base.refcount) == 0; } static inline bool diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h index e2b077df2da0..d229f47d1028 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.h +++ b/drivers/gpu/drm/i915/i915_gem_request.h @@ -413,6 +413,25 @@ i915_gem_active_set(struct i915_gem_active *active, rcu_assign_pointer(active->request, request); } +/** + * i915_gem_active_set_retire_fn - updates the retirement callback + * @active - the active tracker + * @fn - the routine called when the request is retired + * @mutex - struct_mutex used to guard retirements + * + * i915_gem_active_set_retire_fn() updates the function pointer that + * is called when the final request associated with the @active tracker + * is retired. + */ +static inline void +i915_gem_active_set_retire_fn(struct i915_gem_active *active, + i915_gem_retire_fn fn, + struct mutex *mutex) +{ + lockdep_assert_held(mutex); + active->retire = fn ?: i915_gem_retire_noop; +} + static inline struct drm_i915_gem_request * __i915_gem_active_peek(const struct i915_gem_active *active) { diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index a792dcb902b5..e924a9516079 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -185,6 +185,7 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, return ret; } + trace_i915_vma_bind(vma, bind_flags); ret = vma->vm->bind_vma(vma, cache_level, bind_flags); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index dbe9fb41ae53..8d3e515f27ba 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -85,6 +85,8 @@ intel_plane_duplicate_state(struct drm_plane *plane) __drm_atomic_helper_plane_duplicate_state(plane, state); + intel_state->vma = NULL; + return state; } @@ -100,6 +102,24 @@ void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { + struct i915_vma *vma; + + vma = fetch_and_zero(&to_intel_plane_state(state)->vma); + + /* + * FIXME: Normally intel_cleanup_plane_fb handles destruction of vma. + * We currently don't clear all planes during driver unload, so we have + * to be able to unpin vma here for now. + * + * Normally this can only happen during unload when kmscon is disabled + * and userspace doesn't attempt to set a framebuffer at all. + */ + if (vma) { + mutex_lock(&plane->dev->struct_mutex); + intel_unpin_fb_vma(vma); + mutex_unlock(&plane->dev->struct_mutex); + } + drm_atomic_helper_plane_destroy_state(plane, state); } diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 86ecec5601d4..588470eb8d39 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -499,6 +499,7 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) struct drm_i915_private *dev_priv = to_i915(crt->base.base.dev); struct edid *edid; struct i2c_adapter *i2c; + bool ret = false; BUG_ON(crt->base.type != INTEL_OUTPUT_ANALOG); @@ -515,17 +516,17 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) */ if (!is_digital) { DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n"); - return true; + ret = true; + } else { + DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); } - - DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [EDID reports a digital panel]\n"); } else { DRM_DEBUG_KMS("CRT not detected via DDC:0x50 [no valid EDID found]\n"); } kfree(edid); - return false; + return ret; } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6daad8613760..891c86aef99d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2235,24 +2235,22 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation) i915_vma_pin_fence(vma); } + i915_vma_get(vma); err: intel_runtime_pm_put(dev_priv); return vma; } -void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation) +void intel_unpin_fb_vma(struct i915_vma *vma) { - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct i915_ggtt_view view; - struct i915_vma *vma; - - WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); + lockdep_assert_held(&vma->vm->dev->struct_mutex); - intel_fill_fb_ggtt_view(&view, fb, rotation); - vma = i915_gem_object_to_ggtt(obj, &view); + if (WARN_ON_ONCE(!vma)) + return; i915_vma_unpin_fence(vma); i915_gem_object_unpin_from_display_plane(vma); + i915_vma_put(vma); } static int intel_fb_pitch(const struct drm_framebuffer *fb, int plane, @@ -2585,8 +2583,9 @@ intel_fill_fb_info(struct drm_i915_private *dev_priv, * We only keep the x/y offsets, so push all of the * gtt offset into the x/y offsets. */ - _intel_adjust_tile_offset(&x, &y, tile_size, - tile_width, tile_height, pitch_tiles, + _intel_adjust_tile_offset(&x, &y, + tile_width, tile_height, + tile_size, pitch_tiles, gtt_offset_rotated * tile_size, 0); gtt_offset_rotated += rot_info->plane[i].width * rot_info->plane[i].height; @@ -2746,7 +2745,6 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *c; - struct intel_crtc *i; struct drm_i915_gem_object *obj; struct drm_plane *primary = intel_crtc->base.primary; struct drm_plane_state *plane_state = primary->state; @@ -2771,20 +2769,20 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, * an fb with another CRTC instead */ for_each_crtc(dev, c) { - i = to_intel_crtc(c); + struct intel_plane_state *state; if (c == &intel_crtc->base) continue; - if (!i->active) + if (!to_intel_crtc(c)->active) continue; - fb = c->primary->fb; - if (!fb) + state = to_intel_plane_state(c->primary->state); + if (!state->vma) continue; - obj = intel_fb_obj(fb); - if (i915_gem_object_ggtt_offset(obj, NULL) == plane_config->base) { + if (intel_plane_ggtt_offset(state) == plane_config->base) { + fb = c->primary->fb; drm_framebuffer_reference(fb); goto valid_fb; } @@ -2805,6 +2803,19 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: + mutex_lock(&dev->struct_mutex); + intel_state->vma = + intel_pin_and_fence_fb_obj(fb, primary->state->rotation); + mutex_unlock(&dev->struct_mutex); + if (IS_ERR(intel_state->vma)) { + DRM_ERROR("failed to pin boot fb on pipe %d: %li\n", + intel_crtc->pipe, PTR_ERR(intel_state->vma)); + + intel_state->vma = NULL; + drm_framebuffer_unreference(fb); + return; + } + plane_state->src_x = 0; plane_state->src_y = 0; plane_state->src_w = fb->width << 16; @@ -2967,6 +2978,9 @@ int skl_check_plane_surface(struct intel_plane_state *plane_state) unsigned int rotation = plane_state->base.rotation; int ret; + if (!plane_state->base.visible) + return 0; + /* Rotate src coordinates to match rotated GTT view */ if (drm_rotation_90_or_270(rotation)) drm_rect_rotate(&plane_state->base.src, @@ -3097,13 +3111,13 @@ static void i9xx_update_primary_plane(struct drm_plane *primary, I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); if (INTEL_GEN(dev_priv) >= 4) { I915_WRITE(DSPSURF(plane), - intel_fb_gtt_offset(fb, rotation) + + intel_plane_ggtt_offset(plane_state) + intel_crtc->dspaddr_offset); I915_WRITE(DSPTILEOFF(plane), (y << 16) | x); I915_WRITE(DSPLINOFF(plane), linear_offset); } else { I915_WRITE(DSPADDR(plane), - intel_fb_gtt_offset(fb, rotation) + + intel_plane_ggtt_offset(plane_state) + intel_crtc->dspaddr_offset); } POSTING_READ(reg); @@ -3200,7 +3214,7 @@ static void ironlake_update_primary_plane(struct drm_plane *primary, I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]); I915_WRITE(DSPSURF(plane), - intel_fb_gtt_offset(fb, rotation) + + intel_plane_ggtt_offset(plane_state) + intel_crtc->dspaddr_offset); if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) { I915_WRITE(DSPOFFSET(plane), (y << 16) | x); @@ -3223,23 +3237,6 @@ u32 intel_fb_stride_alignment(const struct drm_i915_private *dev_priv, } } -u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, - unsigned int rotation) -{ - struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct i915_ggtt_view view; - struct i915_vma *vma; - - intel_fill_fb_ggtt_view(&view, fb, rotation); - - vma = i915_gem_object_to_ggtt(obj, &view); - if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n", - view.type)) - return -1; - - return i915_ggtt_offset(vma); -} - static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) { struct drm_device *dev = intel_crtc->base.dev; @@ -3434,7 +3431,7 @@ static void skylake_update_primary_plane(struct drm_plane *plane, } I915_WRITE(PLANE_SURF(pipe, 0), - intel_fb_gtt_offset(fb, rotation) + surf_addr); + intel_plane_ggtt_offset(plane_state) + surf_addr); POSTING_READ(PLANE_SURF(pipe, 0)); } @@ -4265,10 +4262,10 @@ static void page_flip_completed(struct intel_crtc *intel_crtc) drm_crtc_vblank_put(&intel_crtc->base); wake_up_all(&dev_priv->pending_flip_queue); - queue_work(dev_priv->wq, &work->unpin_work); - trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj); + + queue_work(dev_priv->wq, &work->unpin_work); } static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) @@ -6846,6 +6843,12 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) } state = drm_atomic_state_alloc(crtc->dev); + if (!state) { + DRM_DEBUG_KMS("failed to disable [CRTC:%d:%s], out of memory", + crtc->base.id, crtc->name); + return; + } + state->acquire_ctx = crtc->dev->mode_config.acquire_ctx; /* Everything's already locked, -EDEADLK can't happen. */ @@ -11243,6 +11246,7 @@ found: } old->restore_state = restore_state; + drm_atomic_state_put(state); /* let the connector get through one full cycle before testing */ intel_wait_for_vblank(dev_priv, intel_crtc->pipe); @@ -11522,7 +11526,7 @@ static void intel_unpin_work_fn(struct work_struct *__work) flush_work(&work->mmio_work); mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(work->old_fb, primary->state->rotation); + intel_unpin_fb_vma(work->old_vma); i915_gem_object_put(work->pending_flip_obj); mutex_unlock(&dev->struct_mutex); @@ -12232,8 +12236,10 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_pending; } - work->gtt_offset = intel_fb_gtt_offset(fb, primary->state->rotation); - work->gtt_offset += intel_crtc->dspaddr_offset; + work->old_vma = to_intel_plane_state(primary->state)->vma; + to_intel_plane_state(primary->state)->vma = vma; + + work->gtt_offset = i915_ggtt_offset(vma) + intel_crtc->dspaddr_offset; work->rotation = crtc->primary->state->rotation; /* @@ -12287,7 +12293,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_request: i915_add_request_no_flush(request); cleanup_unpin: - intel_unpin_fb_obj(fb, crtc->primary->state->rotation); + to_intel_plane_state(primary->state)->vma = work->old_vma; + intel_unpin_fb_vma(vma); cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); unlock: @@ -14512,8 +14519,14 @@ intel_atomic_commit_ready(struct i915_sw_fence *fence, break; case FENCE_FREE: - drm_atomic_state_put(&state->base); - break; + { + struct intel_atomic_helper *helper = + &to_i915(state->base.dev)->atomic_helper; + + if (llist_add(&state->freed, &helper->free_list)) + schedule_work(&helper->free_work); + break; + } } return NOTIFY_DONE; @@ -14774,6 +14787,8 @@ intel_prepare_plane_fb(struct drm_plane *plane, DRM_DEBUG_KMS("failed to pin object\n"); return PTR_ERR(vma); } + + to_intel_plane_state(new_state)->vma = vma; } return 0; @@ -14792,19 +14807,12 @@ void intel_cleanup_plane_fb(struct drm_plane *plane, struct drm_plane_state *old_state) { - struct drm_i915_private *dev_priv = to_i915(plane->dev); - struct intel_plane_state *old_intel_state; - struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb); - struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb); - - old_intel_state = to_intel_plane_state(old_state); - - if (!obj && !old_obj) - return; + struct i915_vma *vma; - if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR || - !INTEL_INFO(dev_priv)->cursor_needs_physical)) - intel_unpin_fb_obj(old_state->fb, old_state->rotation); + /* Should only be called after a successful intel_prepare_plane_fb()! */ + vma = fetch_and_zero(&to_intel_plane_state(old_state)->vma); + if (vma) + intel_unpin_fb_vma(vma); } int @@ -15146,7 +15154,7 @@ intel_update_cursor_plane(struct drm_plane *plane, if (!obj) addr = 0; else if (!INTEL_INFO(dev_priv)->cursor_needs_physical) - addr = i915_gem_object_ggtt_offset(obj, NULL); + addr = intel_plane_ggtt_offset(state); else addr = obj->phys_handle->busaddr; @@ -16392,6 +16400,18 @@ fail: drm_modeset_acquire_fini(&ctx); } +static void intel_atomic_helper_free_state(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), atomic_helper.free_work); + struct intel_atomic_state *state, *next; + struct llist_node *freed; + + freed = llist_del_all(&dev_priv->atomic_helper.free_list); + llist_for_each_entry_safe(state, next, freed, freed) + drm_atomic_state_put(&state->base); +} + int intel_modeset_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -16411,6 +16431,9 @@ int intel_modeset_init(struct drm_device *dev) dev->mode_config.funcs = &intel_mode_funcs; + INIT_WORK(&dev_priv->atomic_helper.free_work, + intel_atomic_helper_free_state); + intel_init_quirks(dev); intel_init_pm(dev_priv); @@ -16791,7 +16814,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) for_each_intel_crtc(dev, crtc) { struct intel_crtc_state *crtc_state = crtc->config; - int pixclk = 0; __drm_atomic_helper_crtc_destroy_state(&crtc_state->base); memset(crtc_state, 0, sizeof(*crtc_state)); @@ -16803,23 +16825,9 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.enabled = crtc_state->base.enable; crtc->active = crtc_state->base.active; - if (crtc_state->base.active) { + if (crtc_state->base.active) dev_priv->active_crtcs |= 1 << crtc->pipe; - if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) - pixclk = ilk_pipe_pixel_rate(crtc_state); - else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) - pixclk = crtc_state->base.adjusted_mode.crtc_clock; - else - WARN_ON(dev_priv->display.modeset_calc_cdclk); - - /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (IS_BROADWELL(dev_priv) && crtc_state->ips_enabled) - pixclk = DIV_ROUND_UP(pixclk * 100, 95); - } - - dev_priv->min_pixclk[crtc->pipe] = pixclk; - readout_plane_state(crtc); DRM_DEBUG_KMS("[CRTC:%d:%s] hw state readout: %s\n", @@ -16892,6 +16900,8 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) } for_each_intel_crtc(dev, crtc) { + int pixclk = 0; + crtc->base.hwmode = crtc->config->base.adjusted_mode; memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); @@ -16919,10 +16929,23 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) */ crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED; + if (INTEL_GEN(dev_priv) >= 9 || IS_BROADWELL(dev_priv)) + pixclk = ilk_pipe_pixel_rate(crtc->config); + else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) + pixclk = crtc->config->base.adjusted_mode.crtc_clock; + else + WARN_ON(dev_priv->display.modeset_calc_cdclk); + + /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ + if (IS_BROADWELL(dev_priv) && crtc->config->ips_enabled) + pixclk = DIV_ROUND_UP(pixclk * 100, 95); + drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); update_scanline_offset(crtc); } + dev_priv->min_pixclk[crtc->pipe] = pixclk; + intel_pipe_config_sanity_check(dev_priv, crtc->config); } } @@ -17024,47 +17047,19 @@ void intel_display_resume(struct drm_device *dev) if (ret) DRM_ERROR("Restoring old state failed with %i\n", ret); - drm_atomic_state_put(state); + if (state) + drm_atomic_state_put(state); } void intel_modeset_gem_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_crtc *c; - struct drm_i915_gem_object *obj; intel_init_gt_powersave(dev_priv); intel_modeset_init_hw(dev); intel_setup_overlay(dev_priv); - - /* - * Make sure any fbs we allocated at startup are properly - * pinned & fenced. When we do the allocation it's too early - * for this. - */ - for_each_crtc(dev, c) { - struct i915_vma *vma; - - obj = intel_fb_obj(c->primary->fb); - if (obj == NULL) - continue; - - mutex_lock(&dev->struct_mutex); - vma = intel_pin_and_fence_fb_obj(c->primary->fb, - c->primary->state->rotation); - mutex_unlock(&dev->struct_mutex); - if (IS_ERR(vma)) { - DRM_ERROR("failed to pin boot fb on pipe %d\n", - to_intel_crtc(c)->pipe); - drm_framebuffer_unreference(c->primary->fb); - c->primary->fb = NULL; - c->primary->crtc = c->primary->state->crtc = NULL; - update_state_fb(c->primary); - c->state->plane_mask &= ~(1 << drm_plane_index(c->primary)); - } - } } int intel_connector_register(struct drm_connector *connector) @@ -17094,6 +17089,9 @@ void intel_modeset_cleanup(struct drm_device *dev) { struct drm_i915_private *dev_priv = to_i915(dev); + flush_work(&dev_priv->atomic_helper.free_work); + WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list)); + intel_disable_gt_powersave(dev_priv); /* diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d9bc19be855e..0b8e8eb85c19 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -355,7 +355,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct intel_dp *intel_dp); static void intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, - struct intel_dp *intel_dp); + struct intel_dp *intel_dp, + bool force_disable_vdd); static void intel_dp_pps_init(struct drm_device *dev, struct intel_dp *intel_dp); @@ -516,7 +517,7 @@ vlv_power_sequencer_pipe(struct intel_dp *intel_dp) /* init power sequencer on this pipe and port */ intel_dp_init_panel_power_sequencer(dev, intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, true); /* * Even vdd force doesn't work until we've made @@ -553,7 +554,7 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp) * Only the HW needs to be reprogrammed, the SW state is fixed and * has been setup during connector init. */ - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false); return 0; } @@ -636,7 +637,7 @@ vlv_initial_power_sequencer_setup(struct intel_dp *intel_dp) port_name(port), pipe_name(intel_dp->pps_pipe)); intel_dp_init_panel_power_sequencer(dev, intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false); } void intel_power_sequencer_reset(struct drm_i915_private *dev_priv) @@ -2912,7 +2913,7 @@ static void vlv_init_panel_power_sequencer(struct intel_dp *intel_dp) /* init power sequencer on this pipe and port */ intel_dp_init_panel_power_sequencer(dev, intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, true); } static void vlv_pre_enable_dp(struct intel_encoder *encoder, @@ -5055,7 +5056,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, static void intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, - struct intel_dp *intel_dp) + struct intel_dp *intel_dp, + bool force_disable_vdd) { struct drm_i915_private *dev_priv = to_i915(dev); u32 pp_on, pp_off, pp_div, port_sel = 0; @@ -5068,6 +5070,31 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, intel_pps_get_registers(dev_priv, intel_dp, ®s); + /* + * On some VLV machines the BIOS can leave the VDD + * enabled even on power seqeuencers which aren't + * hooked up to any port. This would mess up the + * power domain tracking the first time we pick + * one of these power sequencers for use since + * edp_panel_vdd_on() would notice that the VDD was + * already on and therefore wouldn't grab the power + * domain reference. Disable VDD first to avoid this. + * This also avoids spuriously turning the VDD on as + * soon as the new power seqeuencer gets initialized. + */ + if (force_disable_vdd) { + u32 pp = ironlake_get_pp_control(intel_dp); + + WARN(pp & PANEL_POWER_ON, "Panel power already on\n"); + + if (pp & EDP_FORCE_VDD) + DRM_DEBUG_KMS("VDD already on, disabling first\n"); + + pp &= ~EDP_FORCE_VDD; + + I915_WRITE(regs.pp_ctrl, pp); + } + pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) | (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT); pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) | @@ -5122,7 +5149,7 @@ static void intel_dp_pps_init(struct drm_device *dev, vlv_initial_power_sequencer_setup(intel_dp); } else { intel_dp_init_panel_power_sequencer(dev, intel_dp); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false); } } diff --git a/drivers/gpu/drm/i915/intel_dpll_mgr.c b/drivers/gpu/drm/i915/intel_dpll_mgr.c index 58a756f2f224..a2f0e070d38d 100644 --- a/drivers/gpu/drm/i915/intel_dpll_mgr.c +++ b/drivers/gpu/drm/i915/intel_dpll_mgr.c @@ -1730,7 +1730,8 @@ bxt_get_dpll(struct intel_crtc *crtc, return NULL; if ((encoder->type == INTEL_OUTPUT_DP || - encoder->type == INTEL_OUTPUT_EDP) && + encoder->type == INTEL_OUTPUT_EDP || + encoder->type == INTEL_OUTPUT_DP_MST) && !bxt_ddi_dp_set_dpll_hw_state(clock, &dpll_hw_state)) return NULL; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cd132c216a67..03a2112004f9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -370,11 +370,14 @@ struct intel_atomic_state { struct skl_wm_values wm_results; struct i915_sw_fence commit_ready; + + struct llist_node freed; }; struct intel_plane_state { struct drm_plane_state base; struct drm_rect clip; + struct i915_vma *vma; struct { u32 offset; @@ -1044,6 +1047,7 @@ struct intel_flip_work { struct work_struct mmio_work; struct drm_crtc *crtc; + struct i915_vma *old_vma; struct drm_framebuffer *old_fb; struct drm_i915_gem_object *pending_flip_obj; struct drm_pending_vblank_event *event; @@ -1271,7 +1275,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx); struct i915_vma * intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, unsigned int rotation); -void intel_unpin_fb_obj(struct drm_framebuffer *fb, unsigned int rotation); +void intel_unpin_fb_vma(struct i915_vma *vma); struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, @@ -1360,7 +1364,10 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); -u32 intel_fb_gtt_offset(struct drm_framebuffer *fb, unsigned int rotation); +static inline u32 intel_plane_ggtt_offset(const struct intel_plane_state *state) +{ + return i915_ggtt_offset(state->vma); +} u32 skl_plane_ctl_format(uint32_t pixel_format); u32 skl_plane_ctl_tiling(uint64_t fb_modifier); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 62f215b12eb5..f3a1d6a5cabe 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -173,7 +173,7 @@ static void i8xx_fbc_activate(struct drm_i915_private *dev_priv) if (IS_I945GM(dev_priv)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= params->fb.fence_reg; + fbc_ctl |= params->vma->fence->id; I915_WRITE(FBC_CONTROL, fbc_ctl); } @@ -193,8 +193,8 @@ static void g4x_fbc_activate(struct drm_i915_private *dev_priv) else dpfc_ctl |= DPFC_CTL_LIMIT_1X; - if (params->fb.fence_reg != I915_FENCE_REG_NONE) { - dpfc_ctl |= DPFC_CTL_FENCE_EN | params->fb.fence_reg; + if (params->vma->fence) { + dpfc_ctl |= DPFC_CTL_FENCE_EN | params->vma->fence->id; I915_WRITE(DPFC_FENCE_YOFF, params->crtc.fence_y_offset); } else { I915_WRITE(DPFC_FENCE_YOFF, 0); @@ -251,13 +251,14 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv) break; } - if (params->fb.fence_reg != I915_FENCE_REG_NONE) { + if (params->vma->fence) { dpfc_ctl |= DPFC_CTL_FENCE_EN; if (IS_GEN5(dev_priv)) - dpfc_ctl |= params->fb.fence_reg; + dpfc_ctl |= params->vma->fence->id; if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | params->fb.fence_reg); + SNB_CPU_FENCE_ENABLE | + params->vma->fence->id); I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset); } @@ -269,7 +270,8 @@ static void ilk_fbc_activate(struct drm_i915_private *dev_priv) } I915_WRITE(ILK_DPFC_FENCE_YOFF, params->crtc.fence_y_offset); - I915_WRITE(ILK_FBC_RT_BASE, params->fb.ggtt_offset | ILK_FBC_RT_VALID); + I915_WRITE(ILK_FBC_RT_BASE, + i915_ggtt_offset(params->vma) | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -319,10 +321,11 @@ static void gen7_fbc_activate(struct drm_i915_private *dev_priv) break; } - if (params->fb.fence_reg != I915_FENCE_REG_NONE) { + if (params->vma->fence) { dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN; I915_WRITE(SNB_DPFC_CTL_SA, - SNB_CPU_FENCE_ENABLE | params->fb.fence_reg); + SNB_CPU_FENCE_ENABLE | + params->vma->fence->id); I915_WRITE(DPFC_CPU_FENCE_OFFSET, params->crtc.fence_y_offset); } else { I915_WRITE(SNB_DPFC_CTL_SA,0); @@ -727,14 +730,6 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) return effective_w <= max_w && effective_h <= max_h; } -/* XXX replace me when we have VMA tracking for intel_plane_state */ -static int get_fence_id(struct drm_framebuffer *fb) -{ - struct i915_vma *vma = i915_gem_object_to_ggtt(intel_fb_obj(fb), NULL); - - return vma && vma->fence ? vma->fence->id : I915_FENCE_REG_NONE; -} - static void intel_fbc_update_state_cache(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) @@ -743,7 +738,8 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, struct intel_fbc *fbc = &dev_priv->fbc; struct intel_fbc_state_cache *cache = &fbc->state_cache; struct drm_framebuffer *fb = plane_state->base.fb; - struct drm_i915_gem_object *obj; + + cache->vma = NULL; cache->crtc.mode_flags = crtc_state->base.adjusted_mode.flags; if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) @@ -758,16 +754,10 @@ static void intel_fbc_update_state_cache(struct intel_crtc *crtc, if (!cache->plane.visible) return; - obj = intel_fb_obj(fb); - - /* FIXME: We lack the proper locking here, so only run this on the - * platforms that need. */ - if (IS_GEN(dev_priv, 5, 6)) - cache->fb.ilk_ggtt_offset = i915_gem_object_ggtt_offset(obj, NULL); cache->fb.pixel_format = fb->pixel_format; cache->fb.stride = fb->pitches[0]; - cache->fb.fence_reg = get_fence_id(fb); - cache->fb.tiling_mode = i915_gem_object_get_tiling(obj); + + cache->vma = plane_state->vma; } static bool intel_fbc_can_activate(struct intel_crtc *crtc) @@ -784,7 +774,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) return false; } - if (!cache->plane.visible) { + if (!cache->vma) { fbc->no_fbc_reason = "primary plane not visible"; return false; } @@ -807,8 +797,7 @@ static bool intel_fbc_can_activate(struct intel_crtc *crtc) * so have no fence associated with it) due to aperture constaints * at the time of pinning. */ - if (cache->fb.tiling_mode != I915_TILING_X || - cache->fb.fence_reg == I915_FENCE_REG_NONE) { + if (!cache->vma->fence) { fbc->no_fbc_reason = "framebuffer not tiled or fenced"; return false; } @@ -888,17 +877,16 @@ static void intel_fbc_get_reg_params(struct intel_crtc *crtc, * zero. */ memset(params, 0, sizeof(*params)); + params->vma = cache->vma; + params->crtc.pipe = crtc->pipe; params->crtc.plane = crtc->plane; params->crtc.fence_y_offset = get_crtc_fence_y_offset(crtc); params->fb.pixel_format = cache->fb.pixel_format; params->fb.stride = cache->fb.stride; - params->fb.fence_reg = cache->fb.fence_reg; params->cfb_size = intel_fbc_calculate_cfb_size(dev_priv, cache); - - params->fb.ggtt_offset = cache->fb.ilk_ggtt_offset; } static bool intel_fbc_reg_params_equal(struct intel_fbc_reg_params *params1, diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index beb08982dc0b..f4a8c4fc57c4 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -284,7 +284,7 @@ static int intelfb_create(struct drm_fb_helper *helper, out_destroy_fbi: drm_fb_helper_release_fbi(helper); out_unpin: - intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0); + intel_unpin_fb_vma(vma); out_unlock: mutex_unlock(&dev->struct_mutex); return ret; @@ -549,7 +549,7 @@ static void intel_fbdev_destroy(struct intel_fbdev *ifbdev) if (ifbdev->fb) { mutex_lock(&ifbdev->helper.dev->struct_mutex); - intel_unpin_fb_obj(&ifbdev->fb->base, DRM_ROTATE_0); + intel_unpin_fb_vma(ifbdev->vma); mutex_unlock(&ifbdev->helper.dev->struct_mutex); drm_framebuffer_remove(&ifbdev->fb->base); @@ -742,6 +742,9 @@ void intel_fbdev_initial_config_async(struct drm_device *dev) { struct intel_fbdev *ifbdev = to_i915(dev)->fbdev; + if (!ifbdev) + return; + ifbdev->cookie = async_schedule(intel_fbdev_initial_config, ifbdev); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d4961fa20c73..beabc17e7c8a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -979,18 +979,8 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *engine, uint32_t *batch, uint32_t index) { - struct drm_i915_private *dev_priv = engine->i915; uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - /* - * WaDisableLSQCROPERFforOCL:kbl - * This WA is implemented in skl_init_clock_gating() but since - * this batch updates GEN8_L3SQCREG4 with default value we need to - * set this bit here to retain the WA during flush. - */ - if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) - l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; - wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | MI_SRM_LRM_GLOBAL_GTT)); wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index fd0e4dac7cc1..e589e17876dc 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -216,7 +216,8 @@ static void intel_overlay_submit_request(struct intel_overlay *overlay, { GEM_BUG_ON(i915_gem_active_peek(&overlay->last_flip, &overlay->i915->drm.struct_mutex)); - overlay->last_flip.retire = retire; + i915_gem_active_set_retire_fn(&overlay->last_flip, retire, + &overlay->i915->drm.struct_mutex); i915_gem_active_set(&overlay->last_flip, req); i915_add_request(req); } @@ -839,8 +840,8 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret) goto out_unpin; - i915_gem_track_fb(overlay->vma->obj, new_bo, - INTEL_FRONTBUFFER_OVERLAY(pipe)); + i915_gem_track_fb(overlay->vma ? overlay->vma->obj : NULL, + vma->obj, INTEL_FRONTBUFFER_OVERLAY(pipe)); overlay->old_vma = overlay->vma; overlay->vma = vma; @@ -1430,6 +1431,8 @@ void intel_setup_overlay(struct drm_i915_private *dev_priv) overlay->contrast = 75; overlay->saturation = 146; + init_request_active(&overlay->last_flip, NULL); + regs = intel_overlay_map_regs(overlay); if (!regs) goto out_unpin_bo; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index aeb637dc1fdf..91cb4c422ad5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1095,14 +1095,6 @@ static int kbl_init_workarounds(struct intel_engine_cs *engine) WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FENCE_DEST_SLM_DISABLE); - /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes - * involving this register should also be added to WA batch as required. - */ - if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_E0)) - /* WaDisableLSQCROPERFforOCL:kbl */ - I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | - GEN8_LQSC_RO_PERF_DIS); - /* WaToEnableHwFixForPushConstHWBug:kbl */ if (IS_KBL_REVID(dev_priv, KBL_REVID_C0, REVID_FOREVER)) WA_SET_BIT_MASKED(COMMON_SLICE_CHICKEN2, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 8f131a08d440..242a73e66d82 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -273,7 +273,7 @@ skl_update_plane(struct drm_plane *drm_plane, I915_WRITE(PLANE_CTL(pipe, plane), plane_ctl); I915_WRITE(PLANE_SURF(pipe, plane), - intel_fb_gtt_offset(fb, rotation) + surf_addr); + intel_plane_ggtt_offset(plane_state) + surf_addr); POSTING_READ(PLANE_SURF(pipe, plane)); } @@ -458,7 +458,7 @@ vlv_update_plane(struct drm_plane *dplane, I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w); I915_WRITE(SPCNTR(pipe, plane), sprctl); I915_WRITE(SPSURF(pipe, plane), - intel_fb_gtt_offset(fb, rotation) + sprsurf_offset); + intel_plane_ggtt_offset(plane_state) + sprsurf_offset); POSTING_READ(SPSURF(pipe, plane)); } @@ -594,7 +594,7 @@ ivb_update_plane(struct drm_plane *plane, I915_WRITE(SPRSCALE(pipe), sprscale); I915_WRITE(SPRCTL(pipe), sprctl); I915_WRITE(SPRSURF(pipe), - intel_fb_gtt_offset(fb, rotation) + sprsurf_offset); + intel_plane_ggtt_offset(plane_state) + sprsurf_offset); POSTING_READ(SPRSURF(pipe)); } @@ -721,7 +721,7 @@ ilk_update_plane(struct drm_plane *plane, I915_WRITE(DVSSCALE(pipe), dvsscale); I915_WRITE(DVSCNTR(pipe), dvscntr); I915_WRITE(DVSSURF(pipe), - intel_fb_gtt_offset(fb, rotation) + dvssurf_offset); + intel_plane_ggtt_offset(plane_state) + dvssurf_offset); POSTING_READ(DVSSURF(pipe)); } diff --git a/drivers/gpu/drm/meson/meson_plane.c b/drivers/gpu/drm/meson/meson_plane.c index 4942ca090b46..7890e30eb584 100644 --- a/drivers/gpu/drm/meson/meson_plane.c +++ b/drivers/gpu/drm/meson/meson_plane.c @@ -51,6 +51,9 @@ static int meson_plane_atomic_check(struct drm_plane *plane, struct drm_crtc_state *crtc_state; struct drm_rect clip = { 0, }; + if (!state->crtc) + return 0; + crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); diff --git a/drivers/gpu/drm/meson/meson_venc.c b/drivers/gpu/drm/meson/meson_venc.c index d836b2274531..f7c870172220 100644 --- a/drivers/gpu/drm/meson/meson_venc.c +++ b/drivers/gpu/drm/meson/meson_venc.c @@ -38,6 +38,11 @@ * - TV Panel encoding via ENCT */ +/* HHI Registers */ +#define HHI_VDAC_CNTL0 0x2F4 /* 0xbd offset in data sheet */ +#define HHI_VDAC_CNTL1 0x2F8 /* 0xbe offset in data sheet */ +#define HHI_HDMI_PHY_CNTL0 0x3a0 /* 0xe8 offset in data sheet */ + struct meson_cvbs_enci_mode meson_cvbs_enci_pal = { .mode_tag = MESON_VENC_MODE_CVBS_PAL, .hso_begin = 3, @@ -242,6 +247,20 @@ void meson_venc_disable_vsync(struct meson_drm *priv) void meson_venc_init(struct meson_drm *priv) { + /* Disable CVBS VDAC */ + regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); + + /* Power Down Dacs */ + writel_relaxed(0xff, priv->io_base + _REG(VENC_VDAC_SETTING)); + + /* Disable HDMI PHY */ + regmap_write(priv->hhi, HHI_HDMI_PHY_CNTL0, 0); + + /* Disable HDMI */ + writel_bits_relaxed(0x3, 0, + priv->io_base + _REG(VPU_HDMI_SETTING)); + /* Disable all encoders */ writel_relaxed(0, priv->io_base + _REG(ENCI_VIDEO_EN)); writel_relaxed(0, priv->io_base + _REG(ENCP_VIDEO_EN)); diff --git a/drivers/gpu/drm/meson/meson_venc_cvbs.c b/drivers/gpu/drm/meson/meson_venc_cvbs.c index c809c085fd78..a2bcc70a03ef 100644 --- a/drivers/gpu/drm/meson/meson_venc_cvbs.c +++ b/drivers/gpu/drm/meson/meson_venc_cvbs.c @@ -167,7 +167,7 @@ static void meson_venc_cvbs_encoder_disable(struct drm_encoder *encoder) /* Disable CVBS VDAC */ regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0); - regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0); + regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8); } static void meson_venc_cvbs_encoder_enable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index a18126150e11..686a580c711a 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -213,7 +213,14 @@ void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, void adreno_flush(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t wptr = get_wptr(gpu->rb); + uint32_t wptr; + + /* + * Mask wptr value that we calculate to fit in the HW range. This is + * to account for the possibility that the last command fit exactly into + * the ringbuffer and rb->next hasn't wrapped to zero yet + */ + wptr = get_wptr(gpu->rb) & ((gpu->rb->size / 4) - 1); /* ensure writes to ringbuffer have hit system memory: */ mb(); @@ -338,7 +345,6 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, { struct adreno_platform_config *config = pdev->dev.platform_data; struct msm_gpu *gpu = &adreno_gpu->base; - struct msm_mmu *mmu; int ret; adreno_gpu->funcs = funcs; @@ -378,8 +384,8 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, return ret; } - mmu = gpu->aspace->mmu; - if (mmu) { + if (gpu->aspace && gpu->aspace->mmu) { + struct msm_mmu *mmu = gpu->aspace->mmu; ret = mmu->funcs->attach(mmu, iommu_ports, ARRAY_SIZE(iommu_ports)); if (ret) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c index 5f6cd8745dbc..c396d459a9d0 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -119,13 +119,7 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) { - int i; struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); - struct drm_plane *plane; - struct drm_plane_state *plane_state; - - for_each_plane_in_state(state, plane, plane_state, i) - mdp5_plane_complete_commit(plane, plane_state); if (mdp5_kms->smp) mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index 17b0cc101171..cdfc63d90c7b 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -104,8 +104,6 @@ struct mdp5_plane_state { /* assigned by crtc blender */ enum mdp_mixer_stage_id stage; - - bool pending : 1; }; #define to_mdp5_plane_state(x) \ container_of(x, struct mdp5_plane_state, base) @@ -232,8 +230,6 @@ int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms); void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms); uint32_t mdp5_plane_get_flush(struct drm_plane *plane); -void mdp5_plane_complete_commit(struct drm_plane *plane, - struct drm_plane_state *state); enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane); struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index c099da7bc212..25d9d0a97156 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -179,7 +179,6 @@ mdp5_plane_atomic_print_state(struct drm_printer *p, drm_printf(p, "\tzpos=%u\n", pstate->zpos); drm_printf(p, "\talpha=%u\n", pstate->alpha); drm_printf(p, "\tstage=%s\n", stage2name(pstate->stage)); - drm_printf(p, "\tpending=%u\n", pstate->pending); } static void mdp5_plane_reset(struct drm_plane *plane) @@ -220,8 +219,6 @@ mdp5_plane_duplicate_state(struct drm_plane *plane) if (mdp5_state && mdp5_state->base.fb) drm_framebuffer_reference(mdp5_state->base.fb); - mdp5_state->pending = false; - return &mdp5_state->base; } @@ -288,13 +285,6 @@ static int mdp5_plane_atomic_check(struct drm_plane *plane, DBG("%s: check (%d -> %d)", plane->name, plane_enabled(old_state), plane_enabled(state)); - /* We don't allow faster-than-vblank updates.. if we did add this - * some day, we would need to disallow in cases where hwpipe - * changes - */ - if (WARN_ON(to_mdp5_plane_state(old_state)->pending)) - return -EBUSY; - max_width = config->hw->lm.max_width << 16; max_height = config->hw->lm.max_height << 16; @@ -370,12 +360,9 @@ static void mdp5_plane_atomic_update(struct drm_plane *plane, struct drm_plane_state *old_state) { struct drm_plane_state *state = plane->state; - struct mdp5_plane_state *mdp5_state = to_mdp5_plane_state(state); DBG("%s: update", plane->name); - mdp5_state->pending = true; - if (plane_enabled(state)) { int ret; @@ -851,15 +838,6 @@ uint32_t mdp5_plane_get_flush(struct drm_plane *plane) return pstate->hwpipe->flush_mask; } -/* called after vsync in thread context */ -void mdp5_plane_complete_commit(struct drm_plane *plane, - struct drm_plane_state *state) -{ - struct mdp5_plane_state *pstate = to_mdp5_plane_state(plane->state); - - pstate->pending = false; -} - /* initialize plane */ struct drm_plane *mdp5_plane_init(struct drm_device *dev, bool primary) { diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index d8bc59c7e261..1974ccb781de 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -294,6 +294,8 @@ put_iova(struct drm_gem_object *obj) WARN_ON(!mutex_is_locked(&dev->struct_mutex)); for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { + if (!priv->aspace[id]) + continue; msm_gem_unmap_vma(priv->aspace[id], &msm_obj->domain[id], msm_obj->sgt); } @@ -640,7 +642,7 @@ void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m) seq_printf(m, "%08x: %c %2d (%2d) %08llx %p\t", msm_obj->flags, is_active(msm_obj) ? 'A' : 'I', - obj->name, obj->refcount.refcount.counter, + obj->name, kref_read(&obj->refcount), off, msm_obj->vaddr); for (id = 0; id < priv->num_aspaces; id++) diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 166e84e4f0d4..489676568a10 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -106,7 +106,8 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, pagefault_disable(); } - if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) { + if ((submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) || + !(submit_bo.flags & MSM_SUBMIT_BO_FLAGS)) { DRM_ERROR("invalid flags: %x\n", submit_bo.flags); ret = -EINVAL; goto out_unlock; @@ -290,7 +291,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob { uint32_t i, last_offset = 0; uint32_t *ptr; - int ret; + int ret = 0; if (offset % 4) { DRM_ERROR("non-aligned cmdstream buffer: %u\n", offset); @@ -318,12 +319,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob ret = copy_from_user(&submit_reloc, userptr, sizeof(submit_reloc)); if (ret) - return -EFAULT; + goto out; if (submit_reloc.submit_offset % 4) { DRM_ERROR("non-aligned reloc offset: %u\n", submit_reloc.submit_offset); - return -EINVAL; + ret = -EINVAL; + goto out; } /* offset in dwords: */ @@ -332,12 +334,13 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob if ((off >= (obj->base.size / 4)) || (off < last_offset)) { DRM_ERROR("invalid offset %u at reloc %u\n", off, i); - return -EINVAL; + ret = -EINVAL; + goto out; } ret = submit_bo(submit, submit_reloc.reloc_idx, NULL, &iova, &valid); if (ret) - return ret; + goto out; if (valid) continue; @@ -354,9 +357,10 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob last_offset = off; } +out: msm_gem_put_vaddr_locked(&obj->base); - return 0; + return ret; } static void submit_cleanup(struct msm_gem_submit *submit) diff --git a/drivers/gpu/drm/msm/msm_ringbuffer.c b/drivers/gpu/drm/msm/msm_ringbuffer.c index f326cf6a32e6..67b34e069abf 100644 --- a/drivers/gpu/drm/msm/msm_ringbuffer.c +++ b/drivers/gpu/drm/msm/msm_ringbuffer.c @@ -23,7 +23,8 @@ struct msm_ringbuffer *msm_ringbuffer_new(struct msm_gpu *gpu, int size) struct msm_ringbuffer *ring; int ret; - size = ALIGN(size, 4); /* size should be dword aligned */ + if (WARN_ON(!is_power_of_2(size))) + return ERR_PTR(-EINVAL); ring = kzalloc(sizeof(*ring), GFP_KERNEL); if (!ring) { diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index 74856a8b8f35..e64f52464ecf 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -222,6 +222,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype) uint32_t mpllP; pci_read_config_dword(pci_get_bus_and_slot(0, 3), 0x6c, &mpllP); + mpllP = (mpllP >> 8) & 0xf; if (!mpllP) mpllP = 4; @@ -232,7 +233,7 @@ nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype) uint32_t clock; pci_read_config_dword(pci_get_bus_and_slot(0, 5), 0x4c, &clock); - return clock; + return clock / 1000; } ret = nouveau_hw_get_pllvals(dev, plltype, &pllvals); diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index cef08da1da4e..6a157763dfc3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -411,7 +411,8 @@ nouveau_display_init(struct drm_device *dev) return ret; /* enable polling for external displays */ - drm_kms_helper_poll_enable(dev); + if (!dev->mode_config.poll_enabled) + drm_kms_helper_poll_enable(dev); /* enable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 59348fc41c77..bc85a45f91cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -773,7 +773,10 @@ nouveau_pmops_runtime_resume(struct device *dev) pci_set_master(pdev); ret = nouveau_do_resume(drm_dev, true); - drm_kms_helper_poll_enable(drm_dev); + + if (!drm_dev->mode_config.poll_enabled) + drm_kms_helper_poll_enable(drm_dev); + /* do magic */ nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 8d5ed5bfdacb..42c1fa53d431 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -165,6 +165,8 @@ struct nouveau_drm { struct backlight_device *backlight; struct list_head bl_connectors; struct work_struct hpd_work; + struct work_struct fbcon_work; + int fbcon_new_state; #ifdef CONFIG_ACPI struct notifier_block acpi_nb; #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 2f2a3dcd4ad7..fa2d0a978ccc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -470,19 +470,43 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = { .fb_probe = nouveau_fbcon_create, }; +static void +nouveau_fbcon_set_suspend_work(struct work_struct *work) +{ + struct nouveau_drm *drm = container_of(work, typeof(*drm), fbcon_work); + int state = READ_ONCE(drm->fbcon_new_state); + + if (state == FBINFO_STATE_RUNNING) + pm_runtime_get_sync(drm->dev->dev); + + console_lock(); + if (state == FBINFO_STATE_RUNNING) + nouveau_fbcon_accel_restore(drm->dev); + drm_fb_helper_set_suspend(&drm->fbcon->helper, state); + if (state != FBINFO_STATE_RUNNING) + nouveau_fbcon_accel_save_disable(drm->dev); + console_unlock(); + + if (state == FBINFO_STATE_RUNNING) { + pm_runtime_mark_last_busy(drm->dev->dev); + pm_runtime_put_sync(drm->dev->dev); + } +} + void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon) { - console_lock(); - if (state == FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_restore(dev); - drm_fb_helper_set_suspend(&drm->fbcon->helper, state); - if (state != FBINFO_STATE_RUNNING) - nouveau_fbcon_accel_save_disable(dev); - console_unlock(); - } + + if (!drm->fbcon) + return; + + drm->fbcon_new_state = state; + /* Since runtime resume can happen as a result of a sysfs operation, + * it's possible we already have the console locked. So handle fbcon + * init/deinit from a seperate work thread + */ + schedule_work(&drm->fbcon_work); } int @@ -502,6 +526,7 @@ nouveau_fbcon_init(struct drm_device *dev) return -ENOMEM; drm->fbcon = fbcon; + INIT_WORK(&drm->fbcon_work, nouveau_fbcon_set_suspend_work); drm_fb_helper_prepare(dev, &fbcon->helper, &nouveau_fbcon_helper_funcs); diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index a6126c93f215..88ee60d1b907 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -527,7 +527,7 @@ static bool nouveau_fence_no_signaling(struct dma_fence *f) * caller should have a reference on the fence, * else fence could get freed here */ - WARN_ON(atomic_read(&fence->base.refcount.refcount) <= 1); + WARN_ON(kref_read(&fence->base.refcount) <= 1); /* * This needs uevents to work correctly, but dma_fence_add_callback relies on diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index ccdce1b4eec4..d5e58a38f160 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -99,6 +99,7 @@ struct nv84_fence_priv { struct nouveau_bo *bo; struct nouveau_bo *bo_gart; u32 *suspend; + struct mutex mutex; }; int nv84_fence_context_new(struct nouveau_channel *); diff --git a/drivers/gpu/drm/nouveau/nouveau_led.h b/drivers/gpu/drm/nouveau/nouveau_led.h index 187ecdb82002..21a5775028cc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_led.h +++ b/drivers/gpu/drm/nouveau/nouveau_led.h @@ -42,7 +42,7 @@ nouveau_led(struct drm_device *dev) } /* nouveau_led.c */ -#if IS_ENABLED(CONFIG_LEDS_CLASS) +#if IS_REACHABLE(CONFIG_LEDS_CLASS) int nouveau_led_init(struct drm_device *dev); void nouveau_led_suspend(struct drm_device *dev); void nouveau_led_resume(struct drm_device *dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c index 08f9c6fa0f7f..1fba38622744 100644 --- a/drivers/gpu/drm/nouveau/nouveau_usif.c +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c @@ -313,7 +313,8 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) if (!(ret = nvif_unpack(-ENOSYS, &data, &size, argv->v0, 0, 0, true))) { /* block access to objects not created via this interface */ owner = argv->v0.owner; - if (argv->v0.object == 0ULL) + if (argv->v0.object == 0ULL && + argv->v0.type != NVIF_IOCTL_V0_DEL) argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */ else argv->v0.owner = NVDRM_OBJECT_USIF; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 2c2c64507661..32097fd615fd 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -4052,6 +4052,11 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) } } + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc->state->event) + drm_crtc_vblank_get(crtc); + } + /* Update plane(s). */ for_each_plane_in_state(state, plane, plane_state, i) { struct nv50_wndw_atom *asyw = nv50_wndw_atom(plane->state); @@ -4101,6 +4106,7 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) drm_crtc_send_vblank_event(crtc, crtc->state->event); spin_unlock_irqrestore(&crtc->dev->event_lock, flags); crtc->state->event = NULL; + drm_crtc_vblank_put(crtc); } } diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 52b87ae83e7b..f0b322bec7df 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -107,8 +107,10 @@ nv84_fence_context_del(struct nouveau_channel *chan) struct nv84_fence_chan *fctx = chan->fence; nouveau_bo_wr32(priv->bo, chan->chid * 16 / 4, fctx->base.sequence); + mutex_lock(&priv->mutex); nouveau_bo_vma_del(priv->bo, &fctx->vma_gart); nouveau_bo_vma_del(priv->bo, &fctx->vma); + mutex_unlock(&priv->mutex); nouveau_fence_context_del(&fctx->base); chan->fence = NULL; nouveau_fence_context_free(&fctx->base); @@ -134,11 +136,13 @@ nv84_fence_context_new(struct nouveau_channel *chan) fctx->base.sync32 = nv84_fence_sync32; fctx->base.sequence = nv84_fence_read(chan); + mutex_lock(&priv->mutex); ret = nouveau_bo_vma_add(priv->bo, cli->vm, &fctx->vma); if (ret == 0) { ret = nouveau_bo_vma_add(priv->bo_gart, cli->vm, &fctx->vma_gart); } + mutex_unlock(&priv->mutex); if (ret) nv84_fence_context_del(chan); @@ -212,6 +216,8 @@ nv84_fence_create(struct nouveau_drm *drm) priv->base.context_base = dma_fence_context_alloc(priv->base.contexts); priv->base.uevent = true; + mutex_init(&priv->mutex); + /* Use VRAM if there is any ; otherwise fallback to system memory */ domain = drm->device.info.ram_size != 0 ? TTM_PL_FLAG_VRAM : /* diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index 6f0436df0219..f8f2f16c22a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -59,7 +59,7 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) ); } for (i = 0; i < size; i++) - nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]); + nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[i]); for (; i < 0x60; i++) nvkm_wr32(device, 0x61c440 + soff, (i << 8)); nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 567466f93cd5..0db8efbf1c2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -433,8 +433,6 @@ nv50_disp_dptmds_war(struct nvkm_device *device) case 0x94: case 0x96: case 0x98: - case 0xaa: - case 0xac: return true; default: break; diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 4a90c690f09e..74a9968df421 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -1033,7 +1033,7 @@ void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) off = drm_vma_node_start(&obj->vma_node); seq_printf(m, "%08x: %2d (%2d) %08llx %pad (%2d) %p %4d", - omap_obj->flags, obj->name, obj->refcount.refcount.counter, + omap_obj->flags, obj->name, kref_read(&obj->refcount), off, &omap_obj->paddr, omap_obj->paddr_cnt, omap_obj->vaddr, omap_obj->roll); diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c index fb16070b266e..4a4f9533c53b 100644 --- a/drivers/gpu/drm/radeon/radeon_cursor.c +++ b/drivers/gpu/drm/radeon/radeon_cursor.c @@ -205,8 +205,8 @@ static int radeon_cursor_move_locked(struct drm_crtc *crtc, int x, int y) } if (x <= (crtc->x - w) || y <= (crtc->y - radeon_crtc->cursor_height) || - x >= (crtc->x + crtc->mode.crtc_hdisplay) || - y >= (crtc->y + crtc->mode.crtc_vdisplay)) + x >= (crtc->x + crtc->mode.hdisplay) || + y >= (crtc->y + crtc->mode.vdisplay)) goto out_of_bounds; x += xorigin; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 00ea0002b539..30bd4a6a9d46 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -97,9 +97,10 @@ * 2.46.0 - Add PFP_SYNC_ME support on evergreen * 2.47.0 - Add UVD_NO_OP register support * 2.48.0 - TA_CS_BC_BASE_ADDR allowed on SI + * 2.49.0 - DRM_RADEON_GEM_INFO ioctl returns correct vram_size/visible values */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 48 +#define KMS_DRIVER_MINOR 49 #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); @@ -366,11 +367,10 @@ static void radeon_pci_shutdown(struct pci_dev *pdev) { /* if we are running in a VM, make sure the device - * torn down properly on reboot/shutdown. - * unfortunately we can't detect certain - * hypervisors so just do this all the time. + * torn down properly on reboot/shutdown */ - radeon_pci_remove(pdev); + if (radeon_device_is_virtual()) + radeon_pci_remove(pdev); } static int radeon_pmops_suspend(struct device *dev) diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 0bcffd8a7bd3..96683f5b2b1b 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -220,8 +220,8 @@ int radeon_gem_info_ioctl(struct drm_device *dev, void *data, man = &rdev->mman.bdev.man[TTM_PL_VRAM]; - args->vram_size = rdev->mc.real_vram_size; - args->vram_visible = (u64)man->size << PAGE_SHIFT; + args->vram_size = (u64)man->size << PAGE_SHIFT; + args->vram_visible = rdev->mc.visible_vram_size; args->vram_visible -= rdev->vram_pin_size; args->gart_size = rdev->mc.gtt_size; args->gart_size -= rdev->gart_pin_size; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index ad4d7b8b8322..414776811e71 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -50,7 +50,6 @@ MODULE_FIRMWARE("radeon/tahiti_ce.bin"); MODULE_FIRMWARE("radeon/tahiti_mc.bin"); MODULE_FIRMWARE("radeon/tahiti_rlc.bin"); MODULE_FIRMWARE("radeon/tahiti_smc.bin"); -MODULE_FIRMWARE("radeon/tahiti_k_smc.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_pfp.bin"); MODULE_FIRMWARE("radeon/PITCAIRN_me.bin"); @@ -115,6 +114,9 @@ MODULE_FIRMWARE("radeon/hainan_mc.bin"); MODULE_FIRMWARE("radeon/hainan_rlc.bin"); MODULE_FIRMWARE("radeon/hainan_smc.bin"); MODULE_FIRMWARE("radeon/hainan_k_smc.bin"); +MODULE_FIRMWARE("radeon/banks_k_2_smc.bin"); + +MODULE_FIRMWARE("radeon/si58_mc.bin"); static u32 si_get_cu_active_bitmap(struct radeon_device *rdev, u32 se, u32 sh); static void si_pcie_gen3_enable(struct radeon_device *rdev); @@ -1651,15 +1653,14 @@ static int si_init_microcode(struct radeon_device *rdev) int err; int new_fw = 0; bool new_smc = false; + bool si58_fw = false; + bool banks2_fw = false; DRM_DEBUG("\n"); switch (rdev->family) { case CHIP_TAHITI: chip_name = "TAHITI"; - /* XXX: figure out which Tahitis need the new ucode */ - if (0) - new_smc = true; new_chip_name = "tahiti"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; @@ -1671,12 +1672,9 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_PITCAIRN: chip_name = "PITCAIRN"; - if ((rdev->pdev->revision == 0x81) || - (rdev->pdev->device == 0x6810) || - (rdev->pdev->device == 0x6811) || - (rdev->pdev->device == 0x6816) || - (rdev->pdev->device == 0x6817) || - (rdev->pdev->device == 0x6806)) + if ((rdev->pdev->revision == 0x81) && + ((rdev->pdev->device == 0x6810) || + (rdev->pdev->device == 0x6811))) new_smc = true; new_chip_name = "pitcairn"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; @@ -1689,15 +1687,15 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_VERDE: chip_name = "VERDE"; - if ((rdev->pdev->revision == 0x81) || - (rdev->pdev->revision == 0x83) || - (rdev->pdev->revision == 0x87) || - (rdev->pdev->device == 0x6820) || - (rdev->pdev->device == 0x6821) || - (rdev->pdev->device == 0x6822) || - (rdev->pdev->device == 0x6823) || - (rdev->pdev->device == 0x682A) || - (rdev->pdev->device == 0x682B)) + if (((rdev->pdev->device == 0x6820) && + ((rdev->pdev->revision == 0x81) || + (rdev->pdev->revision == 0x83))) || + ((rdev->pdev->device == 0x6821) && + ((rdev->pdev->revision == 0x83) || + (rdev->pdev->revision == 0x87))) || + ((rdev->pdev->revision == 0x87) && + ((rdev->pdev->device == 0x6823) || + (rdev->pdev->device == 0x682b)))) new_smc = true; new_chip_name = "verde"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; @@ -1710,13 +1708,13 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_OLAND: chip_name = "OLAND"; - if ((rdev->pdev->revision == 0xC7) || - (rdev->pdev->revision == 0x80) || - (rdev->pdev->revision == 0x81) || - (rdev->pdev->revision == 0x83) || - (rdev->pdev->revision == 0x87) || - (rdev->pdev->device == 0x6604) || - (rdev->pdev->device == 0x6605)) + if (((rdev->pdev->revision == 0x81) && + ((rdev->pdev->device == 0x6600) || + (rdev->pdev->device == 0x6604) || + (rdev->pdev->device == 0x6605) || + (rdev->pdev->device == 0x6610))) || + ((rdev->pdev->revision == 0x83) && + (rdev->pdev->device == 0x6610))) new_smc = true; new_chip_name = "oland"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; @@ -1728,13 +1726,17 @@ static int si_init_microcode(struct radeon_device *rdev) break; case CHIP_HAINAN: chip_name = "HAINAN"; - if ((rdev->pdev->revision == 0x81) || - (rdev->pdev->revision == 0x83) || - (rdev->pdev->revision == 0xC3) || - (rdev->pdev->device == 0x6664) || - (rdev->pdev->device == 0x6665) || - (rdev->pdev->device == 0x6667)) + if (((rdev->pdev->revision == 0x81) && + (rdev->pdev->device == 0x6660)) || + ((rdev->pdev->revision == 0x83) && + ((rdev->pdev->device == 0x6660) || + (rdev->pdev->device == 0x6663) || + (rdev->pdev->device == 0x6665) || + (rdev->pdev->device == 0x6667)))) new_smc = true; + else if ((rdev->pdev->revision == 0xc3) && + (rdev->pdev->device == 0x6665)) + banks2_fw = true; new_chip_name = "hainan"; pfp_req_size = SI_PFP_UCODE_SIZE * 4; me_req_size = SI_PM4_UCODE_SIZE * 4; @@ -1746,6 +1748,10 @@ static int si_init_microcode(struct radeon_device *rdev) default: BUG(); } + /* this memory configuration requires special firmware */ + if (((RREG32(MC_SEQ_MISC0) & 0xff000000) >> 24) == 0x58) + si58_fw = true; + DRM_INFO("Loading %s Microcode\n", new_chip_name); snprintf(fw_name, sizeof(fw_name), "radeon/%s_pfp.bin", new_chip_name); @@ -1849,7 +1855,10 @@ static int si_init_microcode(struct radeon_device *rdev) } } - snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); + if (si58_fw) + snprintf(fw_name, sizeof(fw_name), "radeon/si58_mc.bin"); + else + snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc.bin", new_chip_name); err = request_firmware(&rdev->mc_fw, fw_name, rdev->dev); if (err) { snprintf(fw_name, sizeof(fw_name), "radeon/%s_mc2.bin", chip_name); @@ -1880,7 +1889,9 @@ static int si_init_microcode(struct radeon_device *rdev) } } - if (new_smc) + if (banks2_fw) + snprintf(fw_name, sizeof(fw_name), "radeon/banks_k_2_smc.bin"); + else if (new_smc) snprintf(fw_name, sizeof(fw_name), "radeon/%s_k_smc.bin", new_chip_name); else snprintf(fw_name, sizeof(fw_name), "radeon/%s_smc.bin", new_chip_name); diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 8b5e697f2549..2944916f7102 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -3008,30 +3008,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, (rdev->pdev->device == 0x6817) || (rdev->pdev->device == 0x6806)) max_mclk = 120000; - } else if (rdev->family == CHIP_VERDE) { - if ((rdev->pdev->revision == 0x81) || - (rdev->pdev->revision == 0x83) || - (rdev->pdev->revision == 0x87) || - (rdev->pdev->device == 0x6820) || - (rdev->pdev->device == 0x6821) || - (rdev->pdev->device == 0x6822) || - (rdev->pdev->device == 0x6823) || - (rdev->pdev->device == 0x682A) || - (rdev->pdev->device == 0x682B)) { - max_sclk = 75000; - max_mclk = 80000; - } - } else if (rdev->family == CHIP_OLAND) { - if ((rdev->pdev->revision == 0xC7) || - (rdev->pdev->revision == 0x80) || - (rdev->pdev->revision == 0x81) || - (rdev->pdev->revision == 0x83) || - (rdev->pdev->revision == 0x87) || - (rdev->pdev->device == 0x6604) || - (rdev->pdev->device == 0x6605)) { - max_sclk = 75000; - max_mclk = 80000; - } } else if (rdev->family == CHIP_HAINAN) { if ((rdev->pdev->revision == 0x81) || (rdev->pdev->revision == 0x83) || @@ -3040,7 +3016,6 @@ static void si_apply_state_adjust_rules(struct radeon_device *rdev, (rdev->pdev->device == 0x6665) || (rdev->pdev->device == 0x6667)) { max_sclk = 75000; - max_mclk = 80000; } } /* Apply dpm quirks */ diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 725dffad5640..6dfdb145f3bb 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -856,7 +856,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; - uint32_t stat; + uint32_t stat, reg; stat = tilcdc_read_irqstatus(dev); tilcdc_clear_irqstatus(dev, stat); @@ -921,17 +921,26 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost", __func__, stat); tilcdc_crtc->frame_intact = false; - if (tilcdc_crtc->sync_lost_count++ > - SYNC_LOST_COUNT_LIMIT) { - dev_err(dev->dev, "%s(0x%08x): Sync lost flood detected, recovering", __func__, stat); - queue_work(system_wq, &tilcdc_crtc->recover_work); - if (priv->rev == 1) + if (priv->rev == 1) { + reg = tilcdc_read(dev, LCDC_RASTER_CTRL_REG); + if (reg & LCDC_RASTER_ENABLE) { tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, - LCDC_V1_SYNC_LOST_INT_ENA); - else + LCDC_RASTER_ENABLE); + tilcdc_set(dev, LCDC_RASTER_CTRL_REG, + LCDC_RASTER_ENABLE); + } + } else { + if (tilcdc_crtc->sync_lost_count++ > + SYNC_LOST_COUNT_LIMIT) { + dev_err(dev->dev, + "%s(0x%08x): Sync lost flood detected, recovering", + __func__, stat); + queue_work(system_wq, + &tilcdc_crtc->recover_work); tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, LCDC_SYNC_LOST); - tilcdc_crtc->sync_lost_count = 0; + tilcdc_crtc->sync_lost_count = 0; + } } } diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index d5063618efa7..ffc6cb55c78c 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -140,8 +140,8 @@ static void ttm_bo_release_list(struct kref *list_kref) struct ttm_bo_device *bdev = bo->bdev; size_t acc_size = bo->acc_size; - BUG_ON(atomic_read(&bo->list_kref.refcount)); - BUG_ON(atomic_read(&bo->kref.refcount)); + BUG_ON(kref_read(&bo->list_kref)); + BUG_ON(kref_read(&bo->kref)); BUG_ON(atomic_read(&bo->cpu_writers)); BUG_ON(bo->mem.mm_node != NULL); BUG_ON(!list_empty(&bo->lru)); @@ -181,61 +181,46 @@ void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) } EXPORT_SYMBOL(ttm_bo_add_to_lru); -int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) +static void ttm_bo_ref_bug(struct kref *list_kref) +{ + BUG(); +} + +void ttm_bo_del_from_lru(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; - int put_count = 0; if (bdev->driver->lru_removal) bdev->driver->lru_removal(bo); if (!list_empty(&bo->swap)) { list_del_init(&bo->swap); - ++put_count; + kref_put(&bo->list_kref, ttm_bo_ref_bug); } if (!list_empty(&bo->lru)) { list_del_init(&bo->lru); - ++put_count; + kref_put(&bo->list_kref, ttm_bo_ref_bug); } - - return put_count; -} - -static void ttm_bo_ref_bug(struct kref *list_kref) -{ - BUG(); -} - -void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, - bool never_free) -{ - kref_sub(&bo->list_kref, count, - (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list); } void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo) { - int put_count; - spin_lock(&bo->glob->lru_lock); - put_count = ttm_bo_del_from_lru(bo); + ttm_bo_del_from_lru(bo); spin_unlock(&bo->glob->lru_lock); - ttm_bo_list_ref_sub(bo, put_count, true); } EXPORT_SYMBOL(ttm_bo_del_sub_from_lru); void ttm_bo_move_to_lru_tail(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; - int put_count = 0; lockdep_assert_held(&bo->resv->lock.base); if (bdev->driver->lru_removal) bdev->driver->lru_removal(bo); - put_count = ttm_bo_del_from_lru(bo); - ttm_bo_list_ref_sub(bo, put_count, true); + ttm_bo_del_from_lru(bo); ttm_bo_add_to_lru(bo); } EXPORT_SYMBOL(ttm_bo_move_to_lru_tail); @@ -447,7 +432,6 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) { struct ttm_bo_device *bdev = bo->bdev; struct ttm_bo_global *glob = bo->glob; - int put_count; int ret; spin_lock(&glob->lru_lock); @@ -455,13 +439,10 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) if (!ret) { if (!ttm_bo_wait(bo, false, true)) { - put_count = ttm_bo_del_from_lru(bo); - + ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); ttm_bo_cleanup_memtype_use(bo); - ttm_bo_list_ref_sub(bo, put_count, true); - return; } else ttm_bo_flush_all_fences(bo); @@ -504,7 +485,6 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, bool no_wait_gpu) { struct ttm_bo_global *glob = bo->glob; - int put_count; int ret; ret = ttm_bo_wait(bo, false, true); @@ -554,15 +534,13 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, return ret; } - put_count = ttm_bo_del_from_lru(bo); + ttm_bo_del_from_lru(bo); list_del_init(&bo->ddestroy); - ++put_count; + kref_put(&bo->list_kref, ttm_bo_ref_bug); spin_unlock(&glob->lru_lock); ttm_bo_cleanup_memtype_use(bo); - ttm_bo_list_ref_sub(bo, put_count, true); - return 0; } @@ -740,7 +718,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, struct ttm_bo_global *glob = bdev->glob; struct ttm_mem_type_manager *man = &bdev->man[mem_type]; struct ttm_buffer_object *bo; - int ret = -EBUSY, put_count; + int ret = -EBUSY; spin_lock(&glob->lru_lock); list_for_each_entry(bo, &man->lru, lru) { @@ -771,13 +749,11 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, return ret; } - put_count = ttm_bo_del_from_lru(bo); + ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); BUG_ON(ret != 0); - ttm_bo_list_ref_sub(bo, put_count, true); - ret = ttm_bo_evict(bo, interruptible, no_wait_gpu); ttm_bo_unreserve(bo); @@ -1669,7 +1645,6 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) container_of(shrink, struct ttm_bo_global, shrink); struct ttm_buffer_object *bo; int ret = -EBUSY; - int put_count; uint32_t swap_placement = (TTM_PL_FLAG_CACHED | TTM_PL_FLAG_SYSTEM); spin_lock(&glob->lru_lock); @@ -1692,11 +1667,9 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) return ret; } - put_count = ttm_bo_del_from_lru(bo); + ttm_bo_del_from_lru(bo); spin_unlock(&glob->lru_lock); - ttm_bo_list_ref_sub(bo, put_count, true); - /** * Move to system cached */ diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index d35bc491e8de..5e1bcabffef5 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -48,9 +48,7 @@ static void ttm_eu_del_from_lru_locked(struct list_head *list) list_for_each_entry(entry, list, head) { struct ttm_buffer_object *bo = entry->bo; - unsigned put_count = ttm_bo_del_from_lru(bo); - - ttm_bo_list_ref_sub(bo, put_count, true); + ttm_bo_del_from_lru(bo); } } diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 4f5fa8d65fe9..fdb451e3ec01 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -304,7 +304,7 @@ bool ttm_ref_object_exists(struct ttm_object_file *tfile, * Verify that the ref->obj pointer was actually valid! */ rmb(); - if (unlikely(atomic_read(&ref->kref.refcount) == 0)) + if (unlikely(kref_read(&ref->kref) == 0)) goto out_false; rcu_read_unlock(); diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index a0fd3e66bc4b..7aadce1f7e7a 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -839,7 +839,7 @@ static void vc4_crtc_destroy_state(struct drm_crtc *crtc, } - __drm_atomic_helper_crtc_destroy_state(state); + drm_atomic_helper_crtc_destroy_state(crtc, state); } static const struct drm_crtc_funcs vc4_crtc_funcs = { diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index db920771bfb5..ab3016982466 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -594,12 +594,14 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec) args->shader_rec_count); struct vc4_bo *bo; - if (uniforms_offset < shader_rec_offset || + if (shader_rec_offset < args->bin_cl_size || + uniforms_offset < shader_rec_offset || exec_size < uniforms_offset || args->shader_rec_count >= (UINT_MAX / sizeof(struct vc4_shader_state)) || temp_size < exec_size) { DRM_ERROR("overflow in exec arguments\n"); + ret = -EINVAL; goto fail; } diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c index 881bf489478b..686cdd3c86f2 100644 --- a/drivers/gpu/drm/vc4/vc4_plane.c +++ b/drivers/gpu/drm/vc4/vc4_plane.c @@ -858,7 +858,7 @@ struct drm_plane *vc4_plane_init(struct drm_device *dev, } } plane = &vc4_plane->base; - ret = drm_universal_plane_init(dev, plane, 0xff, + ret = drm_universal_plane_init(dev, plane, 0, &vc4_plane_funcs, formats, num_formats, type, NULL); diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c index 08886a309757..5cdd003605f5 100644 --- a/drivers/gpu/drm/vc4/vc4_render_cl.c +++ b/drivers/gpu/drm/vc4/vc4_render_cl.c @@ -461,7 +461,7 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec, } ret = vc4_full_res_bounds_check(exec, *obj, surf); - if (!ret) + if (ret) return ret; return 0; diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index dd21f950e129..cde9f3758106 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -331,7 +331,7 @@ static int virtio_gpufb_create(struct drm_fb_helper *helper, info->fbops = &virtio_gpufb_ops; info->pixmap.flags = FB_PIXMAP_SYSTEM; - info->screen_base = obj->vmap; + info->screen_buffer = obj->vmap; info->screen_size = obj->gem_base.size; drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(info, &vfbdev->helper, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 723fd763da8e..7a96798b9c0a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -481,8 +481,7 @@ static int vmw_fb_kms_framebuffer(struct fb_info *info) mode_cmd.height = var->yres; mode_cmd.pitches[0] = ((var->bits_per_pixel + 7) / 8) * mode_cmd.width; mode_cmd.pixel_format = - drm_mode_legacy_fb_format(var->bits_per_pixel, - ((var->bits_per_pixel + 7) / 8) * mode_cmd.width); + drm_mode_legacy_fb_format(var->bits_per_pixel, depth); cur_fb = par->set_fb; if (cur_fb && cur_fb->width == mode_cmd.width && diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4070b7386e9d..1aeb80e52424 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -785,6 +785,11 @@ config HID_SUNPLUS config HID_RMI tristate "Synaptics RMI4 device support" depends on HID + select RMI4_CORE + select RMI4_F03 + select RMI4_F11 + select RMI4_F12 + select RMI4_F30 ---help--- Support for Synaptics RMI4 touchpads. Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index d40ed9fdf68d..70b12f89a193 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -64,7 +64,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_SKIP_INPUT_MAPPING BIT(2) #define QUIRK_IS_MULTITOUCH BIT(3) -#define NOTEBOOK_QUIRKS QUIRK_FIX_NOTEBOOK_REPORT +#define KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ + QUIRK_NO_INIT_REPORTS) #define TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \ QUIRK_SKIP_INPUT_MAPPING | \ QUIRK_IS_MULTITOUCH) @@ -170,11 +171,11 @@ static int asus_raw_event(struct hid_device *hdev, static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) { + struct input_dev *input = hi->input; struct asus_drvdata *drvdata = hid_get_drvdata(hdev); if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { int ret; - struct input_dev *input = hi->input; input_set_abs_params(input, ABS_MT_POSITION_X, 0, MAX_X, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0); @@ -191,10 +192,10 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) hid_err(hdev, "Asus input mt init slots failed: %d\n", ret); return ret; } - - drvdata->input = input; } + drvdata->input = input; + return 0; } @@ -286,7 +287,11 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop_hw; } - drvdata->input->name = "Asus TouchPad"; + if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { + drvdata->input->name = "Asus TouchPad"; + } else { + drvdata->input->name = "Asus Keyboard"; + } if (drvdata->quirks & QUIRK_IS_MULTITOUCH) { ret = asus_start_multitouch(hdev); @@ -315,7 +320,7 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id asus_devices[] = { { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD), NOTEBOOK_QUIRKS}, + USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD), KEYBOARD_QUIRKS}, { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_TOUCHPAD), TOUCHPAD_QUIRKS }, { } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index cff060b56da9..538ff697a4cf 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -43,7 +43,6 @@ */ #define DRIVER_DESC "HID core driver" -#define DRIVER_LICENSE "GPL" int hid_debug = 0; module_param_named(debug, hid_debug, int, 0600); @@ -724,13 +723,7 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP || - hid->product == USB_DEVICE_ID_MS_POWER_COVER) && + hid->product == USB_DEVICE_ID_MS_POWER_COVER && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -826,7 +819,8 @@ static int hid_scan_report(struct hid_device *hid) hid->group = HID_GROUP_WACOM; break; case USB_VENDOR_ID_SYNAPTICS: - if (hid->group == HID_GROUP_GENERIC) + if (hid->group == HID_GROUP_GENERIC || + hid->group == HID_GROUP_MULTITOUCH_WIN_8) if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC) && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER)) /* @@ -1887,6 +1881,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, #if IS_ENABLED(CONFIG_HID_MAYFLASH) { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) }, #endif { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) }, @@ -1933,6 +1930,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, #endif + { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MELFAS_MT) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, @@ -1985,12 +1983,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, @@ -2126,6 +2118,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, { } }; @@ -2314,7 +2307,7 @@ __ATTRIBUTE_GROUPS(hid_dev); static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct hid_device *hdev = to_hid_device(dev); + struct hid_device *hdev = to_hid_device(dev); if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X", hdev->bus, hdev->vendor, hdev->product)) @@ -2496,6 +2489,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) }, { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PETZL, USB_DEVICE_ID_PETZL_HEADLAMP) }, { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, #if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB) @@ -2866,5 +2860,5 @@ module_exit(hid_exit); MODULE_AUTHOR("Andreas Gal"); MODULE_AUTHOR("Vojtech Pavlik"); MODULE_AUTHOR("Jiri Kosina"); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-corsair.c b/drivers/hid/hid-corsair.c index 717704e9ae07..c0303f61c26a 100644 --- a/drivers/hid/hid-corsair.c +++ b/drivers/hid/hid-corsair.c @@ -148,26 +148,36 @@ static enum led_brightness k90_backlight_get(struct led_classdev *led_cdev) struct usb_interface *usbif = to_usb_interface(dev->parent); struct usb_device *usbdev = interface_to_usbdev(usbif); int brightness; - char data[8]; + char *data; + + data = kmalloc(8, GFP_KERNEL); + if (!data) + return -ENOMEM; ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), K90_REQUEST_STATUS, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, data, 8, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { + if (ret < 5) { dev_warn(dev, "Failed to get K90 initial state (error %d).\n", ret); - return -EIO; + ret = -EIO; + goto out; } brightness = data[4]; if (brightness < 0 || brightness > 3) { dev_warn(dev, "Read invalid backlight brightness: %02hhx.\n", data[4]); - return -EIO; + ret = -EIO; + goto out; } - return brightness; + ret = brightness; +out: + kfree(data); + + return ret; } static enum led_brightness k90_record_led_get(struct led_classdev *led_cdev) @@ -253,17 +263,22 @@ static ssize_t k90_show_macro_mode(struct device *dev, struct usb_interface *usbif = to_usb_interface(dev->parent); struct usb_device *usbdev = interface_to_usbdev(usbif); const char *macro_mode; - char data[8]; + char *data; + + data = kmalloc(2, GFP_KERNEL); + if (!data) + return -ENOMEM; ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), K90_REQUEST_GET_MODE, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, data, 2, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { + if (ret < 1) { dev_warn(dev, "Failed to get K90 initial mode (error %d).\n", ret); - return -EIO; + ret = -EIO; + goto out; } switch (data[0]) { @@ -277,10 +292,15 @@ static ssize_t k90_show_macro_mode(struct device *dev, default: dev_warn(dev, "K90 in unknown mode: %02hhx.\n", data[0]); - return -EIO; + ret = -EIO; + goto out; } - return snprintf(buf, PAGE_SIZE, "%s\n", macro_mode); + ret = snprintf(buf, PAGE_SIZE, "%s\n", macro_mode); +out: + kfree(data); + + return ret; } static ssize_t k90_store_macro_mode(struct device *dev, @@ -320,26 +340,36 @@ static ssize_t k90_show_current_profile(struct device *dev, struct usb_interface *usbif = to_usb_interface(dev->parent); struct usb_device *usbdev = interface_to_usbdev(usbif); int current_profile; - char data[8]; + char *data; + + data = kmalloc(8, GFP_KERNEL); + if (!data) + return -ENOMEM; ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), K90_REQUEST_STATUS, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, 0, data, 8, USB_CTRL_SET_TIMEOUT); - if (ret < 0) { + if (ret < 8) { dev_warn(dev, "Failed to get K90 initial state (error %d).\n", ret); - return -EIO; + ret = -EIO; + goto out; } current_profile = data[7]; if (current_profile < 1 || current_profile > 3) { dev_warn(dev, "Read invalid current profile: %02hhx.\n", data[7]); - return -EIO; + ret = -EIO; + goto out; } - return snprintf(buf, PAGE_SIZE, "%d\n", current_profile); + ret = snprintf(buf, PAGE_SIZE, "%d\n", current_profile); +out: + kfree(data); + + return ret; } static ssize_t k90_store_current_profile(struct device *dev, diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index f31a778b0851..b22d0f83f8e3 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -168,7 +168,7 @@ struct cp2112_device { atomic_t xfer_avail; struct gpio_chip gc; u8 *in_out_buffer; - spinlock_t lock; + struct mutex lock; struct gpio_desc *desc[8]; bool gpio_poll; @@ -186,10 +186,9 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) struct cp2112_device *dev = gpiochip_get_data(chip); struct hid_device *hdev = dev->hdev; u8 *buf = dev->in_out_buffer; - unsigned long flags; int ret; - spin_lock_irqsave(&dev->lock, flags); + mutex_lock(&dev->lock); ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, @@ -213,8 +212,8 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ret = 0; exit: - spin_unlock_irqrestore(&dev->lock, flags); - return ret <= 0 ? ret : -EIO; + mutex_unlock(&dev->lock); + return ret < 0 ? ret : -EIO; } static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) @@ -222,10 +221,9 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) struct cp2112_device *dev = gpiochip_get_data(chip); struct hid_device *hdev = dev->hdev; u8 *buf = dev->in_out_buffer; - unsigned long flags; int ret; - spin_lock_irqsave(&dev->lock, flags); + mutex_lock(&dev->lock); buf[0] = CP2112_GPIO_SET; buf[1] = value ? 0xff : 0; @@ -237,7 +235,7 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value) if (ret < 0) hid_err(hdev, "error setting GPIO values: %d\n", ret); - spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock); } static int cp2112_gpio_get_all(struct gpio_chip *chip) @@ -245,10 +243,9 @@ static int cp2112_gpio_get_all(struct gpio_chip *chip) struct cp2112_device *dev = gpiochip_get_data(chip); struct hid_device *hdev = dev->hdev; u8 *buf = dev->in_out_buffer; - unsigned long flags; int ret; - spin_lock_irqsave(&dev->lock, flags); + mutex_lock(&dev->lock); ret = hid_hw_raw_request(hdev, CP2112_GPIO_GET, buf, CP2112_GPIO_GET_LENGTH, HID_FEATURE_REPORT, @@ -262,7 +259,7 @@ static int cp2112_gpio_get_all(struct gpio_chip *chip) ret = buf[1]; exit: - spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock); return ret; } @@ -284,10 +281,9 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip, struct cp2112_device *dev = gpiochip_get_data(chip); struct hid_device *hdev = dev->hdev; u8 *buf = dev->in_out_buffer; - unsigned long flags; int ret; - spin_lock_irqsave(&dev->lock, flags); + mutex_lock(&dev->lock); ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, @@ -308,7 +304,7 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip, goto fail; } - spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock); /* * Set gpio value when output direction is already set, @@ -319,7 +315,7 @@ static int cp2112_gpio_direction_output(struct gpio_chip *chip, return 0; fail: - spin_unlock_irqrestore(&dev->lock, flags); + mutex_unlock(&dev->lock); return ret < 0 ? ret : -EIO; } @@ -1235,7 +1231,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!dev->in_out_buffer) return -ENOMEM; - spin_lock_init(&dev->lock); + mutex_init(&dev->lock); ret = hid_parse(hdev); if (ret) { diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index 1b764d1745f3..1689568b597d 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -39,6 +39,9 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) return rdesc; + if (*rsize < 4) + return rdesc; + for (i = 0; i < *rsize - 4; i++) if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { rdesc[i] = 0x19; diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ec277b96eaa1..86c95d30ac80 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -76,6 +76,9 @@ #define USB_VENDOR_ID_ALPS_JP 0x044E #define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B +#define USB_VENDOR_ID_AMI 0x046b +#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE 0xff10 + #define USB_VENDOR_ID_ANTON 0x1130 #define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 @@ -319,7 +322,9 @@ #define USB_VENDOR_ID_DRAGONRISE 0x0079 #define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800 #define USB_DEVICE_ID_DRAGONRISE_PS3 0x1801 -#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE 0x1843 +#define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803 +#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843 +#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844 #define USB_VENDOR_ID_DWAV 0x0eef #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 @@ -365,6 +370,9 @@ #define USB_VENDOR_ID_FLATFROG 0x25b5 #define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 +#define USB_VENDOR_ID_FUTABA 0x0547 +#define USB_DEVICE_ID_LED_DISPLAY 0x7000 + #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 @@ -623,9 +631,11 @@ #define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047 #define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 +#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_VENDOR_ID_LG 0x1fd2 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 +#define USB_DEVICE_ID_LG_MELFAS_MT 0x6007 #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e @@ -718,12 +728,6 @@ #define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e4 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 0x07e8 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9 #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 @@ -812,6 +816,9 @@ #define USB_VENDOR_ID_PETALYNX 0x18b1 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 +#define USB_VENDOR_ID_PETZL 0x2122 +#define USB_DEVICE_ID_PETZL_HEADLAMP 0x1234 + #define USB_VENDOR_ID_PHILIPS 0x0471 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index c5c5fbe9d605..52026dc94d5c 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -872,7 +872,7 @@ static const struct hid_device_id lg_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG), .driver_data = LG_NOGET | LG_FF4 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2), - .driver_data = LG_FF2 }, + .driver_data = LG_NOGET | LG_FF2 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940), .driver_data = LG_FF3 }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR), diff --git a/drivers/hid/hid-mf.c b/drivers/hid/hid-mf.c index d9090765a6e5..03f10516131d 100644 --- a/drivers/hid/hid-mf.c +++ b/drivers/hid/hid-mf.c @@ -6,12 +6,14 @@ * * Tested with: * 0079:1801 "DragonRise Inc. Mayflash PS3 Game Controller Adapter" + * 0079:1803 "DragonRise Inc. Mayflash Wireless Sensor DolphinBar" + * 0079:1843 "DragonRise Inc. Mayflash GameCube Game Controller Adapter" + * 0079:1844 "DragonRise Inc. Mayflash GameCube Game Controller Adapter (v04)" * * The following adapters probably work too, but need to be tested: * 0079:1800 "DragonRise Inc. Mayflash WIIU Game Controller Adapter" - * 0079:1843 "DragonRise Inc. Mayflash GameCube Game Controller Adapter" * - * Copyright (c) 2016 Marcel Hasler <mahasler@gmail.com> + * Copyright (c) 2016-2017 Marcel Hasler <mahasler@gmail.com> */ /* @@ -125,8 +127,8 @@ static int mf_probe(struct hid_device *hid, const struct hid_device_id *id) dev_dbg(&hid->dev, "Mayflash HID hardware probe...\n"); - /* Split device into four inputs */ - hid->quirks |= HID_QUIRK_MULTI_INPUT; + /* Apply quirks as needed */ + hid->quirks |= id->driver_data; error = hid_parse(hid); if (error) { @@ -151,7 +153,14 @@ static int mf_probe(struct hid_device *hid, const struct hid_device_id *id) } static const struct hid_device_id mf_devices[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), + .driver_data = HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), + .driver_data = HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), + .driver_data = HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2), + .driver_data = 0 }, /* No quirk required */ { } }; MODULE_DEVICE_TABLE(hid, mf_devices); diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 74b7b84a0420..96e7d3231d2f 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -274,18 +274,6 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2), - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4), - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2), - .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP), - .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6dca66806844..692647485a53 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -68,6 +68,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_HOVERING (1 << 11) #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) #define MT_QUIRK_FORCE_GET_FEATURE (1 << 13) +#define MT_QUIRK_FIX_CONST_CONTACT_ID (1 << 14) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -157,6 +158,7 @@ static void mt_post_parse(struct mt_device *td); #define MT_CLS_FLATFROG 0x0107 #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 +#define MT_CLS_LG 0x010a #define MT_CLS_VTL 0x0110 #define MT_DEFAULT_MAXCONTACT 10 @@ -263,6 +265,12 @@ static struct mt_class mt_classes[] = { .sn_move = 2048, .maxcontacts = 40, }, + { .name = MT_CLS_LG, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_FIX_CONST_CONTACT_ID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | + MT_QUIRK_CONTACT_CNT_ACCURATE }, { .name = MT_CLS_VTL, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE | @@ -1078,6 +1086,34 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) return 0; } +static void mt_fix_const_field(struct hid_field *field, unsigned int usage) +{ + if (field->usage[0].hid != usage || + !(field->flags & HID_MAIN_ITEM_CONSTANT)) + return; + + field->flags &= ~HID_MAIN_ITEM_CONSTANT; + field->flags |= HID_MAIN_ITEM_VARIABLE; +} + +static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) +{ + struct hid_report *report; + int i; + + list_for_each_entry(report, + &hdev->report_enum[HID_INPUT_REPORT].report_list, + list) { + + if (!report->maxfield) + continue; + + for (i = 0; i < report->maxfield; i++) + if (report->field[i]->maxusage >= 1) + mt_fix_const_field(report->field[i], usage); + } +} + static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) { int ret, i; @@ -1151,6 +1187,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret != 0) return ret; + if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) + mt_fix_const_fields(hdev, HID_DG_CONTACTID); + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) return ret; @@ -1398,6 +1437,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, + /* LG Melfas panel */ + { .driver_data = MT_CLS_LG, + HID_USB_DEVICE(USB_VENDOR_ID_LG, + USB_DEVICE_ID_LG_MELFAS_MT) }, + /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, MT_USB_DEVICE(USB_VENDOR_ID_ASUS, diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index be89bcbf6a71..5b40c2614599 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -14,11 +14,14 @@ #include <linux/hid.h> #include <linux/input.h> #include <linux/input/mt.h> +#include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/module.h> #include <linux/pm.h> #include <linux/slab.h> #include <linux/wait.h> #include <linux/sched.h> +#include <linux/rmi.h> #include "hid-ids.h" #define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */ @@ -33,9 +36,6 @@ #define RMI_READ_DATA_PENDING 1 #define RMI_STARTED 2 -#define RMI_SLEEP_NORMAL 0x0 -#define RMI_SLEEP_DEEP_SLEEP 0x1 - /* device flags */ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) @@ -54,25 +54,12 @@ enum rmi_mode_type { RMI_MODE_NO_PACKED_ATTN_REPORTS = 2, }; -struct rmi_function { - unsigned page; /* page of the function */ - u16 query_base_addr; /* base address for queries */ - u16 command_base_addr; /* base address for commands */ - u16 control_base_addr; /* base address for controls */ - u16 data_base_addr; /* base address for datas */ - unsigned int interrupt_base; /* cross-function interrupt number - * (uniq in the device)*/ - unsigned int interrupt_count; /* number of interrupts */ - unsigned int report_size; /* size of a report */ - unsigned long irq_mask; /* mask of the interrupts - * (to be applied against ATTN IRQ) */ -}; - /** * struct rmi_data - stores information for hid communication * * @page_mutex: Locks current page to avoid changing pages in unexpected ways. * @page: Keeps track of the current virtual page + * @xport: transport device to be registered with the RMI4 core. * * @wait: Used for waiting for read data * @@ -84,26 +71,18 @@ struct rmi_function { * * @flags: flags for the current device (started, reading, etc...) * - * @f11: placeholder of internal RMI function F11 description - * @f30: placeholder of internal RMI function F30 description - * - * @max_fingers: maximum finger count reported by the device - * @max_x: maximum x value reported by the device - * @max_y: maximum y value reported by the device - * - * @gpio_led_count: count of GPIOs + LEDs reported by F30 - * @button_count: actual physical buttons count - * @button_mask: button mask used to decode GPIO ATTN reports - * @button_state_mask: pull state of the buttons - * - * @input: pointer to the kernel input device - * * @reset_work: worker which will be called in case of a mouse report * @hdev: pointer to the struct hid_device + * + * @device_flags: flags which describe the device + * + * @domain: the IRQ domain allocated for this RMI4 device + * @rmi_irq: the irq that will be used to generate events to rmi-core */ struct rmi_data { struct mutex page_mutex; int page; + struct rmi_transport_dev xport; wait_queue_head_t wait; @@ -115,34 +94,13 @@ struct rmi_data { unsigned long flags; - struct rmi_function f01; - struct rmi_function f11; - struct rmi_function f30; - - unsigned int max_fingers; - unsigned int max_x; - unsigned int max_y; - unsigned int x_size_mm; - unsigned int y_size_mm; - bool read_f11_ctrl_regs; - u8 f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT]; - - unsigned int gpio_led_count; - unsigned int button_count; - unsigned long button_mask; - unsigned long button_state_mask; - - struct input_dev *input; - struct work_struct reset_work; struct hid_device *hdev; unsigned long device_flags; - unsigned long firmware_id; - u8 f01_ctrl0; - u8 interrupt_enable_mask; - bool restore_interrupt_mask; + struct irq_domain *domain; + int rmi_irq; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -220,10 +178,11 @@ static int rmi_write_report(struct hid_device *hdev, u8 *report, int len) return ret; } -static int rmi_read_block(struct hid_device *hdev, u16 addr, void *buf, - const int len) +static int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr, + void *buf, size_t len) { - struct rmi_data *data = hid_get_drvdata(hdev); + struct rmi_data *data = container_of(xport, struct rmi_data, xport); + struct hid_device *hdev = data->hdev; int ret; int bytes_read; int bytes_needed; @@ -292,15 +251,11 @@ exit: return ret; } -static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf) -{ - return rmi_read_block(hdev, addr, buf, 1); -} - -static int rmi_write_block(struct hid_device *hdev, u16 addr, void *buf, - const int len) +static int rmi_hid_write_block(struct rmi_transport_dev *xport, u16 addr, + const void *buf, size_t len) { - struct rmi_data *data = hid_get_drvdata(hdev); + struct rmi_data *data = container_of(xport, struct rmi_data, xport); + struct hid_device *hdev = data->hdev; int ret; mutex_lock(&data->page_mutex); @@ -332,62 +287,20 @@ exit: return ret; } -static inline int rmi_write(struct hid_device *hdev, u16 addr, void *buf) -{ - return rmi_write_block(hdev, addr, buf, 1); -} - -static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, - u8 finger_state, u8 *touch_data) -{ - int x, y, wx, wy; - int wide, major, minor; - int z; - - input_mt_slot(hdata->input, slot); - input_mt_report_slot_state(hdata->input, MT_TOOL_FINGER, - finger_state == 0x01); - if (finger_state == 0x01) { - x = (touch_data[0] << 4) | (touch_data[2] & 0x0F); - y = (touch_data[1] << 4) | (touch_data[2] >> 4); - wx = touch_data[3] & 0x0F; - wy = touch_data[3] >> 4; - wide = (wx > wy); - major = max(wx, wy); - minor = min(wx, wy); - z = touch_data[4]; - - /* y is inverted */ - y = hdata->max_y - y; - - input_event(hdata->input, EV_ABS, ABS_MT_POSITION_X, x); - input_event(hdata->input, EV_ABS, ABS_MT_POSITION_Y, y); - input_event(hdata->input, EV_ABS, ABS_MT_ORIENTATION, wide); - input_event(hdata->input, EV_ABS, ABS_MT_PRESSURE, z); - input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); - input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); - } -} - static int rmi_reset_attn_mode(struct hid_device *hdev) { struct rmi_data *data = hid_get_drvdata(hdev); + struct rmi_device *rmi_dev = data->xport.rmi_dev; int ret; ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); if (ret) return ret; - if (data->restore_interrupt_mask) { - ret = rmi_write(hdev, data->f01.control_base_addr + 1, - &data->interrupt_enable_mask); - if (ret) { - hid_err(hdev, "can not write F01 control register\n"); - return ret; - } - } + if (test_bit(RMI_STARTED, &data->flags)) + ret = rmi_dev->driver->reset_handler(rmi_dev); - return 0; + return ret; } static void rmi_reset_work(struct work_struct *work) @@ -399,102 +312,22 @@ static void rmi_reset_work(struct work_struct *work) rmi_reset_attn_mode(hdata->hdev); } -static inline int rmi_schedule_reset(struct hid_device *hdev) -{ - struct rmi_data *hdata = hid_get_drvdata(hdev); - return schedule_work(&hdata->reset_work); -} - -static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data, - int size) -{ - struct rmi_data *hdata = hid_get_drvdata(hdev); - int offset; - int i; - - if (!(irq & hdata->f11.irq_mask) || size <= 0) - return 0; - - offset = (hdata->max_fingers >> 2) + 1; - for (i = 0; i < hdata->max_fingers; i++) { - int fs_byte_position = i >> 2; - int fs_bit_position = (i & 0x3) << 1; - int finger_state = (data[fs_byte_position] >> fs_bit_position) & - 0x03; - int position = offset + 5 * i; - - if (position + 5 > size) { - /* partial report, go on with what we received */ - printk_once(KERN_WARNING - "%s %s: Detected incomplete finger report. Finger reports may occasionally get dropped on this platform.\n", - dev_driver_string(&hdev->dev), - dev_name(&hdev->dev)); - hid_dbg(hdev, "Incomplete finger report\n"); - break; - } - - rmi_f11_process_touch(hdata, i, finger_state, &data[position]); - } - input_mt_sync_frame(hdata->input); - input_sync(hdata->input); - return hdata->f11.report_size; -} - -static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data, - int size) +static int rmi_input_event(struct hid_device *hdev, u8 *data, int size) { struct rmi_data *hdata = hid_get_drvdata(hdev); - int i; - int button = 0; - bool value; + struct rmi_device *rmi_dev = hdata->xport.rmi_dev; + unsigned long flags; - if (!(irq & hdata->f30.irq_mask)) + if (!(test_bit(RMI_STARTED, &hdata->flags))) return 0; - if (size < (int)hdata->f30.report_size) { - hid_warn(hdev, "Click Button pressed, but the click data is missing\n"); - return 0; - } + local_irq_save(flags); - for (i = 0; i < hdata->gpio_led_count; i++) { - if (test_bit(i, &hdata->button_mask)) { - value = (data[i / 8] >> (i & 0x07)) & BIT(0); - if (test_bit(i, &hdata->button_state_mask)) - value = !value; - input_event(hdata->input, EV_KEY, BTN_LEFT + button++, - value); - } - } - return hdata->f30.report_size; -} - -static int rmi_input_event(struct hid_device *hdev, u8 *data, int size) -{ - struct rmi_data *hdata = hid_get_drvdata(hdev); - unsigned long irq_mask = 0; - unsigned index = 2; + rmi_set_attn_data(rmi_dev, data[1], &data[2], size - 2); - if (!(test_bit(RMI_STARTED, &hdata->flags))) - return 0; + generic_handle_irq(hdata->rmi_irq); - irq_mask |= hdata->f11.irq_mask; - irq_mask |= hdata->f30.irq_mask; - - if (data[1] & ~irq_mask) - hid_dbg(hdev, "unknown intr source:%02lx %s:%d\n", - data[1] & ~irq_mask, __FILE__, __LINE__); - - if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) { - index += rmi_f11_input_event(hdev, data[1], &data[index], - size - index); - index += rmi_f30_input_event(hdev, data[1], &data[index], - size - index); - } else { - index += rmi_f30_input_event(hdev, data[1], &data[index], - size - index); - index += rmi_f11_input_event(hdev, data[1], &data[index], - size - index); - } + local_irq_restore(flags); return 1; } @@ -568,7 +401,7 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, return 1; } - rmi_schedule_reset(hdev); + schedule_work(&data->reset_work); return 1; } @@ -576,637 +409,71 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, } #ifdef CONFIG_PM -static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) -{ - struct rmi_data *data = hid_get_drvdata(hdev); - int ret; - u8 f01_ctrl0; - - f01_ctrl0 = (data->f01_ctrl0 & ~0x3) | sleep_mode; - - ret = rmi_write(hdev, data->f01.control_base_addr, - &f01_ctrl0); - if (ret) { - hid_err(hdev, "can not write sleep mode\n"); - return ret; - } - - return 0; -} - static int rmi_suspend(struct hid_device *hdev, pm_message_t message) { struct rmi_data *data = hid_get_drvdata(hdev); - int ret; - u8 buf[RMI_F11_CTRL_REG_COUNT]; - - if (!(data->device_flags & RMI_DEVICE)) - return 0; - - ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, - RMI_F11_CTRL_REG_COUNT); - if (ret) - hid_warn(hdev, "can not read F11 control registers\n"); - else - memcpy(data->f11_ctrl_regs, buf, RMI_F11_CTRL_REG_COUNT); - - - if (!device_may_wakeup(hdev->dev.parent)) - return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); - - return 0; -} - -static int rmi_post_reset(struct hid_device *hdev) -{ - struct rmi_data *data = hid_get_drvdata(hdev); + struct rmi_device *rmi_dev = data->xport.rmi_dev; int ret; if (!(data->device_flags & RMI_DEVICE)) return 0; - ret = rmi_reset_attn_mode(hdev); + ret = rmi_driver_suspend(rmi_dev, false); if (ret) { - hid_err(hdev, "can not set rmi mode\n"); + hid_warn(hdev, "Failed to suspend device: %d\n", ret); return ret; } - if (data->read_f11_ctrl_regs) { - ret = rmi_write_block(hdev, data->f11.control_base_addr, - data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); - if (ret) - hid_warn(hdev, - "can not write F11 control registers after reset\n"); - } - - if (!device_may_wakeup(hdev->dev.parent)) { - ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); - if (ret) { - hid_err(hdev, "can not write sleep mode\n"); - return ret; - } - } - - return ret; + return 0; } static int rmi_post_resume(struct hid_device *hdev) { struct rmi_data *data = hid_get_drvdata(hdev); + struct rmi_device *rmi_dev = data->xport.rmi_dev; + int ret; if (!(data->device_flags & RMI_DEVICE)) return 0; - return rmi_reset_attn_mode(hdev); -} -#endif /* CONFIG_PM */ - -#define RMI4_MAX_PAGE 0xff -#define RMI4_PAGE_SIZE 0x0100 - -#define PDT_START_SCAN_LOCATION 0x00e9 -#define PDT_END_SCAN_LOCATION 0x0005 -#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff) - -struct pdt_entry { - u8 query_base_addr:8; - u8 command_base_addr:8; - u8 control_base_addr:8; - u8 data_base_addr:8; - u8 interrupt_source_count:3; - u8 bits3and4:2; - u8 function_version:2; - u8 bit7:1; - u8 function_number:8; -} __attribute__((__packed__)); - -static inline unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count) -{ - return GENMASK(irq_count + irq_base - 1, irq_base); -} - -static void rmi_register_function(struct rmi_data *data, - struct pdt_entry *pdt_entry, int page, unsigned interrupt_count) -{ - struct rmi_function *f = NULL; - u16 page_base = page << 8; - - switch (pdt_entry->function_number) { - case 0x01: - f = &data->f01; - break; - case 0x11: - f = &data->f11; - break; - case 0x30: - f = &data->f30; - break; - } - - if (f) { - f->page = page; - f->query_base_addr = page_base | pdt_entry->query_base_addr; - f->command_base_addr = page_base | pdt_entry->command_base_addr; - f->control_base_addr = page_base | pdt_entry->control_base_addr; - f->data_base_addr = page_base | pdt_entry->data_base_addr; - f->interrupt_base = interrupt_count; - f->interrupt_count = pdt_entry->interrupt_source_count; - f->irq_mask = rmi_gen_mask(f->interrupt_base, - f->interrupt_count); - data->interrupt_enable_mask |= f->irq_mask; - } -} - -static int rmi_scan_pdt(struct hid_device *hdev) -{ - struct rmi_data *data = hid_get_drvdata(hdev); - struct pdt_entry entry; - int page; - bool page_has_function; - int i; - int retval; - int interrupt = 0; - u16 page_start, pdt_start , pdt_end; - - hid_info(hdev, "Scanning PDT...\n"); - - for (page = 0; (page <= RMI4_MAX_PAGE); page++) { - page_start = RMI4_PAGE_SIZE * page; - pdt_start = page_start + PDT_START_SCAN_LOCATION; - pdt_end = page_start + PDT_END_SCAN_LOCATION; - - page_has_function = false; - for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) { - retval = rmi_read_block(hdev, i, &entry, sizeof(entry)); - if (retval) { - hid_err(hdev, - "Read of PDT entry at %#06x failed.\n", - i); - goto error_exit; - } - - if (RMI4_END_OF_PDT(entry.function_number)) - break; - - page_has_function = true; - - hid_info(hdev, "Found F%02X on page %#04x\n", - entry.function_number, page); - - rmi_register_function(data, &entry, page, interrupt); - interrupt += entry.interrupt_source_count; - } - - if (!page_has_function) - break; - } - - hid_info(hdev, "%s: Done with PDT scan.\n", __func__); - retval = 0; - -error_exit: - return retval; -} - -#define RMI_DEVICE_F01_BASIC_QUERY_LEN 11 - -static int rmi_populate_f01(struct hid_device *hdev) -{ - struct rmi_data *data = hid_get_drvdata(hdev); - u8 basic_queries[RMI_DEVICE_F01_BASIC_QUERY_LEN]; - u8 info[3]; - int ret; - bool has_query42; - bool has_lts; - bool has_sensor_id; - bool has_ds4_queries = false; - bool has_build_id_query = false; - bool has_package_id_query = false; - u16 query_offset = data->f01.query_base_addr; - u16 prod_info_addr; - u8 ds4_query_len; - - ret = rmi_read_block(hdev, query_offset, basic_queries, - RMI_DEVICE_F01_BASIC_QUERY_LEN); - if (ret) { - hid_err(hdev, "Can not read basic queries from Function 0x1.\n"); - return ret; - } - - has_lts = !!(basic_queries[0] & BIT(2)); - has_sensor_id = !!(basic_queries[1] & BIT(3)); - has_query42 = !!(basic_queries[1] & BIT(7)); - - query_offset += 11; - prod_info_addr = query_offset + 6; - query_offset += 10; - - if (has_lts) - query_offset += 20; - - if (has_sensor_id) - query_offset++; - - if (has_query42) { - ret = rmi_read(hdev, query_offset, info); - if (ret) { - hid_err(hdev, "Can not read query42.\n"); - return ret; - } - has_ds4_queries = !!(info[0] & BIT(0)); - query_offset++; - } - - if (has_ds4_queries) { - ret = rmi_read(hdev, query_offset, &ds4_query_len); - if (ret) { - hid_err(hdev, "Can not read DS4 Query length.\n"); - return ret; - } - query_offset++; - - if (ds4_query_len > 0) { - ret = rmi_read(hdev, query_offset, info); - if (ret) { - hid_err(hdev, "Can not read DS4 query.\n"); - return ret; - } - - has_package_id_query = !!(info[0] & BIT(0)); - has_build_id_query = !!(info[0] & BIT(1)); - } - } - - if (has_package_id_query) - prod_info_addr++; - - if (has_build_id_query) { - ret = rmi_read_block(hdev, prod_info_addr, info, 3); - if (ret) { - hid_err(hdev, "Can not read product info.\n"); - return ret; - } - - data->firmware_id = info[1] << 8 | info[0]; - data->firmware_id += info[2] * 65536; - } - - ret = rmi_read_block(hdev, data->f01.control_base_addr, info, - 2); - - if (ret) { - hid_err(hdev, "can not read f01 ctrl registers\n"); - return ret; - } - - data->f01_ctrl0 = info[0]; - - if (!info[1]) { - /* - * Do to a firmware bug in some touchpads the F01 interrupt - * enable control register will be cleared on reset. - * This will stop the touchpad from reporting data, so - * if F01 CTRL1 is 0 then we need to explicitly enable - * interrupts for the functions we want data for. - */ - data->restore_interrupt_mask = true; - - ret = rmi_write(hdev, data->f01.control_base_addr + 1, - &data->interrupt_enable_mask); - if (ret) { - hid_err(hdev, "can not write to control reg 1: %d.\n", - ret); - return ret; - } - } - - return 0; -} - -static int rmi_populate_f11(struct hid_device *hdev) -{ - struct rmi_data *data = hid_get_drvdata(hdev); - u8 buf[20]; - int ret; - bool has_query9; - bool has_query10 = false; - bool has_query11; - bool has_query12; - bool has_query27; - bool has_query28; - bool has_query36 = false; - bool has_physical_props; - bool has_gestures; - bool has_rel; - bool has_data40 = false; - bool has_dribble = false; - bool has_palm_detect = false; - unsigned x_size, y_size; - u16 query_offset; - - if (!data->f11.query_base_addr) { - hid_err(hdev, "No 2D sensor found, giving up.\n"); - return -ENODEV; - } - - /* query 0 contains some useful information */ - ret = rmi_read(hdev, data->f11.query_base_addr, buf); - if (ret) { - hid_err(hdev, "can not get query 0: %d.\n", ret); - return ret; - } - has_query9 = !!(buf[0] & BIT(3)); - has_query11 = !!(buf[0] & BIT(4)); - has_query12 = !!(buf[0] & BIT(5)); - has_query27 = !!(buf[0] & BIT(6)); - has_query28 = !!(buf[0] & BIT(7)); - - /* query 1 to get the max number of fingers */ - ret = rmi_read(hdev, data->f11.query_base_addr + 1, buf); - if (ret) { - hid_err(hdev, "can not get NumberOfFingers: %d.\n", ret); - return ret; - } - data->max_fingers = (buf[0] & 0x07) + 1; - if (data->max_fingers > 5) - data->max_fingers = 10; - - data->f11.report_size = data->max_fingers * 5 + - DIV_ROUND_UP(data->max_fingers, 4); - - if (!(buf[0] & BIT(4))) { - hid_err(hdev, "No absolute events, giving up.\n"); - return -ENODEV; - } - - has_rel = !!(buf[0] & BIT(3)); - has_gestures = !!(buf[0] & BIT(5)); - - ret = rmi_read(hdev, data->f11.query_base_addr + 5, buf); - if (ret) { - hid_err(hdev, "can not get absolute data sources: %d.\n", ret); + ret = rmi_reset_attn_mode(hdev); + if (ret) return ret; - } - - has_dribble = !!(buf[0] & BIT(4)); - - /* - * At least 4 queries are guaranteed to be present in F11 - * +1 for query 5 which is present since absolute events are - * reported and +1 for query 12. - */ - query_offset = 6; - - if (has_rel) - ++query_offset; /* query 6 is present */ - - if (has_gestures) { - /* query 8 to find out if query 10 exists */ - ret = rmi_read(hdev, - data->f11.query_base_addr + query_offset + 1, buf); - if (ret) { - hid_err(hdev, "can not read gesture information: %d.\n", - ret); - return ret; - } - has_palm_detect = !!(buf[0] & BIT(0)); - has_query10 = !!(buf[0] & BIT(2)); - - query_offset += 2; /* query 7 and 8 are present */ - } - - if (has_query9) - ++query_offset; - - if (has_query10) - ++query_offset; - - if (has_query11) - ++query_offset; - - /* query 12 to know if the physical properties are reported */ - if (has_query12) { - ret = rmi_read(hdev, data->f11.query_base_addr - + query_offset, buf); - if (ret) { - hid_err(hdev, "can not get query 12: %d.\n", ret); - return ret; - } - has_physical_props = !!(buf[0] & BIT(5)); - - if (has_physical_props) { - query_offset += 1; - ret = rmi_read_block(hdev, - data->f11.query_base_addr - + query_offset, buf, 4); - if (ret) { - hid_err(hdev, "can not read query 15-18: %d.\n", - ret); - return ret; - } - - x_size = buf[0] | (buf[1] << 8); - y_size = buf[2] | (buf[3] << 8); - - data->x_size_mm = DIV_ROUND_CLOSEST(x_size, 10); - data->y_size_mm = DIV_ROUND_CLOSEST(y_size, 10); - - hid_info(hdev, "%s: size in mm: %d x %d\n", - __func__, data->x_size_mm, data->y_size_mm); - - /* - * query 15 - 18 contain the size of the sensor - * and query 19 - 26 contain bezel dimensions - */ - query_offset += 12; - } - } - - if (has_query27) - ++query_offset; - if (has_query28) { - ret = rmi_read(hdev, data->f11.query_base_addr - + query_offset, buf); - if (ret) { - hid_err(hdev, "can not get query 28: %d.\n", ret); - return ret; - } - - has_query36 = !!(buf[0] & BIT(6)); - } - - if (has_query36) { - query_offset += 2; - ret = rmi_read(hdev, data->f11.query_base_addr - + query_offset, buf); - if (ret) { - hid_err(hdev, "can not get query 36: %d.\n", ret); - return ret; - } - - has_data40 = !!(buf[0] & BIT(5)); - } - - - if (has_data40) - data->f11.report_size += data->max_fingers * 2; - - ret = rmi_read_block(hdev, data->f11.control_base_addr, - data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); + ret = rmi_driver_resume(rmi_dev, false); if (ret) { - hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret); + hid_warn(hdev, "Failed to resume device: %d\n", ret); return ret; } - /* data->f11_ctrl_regs now contains valid register data */ - data->read_f11_ctrl_regs = true; - - data->max_x = data->f11_ctrl_regs[6] | (data->f11_ctrl_regs[7] << 8); - data->max_y = data->f11_ctrl_regs[8] | (data->f11_ctrl_regs[9] << 8); - - if (has_dribble) { - data->f11_ctrl_regs[0] = data->f11_ctrl_regs[0] & ~BIT(6); - ret = rmi_write(hdev, data->f11.control_base_addr, - data->f11_ctrl_regs); - if (ret) { - hid_err(hdev, "can not write to control reg 0: %d.\n", - ret); - return ret; - } - } - - if (has_palm_detect) { - data->f11_ctrl_regs[11] = data->f11_ctrl_regs[11] & ~BIT(0); - ret = rmi_write(hdev, data->f11.control_base_addr + 11, - &data->f11_ctrl_regs[11]); - if (ret) { - hid_err(hdev, "can not write to control reg 11: %d.\n", - ret); - return ret; - } - } - - return 0; -} - -static int rmi_populate_f30(struct hid_device *hdev) -{ - struct rmi_data *data = hid_get_drvdata(hdev); - u8 buf[20]; - int ret; - bool has_gpio, has_led; - unsigned bytes_per_ctrl; - u8 ctrl2_addr; - int ctrl2_3_length; - int i; - - /* function F30 is for physical buttons */ - if (!data->f30.query_base_addr) { - hid_err(hdev, "No GPIO/LEDs found, giving up.\n"); - return -ENODEV; - } - - ret = rmi_read_block(hdev, data->f30.query_base_addr, buf, 2); - if (ret) { - hid_err(hdev, "can not get F30 query registers: %d.\n", ret); - return ret; - } - - has_gpio = !!(buf[0] & BIT(3)); - has_led = !!(buf[0] & BIT(2)); - data->gpio_led_count = buf[1] & 0x1f; - - /* retrieve ctrl 2 & 3 registers */ - bytes_per_ctrl = (data->gpio_led_count + 7) / 8; - /* Ctrl0 is present only if both has_gpio and has_led are set*/ - ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0; - /* Ctrl1 is always be present */ - ctrl2_addr += bytes_per_ctrl; - ctrl2_3_length = 2 * bytes_per_ctrl; - - data->f30.report_size = bytes_per_ctrl; - - ret = rmi_read_block(hdev, data->f30.control_base_addr + ctrl2_addr, - buf, ctrl2_3_length); - if (ret) { - hid_err(hdev, "can not read ctrl 2&3 block of size %d: %d.\n", - ctrl2_3_length, ret); - return ret; - } - - for (i = 0; i < data->gpio_led_count; i++) { - int byte_position = i >> 3; - int bit_position = i & 0x07; - u8 dir_byte = buf[byte_position]; - u8 data_byte = buf[byte_position + bytes_per_ctrl]; - bool dir = (dir_byte >> bit_position) & BIT(0); - bool dat = (data_byte >> bit_position) & BIT(0); - - if (dir == 0) { - /* input mode */ - if (dat) { - /* actual buttons have pull up resistor */ - data->button_count++; - set_bit(i, &data->button_mask); - set_bit(i, &data->button_state_mask); - } - } - - } - return 0; } +#endif /* CONFIG_PM */ -static int rmi_populate(struct hid_device *hdev) +static int rmi_hid_reset(struct rmi_transport_dev *xport, u16 reset_addr) { - struct rmi_data *data = hid_get_drvdata(hdev); - int ret; - - ret = rmi_scan_pdt(hdev); - if (ret) { - hid_err(hdev, "PDT scan failed with code %d.\n", ret); - return ret; - } - - ret = rmi_populate_f01(hdev); - if (ret) { - hid_err(hdev, "Error while initializing F01 (%d).\n", ret); - return ret; - } - - ret = rmi_populate_f11(hdev); - if (ret) { - hid_err(hdev, "Error while initializing F11 (%d).\n", ret); - return ret; - } - - if (!(data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS)) { - ret = rmi_populate_f30(hdev); - if (ret) - hid_warn(hdev, "Error while initializing F30 (%d).\n", ret); - } + struct rmi_data *data = container_of(xport, struct rmi_data, xport); + struct hid_device *hdev = data->hdev; - return 0; + return rmi_reset_attn_mode(hdev); } static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct rmi_data *data = hid_get_drvdata(hdev); struct input_dev *input = hi->input; - int ret; - int res_x, res_y, i; + int ret = 0; + + if (!(data->device_flags & RMI_DEVICE)) + return 0; - data->input = input; + data->xport.input = input; hid_dbg(hdev, "Opening low level driver\n"); ret = hid_hw_open(hdev); if (ret) return ret; - if (!(data->device_flags & RMI_DEVICE)) - return 0; - /* Allow incoming hid reports */ hid_device_io_start(hdev); @@ -1222,40 +489,10 @@ static int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) goto exit; } - ret = rmi_populate(hdev); - if (ret) - goto exit; - - hid_info(hdev, "firmware id: %ld\n", data->firmware_id); - - __set_bit(EV_ABS, input->evbit); - input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0); - - if (data->x_size_mm && data->y_size_mm) { - res_x = (data->max_x - 1) / data->x_size_mm; - res_y = (data->max_y - 1) / data->y_size_mm; - - input_abs_set_res(input, ABS_MT_POSITION_X, res_x); - input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); - } - - input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); - input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); - - ret = input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); - if (ret < 0) + ret = rmi_register_transport_device(&data->xport); + if (ret < 0) { + dev_err(&hdev->dev, "failed to register transport driver\n"); goto exit; - - if (data->button_count) { - __set_bit(EV_KEY, input->evbit); - for (i = 0; i < data->button_count; i++) - __set_bit(BTN_LEFT + i, input->keybit); - - if (data->button_count == 1) - __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); } set_bit(RMI_STARTED, &data->flags); @@ -1304,6 +541,71 @@ static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, return 0; } +static struct rmi_device_platform_data rmi_hid_pdata = { + .sensor_pdata = { + .sensor_type = rmi_sensor_touchpad, + .axis_align.flip_y = true, + .dribble = RMI_REG_STATE_ON, + .palm_detect = RMI_REG_STATE_OFF, + }, +}; + +static const struct rmi_transport_ops hid_rmi_ops = { + .write_block = rmi_hid_write_block, + .read_block = rmi_hid_read_block, + .reset = rmi_hid_reset, +}; + +static void rmi_irq_teardown(void *data) +{ + struct rmi_data *hdata = data; + struct irq_domain *domain = hdata->domain; + + if (!domain) + return; + + irq_dispose_mapping(irq_find_mapping(domain, 0)); + + irq_domain_remove(domain); + hdata->domain = NULL; + hdata->rmi_irq = 0; +} + +static int rmi_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw_irq_num) +{ + irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); + + return 0; +} + +static const struct irq_domain_ops rmi_irq_ops = { + .map = rmi_irq_map, +}; + +static int rmi_setup_irq_domain(struct hid_device *hdev) +{ + struct rmi_data *hdata = hid_get_drvdata(hdev); + int ret; + + hdata->domain = irq_domain_create_linear(hdev->dev.fwnode, 1, + &rmi_irq_ops, hdata); + if (!hdata->domain) + return -ENOMEM; + + ret = devm_add_action_or_reset(&hdev->dev, &rmi_irq_teardown, hdata); + if (ret) + return ret; + + hdata->rmi_irq = irq_create_mapping(hdata->domain, 0); + if (hdata->rmi_irq <= 0) { + hid_err(hdev, "Can't allocate an IRQ\n"); + return hdata->rmi_irq < 0 ? hdata->rmi_irq : -ENXIO; + } + + return 0; +} + static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct rmi_data *data = NULL; @@ -1365,8 +667,8 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); if (!data->writeReport) { - ret = -ENOMEM; - return ret; + hid_err(hdev, "failed to allocate buffer for HID reports\n"); + return -ENOMEM; } data->readReport = data->writeReport + data->output_report_size; @@ -1375,6 +677,21 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) mutex_init(&data->page_mutex); + ret = rmi_setup_irq_domain(hdev); + if (ret) { + hid_err(hdev, "failed to allocate IRQ domain\n"); + return ret; + } + + if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) + rmi_hid_pdata.f30_data.disable = true; + + data->xport.dev = hdev->dev.parent; + data->xport.pdata = rmi_hid_pdata; + data->xport.pdata.irq = data->rmi_irq; + data->xport.proto_name = "hid"; + data->xport.ops = &hid_rmi_ops; + start: ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { @@ -1382,17 +699,6 @@ start: return ret; } - if ((data->device_flags & RMI_DEVICE) && - !test_bit(RMI_STARTED, &data->flags)) - /* - * The device maybe in the bootloader if rmi_input_configured - * failed to find F11 in the PDT. Print an error, but don't - * return an error from rmi_probe so that hidraw will be - * accessible from userspace. That way a userspace tool - * can be used to reload working firmware on the touchpad. - */ - hid_err(hdev, "Device failed to be properly configured\n"); - return 0; } @@ -1401,6 +707,8 @@ static void rmi_remove(struct hid_device *hdev) struct rmi_data *hdata = hid_get_drvdata(hdev); clear_bit(RMI_STARTED, &hdata->flags); + cancel_work_sync(&hdata->reset_work); + rmi_unregister_transport_device(&hdata->xport); hid_hw_stop(hdev); } @@ -1408,6 +716,7 @@ static void rmi_remove(struct hid_device *hdev) static const struct hid_device_id rmi_id[] = { { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, { } }; @@ -1425,7 +734,7 @@ static struct hid_driver rmi_driver = { #ifdef CONFIG_PM .suspend = rmi_suspend, .resume = rmi_post_resume, - .reset_resume = rmi_post_reset, + .reset_resume = rmi_post_resume, #endif }; diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 5c925228847c..4ef73374a8f9 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -212,7 +212,6 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, __s32 value; int ret = 0; - memset(buffer, 0, buffer_size); mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); if (!report || (field_index >= report->maxfield)) { @@ -256,6 +255,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, int buffer_index = 0; int i; + memset(buffer, 0, buffer_size); + mutex_lock(&data->mutex); report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); if (!report || (field_index >= report->maxfield) || diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 7687c0875395..f405b07d0381 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1099,8 +1099,11 @@ struct sony_sc { u8 led_delay_on[MAX_LEDS]; u8 led_delay_off[MAX_LEDS]; u8 led_count; + bool ds4_dongle_connected; }; +static void sony_set_leds(struct sony_sc *sc); + static inline void sony_schedule_work(struct sony_sc *sc) { if (!sc->defer_initialization) @@ -1430,6 +1433,31 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, return -EILSEQ; } } + + /* + * In the case of a DS4 USB dongle, bit[2] of byte 31 indicates + * if a DS4 is actually connected (indicated by '0'). + * For non-dongle, this bit is always 0 (connected). + */ + if (sc->hdev->vendor == USB_VENDOR_ID_SONY && + sc->hdev->product == USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE) { + bool connected = (rd[31] & 0x04) ? false : true; + + if (!sc->ds4_dongle_connected && connected) { + hid_info(sc->hdev, "DualShock 4 USB dongle: controller connected\n"); + sony_set_leds(sc); + sc->ds4_dongle_connected = true; + } else if (sc->ds4_dongle_connected && !connected) { + hid_info(sc->hdev, "DualShock 4 USB dongle: controller disconnected\n"); + sc->ds4_dongle_connected = false; + /* Return 0, so hidraw can get the report. */ + return 0; + } else if (!sc->ds4_dongle_connected) { + /* Return 0, so hidraw can get the report. */ + return 0; + } + } + dualshock4_parse_report(sc, rd, size); } @@ -2390,6 +2418,12 @@ static int sony_check_add(struct sony_sc *sc) } memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); + + snprintf(sc->hdev->uniq, sizeof(sc->hdev->uniq), + "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + sc->mac_address[5], sc->mac_address[4], + sc->mac_address[3], sc->mac_address[2], + sc->mac_address[1], sc->mac_address[0]); } else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || (sc->quirks & NAVIGATION_CONTROLLER_USB)) { buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL); @@ -2548,7 +2582,7 @@ static int sony_input_configured(struct hid_device *hdev, hid_err(sc->hdev, "Unable to initialize multi-touch slots: %d\n", ret); - return ret; + goto err_stop; } sony_init_output_report(sc, dualshock4_send_output_report); diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 78fb32a7b103..ea3c3546cef7 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -426,6 +426,15 @@ static int i2c_hid_hwreset(struct i2c_client *client) if (ret) goto out_unlock; + /* + * The HID over I2C specification states that if a DEVICE needs time + * after the PWR_ON request, it should utilise CLOCK stretching. + * However, it has been observered that the Windows driver provides a + * 1ms sleep between the PWR_ON and RESET requests and that some devices + * rely on this. + */ + usleep_range(1000, 5000); + i2c_hid_dbg(ihid, "resetting...\n"); ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h index ab68afcba2a2..a5897b9c0956 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish-regs.h @@ -111,6 +111,14 @@ #define IPC_ILUP_BIT (1<<IPC_ILUP_OFFS) /* + * ISH FW status bits in ISH FW Status Register + */ +#define IPC_ISH_FWSTS_SHIFT 12 +#define IPC_ISH_FWSTS_MASK GENMASK(15, 12) +#define IPC_GET_ISH_FWSTS(status) \ + (((status) & IPC_ISH_FWSTS_MASK) >> IPC_ISH_FWSTS_SHIFT) + +/* * FW status bits (relevant) */ #define IPC_FWSTS_ILUP 0x1 diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h index 46615a03e78f..fd34307a7a70 100644 --- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h +++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h @@ -61,6 +61,18 @@ struct ish_hw { void __iomem *mem_addr; }; +/* + * ISH FW status type + */ +enum { + FWSTS_AFTER_RESET = 0, + FWSTS_WAIT_FOR_HOST = 4, + FWSTS_START_KERNEL_DMA = 5, + FWSTS_FW_IS_RUNNING = 7, + FWSTS_SENSOR_APP_LOADED = 8, + FWSTS_SENSOR_APP_RUNNING = 15 +}; + #define to_ish_hw(dev) (struct ish_hw *)((dev)->hw) irqreturn_t ish_irq_handler(int irq, void *dev_id); diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 20d647d2dd2c..8df81dc84529 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -24,7 +24,6 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/workqueue.h> -#include <linux/miscdevice.h> #define CREATE_TRACE_POINTS #include <trace/events/intel_ish.h> #include "ishtp-dev.h" @@ -47,7 +46,8 @@ MODULE_DEVICE_TABLE(pci, ish_pci_tbl); * * Callback to direct log messages to Linux trace buffers */ -static void ish_event_tracer(struct ishtp_device *dev, char *format, ...) +static __printf(2, 3) +void ish_event_tracer(struct ishtp_device *dev, const char *format, ...) { if (trace_ishtp_dump_enabled()) { va_list args; @@ -205,12 +205,15 @@ static void ish_remove(struct pci_dev *pdev) #ifdef CONFIG_PM static struct device *ish_resume_device; +/* 50ms to get resume response */ +#define WAIT_FOR_RESUME_ACK_MS 50 + /** * ish_resume_handler() - Work function to complete resume * @work: work struct * * The resume work function to complete resume function asynchronously. - * There are two types of platforms, one where ISH is not powered off, + * There are two resume paths, one where ISH is not powered off, * in that case a simple resume message is enough, others we need * a reset sequence. */ @@ -218,20 +221,31 @@ static void ish_resume_handler(struct work_struct *work) { struct pci_dev *pdev = to_pci_dev(ish_resume_device); struct ishtp_device *dev = pci_get_drvdata(pdev); + uint32_t fwsts; int ret; - ishtp_send_resume(dev); + /* Get ISH FW status */ + fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev)); - /* 50 ms to get resume response */ - if (dev->resume_flag) - ret = wait_event_interruptible_timeout(dev->resume_wait, - !dev->resume_flag, - msecs_to_jiffies(50)); + /* + * If currently, in ISH FW, sensor app is loaded or beyond that, + * it means ISH isn't powered off, in this case, send a resume message. + */ + if (fwsts >= FWSTS_SENSOR_APP_LOADED) { + ishtp_send_resume(dev); + + /* Waiting to get resume response */ + if (dev->resume_flag) + ret = wait_event_interruptible_timeout(dev->resume_wait, + !dev->resume_flag, + msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); + } /* - * If no resume response. This platform is not S0ix compatible - * So on resume full reboot of ISH processor will happen, so - * need to go through init sequence again + * If in ISH FW, sensor app isn't loaded yet, or no resume response. + * That means this platform is not S0ix compatible, or something is + * wrong with ISH FW. So on resume, full reboot of ISH processor will + * happen, so need to go through init sequence again. */ if (dev->resume_flag) ish_init(dev); diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c index 277983aa1d90..cd23903ddcf1 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid.c @@ -208,7 +208,7 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, hid->version = le16_to_cpu(ISH_HID_VERSION); hid->vendor = le16_to_cpu(ISH_HID_VENDOR); hid->product = le16_to_cpu(ISH_HID_PRODUCT); - snprintf(hid->name, sizeof(hid->name), "%s %04hX:%04hX", "hid-ishtp", + snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp", hid->vendor, hid->product); rv = hid_add_device(hid); diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index f4cbc744e657..5f382fedc2ab 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -358,7 +358,7 @@ static void ishtp_cl_dev_release(struct device *dev) kfree(to_ishtp_cl_device(dev)); } -static struct device_type ishtp_cl_device_type = { +static const struct device_type ishtp_cl_device_type = { .release = ishtp_cl_dev_release, }; diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c index 59460b66e689..b7213608ce43 100644 --- a/drivers/hid/intel-ish-hid/ishtp/hbm.c +++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c @@ -19,7 +19,6 @@ #include <linux/sched.h> #include <linux/wait.h> #include <linux/spinlock.h> -#include <linux/miscdevice.h> #include "ishtp-dev.h" #include "hbm.h" #include "client.h" diff --git a/drivers/hid/intel-ish-hid/ishtp/init.c b/drivers/hid/intel-ish-hid/ishtp/init.c index ac364418e17c..d27e03526acd 100644 --- a/drivers/hid/intel-ish-hid/ishtp/init.c +++ b/drivers/hid/intel-ish-hid/ishtp/init.c @@ -16,7 +16,6 @@ #include <linux/export.h> #include <linux/slab.h> #include <linux/sched.h> -#include <linux/miscdevice.h> #include "ishtp-dev.h" #include "hbm.h" #include "client.h" diff --git a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h index a94f9a8a96a0..6a6d927b78b0 100644 --- a/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h +++ b/drivers/hid/intel-ish-hid/ishtp/ishtp-dev.h @@ -238,7 +238,8 @@ struct ishtp_device { uint64_t ishtp_host_dma_rx_buf_phys; /* Dump to trace buffers if enabled*/ - void (*print_log)(struct ishtp_device *dev, char *format, ...); + __printf(2, 3) void (*print_log)(struct ishtp_device *dev, + const char *format, ...); /* Debug stats */ unsigned int ipc_rx_cnt; diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 333108ef18cf..961bc6fdd2d9 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -43,7 +43,6 @@ */ #define DRIVER_DESC "USB HID core driver" -#define DRIVER_LICENSE "GPL" /* * Module parameters. @@ -1660,4 +1659,4 @@ MODULE_AUTHOR("Andreas Gal"); MODULE_AUTHOR("Vojtech Pavlik"); MODULE_AUTHOR("Jiri Kosina"); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index b3e01c82af05..d6847a664446 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -57,6 +57,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_AKAI, USB_DEVICE_ID_AKAI_MPKMINI2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_AKAI_09E8, USB_DEVICE_ID_AKAI_09E8_MIDIMIX, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_AMI, USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, @@ -83,11 +84,13 @@ static const struct hid_blacklist { { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3, HID_QUIRK_MULTI_INPUT }, - { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET }, { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_FUTABA, USB_DEVICE_ID_LED_DISPLAY, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, @@ -100,12 +103,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_SURFACE_PRO_2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, @@ -294,7 +291,7 @@ static void usbhid_remove_all_dquirks(void) } -/** +/** * usbhid_quirks_init: apply USB HID quirks specified at module load time */ int usbhid_quirks_init(char **quirks_param) @@ -358,7 +355,7 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor, if (bl_entry != NULL) dbg_hid("Found squirk 0x%x for USB HID vendor 0x%hx prod 0x%hx\n", - bl_entry->quirks, bl_entry->idVendor, + bl_entry->quirks, bl_entry->idVendor, bl_entry->idProduct); return bl_entry; } diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c index 9a332e683db7..7fb2d1e4f5dd 100644 --- a/drivers/hid/usbhid/usbkbd.c +++ b/drivers/hid/usbhid/usbkbd.c @@ -39,11 +39,10 @@ #define DRIVER_VERSION "" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB HID Boot Protocol keyboard driver" -#define DRIVER_LICENSE "GPL" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); static const unsigned char usb_kbd_keycode[256] = { 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, diff --git a/drivers/hid/usbhid/usbmouse.c b/drivers/hid/usbhid/usbmouse.c index bf16d72dc370..dd911c5241d8 100644 --- a/drivers/hid/usbhid/usbmouse.c +++ b/drivers/hid/usbhid/usbmouse.c @@ -42,11 +42,10 @@ #define DRIVER_VERSION "v1.6" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB HID Boot Protocol mouse driver" -#define DRIVER_LICENSE "GPL" MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); struct usb_mouse { char name[128]; diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index d303e413306d..38ee2125412f 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -102,7 +102,6 @@ #define DRIVER_VERSION "v2.00" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB Wacom tablet driver" -#define DRIVER_LICENSE "GPL" #define USB_VENDOR_ID_WACOM 0x056a #define USB_VENDOR_ID_LENOVO 0x17ef @@ -166,7 +165,9 @@ struct wacom { struct work_struct wireless_work; struct work_struct battery_work; struct work_struct remote_work; + struct delayed_work init_work; struct wacom_remote *remote; + bool generic_has_leds; struct wacom_leds { struct wacom_group_leds *groups; unsigned int count; @@ -218,4 +219,6 @@ enum led_brightness wacom_leds_brightness_get(struct wacom_led *led); struct wacom_led *wacom_led_find(struct wacom *wacom, unsigned int group, unsigned int id); struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); +int wacom_equivalent_usage(int usage); +int wacom_initialize_leds(struct wacom *wacom); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index b9779bcbd140..be8f7e2a026f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -16,15 +16,7 @@ #include <linux/input/mt.h> #define WAC_MSG_RETRIES 5 - -#define WAC_CMD_WL_LED_CONTROL 0x03 -#define WAC_CMD_LED_CONTROL 0x20 -#define WAC_CMD_ICON_START 0x21 -#define WAC_CMD_ICON_XFER 0x23 -#define WAC_CMD_ICON_BT_XFER 0x26 #define WAC_CMD_RETRIES 10 -#define WAC_CMD_DELETE_PAIRING 0x20 -#define WAC_CMD_UNPAIR_ALL 0xFF #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) @@ -120,11 +112,12 @@ static void wacom_feature_mapping(struct hid_device *hdev, struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_features *features = &wacom->wacom_wac.features; struct hid_data *hid_data = &wacom->wacom_wac.hid_data; + unsigned int equivalent_usage = wacom_equivalent_usage(usage->hid); u8 *data; int ret; int n; - switch (usage->hid) { + switch (equivalent_usage) { case HID_DG_CONTACTMAX: /* leave touch_max as is if predefined */ if (!features->touch_max) { @@ -333,8 +326,14 @@ static void wacom_post_parse_hid(struct hid_device *hdev, if (features->type == HID_GENERIC) { /* Any last-minute generic device setup */ if (features->touch_max > 1) { - input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max, - INPUT_MT_DIRECT); + if (features->device_type & WACOM_DEVICETYPE_DIRECT) + input_mt_init_slots(wacom_wac->touch_input, + wacom_wac->features.touch_max, + INPUT_MT_DIRECT); + else + input_mt_init_slots(wacom_wac->touch_input, + wacom_wac->features.touch_max, + INPUT_MT_POINTER); } } } @@ -497,11 +496,11 @@ static int wacom_bt_query_tablet_data(struct hid_device *hdev, u8 speed, * from the tablet, it is necessary to switch the tablet out of this * mode and into one which sends the full range of tablet data. */ -static int wacom_query_tablet_data(struct hid_device *hdev, - struct wacom_features *features) +static int _wacom_query_tablet_data(struct wacom *wacom) { - struct wacom *wacom = hid_get_drvdata(hdev); + struct hid_device *hdev = wacom->hdev; struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct wacom_features *features = &wacom_wac->features; if (hdev->bus == BUS_BLUETOOTH) return wacom_bt_query_tablet_data(hdev, 1, features); @@ -740,6 +739,11 @@ static int wacom_add_shared_data(struct hid_device *hdev) return retval; } + if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) + wacom_wac->shared->touch = hdev; + else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN) + wacom_wac->shared->pen = hdev; + out: mutex_unlock(&wacom_udev_list_lock); return retval; @@ -752,9 +756,6 @@ static int wacom_led_control(struct wacom *wacom) unsigned char report_id = WAC_CMD_LED_CONTROL; int buf_size = 9; - if (!hid_get_drvdata(wacom->hdev)) - return -ENODEV; - if (!wacom->led.groups) return -ENOTSUPP; @@ -762,12 +763,21 @@ static int wacom_led_control(struct wacom *wacom) report_id = WAC_CMD_WL_LED_CONTROL; buf_size = 13; } + else if (wacom->wacom_wac.features.type == INTUOSP2_BT) { + report_id = WAC_CMD_WL_INTUOSP2; + buf_size = 51; + } buf = kzalloc(buf_size, GFP_KERNEL); if (!buf) return -ENOMEM; - if (wacom->wacom_wac.features.type >= INTUOS5S && - wacom->wacom_wac.features.type <= INTUOSPL) { + if (wacom->wacom_wac.features.type == HID_GENERIC) { + buf[0] = WAC_CMD_LED_CONTROL_GENERIC; + buf[1] = wacom->led.llv; + buf[2] = wacom->led.groups[0].select & 0x03; + + } else if ((wacom->wacom_wac.features.type >= INTUOS5S && + wacom->wacom_wac.features.type <= INTUOSPL)) { /* * Touch Ring and crop mark LED luminance may take on * one of four values: @@ -787,6 +797,16 @@ static int wacom_led_control(struct wacom *wacom) } else buf[1] = led_bits; } + else if (wacom->wacom_wac.features.type == INTUOSP2_BT) { + buf[0] = report_id; + buf[4] = 100; // Power Connection LED (ORANGE) + buf[5] = 100; // BT Connection LED (BLUE) + buf[6] = 100; // Paper Mode (RED?) + buf[7] = 100; // Paper Mode (GREEN?) + buf[8] = 100; // Paper Mode (BLUE?) + buf[9] = wacom->led.llv; + buf[10] = wacom->led.groups[0].select & 0x03; + } else { int led = wacom->led.groups[0].select | 0x4; @@ -1027,6 +1047,17 @@ static struct attribute_group intuos5_led_attr_group = { .attrs = intuos5_led_attrs, }; +static struct attribute *generic_led_attrs[] = { + &dev_attr_status0_luminance.attr, + &dev_attr_status_led0_select.attr, + NULL +}; + +static struct attribute_group generic_led_attr_group = { + .name = "wacom_led", + .attrs = generic_led_attrs, +}; + struct wacom_sysfs_group_devres { struct attribute_group *group; struct kobject *root; @@ -1348,7 +1379,7 @@ static int wacom_leds_alloc_and_register(struct wacom *wacom, int group_count, return 0; } -static int wacom_initialize_leds(struct wacom *wacom) +int wacom_initialize_leds(struct wacom *wacom) { int error; @@ -1357,6 +1388,23 @@ static int wacom_initialize_leds(struct wacom *wacom) /* Initialize default values */ switch (wacom->wacom_wac.features.type) { + case HID_GENERIC: + if (!wacom->generic_has_leds) + return 0; + wacom->led.llv = 100; + wacom->led.max_llv = 100; + + error = wacom_leds_alloc_and_register(wacom, 1, 4, false); + if (error) { + hid_err(wacom->hdev, + "cannot create leds err: %d\n", error); + return error; + } + + error = wacom_devm_sysfs_create_group(wacom, + &generic_led_attr_group); + break; + case INTUOS4S: case INTUOS4: case INTUOS4WL: @@ -1415,6 +1463,17 @@ static int wacom_initialize_leds(struct wacom *wacom) &intuos5_led_attr_group); break; + case INTUOSP2_BT: + wacom->led.llv = 50; + wacom->led.max_llv = 100; + error = wacom_leds_alloc_and_register(wacom, 1, 4, false); + if (error) { + hid_err(wacom->hdev, + "cannot create leds err: %d\n", error); + return error; + } + return 0; + case REMOTE: wacom->led.llv = 255; wacom->led.max_llv = 255; @@ -1435,11 +1494,23 @@ static int wacom_initialize_leds(struct wacom *wacom) "cannot create sysfs group err: %d\n", error); return error; } - wacom_led_control(wacom); return 0; } +static void wacom_init_work(struct work_struct *work) +{ + struct wacom *wacom = container_of(work, struct wacom, init_work.work); + + _wacom_query_tablet_data(wacom); + wacom_led_control(wacom); +} + +static void wacom_query_tablet_data(struct wacom *wacom) +{ + schedule_delayed_work(&wacom->init_work, msecs_to_jiffies(1000)); +} + static enum power_supply_property wacom_battery_props[] = { POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_PRESENT, @@ -2015,6 +2086,24 @@ static void wacom_release_resources(struct wacom *wacom) wacom->wacom_wac.pad_input = NULL; } +static void wacom_set_shared_values(struct wacom_wac *wacom_wac) +{ + if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) { + wacom_wac->shared->type = wacom_wac->features.type; + wacom_wac->shared->touch_input = wacom_wac->touch_input; + } + + if (wacom_wac->has_mute_touch_switch) + wacom_wac->shared->has_mute_touch_switch = true; + + if (wacom_wac->shared->has_mute_touch_switch && + wacom_wac->shared->touch_input) { + set_bit(EV_SW, wacom_wac->shared->touch_input->evbit); + input_set_capability(wacom_wac->shared->touch_input, EV_SW, + SW_MUTE_DEVICE); + } +} + static int wacom_parse_and_register(struct wacom *wacom, bool wireless) { struct wacom_wac *wacom_wac = &wacom->wacom_wac; @@ -2036,10 +2125,6 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) if (error) goto fail; - error = wacom_add_shared_data(hdev); - if (error) - goto fail; - /* * Bamboo Pad has a generic hid handling for the Pen, and we switch it * into debug mode for the touch part. @@ -2080,10 +2165,9 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) wacom_update_name(wacom, wireless ? " (WL)" : ""); - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) - wacom_wac->shared->touch = hdev; - else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN) - wacom_wac->shared->pen = hdev; + error = wacom_add_shared_data(hdev); + if (error) + goto fail; if (!(features->device_type & WACOM_DEVICETYPE_WL_MONITOR) && (features->quirks & WACOM_QUIRK_BATTERY)) { @@ -2118,7 +2202,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) if (!wireless) { /* Note that if query fails it is not a hard failure */ - wacom_query_tablet_data(hdev, features); + wacom_query_tablet_data(wacom); } /* touch only Bamboo doesn't support pen */ @@ -2139,13 +2223,7 @@ static int wacom_parse_and_register(struct wacom *wacom, bool wireless) if (features->device_type & WACOM_DEVICETYPE_WL_MONITOR) error = hid_hw_open(hdev); - if ((wacom_wac->features.type == INTUOSHT || - wacom_wac->features.type == INTUOSHT2) && - (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH)) { - wacom_wac->shared->type = wacom_wac->features.type; - wacom_wac->shared->touch_input = wacom_wac->touch_input; - } - + wacom_set_shared_values(wacom_wac); devres_close_group(&hdev->dev, wacom); return 0; @@ -2450,6 +2528,7 @@ static int wacom_probe(struct hid_device *hdev, wacom->usbdev = dev; wacom->intf = intf; mutex_init(&wacom->lock); + INIT_DELAYED_WORK(&wacom->init_work, wacom_init_work); INIT_WORK(&wacom->wireless_work, wacom_wireless_work); INIT_WORK(&wacom->battery_work, wacom_battery_work); INIT_WORK(&wacom->remote_work, wacom_remote_work); @@ -2491,12 +2570,17 @@ static void wacom_remove(struct hid_device *hdev) hid_hw_stop(hdev); + cancel_delayed_work_sync(&wacom->init_work); cancel_work_sync(&wacom->wireless_work); cancel_work_sync(&wacom->battery_work); cancel_work_sync(&wacom->remote_work); if (hdev->bus == BUS_BLUETOOTH) device_remove_file(&hdev->dev, &dev_attr_speed); + /* make sure we don't trigger the LEDs */ + wacom_led_groups_release(wacom); + wacom_release_resources(wacom); + hid_set_drvdata(hdev, NULL); } @@ -2504,12 +2588,11 @@ static void wacom_remove(struct hid_device *hdev) static int wacom_resume(struct hid_device *hdev) { struct wacom *wacom = hid_get_drvdata(hdev); - struct wacom_features *features = &wacom->wacom_wac.features; mutex_lock(&wacom->lock); /* switch to wacom mode first */ - wacom_query_tablet_data(hdev, features); + _wacom_query_tablet_data(wacom); wacom_led_control(wacom); mutex_unlock(&wacom->lock); @@ -2540,4 +2623,4 @@ module_hid_driver(wacom_driver); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index b1a9a3ca6d56..4aa3de9f1163 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -43,6 +43,8 @@ static void wacom_report_numbered_buttons(struct input_dev *input_dev, static int wacom_numbered_button_to_key(int n); +static void wacom_update_led(struct wacom *wacom, int button_count, int mask, + int group); /* * Percent of battery capacity for Graphire. * 8th value means AC online and show 100% capacity. @@ -166,19 +168,21 @@ static int wacom_pl_irq(struct wacom_wac *wacom) wacom->id[0] = STYLUS_DEVICE_ID; } - pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); - if (features->pressure_max > 255) - pressure = (pressure << 1) | ((data[4] >> 6) & 1); - pressure += (features->pressure_max + 1) / 2; + if (prox) { + pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1)); + if (features->pressure_max > 255) + pressure = (pressure << 1) | ((data[4] >> 6) & 1); + pressure += (features->pressure_max + 1) / 2; - input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); - input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); - input_report_abs(input, ABS_PRESSURE, pressure); + input_report_abs(input, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14)); + input_report_abs(input, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14)); + input_report_abs(input, ABS_PRESSURE, pressure); - input_report_key(input, BTN_TOUCH, data[4] & 0x08); - input_report_key(input, BTN_STYLUS, data[4] & 0x10); - /* Only allow the stylus2 button to be reported for the pen tool. */ - input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20)); + input_report_key(input, BTN_TOUCH, data[4] & 0x08); + input_report_key(input, BTN_STYLUS, data[4] & 0x10); + /* Only allow the stylus2 button to be reported for the pen tool. */ + input_report_key(input, BTN_STYLUS2, (wacom->tool[0] == BTN_TOOL_PEN) && (data[4] & 0x20)); + } if (!prox) wacom->id[0] = 0; @@ -1190,6 +1194,166 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) return count; } +static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) +{ + const int pen_frame_len = 14; + const int pen_frames = 7; + + struct input_dev *pen_input = wacom->pen_input; + unsigned char *data = wacom->data; + int i; + + wacom->serial[0] = get_unaligned_le64(&data[99]); + wacom->id[0] = get_unaligned_le16(&data[107]); + if (wacom->serial[0] >> 52 == 1) { + /* Add back in missing bits of ID for non-USI pens */ + wacom->id[0] |= (wacom->serial[0] >> 32) & 0xFFFFF; + } + wacom->tool[0] = wacom_intuos_get_tool_type(wacom_intuos_id_mangle(wacom->id[0])); + + for (i = 0; i < pen_frames; i++) { + unsigned char *frame = &data[i*pen_frame_len + 1]; + bool valid = frame[0] & 0x80; + bool prox = frame[0] & 0x40; + bool range = frame[0] & 0x20; + + if (!valid) + continue; + + if (range) { + input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); + input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); + input_report_abs(pen_input, ABS_TILT_X, frame[7]); + input_report_abs(pen_input, ABS_TILT_Y, frame[8]); + input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9])); + input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11])); + } + input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); + input_report_abs(pen_input, ABS_DISTANCE, range ? frame[13] : wacom->features.distance_max); + + input_report_key(pen_input, BTN_TOUCH, frame[0] & 0x01); + input_report_key(pen_input, BTN_STYLUS, frame[0] & 0x02); + input_report_key(pen_input, BTN_STYLUS2, frame[0] & 0x04); + + input_report_key(pen_input, wacom->tool[0], prox); + input_event(pen_input, EV_MSC, MSC_SERIAL, wacom->serial[0]); + input_report_abs(pen_input, ABS_MISC, + wacom_intuos_id_mangle(wacom->id[0])); /* report tool id */ + + wacom->shared->stylus_in_proximity = prox; + + input_sync(pen_input); + } +} + +static void wacom_intuos_pro2_bt_touch(struct wacom_wac *wacom) +{ + const int finger_touch_len = 8; + const int finger_frames = 4; + const int finger_frame_len = 43; + + struct input_dev *touch_input = wacom->touch_input; + unsigned char *data = wacom->data; + int num_contacts_left = 5; + int i, j; + + for (i = 0; i < finger_frames; i++) { + unsigned char *frame = &data[i*finger_frame_len + 109]; + int current_num_contacts = frame[0] & 0x7F; + int contacts_to_send; + + if (!(frame[0] & 0x80)) + continue; + + /* + * First packet resets the counter since only the first + * packet in series will have non-zero current_num_contacts. + */ + if (current_num_contacts) + wacom->num_contacts_left = current_num_contacts; + + contacts_to_send = min(num_contacts_left, wacom->num_contacts_left); + + for (j = 0; j < contacts_to_send; j++) { + unsigned char *touch = &frame[j*finger_touch_len + 1]; + int slot = input_mt_get_slot_by_key(touch_input, touch[0]); + int x = get_unaligned_le16(&touch[2]); + int y = get_unaligned_le16(&touch[4]); + int w = touch[6] * input_abs_get_res(touch_input, ABS_MT_POSITION_X); + int h = touch[7] * input_abs_get_res(touch_input, ABS_MT_POSITION_Y); + + if (slot < 0) + continue; + + input_mt_slot(touch_input, slot); + input_mt_report_slot_state(touch_input, MT_TOOL_FINGER, touch[1] & 0x01); + input_report_abs(touch_input, ABS_MT_POSITION_X, x); + input_report_abs(touch_input, ABS_MT_POSITION_Y, y); + input_report_abs(touch_input, ABS_MT_TOUCH_MAJOR, max(w, h)); + input_report_abs(touch_input, ABS_MT_TOUCH_MINOR, min(w, h)); + input_report_abs(touch_input, ABS_MT_ORIENTATION, w > h); + } + + input_mt_sync_frame(touch_input); + + wacom->num_contacts_left -= contacts_to_send; + if (wacom->num_contacts_left <= 0) { + wacom->num_contacts_left = 0; + wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); + } + } + + input_report_switch(touch_input, SW_MUTE_DEVICE, !(data[281] >> 7)); + input_sync(touch_input); +} + +static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom) +{ + struct input_dev *pad_input = wacom->pad_input; + unsigned char *data = wacom->data; + + int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01); + int ring = data[285]; + int prox = buttons | (ring & 0x80); + + wacom_report_numbered_buttons(pad_input, 9, buttons); + + input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0); + + input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0); + input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0); + input_event(pad_input, EV_MSC, MSC_SERIAL, 0xffffffff); + + input_sync(pad_input); +} + +static void wacom_intuos_pro2_bt_battery(struct wacom_wac *wacom) +{ + unsigned char *data = wacom->data; + + bool chg = data[284] & 0x80; + int battery_status = data[284] & 0x7F; + + wacom_notify_battery(wacom, battery_status, chg, 1, chg); +} + +static int wacom_intuos_pro2_bt_irq(struct wacom_wac *wacom, size_t len) +{ + unsigned char *data = wacom->data; + + if (data[0] != 0x80) { + dev_dbg(wacom->pen_input->dev.parent, + "%s: received unknown report #%d\n", __func__, data[0]); + return 0; + } + + wacom_intuos_pro2_bt_pen(wacom); + wacom_intuos_pro2_bt_touch(wacom); + wacom_intuos_pro2_bt_pad(wacom); + wacom_intuos_pro2_bt_battery(wacom); + return 0; +} + static int wacom_24hdt_irq(struct wacom_wac *wacom) { struct input_dev *input = wacom->touch_input; @@ -1444,7 +1608,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) return 0; } -static int wacom_equivalent_usage(int usage) +int wacom_equivalent_usage(int usage) { if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) { int subpage = (usage & 0xFF00) << 8; @@ -1471,6 +1635,16 @@ static int wacom_equivalent_usage(int usage) return subpage | subusage; } + if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMTOUCH) { + int subpage = (usage & 0xFF00) << 8; + int subusage = (usage & 0xFF); + + if (subpage == HID_UP_UNDEFINED) + subpage = WACOM_HID_SP_DIGITIZER; + + return subpage | subusage; + } + return usage; } @@ -1550,12 +1724,14 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_ABS, ABS_Z, 0); features->device_type |= WACOM_DEVICETYPE_PAD; break; + case WACOM_HID_WD_BUTTONCENTER: + wacom->generic_has_leds = true; + /* fall through */ case WACOM_HID_WD_BUTTONHOME: case WACOM_HID_WD_BUTTONUP: case WACOM_HID_WD_BUTTONDOWN: case WACOM_HID_WD_BUTTONLEFT: case WACOM_HID_WD_BUTTONRIGHT: - case WACOM_HID_WD_BUTTONCENTER: wacom_map_usage(input, usage, field, EV_KEY, wacom_numbered_button_to_key(features->numbered_buttons), 0); @@ -1563,7 +1739,17 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHONOFF: - wacom_map_usage(input, usage, field, EV_SW, SW_MUTE_DEVICE, 0); + /* + * This usage, which is used to mute touch events, comes + * from the pad packet, but is reported on the touch + * interface. Because the touch interface may not have + * been created yet, we cannot call wacom_map_usage(). In + * order to process this usage when we receive it, we set + * the usage type and code directly. + */ + wacom_wac->has_mute_touch_switch = true; + usage->type = EV_SW; + usage->code = SW_MUTE_DEVICE; features->device_type |= WACOM_DEVICETYPE_PAD; break; case WACOM_HID_WD_TOUCHSTRIP: @@ -1578,6 +1764,10 @@ static void wacom_wac_pad_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); features->device_type |= WACOM_DEVICETYPE_PAD; break; + case WACOM_HID_WD_TOUCHRINGSTATUS: + wacom_map_usage(input, usage, field, EV_ABS, ABS_WHEEL, 0); + features->device_type |= WACOM_DEVICETYPE_PAD; + break; } switch (equivalent_usage & 0xfffffff0) { @@ -1620,17 +1810,40 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field struct input_dev *input = wacom_wac->pad_input; struct wacom_features *features = &wacom_wac->features; unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); + int i; + + /* + * Avoid reporting this event and setting inrange_state if this usage + * hasn't been mapped. + */ + if (!usage->type) + return; if (wacom_equivalent_usage(field->physical) == HID_DG_TABLETFUNCTIONKEY) { - wacom_wac->hid_data.inrange_state |= value; + if (usage->hid != WACOM_HID_WD_TOUCHRING) + wacom_wac->hid_data.inrange_state |= value; } switch (equivalent_usage) { case WACOM_HID_WD_TOUCHRINGSTATUS: + if (!value) + input_event(input, usage->type, usage->code, 0); + break; + + case WACOM_HID_WD_TOUCHONOFF: + if (wacom_wac->shared->touch_input) { + input_report_switch(wacom_wac->shared->touch_input, + SW_MUTE_DEVICE, !value); + input_sync(wacom_wac->shared->touch_input); + } break; + case WACOM_HID_WD_BUTTONCENTER: + for (i = 0; i < wacom->led.count; i++) + wacom_update_led(wacom, features->numbered_buttons, + value, i); + /* fall through*/ default: - features->input_event_flag = true; input_event(input, usage->type, usage->code, value); break; } @@ -1668,20 +1881,15 @@ static void wacom_wac_pad_report(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct wacom_features *features = &wacom_wac->features; struct input_dev *input = wacom_wac->pad_input; bool active = wacom_wac->hid_data.inrange_state != 0; /* report prox for expresskey events */ if (wacom_equivalent_usage(report->field[0]->physical) == HID_DG_TABLETFUNCTIONKEY) { - features->input_event_flag = true; input_event(input, EV_ABS, ABS_MISC, active ? PAD_DEVICE_ID : 0); - } - - if (features->input_event_flag) { - features->input_event_flag = false; input_sync(input); } + } static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, @@ -2056,8 +2264,10 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev, for (j = 0; j < field->maxusage; j++) { struct hid_usage *usage = &field->usage[j]; + unsigned int equivalent_usage = + wacom_equivalent_usage(usage->hid); - switch (usage->hid) { + switch (equivalent_usage) { case HID_GD_X: case HID_GD_Y: case HID_DG_WIDTH: @@ -2066,7 +2276,7 @@ static void wacom_wac_finger_pre_report(struct hid_device *hdev, case HID_DG_INRANGE: case HID_DG_INVERT: case HID_DG_TIPSWITCH: - hid_data->last_slot_field = usage->hid; + hid_data->last_slot_field = equivalent_usage; break; case HID_DG_CONTACTCOUNT: hid_data->cc_report = report->id; @@ -2121,8 +2331,8 @@ void wacom_wac_usage_mapping(struct hid_device *hdev, struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_features *features = &wacom_wac->features; - /* currently, only direct devices have proper hid report descriptors */ - features->device_type |= WACOM_DEVICETYPE_DIRECT; + if (WACOM_DIRECT_DEVICE(field)) + features->device_type |= WACOM_DEVICETYPE_DIRECT; if (WACOM_PAD_FIELD(field)) wacom_wac_pad_usage_mapping(hdev, field, usage); @@ -2140,6 +2350,9 @@ void wacom_wac_event(struct hid_device *hdev, struct hid_field *field, if (wacom->wacom_wac.features.type != HID_GENERIC) return; + if (value > field->logical_maximum || value < field->logical_minimum) + return; + if (WACOM_PAD_FIELD(field)) { wacom_wac_pad_battery_event(hdev, field, usage, value); if (wacom->wacom_wac.pad_input) @@ -2187,6 +2400,16 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) wacom_report_events(hdev, report); + /* + * Non-input reports may be sent prior to the device being + * completely initialized. Since only their events need + * to be processed, exit after 'wacom_report_events' has + * been called to prevent potential crashes in the report- + * processing functions. + */ + if (report->type != HID_INPUT_REPORT) + return; + if (WACOM_PAD_FIELD(field)) { wacom_wac_pad_battery_report(hdev, report); if (wacom->wacom_wac.pad_input) @@ -2657,6 +2880,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) sync = wacom_intuos_irq(wacom_wac); break; + case INTUOSP2_BT: + sync = wacom_intuos_pro2_bt_irq(wacom_wac, len); + break; + case TABLETPC: case TABLETPCE: case TABLETPC2FG: @@ -2767,8 +2994,6 @@ void wacom_setup_device_quirks(struct wacom *wacom) struct wacom_features *features = &wacom->wacom_wac.features; /* The pen and pad share the same interface on most devices */ - if (features->numbered_buttons > 0) - features->device_type |= WACOM_DEVICETYPE_PAD; if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 || features->type == DTUS || (features->type >= INTUOS3S && features->type <= WACOM_MO)) { @@ -2828,6 +3053,13 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type == REMOTE) features->device_type = WACOM_DEVICETYPE_PAD; + if (features->type == INTUOSP2_BT) { + features->device_type |= WACOM_DEVICETYPE_PEN | + WACOM_DEVICETYPE_PAD | + WACOM_DEVICETYPE_TOUCH; + features->quirks |= WACOM_QUIRK_BATTERY; + } + switch (features->type) { case PL: case DTU: @@ -2974,6 +3206,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, case INTUOSPL: case INTUOS5S: case INTUOSPS: + case INTUOSP2_BT: input_set_abs_params(input_dev, ABS_DISTANCE, 0, features->distance_max, features->distance_fuzz, 0); @@ -3082,6 +3315,27 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, } switch (features->type) { + case INTUOSP2_BT: + input_dev->evbit[0] |= BIT_MASK(EV_SW); + __set_bit(SW_MUTE_DEVICE, input_dev->swbit); + + if (wacom_wac->shared->touch->product == 0x361) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, 12440, 4, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, 8640, 4, 0); + } + else if (wacom_wac->shared->touch->product == 0x360) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, + 0, 8960, 4, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, + 0, 5920, 4, 0); + } + input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); + input_abs_set_res(input_dev, ABS_MT_POSITION_X, 40); + + /* fall through */ + case INTUOS5: case INTUOS5L: case INTUOSPM: @@ -3278,6 +3532,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, { struct wacom_features *features = &wacom_wac->features; + if ((features->type == HID_GENERIC) && features->numbered_buttons > 0) + features->device_type |= WACOM_DEVICETYPE_PAD; + if (!(features->device_type & WACOM_DEVICETYPE_PAD)) return -ENODEV; @@ -3379,6 +3636,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOSPL: case INTUOS5S: case INTUOSPS: + case INTUOSP2_BT: input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; @@ -3937,6 +4195,12 @@ static const struct wacom_features wacom_features_0x343 = DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; +static const struct wacom_features wacom_features_0x360 = + { "Wacom Intuos Pro M", 44800, 29600, 8191, 63, + INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 }; +static const struct wacom_features wacom_features_0x361 = + { "Wacom Intuos Pro L", 62200, 43200, 8191, 63, + INTUOSP2_BT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 9, .touch_max = 10 }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC, .oVid = HID_ANY_ID, .oPid = HID_ANY_ID }; @@ -4103,6 +4367,8 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x33D) }, { USB_DEVICE_WACOM(0x33E) }, { USB_DEVICE_WACOM(0x343) }, + { BT_DEVICE_WACOM(0x360) }, + { BT_DEVICE_WACOM(0x361) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, @@ -4111,6 +4377,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(HID_ANY_ID) }, { I2C_DEVICE_WACOM(HID_ANY_ID) }, + { BT_DEVICE_WACOM(HID_ANY_ID) }, { } }; MODULE_DEVICE_TABLE(hid, wacom_ids); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index fb0e50acb10d..857ccee16f38 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -12,8 +12,8 @@ #include <linux/types.h> #include <linux/hid.h> -/* maximum packet length for USB devices */ -#define WACOM_PKGLEN_MAX 192 +/* maximum packet length for USB/BT devices */ +#define WACOM_PKGLEN_MAX 361 #define WACOM_NAME_MAX 64 #define WACOM_MAX_REMOTES 5 @@ -72,6 +72,17 @@ #define WACOM_REPORT_REMOTE 17 #define WACOM_REPORT_INTUOSHT2_ID 8 +/* wacom command report ids */ +#define WAC_CMD_WL_LED_CONTROL 0x03 +#define WAC_CMD_LED_CONTROL 0x20 +#define WAC_CMD_ICON_START 0x21 +#define WAC_CMD_ICON_XFER 0x23 +#define WAC_CMD_ICON_BT_XFER 0x26 +#define WAC_CMD_DELETE_PAIRING 0x20 +#define WAC_CMD_LED_CONTROL_GENERIC 0x32 +#define WAC_CMD_UNPAIR_ALL 0xFF +#define WAC_CMD_WL_INTUOSP2 0x82 + /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 #define WACOM_QUIRK_SENSE 0x0002 @@ -91,6 +102,7 @@ #define WACOM_HID_SP_DIGITIZER 0x000d0000 #define WACOM_HID_SP_DIGITIZERINFO 0x00100000 #define WACOM_HID_WD_DIGITIZER (WACOM_HID_UP_WACOMDIGITIZER | 0x01) +#define WACOM_HID_WD_PEN (WACOM_HID_UP_WACOMDIGITIZER | 0x02) #define WACOM_HID_WD_SENSE (WACOM_HID_UP_WACOMDIGITIZER | 0x36) #define WACOM_HID_WD_DIGITIZERFNKEYS (WACOM_HID_UP_WACOMDIGITIZER | 0x39) #define WACOM_HID_WD_SERIALHI (WACOM_HID_UP_WACOMDIGITIZER | 0x5c) @@ -104,6 +116,7 @@ #define WACOM_HID_WD_ACCELEROMETER_Y (WACOM_HID_UP_WACOMDIGITIZER | 0x0402) #define WACOM_HID_WD_ACCELEROMETER_Z (WACOM_HID_UP_WACOMDIGITIZER | 0x0403) #define WACOM_HID_WD_BATTERY_CHARGING (WACOM_HID_UP_WACOMDIGITIZER | 0x0404) +#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0454) #define WACOM_HID_WD_BATTERY_LEVEL (WACOM_HID_UP_WACOMDIGITIZER | 0x043b) #define WACOM_HID_WD_EXPRESSKEY00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0910) #define WACOM_HID_WD_EXPRESSKEYCAP00 (WACOM_HID_UP_WACOMDIGITIZER | 0x0950) @@ -113,7 +126,6 @@ #define WACOM_HID_WD_BUTTONLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0993) #define WACOM_HID_WD_BUTTONRIGHT (WACOM_HID_UP_WACOMDIGITIZER | 0x0994) #define WACOM_HID_WD_BUTTONCENTER (WACOM_HID_UP_WACOMDIGITIZER | 0x0995) -#define WACOM_HID_WD_TOUCHONOFF (WACOM_HID_UP_WACOMDIGITIZER | 0x0996) #define WACOM_HID_WD_FINGERWHEEL (WACOM_HID_UP_WACOMDIGITIZER | 0x0d03) #define WACOM_HID_WD_OFFSETLEFT (WACOM_HID_UP_WACOMDIGITIZER | 0x0d30) #define WACOM_HID_WD_OFFSETTOP (WACOM_HID_UP_WACOMDIGITIZER | 0x0d31) @@ -127,6 +139,12 @@ #define WACOM_HID_UP_G11 0xff110000 #define WACOM_HID_G11_PEN (WACOM_HID_UP_G11 | 0x02) #define WACOM_HID_G11_TOUCHSCREEN (WACOM_HID_UP_G11 | 0x11) +#define WACOM_HID_UP_WACOMTOUCH 0xff000000 +#define WACOM_HID_WT_TOUCHSCREEN (WACOM_HID_UP_WACOMTOUCH | 0x04) +#define WACOM_HID_WT_TOUCHPAD (WACOM_HID_UP_WACOMTOUCH | 0x05) +#define WACOM_HID_WT_CONTACTMAX (WACOM_HID_UP_WACOMTOUCH | 0x55) +#define WACOM_HID_WT_X (WACOM_HID_UP_WACOMTOUCH | 0x130) +#define WACOM_HID_WT_Y (WACOM_HID_UP_WACOMTOUCH | 0x131) #define WACOM_PAD_FIELD(f) (((f)->physical == HID_DG_TABLETFUNCTIONKEY) || \ ((f)->physical == WACOM_HID_WD_DIGITIZERFNKEYS) || \ @@ -144,7 +162,14 @@ ((f)->physical == HID_DG_FINGER) || \ ((f)->application == HID_DG_TOUCHSCREEN) || \ ((f)->application == WACOM_HID_G9_TOUCHSCREEN) || \ - ((f)->application == WACOM_HID_G11_TOUCHSCREEN)) + ((f)->application == WACOM_HID_G11_TOUCHSCREEN) || \ + ((f)->application == WACOM_HID_WT_TOUCHPAD) || \ + ((f)->application == HID_DG_TOUCHPAD)) + +#define WACOM_DIRECT_DEVICE(f) (((f)->application == HID_DG_TOUCHSCREEN) || \ + ((f)->application == WACOM_HID_WT_TOUCHSCREEN) || \ + ((f)->application == HID_DG_PEN) || \ + ((f)->application == WACOM_HID_WD_PEN)) enum { PENPARTNER = 0, @@ -170,6 +195,7 @@ enum { INTUOSPS, INTUOSPM, INTUOSPL, + INTUOSP2_BT, WACOM_21UX2, WACOM_22HD, DTK, @@ -232,7 +258,6 @@ struct wacom_features { int pktlen; bool check_for_hid_type; int hid_type; - bool input_event_flag; }; struct wacom_shared { @@ -244,6 +269,7 @@ struct wacom_shared { struct input_dev *touch_input; struct hid_device *pen; struct hid_device *touch; + bool has_mute_touch_switch; }; struct hid_data { @@ -300,6 +326,7 @@ struct wacom_wac { int mode_report; int mode_value; struct hid_data hid_data; + bool has_mute_touch_switch; }; #endif diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index cd49cb17eb7f..308dbda700eb 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -383,6 +383,7 @@ int hv_ringbuffer_read(struct vmbus_channel *channel, return ret; } + init_cached_read_index(channel); next_read_location = hv_get_next_read_location(inring_info); next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, sizeof(desc), diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 190d270b20a2..0649d53f3d16 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1459,6 +1459,16 @@ config SENSORS_SCH5636 This driver can also be built as a module. If so, the module will be called sch5636. +config SENSORS_STTS751 + tristate "ST Microelectronics STTS751" + depends on I2C + help + If you say yes here you get support for STTS751 + temperature sensor chips. + + This driver can also be built as a module. If so, the module + will be called stts751. + config SENSORS_SMM665 tristate "Summit Microelectronics SMM665" depends on I2C diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index d2cb7e804a0f..5509edf6186a 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -148,6 +148,7 @@ obj-$(CONFIG_SENSORS_SMM665) += smm665.o obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o +obj-$(CONFIG_SENSORS_STTS751) += stts751.o obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o obj-$(CONFIG_SENSORS_TC74) += tc74.o obj-$(CONFIG_SENSORS_THMC50) += thmc50.o diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c index ad2b47e40345..bbe3a5c5b3f5 100644 --- a/drivers/hwmon/adc128d818.c +++ b/drivers/hwmon/adc128d818.c @@ -28,6 +28,7 @@ #include <linux/regulator/consumer.h> #include <linux/mutex.h> #include <linux/bitops.h> +#include <linux/of.h> /* Addresses to scan * The chip also supports addresses 0x35..0x37. Don't scan those addresses @@ -58,15 +59,22 @@ static const unsigned short normal_i2c[] = { #define ADC128_REG_MAN_ID 0x3e #define ADC128_REG_DEV_ID 0x3f +/* No. of voltage entries in adc128_attrs */ +#define ADC128_ATTR_NUM_VOLT (8 * 4) + +/* Voltage inputs visible per operation mode */ +static const u8 num_inputs[] = { 7, 8, 4, 6 }; + struct adc128_data { struct i2c_client *client; struct regulator *regulator; int vref; /* Reference voltage in mV */ struct mutex update_lock; + u8 mode; /* Operation mode */ bool valid; /* true if following fields are valid */ unsigned long last_updated; /* In jiffies */ - u16 in[3][7]; /* Register value, normalized to 12 bit + u16 in[3][8]; /* Register value, normalized to 12 bit * 0: input voltage * 1: min limit * 2: max limit @@ -87,7 +95,7 @@ static struct adc128_data *adc128_update_device(struct device *dev) mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { - for (i = 0; i < 7; i++) { + for (i = 0; i < num_inputs[data->mode]; i++) { rv = i2c_smbus_read_word_swapped(client, ADC128_REG_IN(i)); if (rv < 0) @@ -107,20 +115,25 @@ static struct adc128_data *adc128_update_device(struct device *dev) data->in[2][i] = rv << 4; } - rv = i2c_smbus_read_word_swapped(client, ADC128_REG_TEMP); - if (rv < 0) - goto abort; - data->temp[0] = rv >> 7; + if (data->mode != 1) { + rv = i2c_smbus_read_word_swapped(client, + ADC128_REG_TEMP); + if (rv < 0) + goto abort; + data->temp[0] = rv >> 7; - rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_MAX); - if (rv < 0) - goto abort; - data->temp[1] = rv << 1; + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_TEMP_MAX); + if (rv < 0) + goto abort; + data->temp[1] = rv << 1; - rv = i2c_smbus_read_byte_data(client, ADC128_REG_TEMP_HYST); - if (rv < 0) - goto abort; - data->temp[2] = rv << 1; + rv = i2c_smbus_read_byte_data(client, + ADC128_REG_TEMP_HYST); + if (rv < 0) + goto abort; + data->temp[2] = rv << 1; + } rv = i2c_smbus_read_byte_data(client, ADC128_REG_ALARM); if (rv < 0) @@ -240,6 +253,25 @@ static ssize_t adc128_show_alarm(struct device *dev, return sprintf(buf, "%u\n", !!(alarms & mask)); } +static umode_t adc128_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct adc128_data *data = dev_get_drvdata(dev); + + if (index < ADC128_ATTR_NUM_VOLT) { + /* Voltage, visible according to num_inputs[] */ + if (index >= num_inputs[data->mode] * 4) + return 0; + } else { + /* Temperature, visible if not in mode 1 */ + if (data->mode == 1) + return 0; + } + + return attr->mode; +} + static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, adc128_show_in, NULL, 0, 0); static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, @@ -289,6 +321,13 @@ static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, adc128_show_in, adc128_set_in, 6, 2); +static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, + adc128_show_in, NULL, 7, 0); +static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 7, 1); +static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, + adc128_show_in, adc128_set_in, 7, 2); + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, adc128_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, adc128_show_temp, adc128_set_temp, 1); @@ -302,44 +341,54 @@ static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, adc128_show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, adc128_show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, adc128_show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, adc128_show_alarm, NULL, 6); +static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, adc128_show_alarm, NULL, 7); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adc128_show_alarm, NULL, 7); static struct attribute *adc128_attrs[] = { - &sensor_dev_attr_in0_min.dev_attr.attr, - &sensor_dev_attr_in1_min.dev_attr.attr, - &sensor_dev_attr_in2_min.dev_attr.attr, - &sensor_dev_attr_in3_min.dev_attr.attr, - &sensor_dev_attr_in4_min.dev_attr.attr, - &sensor_dev_attr_in5_min.dev_attr.attr, - &sensor_dev_attr_in6_min.dev_attr.attr, - &sensor_dev_attr_in0_max.dev_attr.attr, - &sensor_dev_attr_in1_max.dev_attr.attr, - &sensor_dev_attr_in2_max.dev_attr.attr, - &sensor_dev_attr_in3_max.dev_attr.attr, - &sensor_dev_attr_in4_max.dev_attr.attr, - &sensor_dev_attr_in5_max.dev_attr.attr, - &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in0_alarm.dev_attr.attr, &sensor_dev_attr_in0_input.dev_attr.attr, + &sensor_dev_attr_in0_max.dev_attr.attr, + &sensor_dev_attr_in0_min.dev_attr.attr, + &sensor_dev_attr_in1_alarm.dev_attr.attr, &sensor_dev_attr_in1_input.dev_attr.attr, + &sensor_dev_attr_in1_max.dev_attr.attr, + &sensor_dev_attr_in1_min.dev_attr.attr, + &sensor_dev_attr_in2_alarm.dev_attr.attr, &sensor_dev_attr_in2_input.dev_attr.attr, + &sensor_dev_attr_in2_max.dev_attr.attr, + &sensor_dev_attr_in2_min.dev_attr.attr, + &sensor_dev_attr_in3_alarm.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_in3_max.dev_attr.attr, + &sensor_dev_attr_in3_min.dev_attr.attr, + &sensor_dev_attr_in4_alarm.dev_attr.attr, &sensor_dev_attr_in4_input.dev_attr.attr, + &sensor_dev_attr_in4_max.dev_attr.attr, + &sensor_dev_attr_in4_min.dev_attr.attr, + &sensor_dev_attr_in5_alarm.dev_attr.attr, &sensor_dev_attr_in5_input.dev_attr.attr, + &sensor_dev_attr_in5_max.dev_attr.attr, + &sensor_dev_attr_in5_min.dev_attr.attr, + &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_in6_input.dev_attr.attr, + &sensor_dev_attr_in6_max.dev_attr.attr, + &sensor_dev_attr_in6_min.dev_attr.attr, + &sensor_dev_attr_in7_alarm.dev_attr.attr, + &sensor_dev_attr_in7_input.dev_attr.attr, + &sensor_dev_attr_in7_max.dev_attr.attr, + &sensor_dev_attr_in7_min.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_max.dev_attr.attr, - &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, - &sensor_dev_attr_in0_alarm.dev_attr.attr, - &sensor_dev_attr_in1_alarm.dev_attr.attr, - &sensor_dev_attr_in2_alarm.dev_attr.attr, - &sensor_dev_attr_in3_alarm.dev_attr.attr, - &sensor_dev_attr_in4_alarm.dev_attr.attr, - &sensor_dev_attr_in5_alarm.dev_attr.attr, - &sensor_dev_attr_in6_alarm.dev_attr.attr, &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, NULL }; -ATTRIBUTE_GROUPS(adc128); + +static struct attribute_group adc128_group = { + .attrs = adc128_attrs, + .is_visible = adc128_is_visible, +}; +__ATTRIBUTE_GROUPS(adc128); static int adc128_detect(struct i2c_client *client, struct i2c_board_info *info) { @@ -387,6 +436,15 @@ static int adc128_init_client(struct adc128_data *data) if (err) return err; + /* Set operation mode, if non-default */ + if (data->mode != 0) { + err = i2c_smbus_write_byte_data(client, + ADC128_REG_CONFIG_ADV, + data->mode << 1); + if (err) + return err; + } + /* Start monitoring */ err = i2c_smbus_write_byte_data(client, ADC128_REG_CONFIG, 0x01); if (err) @@ -433,6 +491,21 @@ static int adc128_probe(struct i2c_client *client, data->vref = 2560; /* 2.56V, in mV */ } + /* Operation mode is optional. If unspecified, keep current mode */ + if (of_property_read_u8(dev->of_node, "ti,mode", &data->mode) == 0) { + if (data->mode > 3) { + dev_err(dev, "invalid operation mode %d\n", + data->mode); + err = -EINVAL; + goto error; + } + } else { + err = i2c_smbus_read_byte_data(client, ADC128_REG_CONFIG_ADV); + if (err < 0) + goto error; + data->mode = (err >> 1) & ADC128_REG_MASK; + } + data->client = client; i2c_set_clientdata(client, data); mutex_init(&data->update_lock); diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c index 1fdcc3e703b9..eacf10fadbc6 100644 --- a/drivers/hwmon/adm1021.c +++ b/drivers/hwmon/adm1021.c @@ -191,7 +191,7 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%u\n", (data->alarms >> index) & 1); } -static ssize_t show_alarms(struct device *dev, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -251,16 +251,16 @@ static ssize_t set_temp_min(struct device *dev, return count; } -static ssize_t show_low_power(struct device *dev, +static ssize_t low_power_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct adm1021_data *data = adm1021_update_device(dev); return sprintf(buf, "%d\n", data->low_power); } -static ssize_t set_low_power(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t low_power_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct adm1021_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -303,8 +303,8 @@ static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(low_power, S_IWUSR | S_IRUGO, show_low_power, set_low_power); +static DEVICE_ATTR_RO(alarms); +static DEVICE_ATTR_RW(low_power); static struct attribute *adm1021_attributes[] = { &sensor_dev_attr_temp1_max.dev_attr.attr, diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c index 1abb4609b412..1e4dad36f5ef 100644 --- a/drivers/hwmon/adm1025.c +++ b/drivers/hwmon/adm1025.c @@ -333,12 +333,12 @@ set_temp(1); set_temp(2); static ssize_t -show_alarms(struct device *dev, struct device_attribute *attr, char *buf) +alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -358,21 +358,21 @@ static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_alarm, NULL, 14); static ssize_t -show_vid(struct device *dev, struct device_attribute *attr, char *buf) +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = adm1025_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); static ssize_t -show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1025_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct adm1025_data *data = dev_get_drvdata(dev); unsigned long val; @@ -388,7 +388,7 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, data->vrm = val; return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +static DEVICE_ATTR_RW(vrm); /* * Real code diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c index b2a5d9e5c590..e43f09a07cd0 100644 --- a/drivers/hwmon/adm1026.c +++ b/drivers/hwmon/adm1026.c @@ -1034,15 +1034,15 @@ temp_crit_reg(1); temp_crit_reg(2); temp_crit_reg(3); -static ssize_t show_analog_out_reg(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t analog_out_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", DAC_FROM_REG(data->analog_out)); } -static ssize_t set_analog_out_reg(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t analog_out_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1060,11 +1060,10 @@ static ssize_t set_analog_out_reg(struct device *dev, return count; } -static DEVICE_ATTR(analog_out, S_IRUGO | S_IWUSR, show_analog_out_reg, - set_analog_out_reg); +static DEVICE_ATTR_RW(analog_out); -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); int vid = (data->gpio >> 11) & 0x1f; @@ -1073,17 +1072,17 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", vid_from_reg(vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); unsigned long val; @@ -1100,16 +1099,16 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_alarms_reg(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -1148,14 +1147,15 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 24); static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 25); static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 26); -static ssize_t show_alarm_mask(struct device *dev, +static ssize_t alarm_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->alarm_mask); } -static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t alarm_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1186,18 +1186,17 @@ static ssize_t set_alarm_mask(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(alarm_mask, S_IRUGO | S_IWUSR, show_alarm_mask, - set_alarm_mask); +static DEVICE_ATTR_RW(alarm_mask); -static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, +static ssize_t gpio_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->gpio); } -static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gpio_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1221,16 +1220,18 @@ static ssize_t set_gpio(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(gpio, S_IRUGO | S_IWUSR, show_gpio, set_gpio); +static DEVICE_ATTR_RW(gpio); -static ssize_t show_gpio_mask(struct device *dev, struct device_attribute *attr, +static ssize_t gpio_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%ld\n", data->gpio_mask); } -static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gpio_mask_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1254,17 +1255,17 @@ static ssize_t set_gpio_mask(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(gpio_mask, S_IRUGO | S_IWUSR, show_gpio_mask, set_gpio_mask); +static DEVICE_ATTR_RW(gpio_mask); -static ssize_t show_pwm_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", PWM_FROM_REG(data->pwm1.pwm)); } -static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1285,16 +1286,17 @@ static ssize_t set_pwm_reg(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_auto_pwm_min(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_auto_point1_pwm_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", data->pwm1.auto_pwm_min); } -static ssize_t set_auto_pwm_min(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t temp1_auto_point1_pwm_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1316,21 +1318,23 @@ static ssize_t set_auto_pwm_min(struct device *dev, return count; } -static ssize_t show_auto_pwm_max(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_auto_point2_pwm_show(struct device *dev, + struct device_attribute *attr, + char *buf) { return sprintf(buf, "%d\n", ADM1026_PWM_MAX); } -static ssize_t show_pwm_enable(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pwm1_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm1026_data *data = adm1026_update_device(dev); return sprintf(buf, "%d\n", data->pwm1.enable); } -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm1026_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1366,25 +1370,25 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, } /* enable PWM fan control */ -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm_reg, set_pwm_reg); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); -static DEVICE_ATTR(temp1_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); +static DEVICE_ATTR_RW(pwm1); +static DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, pwm1_show, pwm1_store); +static DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, pwm1_show, pwm1_store); +static DEVICE_ATTR_RW(pwm1_enable); +static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, pwm1_enable_show, + pwm1_enable_store); +static DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, pwm1_enable_show, + pwm1_enable_store); +static DEVICE_ATTR_RW(temp1_auto_point1_pwm); static DEVICE_ATTR(temp2_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); + temp1_auto_point1_pwm_show, temp1_auto_point1_pwm_store); static DEVICE_ATTR(temp3_auto_point1_pwm, S_IRUGO | S_IWUSR, - show_auto_pwm_min, set_auto_pwm_min); + temp1_auto_point1_pwm_show, temp1_auto_point1_pwm_store); -static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); -static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL); +static DEVICE_ATTR_RO(temp1_auto_point2_pwm); +static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, temp1_auto_point2_pwm_show, + NULL); +static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, temp1_auto_point2_pwm_show, + NULL); static struct attribute *adm1026_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c index a5818980dad7..bcf508269fd6 100644 --- a/drivers/hwmon/adm1031.c +++ b/drivers/hwmon/adm1031.c @@ -829,14 +829,14 @@ temp_reg(2); temp_reg(3); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1031_data *data = adm1031_update_device(dev); return sprintf(buf, "%d\n", data->alarm); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -867,7 +867,7 @@ static const unsigned int update_intervals[] = { 16000, 8000, 4000, 2000, 1000, 500, 250, 125, }; -static ssize_t show_update_interval(struct device *dev, +static ssize_t update_interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm1031_data *data = dev_get_drvdata(dev); @@ -875,9 +875,9 @@ static ssize_t show_update_interval(struct device *dev, return sprintf(buf, "%u\n", data->update_interval); } -static ssize_t set_update_interval(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm1031_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -912,8 +912,7 @@ static ssize_t set_update_interval(struct device *dev, return count; } -static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, - set_update_interval); +static DEVICE_ATTR_RW(update_interval); static struct attribute *adm1031_attributes[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c index 72bf2489511e..255413fdbde9 100644 --- a/drivers/hwmon/adm9240.c +++ b/drivers/hwmon/adm9240.c @@ -262,8 +262,8 @@ static struct adm9240_data *adm9240_update_device(struct device *dev) /*** sysfs accessors ***/ /* temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *dummy, - char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *dummy, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", data->temp / 128 * 500); /* 9-bit value */ @@ -298,7 +298,7 @@ static ssize_t set_max(struct device *dev, struct device_attribute *devattr, return count; } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR_RO(temp1_input); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 0); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, @@ -501,13 +501,13 @@ fan(1); fan(2); /* alarms */ -static ssize_t show_alarms(struct device *dev, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -527,25 +527,25 @@ static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); /* vid */ -static ssize_t show_vid(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); /* analog output */ -static ssize_t show_aout(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t aout_output_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct adm9240_data *data = adm9240_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t aout_output_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct adm9240_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -562,7 +562,7 @@ static ssize_t set_aout(struct device *dev, mutex_unlock(&data->update_lock); return count; } -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +static DEVICE_ATTR_RW(aout_output); static ssize_t chassis_clear(struct device *dev, struct device_attribute *attr, diff --git a/drivers/hwmon/adt7411.c b/drivers/hwmon/adt7411.c index bdeaece9641d..b939f8a115ba 100644 --- a/drivers/hwmon/adt7411.c +++ b/drivers/hwmon/adt7411.c @@ -21,6 +21,21 @@ #include <linux/hwmon-sysfs.h> #include <linux/slab.h> +#define ADT7411_REG_STAT_1 0x00 +#define ADT7411_STAT_1_INT_TEMP_HIGH BIT(0) +#define ADT7411_STAT_1_INT_TEMP_LOW BIT(1) +#define ADT7411_STAT_1_EXT_TEMP_HIGH_AIN1 BIT(2) +#define ADT7411_STAT_1_EXT_TEMP_LOW BIT(3) +#define ADT7411_STAT_1_EXT_TEMP_FAULT BIT(4) +#define ADT7411_STAT_1_AIN2 BIT(5) +#define ADT7411_STAT_1_AIN3 BIT(6) +#define ADT7411_STAT_1_AIN4 BIT(7) +#define ADT7411_REG_STAT_2 0x01 +#define ADT7411_STAT_2_AIN5 BIT(0) +#define ADT7411_STAT_2_AIN6 BIT(1) +#define ADT7411_STAT_2_AIN7 BIT(2) +#define ADT7411_STAT_2_AIN8 BIT(3) +#define ADT7411_STAT_2_VDD BIT(4) #define ADT7411_REG_INT_TEMP_VDD_LSB 0x03 #define ADT7411_REG_EXT_TEMP_AIN14_LSB 0x04 #define ADT7411_REG_VDD_MSB 0x06 @@ -28,20 +43,31 @@ #define ADT7411_REG_EXT_TEMP_AIN1_MSB 0x08 #define ADT7411_REG_CFG1 0x18 -#define ADT7411_CFG1_START_MONITOR (1 << 0) -#define ADT7411_CFG1_RESERVED_BIT1 (1 << 1) -#define ADT7411_CFG1_EXT_TDM (1 << 2) -#define ADT7411_CFG1_RESERVED_BIT3 (1 << 3) +#define ADT7411_CFG1_START_MONITOR BIT(0) +#define ADT7411_CFG1_RESERVED_BIT1 BIT(1) +#define ADT7411_CFG1_EXT_TDM BIT(2) +#define ADT7411_CFG1_RESERVED_BIT3 BIT(3) #define ADT7411_REG_CFG2 0x19 -#define ADT7411_CFG2_DISABLE_AVG (1 << 5) +#define ADT7411_CFG2_DISABLE_AVG BIT(5) #define ADT7411_REG_CFG3 0x1a -#define ADT7411_CFG3_ADC_CLK_225 (1 << 0) -#define ADT7411_CFG3_RESERVED_BIT1 (1 << 1) -#define ADT7411_CFG3_RESERVED_BIT2 (1 << 2) -#define ADT7411_CFG3_RESERVED_BIT3 (1 << 3) -#define ADT7411_CFG3_REF_VDD (1 << 4) +#define ADT7411_CFG3_ADC_CLK_225 BIT(0) +#define ADT7411_CFG3_RESERVED_BIT1 BIT(1) +#define ADT7411_CFG3_RESERVED_BIT2 BIT(2) +#define ADT7411_CFG3_RESERVED_BIT3 BIT(3) +#define ADT7411_CFG3_REF_VDD BIT(4) + +#define ADT7411_REG_VDD_HIGH 0x23 +#define ADT7411_REG_VDD_LOW 0x24 +#define ADT7411_REG_TEMP_HIGH(nr) (0x25 + 2 * (nr)) +#define ADT7411_REG_TEMP_LOW(nr) (0x26 + 2 * (nr)) +#define ADT7411_REG_IN_HIGH(nr) ((nr) > 1 \ + ? 0x2b + 2 * ((nr)-2) \ + : 0x27) +#define ADT7411_REG_IN_LOW(nr) ((nr) > 1 \ + ? 0x2c + 2 * ((nr)-2) \ + : 0x28) #define ADT7411_REG_DEVICE_ID 0x4d #define ADT7411_REG_MANUFACTURER_ID 0x4e @@ -51,6 +77,30 @@ static const unsigned short normal_i2c[] = { 0x48, 0x4a, 0x4b, I2C_CLIENT_END }; +static const u8 adt7411_in_alarm_reg[] = { + ADT7411_REG_STAT_2, + ADT7411_REG_STAT_1, + ADT7411_REG_STAT_1, + ADT7411_REG_STAT_1, + ADT7411_REG_STAT_1, + ADT7411_REG_STAT_2, + ADT7411_REG_STAT_2, + ADT7411_REG_STAT_2, + ADT7411_REG_STAT_2, +}; + +static const u8 adt7411_in_alarm_bits[] = { + ADT7411_STAT_2_VDD, + ADT7411_STAT_1_EXT_TEMP_HIGH_AIN1, + ADT7411_STAT_1_AIN2, + ADT7411_STAT_1_AIN3, + ADT7411_STAT_1_AIN4, + ADT7411_STAT_2_AIN5, + ADT7411_STAT_2_AIN6, + ADT7411_STAT_2_AIN7, + ADT7411_STAT_2_AIN8, +}; + struct adt7411_data { struct mutex device_lock; /* for "atomic" device accesses */ struct mutex update_lock; @@ -165,6 +215,19 @@ static struct attribute *adt7411_attrs[] = { }; ATTRIBUTE_GROUPS(adt7411); +static int adt7411_read_in_alarm(struct device *dev, int channel, long *val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret; + + ret = i2c_smbus_read_byte_data(client, adt7411_in_alarm_reg[channel]); + if (ret < 0) + return ret; + *val = !!(ret & adt7411_in_alarm_bits[channel]); + return 0; +} + static int adt7411_read_in_vdd(struct device *dev, u32 attr, long *val) { struct adt7411_data *data = dev_get_drvdata(dev); @@ -179,32 +242,41 @@ static int adt7411_read_in_vdd(struct device *dev, u32 attr, long *val) return ret; *val = ret * 7000 / 1024; return 0; + case hwmon_in_min: + ret = i2c_smbus_read_byte_data(client, ADT7411_REG_VDD_LOW); + if (ret < 0) + return ret; + *val = ret * 7000 / 256; + return 0; + case hwmon_in_max: + ret = i2c_smbus_read_byte_data(client, ADT7411_REG_VDD_HIGH); + if (ret < 0) + return ret; + *val = ret * 7000 / 256; + return 0; + case hwmon_in_alarm: + return adt7411_read_in_alarm(dev, 0, val); default: return -EOPNOTSUPP; } } -static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, - long *val) +static int adt7411_update_vref(struct device *dev) { struct adt7411_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; + int val; - int ret; - int lsb_reg, lsb_shift; - int nr = channel - 1; - - mutex_lock(&data->update_lock); if (time_after_eq(jiffies, data->next_update)) { - ret = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); - if (ret < 0) - goto exit_unlock; + val = i2c_smbus_read_byte_data(client, ADT7411_REG_CFG3); + if (val < 0) + return val; - if (ret & ADT7411_CFG3_REF_VDD) { - ret = adt7411_read_in_vdd(dev, hwmon_in_input, + if (val & ADT7411_CFG3_REF_VDD) { + val = adt7411_read_in_vdd(dev, hwmon_in_input, &data->vref_cached); - if (ret < 0) - goto exit_unlock; + if (val < 0) + return val; } else { data->vref_cached = 2250; } @@ -212,6 +284,24 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, data->next_update = jiffies + HZ; } + return 0; +} + +static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, + long *val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + int ret; + int reg, lsb_reg, lsb_shift; + int nr = channel - 1; + + mutex_lock(&data->update_lock); + ret = adt7411_update_vref(dev); + if (ret < 0) + goto exit_unlock; + switch (attr) { case hwmon_in_input: lsb_reg = ADT7411_REG_EXT_TEMP_AIN14_LSB + (nr >> 2); @@ -224,6 +314,20 @@ static int adt7411_read_in_chan(struct device *dev, u32 attr, int channel, *val = ret * data->vref_cached / 1024; ret = 0; break; + case hwmon_in_min: + case hwmon_in_max: + reg = (attr == hwmon_in_min) + ? ADT7411_REG_IN_LOW(channel) + : ADT7411_REG_IN_HIGH(channel); + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + goto exit_unlock; + *val = ret * data->vref_cached / 256; + ret = 0; + break; + case hwmon_in_alarm: + ret = adt7411_read_in_alarm(dev, channel, val); + break; default: ret = -EOPNOTSUPP; break; @@ -242,12 +346,44 @@ static int adt7411_read_in(struct device *dev, u32 attr, int channel, return adt7411_read_in_chan(dev, attr, channel, val); } + +static int adt7411_read_temp_alarm(struct device *dev, u32 attr, int channel, + long *val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret, bit; + + ret = i2c_smbus_read_byte_data(client, ADT7411_REG_STAT_1); + if (ret < 0) + return ret; + + switch (attr) { + case hwmon_temp_min_alarm: + bit = channel ? ADT7411_STAT_1_EXT_TEMP_LOW + : ADT7411_STAT_1_INT_TEMP_LOW; + break; + case hwmon_temp_max_alarm: + bit = channel ? ADT7411_STAT_1_EXT_TEMP_HIGH_AIN1 + : ADT7411_STAT_1_INT_TEMP_HIGH; + break; + case hwmon_temp_fault: + bit = ADT7411_STAT_1_EXT_TEMP_FAULT; + break; + default: + return -EOPNOTSUPP; + } + + *val = !!(ret & bit); + return 0; +} + static int adt7411_read_temp(struct device *dev, u32 attr, int channel, long *val) { struct adt7411_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; - int ret, regl, regh; + int ret, reg, regl, regh; switch (attr) { case hwmon_temp_input: @@ -261,6 +397,21 @@ static int adt7411_read_temp(struct device *dev, u32 attr, int channel, ret = ret & 0x200 ? ret - 0x400 : ret; /* 10 bit signed */ *val = ret * 250; return 0; + case hwmon_temp_min: + case hwmon_temp_max: + reg = (attr == hwmon_temp_min) + ? ADT7411_REG_TEMP_LOW(channel) + : ADT7411_REG_TEMP_HIGH(channel); + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) + return ret; + ret = ret & 0x80 ? ret - 0x100 : ret; /* 8 bit signed */ + *val = ret * 1000; + return 0; + case hwmon_temp_min_alarm: + case hwmon_temp_max_alarm: + case hwmon_temp_fault: + return adt7411_read_temp_alarm(dev, attr, channel, val); default: return -EOPNOTSUPP; } @@ -279,26 +430,143 @@ static int adt7411_read(struct device *dev, enum hwmon_sensor_types type, } } +static int adt7411_write_in_vdd(struct device *dev, u32 attr, long val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int reg; + + val = clamp_val(val, 0, 255 * 7000 / 256); + val = DIV_ROUND_CLOSEST(val * 256, 7000); + + switch (attr) { + case hwmon_in_min: + reg = ADT7411_REG_VDD_LOW; + break; + case hwmon_in_max: + reg = ADT7411_REG_VDD_HIGH; + break; + default: + return -EOPNOTSUPP; + } + + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int adt7411_write_in_chan(struct device *dev, u32 attr, int channel, + long val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int ret, reg; + + mutex_lock(&data->update_lock); + ret = adt7411_update_vref(dev); + if (ret < 0) + goto exit_unlock; + val = clamp_val(val, 0, 255 * data->vref_cached / 256); + val = DIV_ROUND_CLOSEST(val * 256, data->vref_cached); + + switch (attr) { + case hwmon_in_min: + reg = ADT7411_REG_IN_LOW(channel); + break; + case hwmon_in_max: + reg = ADT7411_REG_IN_HIGH(channel); + break; + default: + ret = -EOPNOTSUPP; + goto exit_unlock; + } + + ret = i2c_smbus_write_byte_data(client, reg, val); + exit_unlock: + mutex_unlock(&data->update_lock); + return ret; +} + +static int adt7411_write_in(struct device *dev, u32 attr, int channel, + long val) +{ + if (channel == 0) + return adt7411_write_in_vdd(dev, attr, val); + else + return adt7411_write_in_chan(dev, attr, channel, val); +} + +static int adt7411_write_temp(struct device *dev, u32 attr, int channel, + long val) +{ + struct adt7411_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int reg; + + val = clamp_val(val, -128000, 127000); + val = DIV_ROUND_CLOSEST(val, 1000); + + switch (attr) { + case hwmon_temp_min: + reg = ADT7411_REG_TEMP_LOW(channel); + break; + case hwmon_temp_max: + reg = ADT7411_REG_TEMP_HIGH(channel); + break; + default: + return -EOPNOTSUPP; + } + + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int adt7411_write(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long val) +{ + switch (type) { + case hwmon_in: + return adt7411_write_in(dev, attr, channel, val); + case hwmon_temp: + return adt7411_write_temp(dev, attr, channel, val); + default: + return -EOPNOTSUPP; + } +} + static umode_t adt7411_is_visible(const void *_data, enum hwmon_sensor_types type, u32 attr, int channel) { const struct adt7411_data *data = _data; + bool visible; switch (type) { case hwmon_in: - if (channel > 0 && channel < 3) - return data->use_ext_temp ? 0 : S_IRUGO; - else - return S_IRUGO; + visible = channel == 0 || channel >= 3 || !data->use_ext_temp; + switch (attr) { + case hwmon_in_input: + case hwmon_in_alarm: + return visible ? S_IRUGO : 0; + case hwmon_in_min: + case hwmon_in_max: + return visible ? S_IRUGO | S_IWUSR : 0; + } + break; case hwmon_temp: - if (channel == 1) - return data->use_ext_temp ? S_IRUGO : 0; - else - return S_IRUGO; + visible = channel == 0 || data->use_ext_temp; + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_min_alarm: + case hwmon_temp_max_alarm: + case hwmon_temp_fault: + return visible ? S_IRUGO : 0; + case hwmon_temp_min: + case hwmon_temp_max: + return visible ? S_IRUGO | S_IWUSR : 0; + } + break; default: - return 0; + break; } + return 0; } static int adt7411_detect(struct i2c_client *client, @@ -372,15 +640,15 @@ static int adt7411_init_device(struct adt7411_data *data) } static const u32 adt7411_in_config[] = { - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, - HWMON_I_INPUT, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, + HWMON_I_INPUT | HWMON_I_MIN | HWMON_I_MAX | HWMON_I_ALARM, 0 }; @@ -390,8 +658,10 @@ static const struct hwmon_channel_info adt7411_in = { }; static const u32 adt7411_temp_config[] = { - HWMON_T_INPUT, - HWMON_T_INPUT, + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MIN_ALARM | + HWMON_T_MAX | HWMON_T_MAX_ALARM, + HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MIN_ALARM | + HWMON_T_MAX | HWMON_T_MAX_ALARM | HWMON_T_FAULT, 0 }; @@ -409,6 +679,7 @@ static const struct hwmon_channel_info *adt7411_info[] = { static const struct hwmon_ops adt7411_hwmon_ops = { .is_visible = adt7411_is_visible, .read = adt7411_read, + .write = adt7411_write, }; static const struct hwmon_chip_info adt7411_chip_info = { diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c index c9a1d9c25572..2cd920751441 100644 --- a/drivers/hwmon/adt7470.c +++ b/drivers/hwmon/adt7470.c @@ -403,7 +403,7 @@ out: return data; } -static ssize_t show_auto_update_interval(struct device *dev, +static ssize_t auto_update_interval_show(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -411,10 +411,9 @@ static ssize_t show_auto_update_interval(struct device *dev, return sprintf(buf, "%d\n", data->auto_update_interval); } -static ssize_t set_auto_update_interval(struct device *dev, - struct device_attribute *devattr, - const char *buf, - size_t count) +static ssize_t auto_update_interval_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct adt7470_data *data = dev_get_drvdata(dev); long temp; @@ -431,7 +430,7 @@ static ssize_t set_auto_update_interval(struct device *dev, return count; } -static ssize_t show_num_temp_sensors(struct device *dev, +static ssize_t num_temp_sensors_show(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -439,10 +438,9 @@ static ssize_t show_num_temp_sensors(struct device *dev, return sprintf(buf, "%d\n", data->num_temp_sensors); } -static ssize_t set_num_temp_sensors(struct device *dev, - struct device_attribute *devattr, - const char *buf, - size_t count) +static ssize_t num_temp_sensors_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct adt7470_data *data = dev_get_drvdata(dev); long temp; @@ -537,7 +535,7 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]); } -static ssize_t show_alarm_mask(struct device *dev, +static ssize_t alarm_mask_show(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -546,10 +544,9 @@ static ssize_t show_alarm_mask(struct device *dev, return sprintf(buf, "%x\n", data->alarms_mask); } -static ssize_t set_alarm_mask(struct device *dev, - struct device_attribute *devattr, - const char *buf, - size_t count) +static ssize_t alarm_mask_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct adt7470_data *data = dev_get_drvdata(dev); long mask; @@ -723,8 +720,8 @@ static const int adt7470_freq_map[] = { 11, 15, 22, 29, 35, 44, 59, 88, 1400, 22500 }; -static ssize_t show_pwm_freq(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t pwm1_freq_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct adt7470_data *data = adt7470_update_device(dev); unsigned char cfg_reg_1; @@ -745,9 +742,9 @@ static ssize_t show_pwm_freq(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", adt7470_freq_map[index]); } -static ssize_t set_pwm_freq(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t pwm1_freq_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct adt7470_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -1012,12 +1009,9 @@ static ssize_t show_alarm(struct device *dev, return sprintf(buf, "0\n"); } -static DEVICE_ATTR(alarm_mask, S_IWUSR | S_IRUGO, show_alarm_mask, - set_alarm_mask); -static DEVICE_ATTR(num_temp_sensors, S_IWUSR | S_IRUGO, show_num_temp_sensors, - set_num_temp_sensors); -static DEVICE_ATTR(auto_update_interval, S_IWUSR | S_IRUGO, - show_auto_update_interval, set_auto_update_interval); +static DEVICE_ATTR_RW(alarm_mask); +static DEVICE_ATTR_RW(num_temp_sensors); +static DEVICE_ATTR_RW(auto_update_interval); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max, 0); @@ -1133,7 +1127,7 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); -static DEVICE_ATTR(pwm1_freq, S_IWUSR | S_IRUGO, show_pwm_freq, set_pwm_freq); +static DEVICE_ATTR_RW(pwm1_freq); static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO, show_pwm_min, set_pwm_min, 0); diff --git a/drivers/hwmon/adt7475.c b/drivers/hwmon/adt7475.c index 3cefd1aeb24f..c646670b9ea9 100644 --- a/drivers/hwmon/adt7475.c +++ b/drivers/hwmon/adt7475.c @@ -856,16 +856,17 @@ static ssize_t set_pwmfreq(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_pwm_at_crit(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t pwm_use_point2_pwm_at_crit_show(struct device *dev, + struct device_attribute *devattr, + char *buf) { struct adt7475_data *data = adt7475_update_device(dev); return sprintf(buf, "%d\n", !!(data->config4 & CONFIG4_MAXDUTY)); } -static ssize_t set_pwm_at_crit(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t pwm_use_point2_pwm_at_crit_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct adt7475_data *data = i2c_get_clientdata(client); @@ -888,15 +889,15 @@ static ssize_t set_pwm_at_crit(struct device *dev, return count; } -static ssize_t show_vrm(struct device *dev, struct device_attribute *devattr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct adt7475_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", (int)data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) { struct adt7475_data *data = dev_get_drvdata(dev); long val; @@ -910,8 +911,8 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_vid(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct adt7475_data *data = adt7475_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); @@ -1057,11 +1058,10 @@ static SENSOR_DEVICE_ATTR_2(pwm3_auto_point2_pwm, S_IRUGO | S_IWUSR, show_pwm, set_pwm, MAX, 2); /* Non-standard name, might need revisiting */ -static DEVICE_ATTR(pwm_use_point2_pwm_at_crit, S_IWUSR | S_IRUGO, - show_pwm_at_crit, set_pwm_at_crit); +static DEVICE_ATTR_RW(pwm_use_point2_pwm_at_crit); -static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, set_vrm); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RW(vrm); +static DEVICE_ATTR_RO(cpu0_vid); static struct attribute *adt7475_attrs[] = { &sensor_dev_attr_in1_input.dev_attr.attr, diff --git a/drivers/hwmon/adt7x10.c b/drivers/hwmon/adt7x10.c index 98141f483165..0f538f8be6bf 100644 --- a/drivers/hwmon/adt7x10.c +++ b/drivers/hwmon/adt7x10.c @@ -331,9 +331,8 @@ static ssize_t adt7x10_show_alarm(struct device *dev, return sprintf(buf, "%d\n", !!(ret & attr->index)); } -static ssize_t adt7x10_show_name(struct device *dev, - struct device_attribute *da, - char *buf) +static ssize_t name_show(struct device *dev, struct device_attribute *da, + char *buf) { struct adt7x10_data *data = dev_get_drvdata(dev); @@ -359,7 +358,7 @@ static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, adt7x10_show_alarm, NULL, ADT7X10_STAT_T_HIGH); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, adt7x10_show_alarm, NULL, ADT7X10_STAT_T_CRIT); -static DEVICE_ATTR(name, S_IRUGO, adt7x10_show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *adt7x10_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c index 272fcc837ecc..62e191311139 100644 --- a/drivers/hwmon/asb100.c +++ b/drivers/hwmon/asb100.c @@ -483,25 +483,25 @@ sysfs_temp(3); sysfs_temp(4); /* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); /* VRM */ -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct asb100_data *data = dev_get_drvdata(dev); unsigned long val; @@ -519,16 +519,16 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, } /* Alarms */ -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -550,15 +550,15 @@ static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); /* 1 PWM */ -static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, +static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", ASB100_PWM_FROM_REG(data->pwm & 0x0f)); } -static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -577,15 +577,16 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_pwm_enable1(struct device *dev, +static ssize_t pwm1_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct asb100_data *data = asb100_update_device(dev); return sprintf(buf, "%d\n", (data->pwm & 0x80) ? 1 : 0); } -static ssize_t set_pwm_enable1(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct asb100_data *data = i2c_get_clientdata(client); @@ -604,9 +605,8 @@ static ssize_t set_pwm_enable1(struct device *dev, return count; } -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, - show_pwm_enable1, set_pwm_enable1); +static DEVICE_ATTR_RW(pwm1); +static DEVICE_ATTR_RW(pwm1_enable); static struct attribute *asb100_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c index f2f2f2fc755a..b7eadb54c8cb 100644 --- a/drivers/hwmon/atxp1.c +++ b/drivers/hwmon/atxp1.c @@ -81,8 +81,8 @@ static struct atxp1_data *atxp1_update_device(struct device *dev) } /* sys file functions for cpu0_vid */ -static ssize_t atxp1_showvcore(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { int size; struct atxp1_data *data; @@ -95,9 +95,9 @@ static ssize_t atxp1_showvcore(struct device *dev, return size; } -static ssize_t atxp1_storevcore(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t cpu0_vid_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct atxp1_data *data = atxp1_update_device(dev); struct i2c_client *client = data->client; @@ -154,12 +154,11 @@ static ssize_t atxp1_storevcore(struct device *dev, * CPU core reference voltage * unit: millivolt */ -static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, - atxp1_storevcore); +static DEVICE_ATTR_RW(cpu0_vid); /* sys file functions for GPIO1 */ -static ssize_t atxp1_showgpio1(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t gpio1_show(struct device *dev, struct device_attribute *attr, + char *buf) { int size; struct atxp1_data *data; @@ -171,9 +170,8 @@ static ssize_t atxp1_showgpio1(struct device *dev, return size; } -static ssize_t atxp1_storegpio1(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) +static ssize_t gpio1_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct atxp1_data *data = atxp1_update_device(dev); struct i2c_client *client = data->client; @@ -201,11 +199,11 @@ static ssize_t atxp1_storegpio1(struct device *dev, * GPIO1 data register * unit: Four bit as hex (e.g. 0x0f) */ -static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); +static DEVICE_ATTR_RW(gpio1); /* sys file functions for GPIO2 */ -static ssize_t atxp1_showgpio2(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t gpio2_show(struct device *dev, struct device_attribute *attr, + char *buf) { int size; struct atxp1_data *data; @@ -217,9 +215,8 @@ static ssize_t atxp1_showgpio2(struct device *dev, return size; } -static ssize_t atxp1_storegpio2(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t gpio2_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct atxp1_data *data = atxp1_update_device(dev); struct i2c_client *client = data->client; @@ -246,7 +243,7 @@ static ssize_t atxp1_storegpio2(struct device *dev, * GPIO2 data register * unit: Eight bit as hex (e.g. 0xff) */ -static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); +static DEVICE_ATTR_RW(gpio2); static struct attribute *atxp1_attrs[] = { &dev_attr_gpio1.attr, diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c index 8763c4a8280c..aa40a00ad689 100644 --- a/drivers/hwmon/dme1737.c +++ b/drivers/hwmon/dme1737.c @@ -279,7 +279,8 @@ static inline int IN_FROM_REG(int reg, int nominal, int res) static inline int IN_TO_REG(long val, int nominal) { - return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255); + val = clamp_val(val, 0, 255 * nominal / 192); + return DIV_ROUND_CLOSEST(val * 192, nominal); } /* @@ -295,7 +296,8 @@ static inline int TEMP_FROM_REG(int reg, int res) static inline int TEMP_TO_REG(long val) { - return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127); + val = clamp_val(val, -128000, 127000); + return DIV_ROUND_CLOSEST(val, 1000); } /* Temperature range */ @@ -331,9 +333,10 @@ static inline int TEMP_HYST_FROM_REG(int reg, int ix) return (((ix == 1) ? reg : reg >> 4) & 0x0f) * 1000; } -static inline int TEMP_HYST_TO_REG(long val, int ix, int reg) +static inline int TEMP_HYST_TO_REG(int temp, long hyst, int ix, int reg) { - int hyst = clamp_val((val + 500) / 1000, 0, 15); + hyst = clamp_val(hyst, temp - 15000, temp); + hyst = DIV_ROUND_CLOSEST(temp - hyst, 1000); return (ix == 1) ? (reg & 0xf0) | hyst : (reg & 0x0f) | (hyst << 4); } @@ -1022,7 +1025,9 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, int ix = sensor_attr_2->index; int fn = sensor_attr_2->nr; long val; + int temp; int err; + u8 reg; err = kstrtol(buf, 10, &val); if (err) @@ -1035,10 +1040,9 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, data->zone_low[ix] = dme1737_read(data, DME1737_REG_ZONE_LOW(ix)); /* Modify the temp hyst value */ - data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG( - TEMP_FROM_REG(data->zone_low[ix], 8) - - val, ix, dme1737_read(data, - DME1737_REG_ZONE_HYST(ix == 2))); + temp = TEMP_FROM_REG(data->zone_low[ix], 8); + reg = dme1737_read(data, DME1737_REG_ZONE_HYST(ix == 2)); + data->zone_hyst[ix == 2] = TEMP_HYST_TO_REG(temp, val, ix, reg); dme1737_write(data, DME1737_REG_ZONE_HYST(ix == 2), data->zone_hyst[ix == 2]); break; @@ -1055,10 +1059,10 @@ static ssize_t set_zone(struct device *dev, struct device_attribute *attr, * Modify the temp range value (which is stored in the upper * nibble of the pwm_freq register) */ - data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - - TEMP_FROM_REG(data->zone_low[ix], 8), - dme1737_read(data, - DME1737_REG_PWM_FREQ(ix))); + temp = TEMP_FROM_REG(data->zone_low[ix], 8); + val = clamp_val(val, temp, temp + 80000); + reg = dme1737_read(data, DME1737_REG_PWM_FREQ(ix)); + data->pwm_freq[ix] = TEMP_RANGE_TO_REG(val - temp, reg); dme1737_write(data, DME1737_REG_PWM_FREQ(ix), data->pwm_freq[ix]); break; @@ -1468,7 +1472,7 @@ exit: * Miscellaneous sysfs attributes * --------------------------------------------------------------------- */ -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); @@ -1477,8 +1481,8 @@ static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct dme1737_data *data = dev_get_drvdata(dev); unsigned long val; @@ -1495,15 +1499,15 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct dme1737_data *data = dme1737_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static ssize_t show_name(struct device *dev, struct device_attribute *attr, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct dme1737_data *data = dev_get_drvdata(dev); @@ -1645,9 +1649,9 @@ SENSOR_DEVICE_ATTR_PWM_5TO6(6); /* Misc */ -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); /* for ISA devices */ +static DEVICE_ATTR_RW(vrm); +static DEVICE_ATTR_RO(cpu0_vid); +static DEVICE_ATTR_RO(name); /* for ISA devices */ /* * This struct holds all the attributes that are always present and need to be diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c index 8890870309e4..5c317fc32a4a 100644 --- a/drivers/hwmon/ds1621.c +++ b/drivers/hwmon/ds1621.c @@ -263,7 +263,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *da, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *da, +static ssize_t alarms_show(struct device *dev, struct device_attribute *da, char *buf) { struct ds1621_data *data = ds1621_update_client(dev); @@ -278,15 +278,16 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", !!(data->conf & attr->index)); } -static ssize_t show_convrate(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t update_interval_show(struct device *dev, + struct device_attribute *da, char *buf) { struct ds1621_data *data = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%hu\n", data->update_interval); } -static ssize_t set_convrate(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) { struct ds1621_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -315,9 +316,8 @@ static ssize_t set_convrate(struct device *dev, struct device_attribute *da, return count; } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); -static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_convrate, - set_convrate); +static DEVICE_ATTR_RO(alarms); +static DEVICE_ATTR_RW(update_interval); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, 1); diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c index 4b870ee9b0d3..1ed9a7aa953d 100644 --- a/drivers/hwmon/emc2103.c +++ b/drivers/hwmon/emc2103.c @@ -284,7 +284,7 @@ static ssize_t set_temp_max(struct device *dev, struct device_attribute *da, } static ssize_t -show_fan(struct device *dev, struct device_attribute *da, char *buf) +fan1_input_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); int rpm = 0; @@ -294,7 +294,7 @@ show_fan(struct device *dev, struct device_attribute *da, char *buf) } static ssize_t -show_fan_div(struct device *dev, struct device_attribute *da, char *buf) +fan1_div_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); int fan_div = 8 / data->fan_multiplier; @@ -307,8 +307,8 @@ show_fan_div(struct device *dev, struct device_attribute *da, char *buf) * of least surprise; the user doesn't expect the fan target to change just * because the divider changed. */ -static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t fan1_div_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { struct emc2103_data *data = emc2103_update_device(dev); struct i2c_client *client = data->client; @@ -369,7 +369,7 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *da, } static ssize_t -show_fan_target(struct device *dev, struct device_attribute *da, char *buf) +fan1_target_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); int rpm = 0; @@ -382,8 +382,9 @@ show_fan_target(struct device *dev, struct device_attribute *da, char *buf) return sprintf(buf, "%d\n", rpm); } -static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t fan1_target_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { struct emc2103_data *data = emc2103_update_device(dev); struct i2c_client *client = data->client; @@ -412,7 +413,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, } static ssize_t -show_fan_fault(struct device *dev, struct device_attribute *da, char *buf) +fan1_fault_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); bool fault = ((data->fan_tach & 0x1fe0) == 0x1fe0); @@ -420,14 +421,15 @@ show_fan_fault(struct device *dev, struct device_attribute *da, char *buf) } static ssize_t -show_pwm_enable(struct device *dev, struct device_attribute *da, char *buf) +pwm1_enable_show(struct device *dev, struct device_attribute *da, char *buf) { struct emc2103_data *data = emc2103_update_device(dev); return sprintf(buf, "%d\n", data->fan_rpm_control ? 3 : 0); } -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { struct emc2103_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -512,14 +514,12 @@ static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_temp_min_alarm, static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 3); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL); -static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, show_fan_div, set_fan_div); -static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_fan_target, - set_fan_target); -static DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL); +static DEVICE_ATTR_RO(fan1_input); +static DEVICE_ATTR_RW(fan1_div); +static DEVICE_ATTR_RW(fan1_target); +static DEVICE_ATTR_RO(fan1_fault); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, show_pwm_enable, - set_pwm_enable); +static DEVICE_ATTR_RW(pwm1_enable); /* sensors present on all models */ static struct attribute *emc2103_attributes[] = { diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c index facd05cda26d..73c681162653 100644 --- a/drivers/hwmon/f71805f.c +++ b/drivers/hwmon/f71805f.c @@ -946,7 +946,7 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute return count; } -static ssize_t show_alarms_in(struct device *dev, struct device_attribute +static ssize_t alarms_in_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct f71805f_data *data = f71805f_update_device(dev); @@ -954,7 +954,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute return sprintf(buf, "%lu\n", data->alarms & 0x7ff); } -static ssize_t show_alarms_fan(struct device *dev, struct device_attribute +static ssize_t alarms_fan_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct f71805f_data *data = f71805f_update_device(dev); @@ -962,7 +962,7 @@ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07); } -static ssize_t show_alarms_temp(struct device *dev, struct device_attribute +static ssize_t alarms_temp_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct f71805f_data *data = f71805f_update_device(dev); @@ -980,7 +980,7 @@ static ssize_t show_alarm(struct device *dev, struct device_attribute return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1); } -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct f71805f_data *data = dev_get_drvdata(dev); @@ -1176,11 +1176,11 @@ static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17); static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18); -static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL); -static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL); -static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); +static DEVICE_ATTR_RO(alarms_in); +static DEVICE_ATTR_RO(alarms_fan); +static DEVICE_ATTR_RO(alarms_temp); -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *f71805f_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index cb28e4b4fb10..ca54ce5c8e10 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c @@ -390,7 +390,7 @@ static ssize_t show_pwm_auto_point_temp(struct device *dev, static ssize_t store_pwm_auto_point_temp(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count); /* Sysfs misc */ -static ssize_t show_name(struct device *dev, struct device_attribute *devattr, +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf); static int f71882fg_probe(struct platform_device *pdev); @@ -404,7 +404,7 @@ static struct platform_driver f71882fg_driver = { .remove = f71882fg_remove, }; -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); /* * Temp attr for the f71858fg, the f71858fg is special as it has its @@ -2212,7 +2212,7 @@ static ssize_t store_pwm_auto_point_temp(struct device *dev, return count; } -static ssize_t show_name(struct device *dev, struct device_attribute *devattr, +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct f71882fg_data *data = dev_get_drvdata(dev); diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c index 15aa49d082c4..9545a346044f 100644 --- a/drivers/hwmon/fam15h_power.c +++ b/drivers/hwmon/fam15h_power.c @@ -83,8 +83,8 @@ static bool is_carrizo_or_later(void) return boot_cpu_data.x86 == 0x15 && boot_cpu_data.x86_model >= 0x60; } -static ssize_t show_power(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t power1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 val, tdp_limit, running_avg_range; s32 running_avg_capture; @@ -136,16 +136,16 @@ static ssize_t show_power(struct device *dev, curr_pwr_watts = (curr_pwr_watts * 15625) >> (10 + running_avg_range); return sprintf(buf, "%u\n", (unsigned int) curr_pwr_watts); } -static DEVICE_ATTR(power1_input, S_IRUGO, show_power, NULL); +static DEVICE_ATTR_RO(power1_input); -static ssize_t show_power_crit(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t power1_crit_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fam15h_power_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->processor_pwr_watts); } -static DEVICE_ATTR(power1_crit, S_IRUGO, show_power_crit, NULL); +static DEVICE_ATTR_RO(power1_crit); static void do_read_registers_on_cu(void *_data) { @@ -212,9 +212,8 @@ static int read_registers(struct fam15h_power_data *data) return 0; } -static ssize_t acc_show_power(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t power1_average_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct fam15h_power_data *data = dev_get_drvdata(dev); u64 prev_cu_acc_power[MAX_CUS], prev_ptsc[MAX_CUS], @@ -267,20 +266,20 @@ static ssize_t acc_show_power(struct device *dev, return sprintf(buf, "%llu\n", (unsigned long long)avg_acc); } -static DEVICE_ATTR(power1_average, S_IRUGO, acc_show_power, NULL); +static DEVICE_ATTR_RO(power1_average); -static ssize_t acc_show_power_period(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t power1_average_interval_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct fam15h_power_data *data = dev_get_drvdata(dev); return sprintf(buf, "%lu\n", data->power_period); } -static ssize_t acc_set_power_period(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t power1_average_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct fam15h_power_data *data = dev_get_drvdata(dev); unsigned long temp; @@ -301,8 +300,7 @@ static ssize_t acc_set_power_period(struct device *dev, return count; } -static DEVICE_ATTR(power1_average_interval, S_IRUGO | S_IWUSR, - acc_show_power_period, acc_set_power_period); +static DEVICE_ATTR_RW(power1_average_interval); static int fam15h_power_init_attrs(struct pci_dev *pdev, struct fam15h_power_data *data) diff --git a/drivers/hwmon/fschmd.c b/drivers/hwmon/fschmd.c index d58abdc5a4cf..5e78229ade04 100644 --- a/drivers/hwmon/fschmd.c +++ b/drivers/hwmon/fschmd.c @@ -561,7 +561,7 @@ static ssize_t store_pwm_auto_point1_pwm(struct device *dev, * The FSC hwmon family has the ability to force an attached alert led to flash * from software, we export this as an alert_led sysfs attr */ -static ssize_t show_alert_led(struct device *dev, +static ssize_t alert_led_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct fschmd_data *data = fschmd_update_device(dev); @@ -572,7 +572,7 @@ static ssize_t show_alert_led(struct device *dev, return sprintf(buf, "0\n"); } -static ssize_t store_alert_led(struct device *dev, +static ssize_t alert_led_store(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) { u8 reg; @@ -602,7 +602,7 @@ static ssize_t store_alert_led(struct device *dev, return count; } -static DEVICE_ATTR(alert_led, 0644, show_alert_led, store_alert_led); +static DEVICE_ATTR_RW(alert_led); static struct sensor_device_attribute fschmd_attr[] = { SENSOR_ATTR(in0_input, 0444, show_in_value, NULL, 0), diff --git a/drivers/hwmon/g760a.c b/drivers/hwmon/g760a.c index ec6a77da411a..7be1371b2c3d 100644 --- a/drivers/hwmon/g760a.c +++ b/drivers/hwmon/g760a.c @@ -107,8 +107,8 @@ static struct g760a_data *g760a_update_client(struct device *dev) return data; } -static ssize_t show_fan(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t fan1_input_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g760a_data *data = g760a_update_client(dev); unsigned int rpm = 0; @@ -121,8 +121,8 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", rpm); } -static ssize_t show_fan_alarm(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t fan1_alarm_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g760a_data *data = g760a_update_client(dev); @@ -131,16 +131,16 @@ static ssize_t show_fan_alarm(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", fan_alarm); } -static ssize_t get_pwm(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t pwm1_show(struct device *dev, struct device_attribute *da, + char *buf) { struct g760a_data *data = g760a_update_client(dev); return sprintf(buf, "%d\n", PWM_FROM_CNT(data->set_cnt)); } -static ssize_t set_pwm(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { struct g760a_data *data = g760a_update_client(dev); struct i2c_client *client = data->client; @@ -157,9 +157,9 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *da, return count; } -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL); -static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL); +static DEVICE_ATTR_RW(pwm1); +static DEVICE_ATTR_RO(fan1_input); +static DEVICE_ATTR_RO(fan1_alarm); static struct attribute *g760a_attrs[] = { &dev_attr_pwm1.attr, diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 628be9c95ff9..6dca2fd3d303 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c @@ -738,8 +738,8 @@ static int g762_pdata_prop_import(struct i2c_client *client) * Read function for fan1_input sysfs file. Return current fan RPM value, or * 0 if fan is out of control. */ -static ssize_t get_fan_rpm(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t fan1_input_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); unsigned int rpm = 0; @@ -764,8 +764,8 @@ static ssize_t get_fan_rpm(struct device *dev, struct device_attribute *da, * Read and write functions for pwm1_mode sysfs file. Get and set fan speed * control mode i.e. PWM (1) or DC (0). */ -static ssize_t get_pwm_mode(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t pwm1_mode_show(struct device *dev, struct device_attribute *da, + char *buf) { struct g762_data *data = g762_update_client(dev); @@ -776,8 +776,9 @@ static ssize_t get_pwm_mode(struct device *dev, struct device_attribute *da, !!(data->fan_cmd1 & G762_REG_FAN_CMD1_OUT_MODE)); } -static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t pwm1_mode_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { unsigned long val; int ret; @@ -796,8 +797,8 @@ static ssize_t set_pwm_mode(struct device *dev, struct device_attribute *da, * Read and write functions for fan1_div sysfs file. Get and set fan * controller prescaler value */ -static ssize_t get_fan_div(struct device *dev, - struct device_attribute *da, char *buf) +static ssize_t fan1_div_show(struct device *dev, struct device_attribute *da, + char *buf) { struct g762_data *data = g762_update_client(dev); @@ -807,9 +808,8 @@ static ssize_t get_fan_div(struct device *dev, return sprintf(buf, "%d\n", G762_CLKDIV_FROM_REG(data->fan_cmd1)); } -static ssize_t set_fan_div(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +static ssize_t fan1_div_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { unsigned long val; int ret; @@ -828,8 +828,8 @@ static ssize_t set_fan_div(struct device *dev, * Read and write functions for fan1_pulses sysfs file. Get and set number * of tachometer pulses per fan revolution. */ -static ssize_t get_fan_pulses(struct device *dev, - struct device_attribute *da, char *buf) +static ssize_t fan1_pulses_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); @@ -839,9 +839,9 @@ static ssize_t get_fan_pulses(struct device *dev, return sprintf(buf, "%d\n", G762_PULSE_FROM_REG(data->fan_cmd1)); } -static ssize_t set_fan_pulses(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +static ssize_t fan1_pulses_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { unsigned long val; int ret; @@ -870,8 +870,8 @@ static ssize_t set_fan_pulses(struct device *dev, * but we do not accept 0 as this mode is not natively supported by the chip * and it is not emulated by g762 driver. -EINVAL is returned in this case. */ -static ssize_t get_pwm_enable(struct device *dev, - struct device_attribute *da, char *buf) +static ssize_t pwm1_enable_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); @@ -882,9 +882,9 @@ static ssize_t get_pwm_enable(struct device *dev, (!!(data->fan_cmd1 & G762_REG_FAN_CMD1_FAN_MODE)) + 1); } -static ssize_t set_pwm_enable(struct device *dev, - struct device_attribute *da, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { unsigned long val; int ret; @@ -904,8 +904,8 @@ static ssize_t set_pwm_enable(struct device *dev, * (which affects fan speed) in open-loop mode. 0 stops the fan and 255 * makes it run at full speed. */ -static ssize_t get_pwm(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t pwm1_show(struct device *dev, struct device_attribute *da, + char *buf) { struct g762_data *data = g762_update_client(dev); @@ -915,8 +915,8 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *da, return sprintf(buf, "%d\n", data->set_out); } -static ssize_t set_pwm(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) { unsigned long val; int ret; @@ -942,8 +942,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *da, * Also note that due to rounding errors it is possible that you don't read * back exactly the value you have set. */ -static ssize_t get_fan_target(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t fan1_target_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); unsigned int rpm; @@ -961,8 +961,9 @@ static ssize_t get_fan_target(struct device *dev, struct device_attribute *da, return sprintf(buf, "%u\n", rpm); } -static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t fan1_target_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { unsigned long val; int ret; @@ -978,7 +979,7 @@ static ssize_t set_fan_target(struct device *dev, struct device_attribute *da, } /* read function for fan1_fault sysfs file. */ -static ssize_t get_fan_failure(struct device *dev, struct device_attribute *da, +static ssize_t fan1_fault_show(struct device *dev, struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); @@ -993,8 +994,8 @@ static ssize_t get_fan_failure(struct device *dev, struct device_attribute *da, * read function for fan1_alarm sysfs file. Note that OOC condition is * enabled low */ -static ssize_t get_fan_ooc(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t fan1_alarm_show(struct device *dev, + struct device_attribute *da, char *buf) { struct g762_data *data = g762_update_client(dev); @@ -1004,18 +1005,15 @@ static ssize_t get_fan_ooc(struct device *dev, struct device_attribute *da, return sprintf(buf, "%u\n", !(data->fan_sta & G762_REG_FAN_STA_OOC)); } -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); -static DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, get_pwm_mode, set_pwm_mode); -static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, - get_pwm_enable, set_pwm_enable); -static DEVICE_ATTR(fan1_input, S_IRUGO, get_fan_rpm, NULL); -static DEVICE_ATTR(fan1_alarm, S_IRUGO, get_fan_ooc, NULL); -static DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan_failure, NULL); -static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, - get_fan_target, set_fan_target); -static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_fan_div, set_fan_div); -static DEVICE_ATTR(fan1_pulses, S_IWUSR | S_IRUGO, - get_fan_pulses, set_fan_pulses); +static DEVICE_ATTR_RW(pwm1); +static DEVICE_ATTR_RW(pwm1_mode); +static DEVICE_ATTR_RW(pwm1_enable); +static DEVICE_ATTR_RO(fan1_input); +static DEVICE_ATTR_RO(fan1_alarm); +static DEVICE_ATTR_RO(fan1_fault); +static DEVICE_ATTR_RW(fan1_target); +static DEVICE_ATTR_RW(fan1_div); +static DEVICE_ATTR_RW(fan1_pulses); /* Driver data */ static struct attribute *g762_attrs[] = { diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c index 0212c8317bca..b267510daeb2 100644 --- a/drivers/hwmon/gl518sm.c +++ b/drivers/hwmon/gl518sm.c @@ -86,9 +86,8 @@ enum chips { gl518sm_r00, gl518sm_r80 }; #define BOOL_FROM_REG(val) ((val) ? 0 : 1) #define BOOL_TO_REG(val) ((val) ? 0 : 1) -#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \ - (val) - 500 : \ - (val) + 500) / 1000) + 119), 0, 255) +#define TEMP_CLAMP(val) clamp_val(val, -119000, 136000) +#define TEMP_TO_REG(val) (DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 119) #define TEMP_FROM_REG(val) (((val) - 119) * 1000) static inline u8 FAN_TO_REG(long rpm, int div) @@ -101,11 +100,13 @@ static inline u8 FAN_TO_REG(long rpm, int div) } #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) * (div)))) -#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255) +#define IN_CLAMP(val) clamp_val(val, 0, 255 * 19) +#define IN_TO_REG(val) DIV_ROUND_CLOSEST(IN_CLAMP(val), 19) #define IN_FROM_REG(val) ((val) * 19) -#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255) -#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) +#define VDD_CLAMP(val) clamp_val(val, 0, 255 * 95 / 4) +#define VDD_TO_REG(val) DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95) +#define VDD_FROM_REG(val) DIV_ROUND_CLOSEST((val) * 95, 4) #define DIV_FROM_REG(val) (1 << (val)) diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c index dee93ec87d02..4ff32ee67fb6 100644 --- a/drivers/hwmon/gl520sm.c +++ b/drivers/hwmon/gl520sm.c @@ -200,19 +200,21 @@ static struct gl520_data *gl520_update_device(struct device *dev) * Sysfs stuff */ -static ssize_t get_cpu_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, get_cpu_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -#define VDD_FROM_REG(val) (((val) * 95 + 2) / 4) -#define VDD_TO_REG(val) clamp_val((((val) * 4 + 47) / 95), 0, 255) +#define VDD_FROM_REG(val) DIV_ROUND_CLOSEST((val) * 95, 4) +#define VDD_CLAMP(val) clamp_val(val, 0, 255 * 95 / 4) +#define VDD_TO_REG(val) DIV_ROUND_CLOSEST(VDD_CLAMP(val) * 4, 95) -#define IN_FROM_REG(val) ((val) * 19) -#define IN_TO_REG(val) clamp_val((((val) + 9) / 19), 0, 255) +#define IN_FROM_REG(val) ((val) * 19) +#define IN_CLAMP(val) clamp_val(val, 0, 255 * 19) +#define IN_TO_REG(val) DIV_ROUND_CLOSEST(IN_CLAMP(val), 19) static ssize_t get_in_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -349,8 +351,13 @@ static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR, #define DIV_FROM_REG(val) (1 << (val)) #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (480000 / ((val) << (div)))) -#define FAN_TO_REG(val, div) ((val) <= 0 ? 0 : \ - clamp_val((480000 + ((val) << ((div)-1))) / ((val) << (div)), 1, 255)) + +#define FAN_BASE(div) (480000 >> (div)) +#define FAN_CLAMP(val, div) clamp_val(val, FAN_BASE(div) / 255, \ + FAN_BASE(div)) +#define FAN_TO_REG(val, div) ((val) == 0 ? 0 : \ + DIV_ROUND_CLOSEST(480000, \ + FAN_CLAMP(val, div) << (div))) static ssize_t get_fan_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -381,8 +388,8 @@ static ssize_t get_fan_div(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[n])); } -static ssize_t get_fan_off(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t fan1_off_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->fan_off); @@ -476,8 +483,9 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t set_fan_off(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t fan1_off_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct gl520_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -510,12 +518,11 @@ static SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, get_fan_div, set_fan_div, 0); static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, get_fan_div, set_fan_div, 1); -static DEVICE_ATTR(fan1_off, S_IRUGO | S_IWUSR, - get_fan_off, set_fan_off); +static DEVICE_ATTR_RW(fan1_off); -#define TEMP_FROM_REG(val) (((val) - 130) * 1000) -#define TEMP_TO_REG(val) clamp_val(((((val) < 0 ? \ - (val) - 500 : (val) + 500) / 1000) + 130), 0, 255) +#define TEMP_FROM_REG(val) (((val) - 130) * 1000) +#define TEMP_CLAMP(val) clamp_val(val, -130000, 125000) +#define TEMP_TO_REG(val) (DIV_ROUND_CLOSEST(TEMP_CLAMP(val), 1000) + 130) static ssize_t get_temp_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -596,29 +603,30 @@ static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR, get_temp_max_hyst, set_temp_max_hyst, 1); -static ssize_t get_alarms(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static ssize_t get_beep_enable(struct device *dev, struct device_attribute - *attr, char *buf) +static ssize_t beep_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_enable); } -static ssize_t get_beep_mask(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t beep_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gl520_data *data = gl520_update_device(dev); return sprintf(buf, "%d\n", data->beep_mask); } -static ssize_t set_beep_enable(struct device *dev, struct device_attribute - *attr, const char *buf, size_t count) +static ssize_t beep_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct gl520_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -641,8 +649,9 @@ static ssize_t set_beep_enable(struct device *dev, struct device_attribute return count; } -static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t beep_mask_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct gl520_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -661,11 +670,9 @@ static ssize_t set_beep_mask(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); -static DEVICE_ATTR(beep_enable, S_IRUGO | S_IWUSR, - get_beep_enable, set_beep_enable); -static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, - get_beep_mask, set_beep_mask); +static DEVICE_ATTR_RO(alarms); +static DEVICE_ATTR_RW(beep_enable); +static DEVICE_ATTR_RW(beep_mask); static ssize_t get_alarm(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 685568b1236d..9c355b9d31c5 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -77,8 +77,8 @@ static irqreturn_t fan_alarm_irq_handler(int irq, void *dev_id) return IRQ_NONE; } -static ssize_t show_fan_alarm(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fan1_alarm_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); struct gpio_fan_alarm *alarm = fan_data->alarm; @@ -90,7 +90,7 @@ static ssize_t show_fan_alarm(struct device *dev, return sprintf(buf, "%d\n", value); } -static DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL); +static DEVICE_ATTR_RO(fan1_alarm); static int fan_alarm_init(struct gpio_fan_data *fan_data, struct gpio_fan_alarm *alarm) @@ -188,8 +188,8 @@ static int rpm_to_speed_index(struct gpio_fan_data *fan_data, unsigned long rpm) return fan_data->num_speed - 1; } -static ssize_t show_pwm(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pwm1_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); u8 pwm = fan_data->speed_index * 255 / (fan_data->num_speed - 1); @@ -197,8 +197,8 @@ static ssize_t show_pwm(struct device *dev, return sprintf(buf, "%d\n", pwm); } -static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); unsigned long pwm; @@ -224,16 +224,17 @@ exit_unlock: return ret; } -static ssize_t show_pwm_enable(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pwm1_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", fan_data->pwm_enable); } -static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); unsigned long val; @@ -257,22 +258,22 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_pwm_mode(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pwm1_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "0\n"); } -static ssize_t show_rpm_min(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fan1_min_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", fan_data->speed[0].rpm); } -static ssize_t show_rpm_max(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fan1_max_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); @@ -280,8 +281,8 @@ static ssize_t show_rpm_max(struct device *dev, fan_data->speed[fan_data->num_speed - 1].rpm); } -static ssize_t show_rpm(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t fan1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct gpio_fan_data *fan_data = dev_get_drvdata(dev); @@ -313,14 +314,13 @@ exit_unlock: return ret; } -static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm, set_pwm); -static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, - show_pwm_enable, set_pwm_enable); -static DEVICE_ATTR(pwm1_mode, S_IRUGO, show_pwm_mode, NULL); -static DEVICE_ATTR(fan1_min, S_IRUGO, show_rpm_min, NULL); -static DEVICE_ATTR(fan1_max, S_IRUGO, show_rpm_max, NULL); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_rpm, NULL); -static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, show_rpm, set_rpm); +static DEVICE_ATTR_RW(pwm1); +static DEVICE_ATTR_RW(pwm1_enable); +static DEVICE_ATTR_RO(pwm1_mode); +static DEVICE_ATTR_RO(fan1_min); +static DEVICE_ATTR_RO(fan1_max); +static DEVICE_ATTR_RO(fan1_input); +static DEVICE_ATTR(fan1_target, S_IRUGO | S_IWUSR, fan1_input_show, set_rpm); static umode_t gpio_fan_is_visible(struct kobject *kobj, struct attribute *attr, int index) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 3932f9276c07..28375d59cc36 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -63,11 +63,11 @@ struct hwmon_thermal_data { }; static ssize_t -show_name(struct device *dev, struct device_attribute *attr, char *buf) +name_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *hwmon_dev_attrs[] = { &dev_attr_name.attr, @@ -544,9 +544,11 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, struct device *hdev; int i, j, err, id; - /* Do not accept invalid characters in hwmon name attribute */ + /* Complain about invalid characters in hwmon name attribute */ if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) - return ERR_PTR(-EINVAL); + dev_warn(dev, + "hwmon: '%s' is not a valid name attribute, please fix\n", + name); id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); if (id < 0) @@ -606,7 +608,7 @@ __hwmon_device_register(struct device *dev, const char *name, void *drvdata, if (err) goto free_hwmon; - if (chip && chip->ops->read && + if (dev && chip && chip->ops->read && chip->info[0]->type == hwmon_chip && (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) { const struct hwmon_channel_info **info = chip->info; @@ -651,6 +653,9 @@ hwmon_device_register_with_groups(struct device *dev, const char *name, void *drvdata, const struct attribute_group **groups) { + if (!name) + return ERR_PTR(-EINVAL); + return __hwmon_device_register(dev, name, drvdata, NULL, groups); } EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); @@ -674,6 +679,9 @@ hwmon_device_register_with_info(struct device *dev, const char *name, const struct hwmon_chip_info *chip, const struct attribute_group **extra_groups) { + if (!name) + return ERR_PTR(-EINVAL); + if (chip && (!chip->ops || !chip->ops->is_visible || !chip->info)) return ERR_PTR(-EINVAL); @@ -695,7 +703,7 @@ struct device *hwmon_device_register(struct device *dev) dev_warn(dev, "hwmon_device_register() is deprecated. Please convert the driver to use hwmon_device_register_with_info().\n"); - return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); + return __hwmon_device_register(dev, NULL, NULL, NULL, NULL); } EXPORT_SYMBOL_GPL(hwmon_device_register); diff --git a/drivers/hwmon/i5500_temp.c b/drivers/hwmon/i5500_temp.c index 3e3ccbf18b4e..400e0675a90b 100644 --- a/drivers/hwmon/i5500_temp.c +++ b/drivers/hwmon/i5500_temp.c @@ -43,8 +43,8 @@ */ /* Sensor resolution : 0.5 degree C */ -static ssize_t show_temp(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct pci_dev *pdev = to_pci_dev(dev->parent); long temp; @@ -83,7 +83,7 @@ static ssize_t show_alarm(struct device *dev, return sprintf(buf, "%u\n", (unsigned int)ctsts & (1 << nr)); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR_RO(temp1_input); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_thresh, NULL, 0xE2); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_thresh, NULL, 0xEC); static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_thresh, NULL, 0xEE); diff --git a/drivers/hwmon/i5k_amb.c b/drivers/hwmon/i5k_amb.c index 6b3d1972cef7..a5a9f457b7f7 100644 --- a/drivers/hwmon/i5k_amb.c +++ b/drivers/hwmon/i5k_amb.c @@ -114,14 +114,14 @@ struct i5k_amb_data { unsigned int num_attrs; }; -static ssize_t show_name(struct device *dev, struct device_attribute *devattr, +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { return sprintf(buf, "%s\n", DRVNAME); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct platform_device *amb_pdev; diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index ad82cb28d87a..efb01c247e2d 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c @@ -12,6 +12,7 @@ * * Supports: IT8603E Super I/O chip w/LPC interface * IT8620E Super I/O chip w/LPC interface + * IT8622E Super I/O chip w/LPC interface * IT8623E Super I/O chip w/LPC interface * IT8628E Super I/O chip w/LPC interface * IT8705F Super I/O chip w/LPC interface @@ -31,6 +32,7 @@ * IT8783E/F Super I/O chip w/LPC interface * IT8786E Super I/O chip w/LPC interface * IT8790E Super I/O chip w/LPC interface + * IT8792E Super I/O chip w/LPC interface * Sis950 A clone of the IT8705F * * Copyright (C) 2001 Chris Gauthron @@ -69,8 +71,8 @@ #define DRVNAME "it87" enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732, - it8771, it8772, it8781, it8782, it8783, it8786, it8790, it8603, - it8620, it8628 }; + it8771, it8772, it8781, it8782, it8783, it8786, it8790, + it8792, it8603, it8620, it8622, it8628 }; static unsigned short force_id; module_param(force_id, ushort, 0); @@ -151,6 +153,7 @@ static inline void superio_exit(int ioreg) #define IT8726F_DEVID 0x8726 #define IT8728F_DEVID 0x8728 #define IT8732F_DEVID 0x8732 +#define IT8792E_DEVID 0x8733 #define IT8771E_DEVID 0x8771 #define IT8772E_DEVID 0x8772 #define IT8781F_DEVID 0x8781 @@ -160,6 +163,7 @@ static inline void superio_exit(int ioreg) #define IT8790E_DEVID 0x8790 #define IT8603E_DEVID 0x8603 #define IT8620E_DEVID 0x8620 +#define IT8622E_DEVID 0x8622 #define IT8623E_DEVID 0x8623 #define IT8628E_DEVID 0x8628 #define IT87_ACT_REG 0x30 @@ -293,9 +297,11 @@ struct it87_devices { #define FEAT_SIX_FANS BIT(11) /* Supports six fans */ #define FEAT_10_9MV_ADC BIT(12) #define FEAT_AVCC3 BIT(13) /* Chip supports in9/AVCC3 */ -#define FEAT_SIX_PWM BIT(14) /* Chip supports 6 pwm chn */ -#define FEAT_PWM_FREQ2 BIT(15) /* Separate pwm freq 2 */ -#define FEAT_SIX_TEMP BIT(16) /* Up to 6 temp sensors */ +#define FEAT_FIVE_PWM BIT(14) /* Chip supports 5 pwm chn */ +#define FEAT_SIX_PWM BIT(15) /* Chip supports 6 pwm chn */ +#define FEAT_PWM_FREQ2 BIT(16) /* Separate pwm freq 2 */ +#define FEAT_SIX_TEMP BIT(17) /* Up to 6 temp sensors */ +#define FEAT_VIN3_5V BIT(18) /* VIN3 connected to +5V */ static const struct it87_devices it87_devices[] = { [it87] = { @@ -419,6 +425,15 @@ static const struct it87_devices it87_devices[] = { | FEAT_PWM_FREQ2, .peci_mask = 0x07, }, + [it8792] = { + .name = "it8792", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI + | FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL, + .peci_mask = 0x07, + .old_peci_mask = 0x02, /* Actually reports PCH */ + }, [it8603] = { .name = "it8603", .suffix = "E", @@ -433,7 +448,16 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP, + | FEAT_SIX_TEMP | FEAT_VIN3_5V, + .peci_mask = 0x07, + }, + [it8622] = { + .name = "it8622", + .suffix = "E", + .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS + | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS + | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2 + | FEAT_AVCC3 | FEAT_VIN3_5V, .peci_mask = 0x07, }, [it8628] = { @@ -442,7 +466,7 @@ static const struct it87_devices it87_devices[] = { .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS | FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2 - | FEAT_SIX_TEMP, + | FEAT_SIX_TEMP | FEAT_VIN3_5V, .peci_mask = 0x07, }, }; @@ -465,9 +489,12 @@ static const struct it87_devices it87_devices[] = { #define has_in7_internal(data) ((data)->features & FEAT_IN7_INTERNAL) #define has_six_fans(data) ((data)->features & FEAT_SIX_FANS) #define has_avcc3(data) ((data)->features & FEAT_AVCC3) +#define has_five_pwm(data) ((data)->features & (FEAT_FIVE_PWM \ + | FEAT_SIX_PWM)) #define has_six_pwm(data) ((data)->features & FEAT_SIX_PWM) #define has_pwm_freq2(data) ((data)->features & FEAT_PWM_FREQ2) #define has_six_temp(data) ((data)->features & FEAT_SIX_TEMP) +#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V) struct it87_sio_data { enum chips type; @@ -1300,25 +1327,35 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr, it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl); } else { + u8 ctrl; + /* No on/off mode, set maximum pwm value */ data->pwm_duty[nr] = pwm_to_reg(data, 0xff); it87_write_value(data, IT87_REG_PWM_DUTY[nr], data->pwm_duty[nr]); /* and set manual mode */ - data->pwm_ctrl[nr] = has_newer_autopwm(data) ? - data->pwm_temp_map[nr] : - data->pwm_duty[nr]; - it87_write_value(data, IT87_REG_PWM[nr], - data->pwm_ctrl[nr]); + if (has_newer_autopwm(data)) { + ctrl = (data->pwm_ctrl[nr] & 0x7c) | + data->pwm_temp_map[nr]; + } else { + ctrl = data->pwm_duty[nr]; + } + data->pwm_ctrl[nr] = ctrl; + it87_write_value(data, IT87_REG_PWM[nr], ctrl); } } else { - if (val == 1) /* Manual mode */ - data->pwm_ctrl[nr] = has_newer_autopwm(data) ? - data->pwm_temp_map[nr] : - data->pwm_duty[nr]; - else /* Automatic mode */ - data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; - it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]); + u8 ctrl; + + if (has_newer_autopwm(data)) { + ctrl = (data->pwm_ctrl[nr] & 0x7c) | + data->pwm_temp_map[nr]; + if (val != 1) + ctrl |= 0x80; + } else { + ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80); + } + data->pwm_ctrl[nr] = ctrl; + it87_write_value(data, IT87_REG_PWM[nr], ctrl); if (data->type != it8603 && nr < 3) { /* set SmartGuardian mode */ @@ -1344,6 +1381,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr, return -EINVAL; mutex_lock(&data->update_lock); + it87_update_pwm_ctrl(data, nr); if (has_newer_autopwm(data)) { /* * If we are in automatic mode, the PWM duty cycle register @@ -1456,13 +1494,15 @@ static ssize_t set_pwm_temp_map(struct device *dev, } mutex_lock(&data->update_lock); + it87_update_pwm_ctrl(data, nr); data->pwm_temp_map[nr] = reg; /* * If we are in automatic mode, write the temp mapping immediately; * otherwise, just store it for later use. */ if (data->pwm_ctrl[nr] & 0x80) { - data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr]; + data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) | + data->pwm_temp_map[nr]; it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]); } mutex_unlock(&data->update_lock); @@ -1762,14 +1802,14 @@ static SENSOR_DEVICE_ATTR(pwm6_auto_slope, S_IRUGO | S_IWUSR, show_auto_pwm_slope, set_auto_pwm_slope, 5); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -1877,16 +1917,16 @@ static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2); static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2); -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct it87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct it87_data *data = dev_get_drvdata(dev); unsigned long val; @@ -1898,16 +1938,16 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct it87_data *data = it87_update_device(dev); return sprintf(buf, "%ld\n", (long)vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); static ssize_t show_label(struct device *dev, struct device_attribute *attr, char *buf) @@ -1916,17 +1956,21 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr, "+5V", "5VSB", "Vbat", + "AVCC", }; static const char * const labels_it8721[] = { "+3.3V", "3VSB", "Vbat", + "+3.3V", }; struct it87_data *data = dev_get_drvdata(dev); int nr = to_sensor_dev_attr(attr)->index; const char *label; - if (has_12mv_adc(data) || has_10_9mv_adc(data)) + if (has_vin3_5v(data) && nr == 0) + label = labels[0]; + else if (has_12mv_adc(data) || has_10_9mv_adc(data)) label = labels_it8721[nr]; else label = labels[nr]; @@ -1937,7 +1981,7 @@ static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0); static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1); static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2); /* AVCC3 */ -static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0); +static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 3); static umode_t it87_in_is_visible(struct kobject *kobj, struct attribute *attr, int index) @@ -2386,6 +2430,9 @@ static int __init it87_find(int sioaddr, unsigned short *address, case IT8732F_DEVID: sio_data->type = it8732; break; + case IT8792E_DEVID: + sio_data->type = it8792; + break; case IT8771E_DEVID: sio_data->type = it8771; break; @@ -2414,6 +2461,9 @@ static int __init it87_find(int sioaddr, unsigned short *address, case IT8620E_DEVID: sio_data->type = it8620; break; + case IT8622E_DEVID: + sio_data->type = it8622; + break; case IT8628E_DEVID: sio_data->type = it8628; break; @@ -2457,8 +2507,10 @@ static int __init it87_find(int sioaddr, unsigned short *address, else sio_data->skip_in |= BIT(9); - if (!has_six_pwm(config)) + if (!has_five_pwm(config)) sio_data->skip_pwm |= BIT(3) | BIT(4) | BIT(5); + else if (!has_six_pwm(config)) + sio_data->skip_pwm |= BIT(5); if (!has_vid(config)) sio_data->skip_vid = 1; @@ -2587,7 +2639,7 @@ static int __init it87_find(int sioaddr, unsigned short *address, /* Check for pwm4 */ reg = superio_inb(sioaddr, IT87_SIO_GPIO4_REG); - if (!(reg & BIT(2))) + if (reg & BIT(2)) sio_data->skip_pwm |= BIT(3); /* Check for pwm2, fan2 */ @@ -2602,6 +2654,50 @@ static int __init it87_find(int sioaddr, unsigned short *address, sio_data->skip_fan |= BIT(5); } + /* Check if AVCC is on VIN3 */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (reg & BIT(0)) + sio_data->internal |= BIT(0); + else + sio_data->skip_in |= BIT(9); + + sio_data->beep_pin = superio_inb(sioaddr, + IT87_SIO_BEEP_PIN_REG) & 0x3f; + } else if (sio_data->type == it8622) { + int reg; + + superio_select(sioaddr, GPIO); + + /* Check for pwm4, fan4 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO1_REG); + if (reg & BIT(6)) + sio_data->skip_fan |= BIT(3); + if (reg & BIT(5)) + sio_data->skip_pwm |= BIT(3); + + /* Check for pwm3, fan3, pwm5, fan5 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO3_REG); + if (reg & BIT(6)) + sio_data->skip_pwm |= BIT(2); + if (reg & BIT(7)) + sio_data->skip_fan |= BIT(2); + if (reg & BIT(3)) + sio_data->skip_pwm |= BIT(4); + if (reg & BIT(1)) + sio_data->skip_fan |= BIT(4); + + /* Check for pwm2, fan2 */ + reg = superio_inb(sioaddr, IT87_SIO_GPIO5_REG); + if (reg & BIT(1)) + sio_data->skip_pwm |= BIT(1); + if (reg & BIT(2)) + sio_data->skip_fan |= BIT(1); + + /* Check for AVCC */ + reg = superio_inb(sioaddr, IT87_SIO_PINX2_REG); + if (!(reg & BIT(0))) + sio_data->skip_in |= BIT(9); + sio_data->beep_pin = superio_inb(sioaddr, IT87_SIO_BEEP_PIN_REG) & 0x3f; } else { diff --git a/drivers/hwmon/jz4740-hwmon.c b/drivers/hwmon/jz4740-hwmon.c index 0621ee1b3c98..2d40a2e771d7 100644 --- a/drivers/hwmon/jz4740-hwmon.c +++ b/drivers/hwmon/jz4740-hwmon.c @@ -44,8 +44,8 @@ static irqreturn_t jz4740_hwmon_irq(int irq, void *data) return IRQ_HANDLED; } -static ssize_t jz4740_hwmon_read_adcin(struct device *dev, - struct device_attribute *dev_attr, char *buf) +static ssize_t in0_input_show(struct device *dev, + struct device_attribute *dev_attr, char *buf) { struct jz4740_hwmon *hwmon = dev_get_drvdata(dev); struct platform_device *pdev = hwmon->pdev; @@ -79,7 +79,7 @@ static ssize_t jz4740_hwmon_read_adcin(struct device *dev, return ret; } -static DEVICE_ATTR(in0_input, S_IRUGO, jz4740_hwmon_read_adcin, NULL); +static DEVICE_ATTR_RO(in0_input); static struct attribute *jz4740_attrs[] = { &dev_attr_in0_input.attr, diff --git a/drivers/hwmon/k10temp.c b/drivers/hwmon/k10temp.c index 9cdfde6515ad..ce3b91f22e30 100644 --- a/drivers/hwmon/k10temp.c +++ b/drivers/hwmon/k10temp.c @@ -72,8 +72,8 @@ static void amd_nb_smu_index_read(struct pci_dev *pdev, unsigned int devfn, mutex_unlock(&nb_smu_ind_mutex); } -static ssize_t show_temp(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { u32 regval; struct pci_dev *pdev = dev_get_drvdata(dev); @@ -88,8 +88,8 @@ static ssize_t show_temp(struct device *dev, return sprintf(buf, "%u\n", (regval >> 21) * 125); } -static ssize_t show_temp_max(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_max_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "%d\n", 70 * 1000); } @@ -110,8 +110,8 @@ static ssize_t show_temp_crit(struct device *dev, return sprintf(buf, "%d\n", value); } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL); +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RO(temp1_max); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, show_temp_crit, NULL, 1); diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c index 734d55d48cc8..5a632bcf869b 100644 --- a/drivers/hwmon/k8temp.c +++ b/drivers/hwmon/k8temp.c @@ -100,7 +100,7 @@ static struct k8temp_data *k8temp_update_device(struct device *dev) * Sysfs stuff */ -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct k8temp_data *data = dev_get_drvdata(dev); @@ -133,7 +133,7 @@ static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0); static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1); static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0); static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1); -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static const struct pci_device_id k8temp_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index 33bfdb444138..2e1948699114 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -417,16 +417,16 @@ static ssize_t set_pwm1(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_pwm1_enable(struct device *dev, +static ssize_t pwm1_enable_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); return sprintf(buf, "%d\n", data->config_fan & 0x20 ? 1 : 2); } -static ssize_t set_pwm1_enable(struct device *dev, - struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *dummy, + const char *buf, size_t count) { struct lm63_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -600,7 +600,7 @@ static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, * Hysteresis register holds a relative value, while we want to present * an absolute to user-space */ -static ssize_t show_temp2_crit_hyst(struct device *dev, +static ssize_t temp2_crit_hyst_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); @@ -624,9 +624,9 @@ static ssize_t show_lut_temp_hyst(struct device *dev, * And now the other way around, user-space provides an absolute * hysteresis value and we have to store a relative one */ -static ssize_t set_temp2_crit_hyst(struct device *dev, - struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t temp2_crit_hyst_store(struct device *dev, + struct device_attribute *dummy, + const char *buf, size_t count) { struct lm63_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -670,7 +670,7 @@ static void lm63_set_convrate(struct lm63_data *data, unsigned int interval) data->update_interval = UPDATE_INTERVAL(data->max_convrate_hz, i); } -static ssize_t show_update_interval(struct device *dev, +static ssize_t update_interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm63_data *data = dev_get_drvdata(dev); @@ -678,9 +678,9 @@ static ssize_t show_update_interval(struct device *dev, return sprintf(buf, "%u\n", data->update_interval); } -static ssize_t set_update_interval(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lm63_data *data = dev_get_drvdata(dev); unsigned long val; @@ -697,16 +697,17 @@ static ssize_t set_update_interval(struct device *dev, return count; } -static ssize_t show_type(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp2_type_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm63_data *data = dev_get_drvdata(dev); return sprintf(buf, data->trutherm ? "1\n" : "2\n"); } -static ssize_t set_type(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t temp2_type_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lm63_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -731,7 +732,7 @@ static ssize_t set_type(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, +static ssize_t alarms_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm63_data *data = lm63_update_device(dev); @@ -753,8 +754,7 @@ static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan, set_fan, 1); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 0); -static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, - show_pwm1_enable, set_pwm1_enable); +static DEVICE_ATTR_RW(pwm1_enable); static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO, show_pwm1, set_pwm1, 1); static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO, @@ -841,10 +841,9 @@ static SENSOR_DEVICE_ATTR(temp2_offset, S_IWUSR | S_IRUGO, show_temp11, set_temp11, 3); static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_remote_temp8, set_temp8, 2); -static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst, - set_temp2_crit_hyst); +static DEVICE_ATTR_RW(temp2_crit_hyst); -static DEVICE_ATTR(temp2_type, S_IWUSR | S_IRUGO, show_type, set_type); +static DEVICE_ATTR_RW(temp2_type); /* Individual alarm files */ static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0); @@ -854,10 +853,9 @@ static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6); /* Raw alarm file for compatibility */ -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); -static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, - set_update_interval); +static DEVICE_ATTR_RW(update_interval); static struct attribute *lm63_attributes[] = { &sensor_dev_attr_pwm1.dev_attr.attr, diff --git a/drivers/hwmon/lm70.c b/drivers/hwmon/lm70.c index 583f883a4cfe..543556dc563b 100644 --- a/drivers/hwmon/lm70.c +++ b/drivers/hwmon/lm70.c @@ -46,6 +46,7 @@ #define LM70_CHIP_TMP121 1 /* TI TMP121/TMP123 */ #define LM70_CHIP_LM71 2 /* NS LM71 */ #define LM70_CHIP_LM74 3 /* NS LM74 */ +#define LM70_CHIP_TMP122 4 /* TI TMP122/TMP124 */ struct lm70 { struct spi_device *spi; @@ -54,8 +55,8 @@ struct lm70 { }; /* sysfs hook function */ -static ssize_t lm70_sense_temp(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm70 *p_lm70 = dev_get_drvdata(dev); struct spi_device *spi = p_lm70->spi; @@ -72,7 +73,8 @@ static ssize_t lm70_sense_temp(struct device *dev, */ status = spi_write_then_read(spi, NULL, 0, &rxbuf[0], 2); if (status < 0) { - pr_warn("spi_write_then_read failed with status %d\n", status); + dev_warn(dev, "spi_write_then_read failed with status %d\n", + status); goto out; } raw = (rxbuf[0] << 8) + rxbuf[1]; @@ -91,7 +93,7 @@ static ssize_t lm70_sense_temp(struct device *dev, * Celsius. * So it's equivalent to multiplying by 0.25 * 1000 = 250. * - * LM74 and TMP121/TMP123: + * LM74 and TMP121/TMP122/TMP123/TMP124: * 13 bits of 2's complement data, discard LSB 3 bits, * resolution 0.0625 degrees celsius. * @@ -105,6 +107,7 @@ static ssize_t lm70_sense_temp(struct device *dev, break; case LM70_CHIP_TMP121: + case LM70_CHIP_TMP122: case LM70_CHIP_LM74: val = ((int)raw / 8) * 625 / 10; break; @@ -120,7 +123,7 @@ out: return status; } -static DEVICE_ATTR(temp1_input, S_IRUGO, lm70_sense_temp, NULL); +static DEVICE_ATTR_RO(temp1_input); static struct attribute *lm70_attrs[] = { &dev_attr_temp1_input.attr, @@ -142,6 +145,10 @@ static const struct of_device_id lm70_of_ids[] = { .data = (void *) LM70_CHIP_TMP121, }, { + .compatible = "ti,tmp122", + .data = (void *) LM70_CHIP_TMP122, + }, + { .compatible = "ti,lm71", .data = (void *) LM70_CHIP_LM71, }, @@ -190,6 +197,7 @@ static int lm70_probe(struct spi_device *spi) static const struct spi_device_id lm70_ids[] = { { "lm70", LM70_CHIP_LM70 }, { "tmp121", LM70_CHIP_TMP121 }, + { "tmp122", LM70_CHIP_TMP122 }, { "lm71", LM70_CHIP_LM71 }, { "lm74", LM70_CHIP_LM74 }, { }, diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c index 539efe4ad991..0cb7ff613b80 100644 --- a/drivers/hwmon/lm78.c +++ b/drivers/hwmon/lm78.c @@ -236,22 +236,23 @@ show_in_offset(5); show_in_offset(6); /* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *da, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *da, +static ssize_t temp1_max_show(struct device *dev, struct device_attribute *da, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t temp1_max_store(struct device *dev, + struct device_attribute *da, const char *buf, + size_t count) { struct lm78_data *data = dev_get_drvdata(dev); long val; @@ -268,15 +269,16 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *da, return count; } -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t temp1_max_hyst_show(struct device *dev, + struct device_attribute *da, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, - const char *buf, size_t count) +static ssize_t temp1_max_hyst_store(struct device *dev, + struct device_attribute *da, + const char *buf, size_t count) { struct lm78_data *data = dev_get_drvdata(dev); long val; @@ -293,11 +295,9 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, return count; } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RW(temp1_max); +static DEVICE_ATTR_RW(temp1_max_hyst); /* 3 Fans */ static ssize_t show_fan(struct device *dev, struct device_attribute *da, @@ -431,22 +431,22 @@ static SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, static SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2); /* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *da, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, struct device_attribute *da, + char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *da, +static ssize_t alarms_show(struct device *dev, struct device_attribute *da, char *buf) { struct lm78_data *data = lm78_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *da, char *buf) diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c index 4bcd9b882948..08e3945a6fbf 100644 --- a/drivers/hwmon/lm80.c +++ b/drivers/hwmon/lm80.c @@ -432,7 +432,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm80_data *data = lm80_update_device(dev); @@ -505,7 +505,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, t_os_max); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, t_os_hyst); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c index 9e4d0e1d3c4b..cbfd0bb7f135 100644 --- a/drivers/hwmon/lm83.c +++ b/drivers/hwmon/lm83.c @@ -188,7 +188,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy, +static ssize_t alarms_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct lm83_data *data = lm83_update_device(dev); @@ -236,7 +236,7 @@ static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12); static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 13); static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15); /* Raw alarm file for compatibility */ -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static struct attribute *lm83_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c index 29c8136ce9c5..691469ffa24e 100644 --- a/drivers/hwmon/lm85.c +++ b/drivers/hwmon/lm85.c @@ -604,8 +604,8 @@ show_fan_offset(4); /* vid, vrm, alarms */ -static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm85_data *data = lm85_update_device(dev); int vid; @@ -621,17 +621,17 @@ static ssize_t show_vid_reg(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", vid); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm_reg(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm85_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lm85_data *data = dev_get_drvdata(dev); unsigned long val; @@ -648,16 +648,16 @@ static ssize_t store_vrm_reg(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_alarms_reg(struct device *dev, struct device_attribute - *attr, char *buf) +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct lm85_data *data = lm85_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c index 13cca3606e06..e06faf9d3f0f 100644 --- a/drivers/hwmon/lm87.c +++ b/drivers/hwmon/lm87.c @@ -445,23 +445,23 @@ set_temp(1); set_temp(2); set_temp(3); -static ssize_t show_temp_crit_int(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_crit_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_int)); } -static ssize_t show_temp_crit_ext(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp2_crit_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_crit_ext)); } -static DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit_int, NULL); -static DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit_ext, NULL); -static DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit_ext, NULL); +static DEVICE_ATTR_RO(temp1_crit); +static DEVICE_ATTR_RO(temp2_crit); +static DEVICE_ATTR(temp3_crit, S_IRUGO, temp2_crit_show, NULL); static ssize_t show_fan_input(struct device *dev, struct device_attribute *attr, char *buf) @@ -586,30 +586,30 @@ static SENSOR_DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ set_fan(1); set_fan(2); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm87_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct lm87_data *data = dev_get_drvdata(dev); unsigned long val; @@ -625,16 +625,17 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, data->vrm = val; return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_aout(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t aout_output_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm87_data *data = lm87_update_device(dev); return sprintf(buf, "%d\n", AOUT_FROM_REG(data->aout)); } -static ssize_t set_aout(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t aout_output_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = dev_get_drvdata(dev); struct lm87_data *data = i2c_get_clientdata(client); @@ -651,7 +652,7 @@ static ssize_t set_aout(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->update_lock); return count; } -static DEVICE_ATTR(aout_output, S_IRUGO | S_IWUSR, show_aout, set_aout); +static DEVICE_ATTR_RW(aout_output); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c index 322ed9272811..aff5297bc2bc 100644 --- a/drivers/hwmon/lm90.c +++ b/drivers/hwmon/lm90.c @@ -830,7 +830,7 @@ static u16 temp_to_u16_adt7461(struct lm90_data *data, long val) } /* pec used for ADM1032 only */ -static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, +static ssize_t pec_show(struct device *dev, struct device_attribute *dummy, char *buf) { struct i2c_client *client = to_i2c_client(dev); @@ -838,8 +838,8 @@ static ssize_t show_pec(struct device *dev, struct device_attribute *dummy, return sprintf(buf, "%d\n", !!(client->flags & I2C_CLIENT_PEC)); } -static ssize_t set_pec(struct device *dev, struct device_attribute *dummy, - const char *buf, size_t count) +static ssize_t pec_store(struct device *dev, struct device_attribute *dummy, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); long val; @@ -863,7 +863,7 @@ static ssize_t set_pec(struct device *dev, struct device_attribute *dummy, return count; } -static DEVICE_ATTR(pec, S_IWUSR | S_IRUGO, show_pec, set_pec); +static DEVICE_ATTR_RW(pec); static int lm90_get_temp11(struct lm90_data *data, int index) { @@ -1036,7 +1036,7 @@ static const u8 lm90_temp_emerg_index[3] = { }; static const u8 lm90_min_alarm_bits[3] = { 5, 3, 11 }; -static const u8 lm90_max_alarm_bits[3] = { 0, 4, 12 }; +static const u8 lm90_max_alarm_bits[3] = { 6, 4, 12 }; static const u8 lm90_crit_alarm_bits[3] = { 0, 1, 9 }; static const u8 lm90_emergency_alarm_bits[3] = { 15, 13, 14 }; static const u8 lm90_fault_bits[3] = { 0, 2, 10 }; diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c index cfaf70b9cba7..2a91974a10bb 100644 --- a/drivers/hwmon/lm92.c +++ b/drivers/hwmon/lm92.c @@ -181,8 +181,8 @@ static ssize_t show_temp_hyst(struct device *dev, - TEMP_FROM_REG(data->temp[t_hyst])); } -static ssize_t show_temp_min_hyst(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t temp1_min_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[t_min]) @@ -213,7 +213,7 @@ static ssize_t set_temp_hyst(struct device *dev, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm92_data *data = lm92_update_device(dev); @@ -235,11 +235,11 @@ static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst, set_temp_hyst, t_crit); static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp, set_temp, t_min); -static DEVICE_ATTR(temp1_min_hyst, S_IRUGO, show_temp_min_hyst, NULL); +static DEVICE_ATTR_RO(temp1_min_hyst); static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp, set_temp, t_max); static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO, show_temp_hyst, NULL, t_max); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 1); diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c index 90bb04858117..77a0a83399b3 100644 --- a/drivers/hwmon/lm93.c +++ b/drivers/hwmon/lm93.c @@ -2156,7 +2156,7 @@ static SENSOR_DEVICE_ATTR(pwm2_auto_spinup_time, S_IWUSR | S_IRUGO, show_pwm_auto_spinup_time, store_pwm_auto_spinup_time, 1); -static ssize_t show_pwm_auto_prochot_ramp(struct device *dev, +static ssize_t pwm_auto_prochot_ramp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); @@ -2164,7 +2164,7 @@ static ssize_t show_pwm_auto_prochot_ramp(struct device *dev, LM93_RAMP_FROM_REG(data->pwm_ramp_ctl >> 4 & 0x0f)); } -static ssize_t store_pwm_auto_prochot_ramp(struct device *dev, +static ssize_t pwm_auto_prochot_ramp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -2186,11 +2186,9 @@ static ssize_t store_pwm_auto_prochot_ramp(struct device *dev, return count; } -static DEVICE_ATTR(pwm_auto_prochot_ramp, S_IRUGO | S_IWUSR, - show_pwm_auto_prochot_ramp, - store_pwm_auto_prochot_ramp); +static DEVICE_ATTR_RW(pwm_auto_prochot_ramp); -static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev, +static ssize_t pwm_auto_vrdhot_ramp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); @@ -2198,7 +2196,7 @@ static ssize_t show_pwm_auto_vrdhot_ramp(struct device *dev, LM93_RAMP_FROM_REG(data->pwm_ramp_ctl & 0x0f)); } -static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev, +static ssize_t pwm_auto_vrdhot_ramp_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -2220,9 +2218,7 @@ static ssize_t store_pwm_auto_vrdhot_ramp(struct device *dev, return 0; } -static DEVICE_ATTR(pwm_auto_vrdhot_ramp, S_IRUGO | S_IWUSR, - show_pwm_auto_vrdhot_ramp, - store_pwm_auto_vrdhot_ramp); +static DEVICE_ATTR_RW(pwm_auto_vrdhot_ramp); static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf) @@ -2378,7 +2374,7 @@ static SENSOR_DEVICE_ATTR(prochot1_interval, S_IWUSR | S_IRUGO, static SENSOR_DEVICE_ATTR(prochot2_interval, S_IWUSR | S_IRUGO, show_prochot_interval, store_prochot_interval, 1); -static ssize_t show_prochot_override_duty_cycle(struct device *dev, +static ssize_t prochot_override_duty_cycle_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -2386,7 +2382,7 @@ static ssize_t show_prochot_override_duty_cycle(struct device *dev, return sprintf(buf, "%d\n", data->prochot_override & 0x0f); } -static ssize_t store_prochot_override_duty_cycle(struct device *dev, +static ssize_t prochot_override_duty_cycle_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -2408,18 +2404,16 @@ static ssize_t store_prochot_override_duty_cycle(struct device *dev, return count; } -static DEVICE_ATTR(prochot_override_duty_cycle, S_IRUGO | S_IWUSR, - show_prochot_override_duty_cycle, - store_prochot_override_duty_cycle); +static DEVICE_ATTR_RW(prochot_override_duty_cycle); -static ssize_t show_prochot_short(struct device *dev, +static ssize_t prochot_short_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); return sprintf(buf, "%d\n", (data->config & 0x10) ? 1 : 0); } -static ssize_t store_prochot_short(struct device *dev, +static ssize_t prochot_short_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -2442,8 +2436,7 @@ static ssize_t store_prochot_short(struct device *dev, return count; } -static DEVICE_ATTR(prochot_short, S_IRUGO | S_IWUSR, - show_prochot_short, store_prochot_short); +static DEVICE_ATTR_RW(prochot_short); static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr, char *buf) @@ -2457,23 +2450,23 @@ static ssize_t show_vrdhot(struct device *dev, struct device_attribute *attr, static SENSOR_DEVICE_ATTR(vrdhot1, S_IRUGO, show_vrdhot, NULL, 0); static SENSOR_DEVICE_ATTR(vrdhot2, S_IRUGO, show_vrdhot, NULL, 1); -static ssize_t show_gpio(struct device *dev, struct device_attribute *attr, +static ssize_t gpio_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); return sprintf(buf, "%d\n", LM93_GPI_FROM_REG(data->gpi)); } -static DEVICE_ATTR(gpio, S_IRUGO, show_gpio, NULL); +static DEVICE_ATTR_RO(gpio); -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct lm93_data *data = lm93_update_device(dev); return sprintf(buf, "%d\n", LM93_ALARMS_FROM_REG(data->block1)); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static struct attribute *lm93_attrs[] = { &sensor_dev_attr_in1_input.dev_attr.attr, diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c index 8796de39ff9b..c7fcc9e7f57a 100644 --- a/drivers/hwmon/lm95234.c +++ b/drivers/hwmon/lm95234.c @@ -450,8 +450,8 @@ static ssize_t set_offset(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_interval(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t update_interval_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct lm95234_data *data = dev_get_drvdata(dev); int ret = lm95234_update_device(data); @@ -463,8 +463,9 @@ static ssize_t show_interval(struct device *dev, struct device_attribute *attr, DIV_ROUND_CLOSEST(data->interval * 1000, HZ)); } -static ssize_t set_interval(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct lm95234_data *data = dev_get_drvdata(dev); int ret = lm95234_update_device(data); @@ -566,8 +567,7 @@ static SENSOR_DEVICE_ATTR(temp4_offset, S_IWUSR | S_IRUGO, show_offset, static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset, set_offset, 3); -static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval, - set_interval); +static DEVICE_ATTR_RW(update_interval); static struct attribute *lm95234_common_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, diff --git a/drivers/hwmon/ltc4151.c b/drivers/hwmon/ltc4151.c index 8445c9fd946b..b904cb547ffb 100644 --- a/drivers/hwmon/ltc4151.c +++ b/drivers/hwmon/ltc4151.c @@ -215,6 +215,7 @@ static const struct of_device_id ltc4151_match[] = { { .compatible = "lltc,ltc4151" }, {}, }; +MODULE_DEVICE_TABLE(of, ltc4151_match); /* This is the driver that will be inserted */ static struct i2c_driver ltc4151_driver = { diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c index 303d0c9df907..8ddd4d690652 100644 --- a/drivers/hwmon/max1111.c +++ b/drivers/hwmon/max1111.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL(max1111_read_channel); * likely to be used by hwmon applications to distinguish between * different devices, explicitly add a name attribute here. */ -static ssize_t show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { return sprintf(buf, "%s\n", to_spi_device(dev)->modalias); @@ -125,7 +125,7 @@ static ssize_t show_adc(struct device *dev, #define MAX1111_ADC_ATTR(_id) \ SENSOR_DEVICE_ATTR(in##_id##_input, S_IRUGO, show_adc, NULL, _id) -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static MAX1111_ADC_ATTR(0); static MAX1111_ADC_ATTR(1); static MAX1111_ADC_ATTR(2); diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c index eda9cf599685..a18278938494 100644 --- a/drivers/hwmon/max1619.c +++ b/drivers/hwmon/max1619.c @@ -173,7 +173,7 @@ static ssize_t set_temp(struct device *dev, struct device_attribute *devattr, return count; } -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct max1619_data *data = max1619_update_device(dev); @@ -199,7 +199,7 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp, set_temp, static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp, set_temp, t_hyst2); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3); diff --git a/drivers/hwmon/max197.c b/drivers/hwmon/max197.c index 07628569547a..638567fb7cd8 100644 --- a/drivers/hwmon/max197.c +++ b/drivers/hwmon/max197.c @@ -207,8 +207,8 @@ unlock: return ret; } -static ssize_t max197_show_name(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t name_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct platform_device *pdev = to_platform_device(dev); return sprintf(buf, "%s\n", pdev->name); @@ -231,7 +231,7 @@ static ssize_t max197_show_name(struct device *dev, &sensor_dev_attr_in##chan##_max.dev_attr.attr, \ &sensor_dev_attr_in##chan##_min.dev_attr.attr -static DEVICE_ATTR(name, S_IRUGO, max197_show_name, NULL); +static DEVICE_ATTR_RO(name); MAX197_SENSOR_DEVICE_ATTR_CH(0); MAX197_SENSOR_DEVICE_ATTR_CH(1); diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index a993b44ed538..65be4b19fe47 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c @@ -270,8 +270,8 @@ static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, * controlled. */ -static ssize_t get_target(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t fan1_target_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct max6650_data *data = max6650_update_device(dev); int kscale, ktach, rpm; @@ -318,8 +318,9 @@ static int max6650_set_target(struct max6650_data *data, unsigned long rpm) data->speed); } -static ssize_t set_target(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t fan1_target_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct max6650_data *data = dev_get_drvdata(dev); unsigned long rpm; @@ -350,8 +351,8 @@ static ssize_t set_target(struct device *dev, struct device_attribute *devattr, * back exactly the value you have set. */ -static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t pwm1_show(struct device *dev, struct device_attribute *devattr, + char *buf) { int pwm; struct max6650_data *data = max6650_update_device(dev); @@ -371,8 +372,9 @@ static ssize_t get_pwm(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%d\n", pwm); } -static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t pwm1_store(struct device *dev, + struct device_attribute *devattr, const char *buf, + size_t count) { struct max6650_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -406,8 +408,8 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, * 2 = Closed loop, RPM for all fans regulated by fan1 tachometer * 3 = Fan off */ -static ssize_t get_enable(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t pwm1_enable_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct max6650_data *data = max6650_update_device(dev); int mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4; @@ -416,8 +418,9 @@ static ssize_t get_enable(struct device *dev, struct device_attribute *devattr, return sprintf(buf, "%d\n", sysfs_modes[mode]); } -static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t pwm1_enable_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct max6650_data *data = dev_get_drvdata(dev); unsigned long mode; @@ -458,16 +461,17 @@ static ssize_t set_enable(struct device *dev, struct device_attribute *devattr, * defined for that. See the data sheet for details. */ -static ssize_t get_div(struct device *dev, struct device_attribute *devattr, - char *buf) +static ssize_t fan1_div_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct max6650_data *data = max6650_update_device(dev); return sprintf(buf, "%d\n", DIV_FROM_REG(data->count)); } -static ssize_t set_div(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) +static ssize_t fan1_div_store(struct device *dev, + struct device_attribute *devattr, + const char *buf, size_t count) { struct max6650_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -534,10 +538,10 @@ static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, get_fan, NULL, 3); -static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); -static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); -static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); -static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); +static DEVICE_ATTR_RW(fan1_target); +static DEVICE_ATTR_RW(fan1_div); +static DEVICE_ATTR_RW(pwm1_enable); +static DEVICE_ATTR_RW(pwm1); static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, MAX6650_ALRM_MAX); static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, diff --git a/drivers/hwmon/mc13783-adc.c b/drivers/hwmon/mc13783-adc.c index 0c02f40eb0c1..960a1db6f269 100644 --- a/drivers/hwmon/mc13783-adc.c +++ b/drivers/hwmon/mc13783-adc.c @@ -40,8 +40,8 @@ struct mc13783_adc_priv { char name[PLATFORM_NAME_SIZE]; }; -static ssize_t mc13783_adc_show_name(struct device *dev, struct device_attribute - *devattr, char *buf) +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, + char *buf) { struct mc13783_adc_priv *priv = dev_get_drvdata(dev); @@ -111,7 +111,7 @@ static ssize_t mc13783_adc_read_gp(struct device *dev, return sprintf(buf, "%u\n", val); } -static DEVICE_ATTR(name, S_IRUGO, mc13783_adc_show_name, NULL); +static DEVICE_ATTR_RO(name); static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, mc13783_adc_read_bp, NULL, 2); static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, mc13783_adc_read_gp, NULL, 5); static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, mc13783_adc_read_gp, NULL, 6); diff --git a/drivers/hwmon/mcp3021.c b/drivers/hwmon/mcp3021.c index 1929734c3b1d..de886f82101b 100644 --- a/drivers/hwmon/mcp3021.c +++ b/drivers/hwmon/mcp3021.c @@ -86,8 +86,8 @@ static inline u16 volts_from_reg(struct mcp3021_data *data, u16 val) return DIV_ROUND_CLOSEST(data->vdd * val, 1 << data->output_res); } -static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t in0_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct i2c_client *client = to_i2c_client(dev); struct mcp3021_data *data = i2c_get_clientdata(client); @@ -102,7 +102,7 @@ static ssize_t show_in_input(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", in_input); } -static DEVICE_ATTR(in0_input, 0444, show_in_input, NULL); +static DEVICE_ATTR_RO(in0_input); static int mcp3021_probe(struct i2c_client *client, const struct i2c_device_id *id) diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c index 559c596b24f9..8b0bc4fc06e8 100644 --- a/drivers/hwmon/nct6683.c +++ b/drivers/hwmon/nct6683.c @@ -979,7 +979,7 @@ static const struct sensor_template_group nct6683_pwm_template_group = { }; static ssize_t -show_global_beep(struct device *dev, struct device_attribute *attr, char *buf) +beep_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nct6683_data *data = dev_get_drvdata(dev); int ret; @@ -1004,7 +1004,7 @@ error: } static ssize_t -store_global_beep(struct device *dev, struct device_attribute *attr, +beep_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct nct6683_data *data = dev_get_drvdata(dev); @@ -1039,7 +1039,8 @@ error: /* Case open detection */ static ssize_t -show_caseopen(struct device *dev, struct device_attribute *attr, char *buf) +intrusion0_alarm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct nct6683_data *data = dev_get_drvdata(dev); int ret; @@ -1064,8 +1065,8 @@ error: } static ssize_t -clear_caseopen(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +intrusion0_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct nct6683_data *data = dev_get_drvdata(dev); unsigned long val; @@ -1102,10 +1103,8 @@ error: return count; } -static DEVICE_ATTR(intrusion0_alarm, S_IWUSR | S_IRUGO, show_caseopen, - clear_caseopen); -static DEVICE_ATTR(beep_enable, S_IWUSR | S_IRUGO, show_global_beep, - store_global_beep); +static DEVICE_ATTR_RW(intrusion0_alarm); +static DEVICE_ATTR_RW(beep_enable); static struct attribute *nct6683_attributes_other[] = { &dev_attr_intrusion0_alarm.attr, diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c index ce75dd4db7eb..2458b406f6aa 100644 --- a/drivers/hwmon/nct6775.c +++ b/drivers/hwmon/nct6775.c @@ -3127,14 +3127,14 @@ static const struct sensor_template_group nct6775_pwm_template_group = { }; static ssize_t -show_vid(struct device *dev, struct device_attribute *attr, char *buf) +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct nct6775_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); /* Case open detection */ diff --git a/drivers/hwmon/nsa320-hwmon.c b/drivers/hwmon/nsa320-hwmon.c index 0517a265741f..5a16109cdea8 100644 --- a/drivers/hwmon/nsa320-hwmon.c +++ b/drivers/hwmon/nsa320-hwmon.c @@ -122,8 +122,8 @@ static ssize_t show_label(struct device *dev, return sprintf(buf, "%s\n", nsa320_input_names[channel]); } -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { s32 mcu_data = nsa320_hwmon_update(dev); @@ -133,8 +133,8 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *attr, return sprintf(buf, "%d\n", (mcu_data & 0xffff) * 100); } -static ssize_t show_fan(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t fan1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { s32 mcu_data = nsa320_hwmon_update(dev); @@ -145,9 +145,9 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *attr, } static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, NSA320_TEMP); -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); +static DEVICE_ATTR_RO(temp1_input); static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, show_label, NULL, NSA320_FAN); -static DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL); +static DEVICE_ATTR_RO(fan1_input); static struct attribute *nsa320_attrs[] = { &sensor_dev_attr_temp1_label.dev_attr.attr, diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c index d50fbf93a737..7e3697727537 100644 --- a/drivers/hwmon/pc87360.c +++ b/drivers/hwmon/pc87360.c @@ -589,22 +589,22 @@ static struct sensor_device_attribute in_max_alarm[] = { &in_min_alarm[X].dev_attr.attr, \ &in_max_alarm[X].dev_attr.attr -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%u\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct pc87360_data *data = dev_get_drvdata(dev); unsigned long val; @@ -620,15 +620,15 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, data->vrm = val; return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +static DEVICE_ATTR_RW(vrm); -static ssize_t show_in_alarms(struct device *dev, +static ssize_t alarms_in_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->in_alarms); } -static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); +static DEVICE_ATTR_RO(alarms_in); static struct attribute *pc8736x_vin_attr_array[] = { VIN_UNIT_ATTRS(0), @@ -1006,14 +1006,14 @@ static struct sensor_device_attribute temp_crit[] = { show_temp_crit, set_temp_crit, 2), }; -static ssize_t show_temp_alarms(struct device *dev, +static ssize_t alarms_temp_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pc87360_data *data = pc87360_update_device(dev); return sprintf(buf, "%u\n", data->temp_alarms); } -static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); +static DEVICE_ATTR_RO(alarms_temp); /* * show_temp_min/max_alarm() reads data from the per-channel status @@ -1106,14 +1106,14 @@ static const struct attribute_group pc8736x_temp_attr_group[] = { { .attrs = pc8736x_temp_attr[2] } }; -static ssize_t show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct pc87360_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); /* * Device detection, registration and update diff --git a/drivers/hwmon/pc87427.c b/drivers/hwmon/pc87427.c index cb9fdd37bd0d..dc5a9d5ada51 100644 --- a/drivers/hwmon/pc87427.c +++ b/drivers/hwmon/pc87427.c @@ -943,14 +943,14 @@ static const struct attribute_group pc87427_group_temp[6] = { { .attrs = pc87427_attributes_temp[5] }, }; -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct pc87427_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); /* diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index 5740888c6242..60e25c85e71c 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c @@ -103,16 +103,16 @@ show_in_channel(1); show_in_channel(2); show_in_channel(3); -static ssize_t show_out0_ouput(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t out0_output_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%d\n", data->aout * 10); } -static ssize_t set_out0_output(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t out0_output_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { unsigned long val; struct i2c_client *client = to_i2c_client(dev); @@ -132,19 +132,18 @@ static ssize_t set_out0_output(struct device *dev, return count; } -static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, - show_out0_ouput, set_out0_output); +static DEVICE_ATTR_RW(out0_output); -static ssize_t show_out0_enable(struct device *dev, +static ssize_t out0_enable_show(struct device *dev, struct device_attribute *attr, char *buf) { struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); } -static ssize_t set_out0_enable(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t out0_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct pcf8591_data *data = i2c_get_clientdata(client); @@ -165,8 +164,7 @@ static ssize_t set_out0_enable(struct device *dev, return count; } -static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO, - show_out0_enable, set_out0_enable); +static DEVICE_ATTR_RW(out0_enable); static struct attribute *pcf8591_attributes[] = { &dev_attr_out0_enable.attr, diff --git a/drivers/hwmon/sch5627.c b/drivers/hwmon/sch5627.c index 19f85c0da270..91544f2312e6 100644 --- a/drivers/hwmon/sch5627.c +++ b/drivers/hwmon/sch5627.c @@ -205,7 +205,7 @@ static int reg_to_rpm(u16 reg) return 5400540 / reg; } -static ssize_t show_name(struct device *dev, struct device_attribute *devattr, +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", DEVNAME); @@ -326,7 +326,7 @@ static ssize_t show_in_label(struct device *dev, struct device_attribute SCH5627_IN_LABELS[attr->index]); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); diff --git a/drivers/hwmon/sch56xx-common.c b/drivers/hwmon/sch56xx-common.c index 68c350c704fb..bda3d5285586 100644 --- a/drivers/hwmon/sch56xx-common.c +++ b/drivers/hwmon/sch56xx-common.c @@ -28,7 +28,6 @@ #include <linux/delay.h> #include <linux/fs.h> #include <linux/watchdog.h> -#include <linux/miscdevice.h> #include <linux/uaccess.h> #include <linux/slab.h> #include "sch56xx-common.h" diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index a2fdbb7d20ed..e4d642b673c6 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c @@ -34,6 +34,7 @@ #include <linux/slab.h> #include <linux/atomic.h> #include <linux/bitrev.h> +#include <linux/of_gpio.h> /* Commands */ #define SHT15_MEASURE_TEMP 0x03 @@ -769,7 +770,7 @@ static ssize_t sht15_show_humidity(struct device *dev, return ret ? ret : sprintf(buf, "%d\n", sht15_calc_humid(data)); } -static ssize_t show_name(struct device *dev, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -787,7 +788,7 @@ static SENSOR_DEVICE_ATTR(humidity1_fault, S_IRUGO, sht15_show_status, NULL, SHT15_STATUS_LOW_BATTERY); static SENSOR_DEVICE_ATTR(heater_enable, S_IRUGO | S_IWUSR, sht15_show_status, sht15_store_heater, SHT15_STATUS_HEATER); -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *sht15_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_humidity1_input.dev_attr.attr, @@ -911,6 +912,54 @@ static int sht15_invalidate_voltage(struct notifier_block *nb, return NOTIFY_OK; } +#ifdef CONFIG_OF +static const struct of_device_id sht15_dt_match[] = { + { .compatible = "sensirion,sht15" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sht15_dt_match); + +/* + * This function returns NULL if pdev isn't a device instatiated by dt, + * a pointer to pdata if it could successfully get all information + * from dt or a negative ERR_PTR() on error. + */ +static struct sht15_platform_data *sht15_probe_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct sht15_platform_data *pdata; + + /* no device tree device */ + if (!np) + return NULL; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->gpio_data = of_get_named_gpio(np, "data-gpios", 0); + if (pdata->gpio_data < 0) { + if (pdata->gpio_data != -EPROBE_DEFER) + dev_err(dev, "data-gpios not found\n"); + return ERR_PTR(pdata->gpio_data); + } + + pdata->gpio_sck = of_get_named_gpio(np, "clk-gpios", 0); + if (pdata->gpio_sck < 0) { + if (pdata->gpio_sck != -EPROBE_DEFER) + dev_err(dev, "clk-gpios not found\n"); + return ERR_PTR(pdata->gpio_sck); + } + + return pdata; +} +#else +static inline struct sht15_platform_data *sht15_probe_dt(struct device *dev) +{ + return NULL; +} +#endif + static int sht15_probe(struct platform_device *pdev) { int ret; @@ -928,11 +977,17 @@ static int sht15_probe(struct platform_device *pdev) data->dev = &pdev->dev; init_waitqueue_head(&data->wait_queue); - if (dev_get_platdata(&pdev->dev) == NULL) { - dev_err(&pdev->dev, "no platform data supplied\n"); - return -EINVAL; + data->pdata = sht15_probe_dt(&pdev->dev); + if (IS_ERR(data->pdata)) + return PTR_ERR(data->pdata); + if (data->pdata == NULL) { + data->pdata = dev_get_platdata(&pdev->dev); + if (data->pdata == NULL) { + dev_err(&pdev->dev, "no platform data supplied\n"); + return -EINVAL; + } } - data->pdata = dev_get_platdata(&pdev->dev); + data->supply_uv = data->pdata->supply_mv * 1000; if (data->pdata->checksum) data->checksumming = true; @@ -1075,6 +1130,7 @@ MODULE_DEVICE_TABLE(platform, sht15_device_ids); static struct platform_driver sht15_driver = { .driver = { .name = "sht15", + .of_match_table = of_match_ptr(sht15_dt_match), }, .probe = sht15_probe, .remove = sht15_remove, diff --git a/drivers/hwmon/sht21.c b/drivers/hwmon/sht21.c index 84cdb1cf0fb4..06706d288355 100644 --- a/drivers/hwmon/sht21.c +++ b/drivers/hwmon/sht21.c @@ -34,23 +34,29 @@ /* I2C command bytes */ #define SHT21_TRIG_T_MEASUREMENT_HM 0xe3 #define SHT21_TRIG_RH_MEASUREMENT_HM 0xe5 +#define SHT21_READ_SNB_CMD1 0xFA +#define SHT21_READ_SNB_CMD2 0x0F +#define SHT21_READ_SNAC_CMD1 0xFC +#define SHT21_READ_SNAC_CMD2 0xC9 /** * struct sht21 - SHT21 device specific data * @hwmon_dev: device registered with hwmon * @lock: mutex to protect measurement values - * @valid: only 0 before first measurement is taken * @last_update: time of last update (jiffies) * @temperature: cached temperature measurement value * @humidity: cached humidity measurement value + * @valid: only 0 before first measurement is taken + * @eic: cached electronic identification code text */ struct sht21 { struct i2c_client *client; struct mutex lock; - char valid; unsigned long last_update; int temperature; int humidity; + char valid; + char eic[18]; }; /** @@ -165,15 +171,97 @@ static ssize_t sht21_show_humidity(struct device *dev, return sprintf(buf, "%d\n", sht21->humidity); } +static ssize_t eic_read(struct sht21 *sht21) +{ + struct i2c_client *client = sht21->client; + u8 tx[2]; + u8 rx[8]; + u8 eic[8]; + struct i2c_msg msgs[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = tx, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 8, + .buf = rx, + }, + }; + int ret; + + tx[0] = SHT21_READ_SNB_CMD1; + tx[1] = SHT21_READ_SNB_CMD2; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + goto out; + eic[2] = rx[0]; + eic[3] = rx[2]; + eic[4] = rx[4]; + eic[5] = rx[6]; + + tx[0] = SHT21_READ_SNAC_CMD1; + tx[1] = SHT21_READ_SNAC_CMD2; + msgs[1].len = 6; + ret = i2c_transfer(client->adapter, msgs, 2); + if (ret < 0) + goto out; + eic[0] = rx[3]; + eic[1] = rx[4]; + eic[6] = rx[0]; + eic[7] = rx[1]; + + ret = snprintf(sht21->eic, sizeof(sht21->eic), + "%02x%02x%02x%02x%02x%02x%02x%02x\n", + eic[0], eic[1], eic[2], eic[3], + eic[4], eic[5], eic[6], eic[7]); +out: + if (ret < 0) + sht21->eic[0] = 0; + + return ret; +} + +/** + * eic_show() - show Electronic Identification Code in sysfs + * @dev: device + * @attr: device attribute + * @buf: sysfs buffer (PAGE_SIZE) where EIC is written + * + * Will be called on read access to eic sysfs attribute. + * Returns number of bytes written into buffer, negative errno on error. + */ +static ssize_t eic_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct sht21 *sht21 = dev_get_drvdata(dev); + int ret; + + ret = sizeof(sht21->eic) - 1; + mutex_lock(&sht21->lock); + if (!sht21->eic[0]) + ret = eic_read(sht21); + if (ret > 0) + memcpy(buf, sht21->eic, ret); + mutex_unlock(&sht21->lock); + return ret; +} + /* sysfs attributes */ static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, sht21_show_temperature, NULL, 0); static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO, sht21_show_humidity, NULL, 0); +static DEVICE_ATTR_RO(eic); static struct attribute *sht21_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_humidity1_input.dev_attr.attr, + &dev_attr_eic.attr, NULL }; diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c index 45a028fb8851..6d789aab54c9 100644 --- a/drivers/hwmon/sis5595.c +++ b/drivers/hwmon/sis5595.c @@ -304,22 +304,23 @@ show_in_offset(3); show_in_offset(4); /* Temperature */ -static ssize_t show_temp(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); } -static ssize_t show_temp_over(struct device *dev, struct device_attribute *attr, +static ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); } -static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t temp1_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct sis5595_data *data = dev_get_drvdata(dev); long val; @@ -336,15 +337,16 @@ static ssize_t set_temp_over(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t show_temp_hyst(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp1_max_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); } -static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t temp1_max_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct sis5595_data *data = dev_get_drvdata(dev); long val; @@ -361,11 +363,9 @@ static ssize_t set_temp_hyst(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, - show_temp_over, set_temp_over); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, - show_temp_hyst, set_temp_hyst); +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RW(temp1_max); +static DEVICE_ATTR_RW(temp1_max_hyst); /* 2 Fans */ static ssize_t show_fan(struct device *dev, struct device_attribute *da, @@ -492,13 +492,13 @@ show_fan_offset(1); show_fan_offset(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = sis5595_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *da, char *buf) @@ -516,13 +516,13 @@ static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 15); -static ssize_t show_name(struct device *dev, struct device_attribute *attr, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct sis5595_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *sis5595_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c index 5d323186d2c1..c7b6a425e2c0 100644 --- a/drivers/hwmon/smsc47m1.c +++ b/drivers/hwmon/smsc47m1.c @@ -264,8 +264,8 @@ static ssize_t get_pwm_en(struct device *dev, struct device_attribute return sprintf(buf, "%d\n", PWM_EN_FROM_REG(data->pwm[attr->index])); } -static ssize_t get_alarms(struct device *dev, struct device_attribute - *devattr, char *buf) +static ssize_t alarms_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct smsc47m1_data *data = smsc47m1_update_device(dev, 0); return sprintf(buf, "%d\n", data->alarms); @@ -440,16 +440,16 @@ fan_present(1); fan_present(2); fan_present(3); -static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL); +static DEVICE_ATTR_RO(alarms); -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct smsc47m1_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *smsc47m1_attributes_fan1[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c index 15650f247679..6989408033ec 100644 --- a/drivers/hwmon/smsc47m192.c +++ b/drivers/hwmon/smsc47m192.c @@ -400,23 +400,23 @@ show_temp_index(2) show_temp_index(3) /* VID */ -static ssize_t show_vid(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct smsc47m192_data *data = smsc47m192_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct smsc47m192_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct smsc47m192_data *data = dev_get_drvdata(dev); unsigned long val; @@ -431,7 +431,7 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, data->vrm = val; return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); +static DEVICE_ATTR_RW(vrm); /* Alarms */ static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, diff --git a/drivers/hwmon/stts751.c b/drivers/hwmon/stts751.c new file mode 100644 index 000000000000..55450680fb58 --- /dev/null +++ b/drivers/hwmon/stts751.c @@ -0,0 +1,834 @@ +/* + * STTS751 sensor driver + * + * Copyright (C) 2016-2017 Istituto Italiano di Tecnologia - RBCS - EDL + * Robotics, Brain and Cognitive Sciences department + * Electronic Design Laboratory + * + * Written by Andrea Merello <andrea.merello@gmail.com> + * + * Based on LM95241 driver and LM90 driver + * + * 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. + */ + +#include <linux/bitops.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/jiffies.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/util_macros.h> + +#define DEVNAME "stts751" + +static const unsigned short normal_i2c[] = { + 0x48, 0x49, 0x38, 0x39, /* STTS751-0 */ + 0x4A, 0x4B, 0x3A, 0x3B, /* STTS751-1 */ + I2C_CLIENT_END }; + +#define STTS751_REG_TEMP_H 0x00 +#define STTS751_REG_STATUS 0x01 +#define STTS751_STATUS_TRIPT BIT(0) +#define STTS751_STATUS_TRIPL BIT(5) +#define STTS751_STATUS_TRIPH BIT(6) +#define STTS751_REG_TEMP_L 0x02 +#define STTS751_REG_CONF 0x03 +#define STTS751_CONF_RES_MASK 0x0C +#define STTS751_CONF_RES_SHIFT 2 +#define STTS751_CONF_EVENT_DIS BIT(7) +#define STTS751_CONF_STOP BIT(6) +#define STTS751_REG_RATE 0x04 +#define STTS751_REG_HLIM_H 0x05 +#define STTS751_REG_HLIM_L 0x06 +#define STTS751_REG_LLIM_H 0x07 +#define STTS751_REG_LLIM_L 0x08 +#define STTS751_REG_TLIM 0x20 +#define STTS751_REG_HYST 0x21 +#define STTS751_REG_SMBUS_TO 0x22 + +#define STTS751_REG_PROD_ID 0xFD +#define STTS751_REG_MAN_ID 0xFE +#define STTS751_REG_REV_ID 0xFF + +#define STTS751_0_PROD_ID 0x00 +#define STTS751_1_PROD_ID 0x01 +#define ST_MAN_ID 0x53 + +/* + * Possible update intervals are (in mS): + * 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 62.5, 31.25 + * However we are not going to complicate things too much and we stick to the + * approx value in mS. + */ +static const int stts751_intervals[] = { + 16000, 8000, 4000, 2000, 1000, 500, 250, 125, 63, 31 +}; + +static const struct i2c_device_id stts751_id[] = { + { "stts751", 0 }, + { } +}; + +struct stts751_priv { + struct device *dev; + struct i2c_client *client; + struct mutex access_lock; + u8 interval; + int res; + int event_max, event_min; + int therm; + int hyst; + bool smbus_timeout; + int temp; + unsigned long last_update, last_alert_update; + u8 config; + bool min_alert, max_alert, therm_trip; + bool data_valid, alert_valid; + bool notify_max, notify_min; +}; + +/* + * These functions converts temperature from HW format to integer format and + * vice-vers. They are (mostly) taken from lm90 driver. Unit is in mC. + */ +static int stts751_to_deg(s16 hw_val) +{ + return hw_val * 125 / 32; +} + +static s32 stts751_to_hw(int val) +{ + return DIV_ROUND_CLOSEST(val, 125) * 32; +} + +static int stts751_adjust_resolution(struct stts751_priv *priv) +{ + u8 res; + + switch (priv->interval) { + case 9: + /* 10 bits */ + res = 0; + break; + case 8: + /* 11 bits */ + res = 1; + break; + default: + /* 12 bits */ + res = 3; + break; + } + + if (priv->res == res) + return 0; + + priv->config &= ~STTS751_CONF_RES_MASK; + priv->config |= res << STTS751_CONF_RES_SHIFT; + dev_dbg(&priv->client->dev, "setting res %d. config %x", + res, priv->config); + priv->res = res; + + return i2c_smbus_write_byte_data(priv->client, + STTS751_REG_CONF, priv->config); +} + +static int stts751_update_temp(struct stts751_priv *priv) +{ + s32 integer1, integer2, frac; + + /* + * There is a trick here, like in the lm90 driver. We have to read two + * registers to get the sensor temperature, but we have to beware a + * conversion could occur between the readings. We could use the + * one-shot conversion register, but we don't want to do this (disables + * hardware monitoring). So the solution used here is to read the high + * byte once, then the low byte, then the high byte again. If the new + * high byte matches the old one, then we have a valid reading. Else we + * have to read the low byte again, and now we believe we have a correct + * reading. + */ + integer1 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); + if (integer1 < 0) { + dev_dbg(&priv->client->dev, + "I2C read failed (temp H). ret: %x\n", integer1); + return integer1; + } + + frac = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_L); + if (frac < 0) { + dev_dbg(&priv->client->dev, + "I2C read failed (temp L). ret: %x\n", frac); + return frac; + } + + integer2 = i2c_smbus_read_byte_data(priv->client, STTS751_REG_TEMP_H); + if (integer2 < 0) { + dev_dbg(&priv->client->dev, + "I2C 2nd read failed (temp H). ret: %x\n", integer2); + return integer2; + } + + if (integer1 != integer2) { + frac = i2c_smbus_read_byte_data(priv->client, + STTS751_REG_TEMP_L); + if (frac < 0) { + dev_dbg(&priv->client->dev, + "I2C 2nd read failed (temp L). ret: %x\n", + frac); + return frac; + } + } + + priv->temp = stts751_to_deg((integer1 << 8) | frac); + return 0; +} + +static int stts751_set_temp_reg16(struct stts751_priv *priv, int temp, + u8 hreg, u8 lreg) +{ + s32 hwval; + int ret; + + hwval = stts751_to_hw(temp); + + ret = i2c_smbus_write_byte_data(priv->client, hreg, hwval >> 8); + if (ret) + return ret; + + return i2c_smbus_write_byte_data(priv->client, lreg, hwval & 0xff); +} + +static int stts751_set_temp_reg8(struct stts751_priv *priv, int temp, u8 reg) +{ + s32 hwval; + + hwval = stts751_to_hw(temp); + return i2c_smbus_write_byte_data(priv->client, reg, hwval >> 8); +} + +static int stts751_read_reg16(struct stts751_priv *priv, int *temp, + u8 hreg, u8 lreg) +{ + int integer, frac; + + integer = i2c_smbus_read_byte_data(priv->client, hreg); + if (integer < 0) + return integer; + + frac = i2c_smbus_read_byte_data(priv->client, lreg); + if (frac < 0) + return frac; + + *temp = stts751_to_deg((integer << 8) | frac); + + return 0; +} + +static int stts751_read_reg8(struct stts751_priv *priv, int *temp, u8 reg) +{ + int integer; + + integer = i2c_smbus_read_byte_data(priv->client, reg); + if (integer < 0) + return integer; + + *temp = stts751_to_deg(integer << 8); + + return 0; +} + +/* + * Update alert flags without waiting for cache to expire. We detects alerts + * immediately for the sake of the alert handler; we still need to deal with + * caching to workaround the fact that alarm flags int the status register, + * despite what the datasheet claims, gets always cleared on read. + */ +static int stts751_update_alert(struct stts751_priv *priv) +{ + int ret; + bool conv_done; + int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); + + /* + * Add another 10% because if we run faster than the HW conversion + * rate we will end up in reporting incorrectly alarms. + */ + cache_time += cache_time / 10; + + ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_STATUS); + if (ret < 0) + return ret; + + dev_dbg(&priv->client->dev, "status reg %x\n", ret); + conv_done = ret & (STTS751_STATUS_TRIPH | STTS751_STATUS_TRIPL); + /* + * Reset the cache if the cache time expired, or if we are sure + * we have valid data from a device conversion, or if we know + * our cache has been never written. + * + * Note that when the cache has been never written the point is + * to correctly initialize the timestamp, rather than clearing + * the cache values. + * + * Note that updating the cache timestamp when we get an alarm flag + * is required, otherwise we could incorrectly report alarms to be zero. + */ + if (time_after(jiffies, priv->last_alert_update + cache_time) || + conv_done || !priv->alert_valid) { + priv->max_alert = false; + priv->min_alert = false; + priv->alert_valid = true; + priv->last_alert_update = jiffies; + dev_dbg(&priv->client->dev, "invalidating alert cache\n"); + } + + priv->max_alert |= !!(ret & STTS751_STATUS_TRIPH); + priv->min_alert |= !!(ret & STTS751_STATUS_TRIPL); + priv->therm_trip = !!(ret & STTS751_STATUS_TRIPT); + + dev_dbg(&priv->client->dev, "max_alert: %d, min_alert: %d, therm_trip: %d\n", + priv->max_alert, priv->min_alert, priv->therm_trip); + + return 0; +} + +static void stts751_alert(struct i2c_client *client, + enum i2c_alert_protocol type, unsigned int data) +{ + int ret; + struct stts751_priv *priv = i2c_get_clientdata(client); + + if (type != I2C_PROTOCOL_SMBUS_ALERT) + return; + + dev_dbg(&client->dev, "alert!"); + + mutex_lock(&priv->access_lock); + ret = stts751_update_alert(priv); + if (ret < 0) { + /* default to worst case */ + priv->max_alert = true; + priv->min_alert = true; + + dev_warn(priv->dev, + "Alert received, but can't communicate to the device. Triggering all alarms!"); + } + + if (priv->max_alert) { + if (priv->notify_max) + dev_notice(priv->dev, "got alert for HIGH temperature"); + priv->notify_max = false; + + /* unblock alert poll */ + sysfs_notify(&priv->dev->kobj, NULL, "temp1_max_alarm"); + } + + if (priv->min_alert) { + if (priv->notify_min) + dev_notice(priv->dev, "got alert for LOW temperature"); + priv->notify_min = false; + + /* unblock alert poll */ + sysfs_notify(&priv->dev->kobj, NULL, "temp1_min_alarm"); + } + + if (priv->min_alert || priv->max_alert) + kobject_uevent(&priv->dev->kobj, KOBJ_CHANGE); + + mutex_unlock(&priv->access_lock); +} + +static int stts751_update(struct stts751_priv *priv) +{ + int ret; + int cache_time = msecs_to_jiffies(stts751_intervals[priv->interval]); + + if (time_after(jiffies, priv->last_update + cache_time) || + !priv->data_valid) { + ret = stts751_update_temp(priv); + if (ret) + return ret; + + ret = stts751_update_alert(priv); + if (ret) + return ret; + priv->data_valid = true; + priv->last_update = jiffies; + } + + return 0; +} + +static ssize_t show_max_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int ret; + struct stts751_priv *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->access_lock); + ret = stts751_update(priv); + if (!ret) + priv->notify_max = true; + mutex_unlock(&priv->access_lock); + if (ret < 0) + return ret; + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->max_alert); +} + +static ssize_t show_min_alarm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int ret; + struct stts751_priv *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->access_lock); + ret = stts751_update(priv); + if (!ret) + priv->notify_min = true; + mutex_unlock(&priv->access_lock); + if (ret < 0) + return ret; + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->min_alert); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int ret; + struct stts751_priv *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->access_lock); + ret = stts751_update(priv); + mutex_unlock(&priv->access_lock); + if (ret < 0) + return ret; + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->temp); +} + +static ssize_t show_therm(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stts751_priv *priv = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm); +} + +static ssize_t set_therm(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + long temp; + struct stts751_priv *priv = dev_get_drvdata(dev); + + if (kstrtol(buf, 10, &temp) < 0) + return -EINVAL; + + /* HW works in range -64C to +127.937C */ + temp = clamp_val(temp, -64000, 127937); + mutex_lock(&priv->access_lock); + ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_TLIM); + if (ret) + goto exit; + + dev_dbg(&priv->client->dev, "setting therm %ld", temp); + + /* + * hysteresis reg is relative to therm, so the HW does not need to be + * adjusted, we need to update our local copy only. + */ + priv->hyst = temp - (priv->therm - priv->hyst); + priv->therm = temp; + +exit: + mutex_unlock(&priv->access_lock); + if (ret) + return ret; + + return count; +} + +static ssize_t show_hyst(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stts751_priv *priv = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->hyst); +} + +static ssize_t set_hyst(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + long temp; + + struct stts751_priv *priv = dev_get_drvdata(dev); + + if (kstrtol(buf, 10, &temp) < 0) + return -EINVAL; + + mutex_lock(&priv->access_lock); + /* HW works in range -64C to +127.937C */ + temp = clamp_val(temp, -64000, priv->therm); + priv->hyst = temp; + dev_dbg(&priv->client->dev, "setting hyst %ld", temp); + temp = priv->therm - temp; + ret = stts751_set_temp_reg8(priv, temp, STTS751_REG_HYST); + mutex_unlock(&priv->access_lock); + if (ret) + return ret; + + return count; +} + +static ssize_t show_therm_trip(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct stts751_priv *priv = dev_get_drvdata(dev); + + mutex_lock(&priv->access_lock); + ret = stts751_update(priv); + mutex_unlock(&priv->access_lock); + if (ret < 0) + return ret; + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->therm_trip); +} + +static ssize_t show_max(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stts751_priv *priv = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_max); +} + +static ssize_t set_max(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + long temp; + struct stts751_priv *priv = dev_get_drvdata(dev); + + if (kstrtol(buf, 10, &temp) < 0) + return -EINVAL; + + mutex_lock(&priv->access_lock); + /* HW works in range -64C to +127.937C */ + temp = clamp_val(temp, priv->event_min, 127937); + ret = stts751_set_temp_reg16(priv, temp, + STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); + if (ret) + goto exit; + + dev_dbg(&priv->client->dev, "setting event max %ld", temp); + priv->event_max = temp; + ret = count; +exit: + mutex_unlock(&priv->access_lock); + return ret; +} + +static ssize_t show_min(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stts751_priv *priv = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", priv->event_min); +} + +static ssize_t set_min(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + long temp; + struct stts751_priv *priv = dev_get_drvdata(dev); + + if (kstrtol(buf, 10, &temp) < 0) + return -EINVAL; + + mutex_lock(&priv->access_lock); + /* HW works in range -64C to +127.937C */ + temp = clamp_val(temp, -64000, priv->event_max); + ret = stts751_set_temp_reg16(priv, temp, + STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); + if (ret) + goto exit; + + dev_dbg(&priv->client->dev, "setting event min %ld", temp); + priv->event_min = temp; + ret = count; +exit: + mutex_unlock(&priv->access_lock); + return ret; +} + +static ssize_t show_interval(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct stts751_priv *priv = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE - 1, "%d\n", + stts751_intervals[priv->interval]); +} + +static ssize_t set_interval(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned long val; + int idx; + int ret = count; + struct stts751_priv *priv = dev_get_drvdata(dev); + + if (kstrtoul(buf, 10, &val) < 0) + return -EINVAL; + + idx = find_closest_descending(val, stts751_intervals, + ARRAY_SIZE(stts751_intervals)); + + dev_dbg(&priv->client->dev, "setting interval. req:%lu, idx: %d, val: %d", + val, idx, stts751_intervals[idx]); + + mutex_lock(&priv->access_lock); + if (priv->interval == idx) + goto exit; + + /* + * In early development stages I've become suspicious about the chip + * starting to misbehave if I ever set, even briefly, an invalid + * configuration. While I'm not sure this is really needed, be + * conservative and set rate/resolution in such an order that avoids + * passing through an invalid configuration. + */ + + /* speed up: lower the resolution, then modify convrate */ + if (priv->interval < idx) { + dev_dbg(&priv->client->dev, "lower resolution, then modify convrate"); + priv->interval = idx; + ret = stts751_adjust_resolution(priv); + if (ret) + goto exit; + } + + ret = i2c_smbus_write_byte_data(priv->client, STTS751_REG_RATE, idx); + if (ret) + goto exit; + /* slow down: modify convrate, then raise resolution */ + if (priv->interval != idx) { + dev_dbg(&priv->client->dev, "modify convrate, then raise resolution"); + priv->interval = idx; + ret = stts751_adjust_resolution(priv); + if (ret) + goto exit; + } + ret = count; +exit: + mutex_unlock(&priv->access_lock); + + return ret; +} + +static int stts751_detect(struct i2c_client *new_client, + struct i2c_board_info *info) +{ + struct i2c_adapter *adapter = new_client->adapter; + const char *name; + int tmp; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_MAN_ID); + if (tmp != ST_MAN_ID) + return -ENODEV; + + /* lower temperaure registers always have bits 0-3 set to zero */ + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_TEMP_L); + if (tmp & 0xf) + return -ENODEV; + + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_HLIM_L); + if (tmp & 0xf) + return -ENODEV; + + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_LLIM_L); + if (tmp & 0xf) + return -ENODEV; + + /* smbus timeout register always have bits 0-7 set to zero */ + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_SMBUS_TO); + if (tmp & 0x7f) + return -ENODEV; + + tmp = i2c_smbus_read_byte_data(new_client, STTS751_REG_PROD_ID); + + switch (tmp) { + case STTS751_0_PROD_ID: + name = "STTS751-0"; + break; + case STTS751_1_PROD_ID: + name = "STTS751-1"; + break; + default: + return -ENODEV; + } + dev_dbg(&new_client->dev, "Chip %s detected", name); + + strlcpy(info->type, stts751_id[0].name, I2C_NAME_SIZE); + return 0; +} + +static int stts751_read_chip_config(struct stts751_priv *priv) +{ + int ret; + int tmp; + + ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_CONF); + if (ret < 0) + return ret; + priv->config = ret; + priv->res = (ret & STTS751_CONF_RES_MASK) >> STTS751_CONF_RES_SHIFT; + + ret = i2c_smbus_read_byte_data(priv->client, STTS751_REG_RATE); + if (ret < 0) + return ret; + priv->interval = ret; + + ret = stts751_read_reg16(priv, &priv->event_max, + STTS751_REG_HLIM_H, STTS751_REG_HLIM_L); + if (ret) + return ret; + + ret = stts751_read_reg16(priv, &priv->event_min, + STTS751_REG_LLIM_H, STTS751_REG_LLIM_L); + if (ret) + return ret; + + ret = stts751_read_reg8(priv, &priv->therm, STTS751_REG_TLIM); + if (ret) + return ret; + + ret = stts751_read_reg8(priv, &tmp, STTS751_REG_HYST); + if (ret) + return ret; + priv->hyst = priv->therm - tmp; + + return 0; +} + +static SENSOR_DEVICE_ATTR(temp1_input, 0444, show_input, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_min, 0644, show_min, set_min, 0); +static SENSOR_DEVICE_ATTR(temp1_max, 0644, show_max, set_max, 0); +static SENSOR_DEVICE_ATTR(temp1_min_alarm, 0444, show_min_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_max_alarm, 0444, show_max_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(temp1_crit, 0644, show_therm, set_therm, 0); +static SENSOR_DEVICE_ATTR(temp1_crit_hyst, 0644, show_hyst, set_hyst, 0); +static SENSOR_DEVICE_ATTR(temp1_crit_alarm, 0444, show_therm_trip, NULL, 0); +static SENSOR_DEVICE_ATTR(update_interval, 0644, + show_interval, set_interval, 0); + +static struct attribute *stts751_attrs[] = { + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp1_min.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, + &sensor_dev_attr_update_interval.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(stts751); + +static int stts751_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct stts751_priv *priv; + int ret; + bool smbus_nto; + int rev_id; + + priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->client = client; + priv->notify_max = true; + priv->notify_min = true; + i2c_set_clientdata(client, priv); + mutex_init(&priv->access_lock); + + if (device_property_present(&client->dev, + "smbus-timeout-disable")) { + smbus_nto = device_property_read_bool(&client->dev, + "smbus-timeout-disable"); + + ret = i2c_smbus_write_byte_data(client, STTS751_REG_SMBUS_TO, + smbus_nto ? 0 : 0x80); + if (ret) + return ret; + } + + rev_id = i2c_smbus_read_byte_data(client, STTS751_REG_REV_ID); + if (rev_id < 0) + return -ENODEV; + if (rev_id != 0x1) { + dev_dbg(&client->dev, "Chip revision 0x%x is untested\n", + rev_id); + } + + ret = stts751_read_chip_config(priv); + if (ret) + return ret; + + priv->config &= ~(STTS751_CONF_STOP | STTS751_CONF_EVENT_DIS); + ret = i2c_smbus_write_byte_data(client, STTS751_REG_CONF, priv->config); + if (ret) + return ret; + + priv->dev = devm_hwmon_device_register_with_groups(&client->dev, + client->name, priv, + stts751_groups); + return PTR_ERR_OR_ZERO(priv->dev); +} + +MODULE_DEVICE_TABLE(i2c, stts751_id); + +static struct i2c_driver stts751_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DEVNAME, + }, + .probe = stts751_probe, + .id_table = stts751_id, + .detect = stts751_detect, + .alert = stts751_alert, + .address_list = normal_i2c, +}; + +module_i2c_driver(stts751_driver); + +MODULE_AUTHOR("Andrea Merello <andrea.merello@gmail.com>"); +MODULE_DESCRIPTION("STTS751 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c index eeeed2c7d081..1f2d13dc9439 100644 --- a/drivers/hwmon/tmp401.c +++ b/drivers/hwmon/tmp401.c @@ -82,16 +82,6 @@ static const u8 TMP401_TEMP_MSB_WRITE[7][2] = { { 0, 0x11 }, /* offset */ }; -static const u8 TMP401_TEMP_LSB[7][2] = { - { 0x15, 0x10 }, /* temp */ - { 0x17, 0x14 }, /* low limit */ - { 0x16, 0x13 }, /* high limit */ - { 0, 0 }, /* therm (crit) limit (unused) */ - { 0x31, 0x35 }, /* lowest */ - { 0x33, 0x37 }, /* highest */ - { 0, 0x12 }, /* offset */ -}; - static const u8 TMP432_TEMP_MSB_READ[4][3] = { { 0x00, 0x01, 0x23 }, /* temp */ { 0x06, 0x08, 0x16 }, /* low limit */ @@ -106,12 +96,6 @@ static const u8 TMP432_TEMP_MSB_WRITE[4][3] = { { 0x20, 0x19, 0x1A }, /* therm (crit) limit */ }; -static const u8 TMP432_TEMP_LSB[3][3] = { - { 0x29, 0x10, 0x24 }, /* temp */ - { 0x3E, 0x14, 0x18 }, /* low limit */ - { 0x3D, 0x13, 0x17 }, /* high limit */ -}; - /* [0] = fault, [1] = low, [2] = high, [3] = therm/crit */ static const u8 TMP432_STATUS_REG[] = { 0x1b, 0x36, 0x35, 0x37 }; @@ -213,25 +197,20 @@ static int tmp401_update_device_reg16(struct i2c_client *client, for (i = 0; i < num_sensors; i++) { /* local / r1 / r2 */ for (j = 0; j < num_regs; j++) { /* temp / low / ... */ u8 regaddr; - /* - * High byte must be read first immediately followed - * by the low byte - */ + regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_READ[j][i] : TMP401_TEMP_MSB_READ[j][i]; - val = i2c_smbus_read_byte_data(client, regaddr); - if (val < 0) - return val; - data->temp[j][i] = val << 8; - if (j == 3) /* crit is msb only */ - continue; - regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[j][i] - : TMP401_TEMP_LSB[j][i]; - val = i2c_smbus_read_byte_data(client, regaddr); + if (j == 3) { /* crit is msb only */ + val = i2c_smbus_read_byte_data(client, regaddr); + } else { + val = i2c_smbus_read_word_swapped(client, + regaddr); + } if (val < 0) return val; - data->temp[j][i] |= val; + + data->temp[j][i] = j == 3 ? val << 8 : val; } } return 0; @@ -373,11 +352,11 @@ static ssize_t store_temp(struct device *dev, struct device_attribute *devattr, regaddr = data->kind == tmp432 ? TMP432_TEMP_MSB_WRITE[nr][index] : TMP401_TEMP_MSB_WRITE[nr][index]; - i2c_smbus_write_byte_data(client, regaddr, reg >> 8); - if (nr != 3) { - regaddr = data->kind == tmp432 ? TMP432_TEMP_LSB[nr][index] - : TMP401_TEMP_LSB[nr][index]; - i2c_smbus_write_byte_data(client, regaddr, reg & 0xFF); + if (nr == 3) { /* crit is msb only */ + i2c_smbus_write_byte_data(client, regaddr, reg >> 8); + } else { + /* Hardware expects big endian data --> use _swapped */ + i2c_smbus_write_word_swapped(client, regaddr, reg); } data->temp[nr][index] = reg; @@ -449,7 +428,7 @@ static ssize_t reset_temp_history(struct device *dev, return count; } -static ssize_t show_update_interval(struct device *dev, +static ssize_t update_interval_show(struct device *dev, struct device_attribute *attr, char *buf) { struct tmp401_data *data = dev_get_drvdata(dev); @@ -457,9 +436,9 @@ static ssize_t show_update_interval(struct device *dev, return sprintf(buf, "%u\n", data->update_interval); } -static ssize_t set_update_interval(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t update_interval_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct tmp401_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; @@ -521,8 +500,7 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_status, NULL, static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_status, NULL, 3, TMP432_STATUS_REMOTE1); -static DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR, show_update_interval, - set_update_interval); +static DEVICE_ATTR_RW(update_interval); static struct attribute *tmp401_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, diff --git a/drivers/hwmon/via-cputemp.c b/drivers/hwmon/via-cputemp.c index d1f209a5feac..07a0cb0a1f28 100644 --- a/drivers/hwmon/via-cputemp.c +++ b/drivers/hwmon/via-cputemp.c @@ -88,8 +88,8 @@ static ssize_t show_temp(struct device *dev, return sprintf(buf, "%lu\n", ((unsigned long)eax & 0xffffff) * 1000); } -static ssize_t show_cpu_vid(struct device *dev, - struct device_attribute *devattr, char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *devattr, char *buf) { struct via_cputemp_data *data = dev_get_drvdata(dev); u32 eax, edx; @@ -119,7 +119,7 @@ static const struct attribute_group via_cputemp_group = { }; /* Optional attributes */ -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_cpu_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); static int via_cputemp_probe(struct platform_device *pdev) { diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c index 40dd93c8f9f4..81f35e3a06b8 100644 --- a/drivers/hwmon/via686a.c +++ b/drivers/hwmon/via686a.c @@ -580,14 +580,14 @@ show_fan_offset(1); show_fan_offset(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct via686a_data *data = via686a_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -607,13 +607,13 @@ static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 15); static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct via686a_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *via686a_attributes[] = { &sensor_dev_attr_in0_input.dev_attr.attr, diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c index cb69a8c2ed5b..367b5eb53fb6 100644 --- a/drivers/hwmon/vt8231.c +++ b/drivers/hwmon/vt8231.c @@ -263,8 +263,8 @@ static ssize_t set_in_max(struct device *dev, struct device_attribute *attr, } /* Special case for input 5 as this has 3.3V scaling built into the chip */ -static ssize_t show_in5(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t in5_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); @@ -272,7 +272,7 @@ static ssize_t show_in5(struct device *dev, struct device_attribute *attr, (((data->in[5] - 3) * 10000 * 54) / (958 * 34))); } -static ssize_t show_in5_min(struct device *dev, struct device_attribute *attr, +static ssize_t in5_min_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); @@ -281,7 +281,7 @@ static ssize_t show_in5_min(struct device *dev, struct device_attribute *attr, (((data->in_min[5] - 3) * 10000 * 54) / (958 * 34))); } -static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr, +static ssize_t in5_max_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); @@ -290,8 +290,9 @@ static ssize_t show_in5_max(struct device *dev, struct device_attribute *attr, (((data->in_max[5] - 3) * 10000 * 54) / (958 * 34))); } -static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t in5_min_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); unsigned long val; @@ -309,8 +310,9 @@ static ssize_t set_in5_min(struct device *dev, struct device_attribute *attr, return count; } -static ssize_t set_in5_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t in5_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); unsigned long val; @@ -342,34 +344,35 @@ define_voltage_sysfs(2); define_voltage_sysfs(3); define_voltage_sysfs(4); -static DEVICE_ATTR(in5_input, S_IRUGO, show_in5, NULL); -static DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR, show_in5_min, set_in5_min); -static DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR, show_in5_max, set_in5_max); +static DEVICE_ATTR_RO(in5_input); +static DEVICE_ATTR_RW(in5_min); +static DEVICE_ATTR_RW(in5_max); /* Temperatures */ -static ssize_t show_temp0(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp1_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); return sprintf(buf, "%d\n", data->temp[0] * 250); } -static ssize_t show_temp0_max(struct device *dev, struct device_attribute *attr, +static ssize_t temp1_max_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); return sprintf(buf, "%d\n", data->temp_max[0] * 1000); } -static ssize_t show_temp0_min(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t temp1_max_hyst_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); return sprintf(buf, "%d\n", data->temp_min[0] * 1000); } -static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t temp1_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); long val; @@ -385,8 +388,9 @@ static ssize_t set_temp0_max(struct device *dev, struct device_attribute *attr, mutex_unlock(&data->update_lock); return count; } -static ssize_t set_temp0_min(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t temp1_max_hyst_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct vt8231_data *data = dev_get_drvdata(dev); long val; @@ -481,10 +485,9 @@ static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ show_temp_min, set_temp_min, offset - 1) -static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp0, NULL); -static DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, show_temp0_max, set_temp0_max); -static DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp0_min, - set_temp0_min); +static DEVICE_ATTR_RO(temp1_input); +static DEVICE_ATTR_RW(temp1_max); +static DEVICE_ATTR_RW(temp1_max_hyst); define_temperature_sysfs(2); define_temperature_sysfs(3); @@ -603,13 +606,13 @@ define_fan_sysfs(1); define_fan_sysfs(2); /* Alarms */ -static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vt8231_data *data = vt8231_update_device(dev); return sprintf(buf, "%d\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -633,13 +636,13 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 2); static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); -static ssize_t show_name(struct device *dev, struct device_attribute +static ssize_t name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct vt8231_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct attribute *vt8231_attributes_temps[6][5] = { { diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index 697007afb99c..ab346ed142de 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c @@ -1687,14 +1687,14 @@ store_##reg(struct device *dev, struct device_attribute *attr, \ fan_time_functions(fan_stop_time, FAN_STOP_TIME) -static ssize_t show_name(struct device *dev, struct device_attribute *attr, +static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627ehf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct sensor_device_attribute sda_sf3_arrays_fan4[] = { SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time, @@ -1754,12 +1754,12 @@ static struct sensor_device_attribute sda_sf3_max_step_arrays[] = { }; static ssize_t -show_vid(struct device *dev, struct device_attribute *attr, char *buf) +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627ehf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); +static DEVICE_ATTR_RO(cpu0_vid); /* Case open detection */ diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c index 721295b9a051..8ac89d0781cc 100644 --- a/drivers/hwmon/w83627hf.c +++ b/drivers/hwmon/w83627hf.c @@ -575,26 +575,30 @@ static ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) return sprintf(buf,"%ld\n", in0); } -static ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t in0_input_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in[0]); } -static ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t in0_min_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_min[0]); } -static ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t in0_max_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return show_in_0(data, buf, data->in_max[0]); } -static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t in0_min_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long val; @@ -622,8 +626,9 @@ static ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *a return count; } -static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t in0_max_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long val; @@ -651,11 +656,9 @@ static ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *a return count; } -static DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); -static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, - show_regs_in_min0, store_regs_in_min0); -static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, - show_regs_in_max0, store_regs_in_max0); +static DEVICE_ATTR_RO(in0_input); +static DEVICE_ATTR_RW(in0_min); +static DEVICE_ATTR_RW(in0_max); static ssize_t show_fan_input(struct device *dev, struct device_attribute *devattr, char *buf) @@ -796,21 +799,22 @@ sysfs_temp_decl(2); sysfs_temp_decl(3); static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); unsigned long val; @@ -826,15 +830,15 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", (long) data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -860,7 +864,7 @@ static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13); static ssize_t -show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf) +beep_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83627hf_data *data = w83627hf_update_device(dev); return sprintf(buf, "%ld\n", @@ -868,7 +872,7 @@ show_beep_mask(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -store_beep_mask(struct device *dev, struct device_attribute *attr, +beep_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83627hf_data *data = dev_get_drvdata(dev); @@ -895,8 +899,7 @@ store_beep_mask(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, - show_beep_mask, store_beep_mask); +static DEVICE_ATTR_RW(beep_mask); static ssize_t show_beep(struct device *dev, struct device_attribute *attr, char *buf) @@ -1264,13 +1267,13 @@ sysfs_temp_type(2); sysfs_temp_type(3); static ssize_t -show_name(struct device *dev, struct device_attribute *devattr, char *buf) +name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct w83627hf_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static int __init w83627hf_find(int sioaddr, unsigned short *addr, struct w83627hf_sio_data *sio_data) diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c index 54848fdd181e..246fb2365126 100644 --- a/drivers/hwmon/w83781d.c +++ b/drivers/hwmon/w83781d.c @@ -416,24 +416,24 @@ sysfs_temp_offsets(2); sysfs_temp_offsets(3); static ssize_t -show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) +cpu0_vid_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); static ssize_t -show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) +vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%ld\n", (long) data->vrm); } static ssize_t -store_vrm_reg(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, + size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); unsigned long val; @@ -447,16 +447,16 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); static ssize_t show_alarm(struct device *dev, struct device_attribute *attr, char *buf) @@ -491,7 +491,7 @@ static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 5); static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_temp3_alarm, NULL, 0); -static ssize_t show_beep_mask(struct device *dev, +static ssize_t beep_mask_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); @@ -500,7 +500,7 @@ static ssize_t show_beep_mask(struct device *dev, } static ssize_t -store_beep_mask(struct device *dev, struct device_attribute *attr, +beep_mask_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); @@ -527,8 +527,7 @@ store_beep_mask(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR(beep_mask, S_IRUGO | S_IWUSR, - show_beep_mask, store_beep_mask); +static DEVICE_ATTR_RW(beep_mask); static ssize_t show_beep(struct device *dev, struct device_attribute *attr, char *buf) @@ -708,7 +707,7 @@ show_pwm(struct device *dev, struct device_attribute *da, char *buf) } static ssize_t -show_pwm2_enable(struct device *dev, struct device_attribute *da, char *buf) +pwm2_enable_show(struct device *dev, struct device_attribute *da, char *buf) { struct w83781d_data *data = w83781d_update_device(dev); return sprintf(buf, "%d\n", (int)data->pwm2_enable); @@ -736,7 +735,7 @@ store_pwm(struct device *dev, struct device_attribute *da, const char *buf, } static ssize_t -store_pwm2_enable(struct device *dev, struct device_attribute *da, +pwm2_enable_store(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { struct w83781d_data *data = dev_get_drvdata(dev); @@ -778,8 +777,7 @@ static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 2); static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, show_pwm, store_pwm, 3); /* only PWM2 can be enabled/disabled */ -static DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, - show_pwm2_enable, store_pwm2_enable); +static DEVICE_ATTR_RW(pwm2_enable); static ssize_t show_sensor(struct device *dev, struct device_attribute *da, char *buf) @@ -1616,12 +1614,12 @@ static unsigned short isa_address = 0x290; * we must create it by ourselves. */ static ssize_t -show_name(struct device *dev, struct device_attribute *devattr, char *buf) +name_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct w83781d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%s\n", data->name); } -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR_RO(name); static struct w83781d_data *w83781d_data_if_isa(void) { diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c index 001df856913f..8af6081b4ab4 100644 --- a/drivers/hwmon/w83791d.c +++ b/drivers/hwmon/w83791d.c @@ -1041,14 +1041,14 @@ static struct sensor_device_attribute sda_temp_alarm[] = { }; /* get realtime status of all sensors items: voltage, temp, fan */ -static ssize_t show_alarms_reg(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t alarms_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct w83791d_data *data = w83791d_update_device(dev); return sprintf(buf, "%u\n", data->alarms); } -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); /* Beep control */ @@ -1147,25 +1147,24 @@ static struct sensor_device_attribute sda_beep_ctrl[] = { }; /* cpu voltage regulation information */ -static ssize_t show_vid_reg(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t cpu0_vid_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct w83791d_data *data = w83791d_update_device(dev); return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); } -static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); +static DEVICE_ATTR_RO(cpu0_vid); -static ssize_t show_vrm_reg(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t vrm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct w83791d_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); } -static ssize_t store_vrm_reg(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t vrm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct w83791d_data *data = dev_get_drvdata(dev); unsigned long val; @@ -1188,7 +1187,7 @@ static ssize_t store_vrm_reg(struct device *dev, return count; } -static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); +static DEVICE_ATTR_RW(vrm); #define IN_UNIT_ATTRS(X) \ &sda_in_input[X].dev_attr.attr, \ diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index 0a8bce726b4b..d764602d70db 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c @@ -578,7 +578,7 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr, /* get realtime status of all sensors items: voltage, temp, fan */ static ssize_t -show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) +alarms_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83792d_data *data = w83792d_update_device(dev); return sprintf(buf, "%d\n", data->alarms); @@ -735,16 +735,16 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr, } static ssize_t -show_chassis_clear(struct device *dev, struct device_attribute *attr, - char *buf) +intrusion0_alarm_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct w83792d_data *data = w83792d_update_device(dev); return sprintf(buf, "%d\n", data->chassis); } static ssize_t -store_chassis_clear(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +intrusion0_alarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct i2c_client *client = to_i2c_client(dev); struct w83792d_data *data = i2c_get_clientdata(client); @@ -1047,7 +1047,7 @@ static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4); static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4); -static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); +static DEVICE_ATTR_RO(alarms); static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 2); @@ -1067,8 +1067,7 @@ static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 20); static SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_alarm, NULL, 21); static SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_alarm, NULL, 22); static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 23); -static DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR, - show_chassis_clear, store_chassis_clear); +static DEVICE_ATTR_RW(intrusion0_alarm); static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0); static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1); static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2); diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c index 816aa6caf5d5..dab5c515d5a3 100644 --- a/drivers/hwmon/w83793.c +++ b/drivers/hwmon/w83793.c @@ -324,7 +324,7 @@ static struct i2c_driver w83793_driver = { }; static ssize_t -show_vrm(struct device *dev, struct device_attribute *attr, char *buf) +vrm_show(struct device *dev, struct device_attribute *attr, char *buf) { struct w83793_data *data = dev_get_drvdata(dev); return sprintf(buf, "%d\n", data->vrm); @@ -342,7 +342,7 @@ show_vid(struct device *dev, struct device_attribute *attr, char *buf) } static ssize_t -store_vrm(struct device *dev, struct device_attribute *attr, +vrm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct w83793_data *data = dev_get_drvdata(dev); @@ -1169,7 +1169,7 @@ static struct sensor_device_attribute_2 w83793_vid[] = { SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0), SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1), }; -static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm); +static DEVICE_ATTR_RW(vrm); static struct sensor_device_attribute_2 sda_single_files[] = { SENSOR_ATTR_2(intrusion0_alarm, S_IWUSR | S_IRUGO, show_alarm_beep, diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 686971263bef..45d6771fac8c 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -962,10 +962,6 @@ static int cdns_i2c_probe(struct platform_device *pdev) goto err_clk_dis; } - ret = i2c_add_adapter(&id->adap); - if (ret < 0) - goto err_clk_dis; - /* * Cadence I2C controller has a bug wherein it generates * invalid read transaction after HW timeout in master receiver mode. @@ -975,6 +971,10 @@ static int cdns_i2c_probe(struct platform_device *pdev) */ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); + ret = i2c_add_adapter(&id->adap); + if (ret < 0) + goto err_clk_dis; + dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n", id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq); diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 6d81c56184d3..e9db857c6226 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -475,30 +475,28 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) { struct i2c_msg *msgs = dev->msgs; - u32 ic_tar = 0; + u32 ic_con, ic_tar = 0; /* Disable the adapter */ __i2c_dw_enable_and_wait(dev, false); /* if the slave address is ten bit address, enable 10BITADDR */ - if (dev->dynamic_tar_update_enabled) { + ic_con = dw_readl(dev, DW_IC_CON); + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) { + ic_con |= DW_IC_CON_10BITADDR_MASTER; /* * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing - * mode has to be enabled via bit 12 of IC_TAR register, - * otherwise bit 4 of IC_CON is used. + * mode has to be enabled via bit 12 of IC_TAR register. + * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be + * detected from registers. */ - if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) - ic_tar = DW_IC_TAR_10BITADDR_MASTER; + ic_tar = DW_IC_TAR_10BITADDR_MASTER; } else { - u32 ic_con = dw_readl(dev, DW_IC_CON); - - if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) - ic_con |= DW_IC_CON_10BITADDR_MASTER; - else - ic_con &= ~DW_IC_CON_10BITADDR_MASTER; - dw_writel(dev, ic_con, DW_IC_CON); + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; } + dw_writel(dev, ic_con, DW_IC_CON); + /* * Set the slave (target) address and enable 10-bit addressing mode * if applicable. @@ -963,7 +961,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; int r; - u32 reg; init_completion(&dev->cmd_complete); @@ -971,26 +968,6 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) if (r) return r; - r = i2c_dw_acquire_lock(dev); - if (r) - return r; - - /* - * Test if dynamic TAR update is enabled in this controller by writing - * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this - * field is read-only so it should not succeed - */ - reg = dw_readl(dev, DW_IC_CON); - dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON); - - if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) == - (reg & DW_IC_CON_10BITADDR_MASTER)) { - dev->dynamic_tar_update_enabled = true; - dev_dbg(dev->dev, "Dynamic TAR update enabled"); - } - - i2c_dw_release_lock(dev); - snprintf(adap->name, sizeof(adap->name), "Synopsys DesignWare I2C adapter"); adap->retries = 3; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 26250b425e2f..c1db3a5a340f 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -125,7 +125,6 @@ struct dw_i2c_dev { int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_runtime_disabled; - bool dynamic_tar_update_enabled; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index c62b7cd475f8..3310f2e0dbd3 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -28,6 +28,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/slab.h> @@ -636,12 +637,31 @@ static int lpi2c_imx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int lpi2c_imx_suspend(struct device *dev) +{ + pinctrl_pm_select_sleep_state(dev); + + return 0; +} + +static int lpi2c_imx_resume(struct device *dev) +{ + pinctrl_pm_select_default_state(dev); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(imx_lpi2c_pm, lpi2c_imx_suspend, lpi2c_imx_resume); + static struct platform_driver lpi2c_imx_driver = { .probe = lpi2c_imx_probe, .remove = lpi2c_imx_remove, .driver = { .name = DRIVER_NAME, .of_match_table = lpi2c_imx_of_match, + .pm = &imx_lpi2c_pm, }, }; diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index c2268cdf38e8..c21ca7bf2efe 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -58,7 +58,7 @@ #define SMBSLVDAT (0xC + piix4_smba) /* count for request_region */ -#define SMBIOSIZE 8 +#define SMBIOSIZE 9 /* PCI Address Constants */ #define SMBBA 0x090 @@ -585,12 +585,33 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, u8 command, int size, union i2c_smbus_data *data) { struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(adap); + unsigned short piix4_smba = adapdata->smba; + int retries = MAX_TIMEOUT; + int smbslvcnt; u8 smba_en_lo; u8 port; int retval; mutex_lock(&piix4_mutex_sb800); + /* Request the SMBUS semaphore, avoid conflicts with the IMC */ + smbslvcnt = inb_p(SMBSLVCNT); + do { + outb_p(smbslvcnt | 0x10, SMBSLVCNT); + + /* Check the semaphore status */ + smbslvcnt = inb_p(SMBSLVCNT); + if (smbslvcnt & 0x10) + break; + + usleep_range(1000, 2000); + } while (--retries); + /* SMBus is still owned by the IMC, we give up */ + if (!retries) { + mutex_unlock(&piix4_mutex_sb800); + return -EBUSY; + } + outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX); smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); @@ -604,6 +625,9 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1); + /* Release the semaphore */ + outb_p(smbslvcnt | 0x20, SMBSLVCNT); + mutex_unlock(&piix4_mutex_sb800); return retval; diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index cf9e396d7702..bfb6ba7cac00 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -221,7 +221,8 @@ static int i2c_acpi_get_info(struct acpi_device *adev, acpi_dev_free_resource_list(&resource_list); - strlcpy(info->type, dev_name(&adev->dev), sizeof(info->type)); + acpi_set_modalias(adev, dev_name(&adev->dev), info->type, + sizeof(info->type)); return 0; } @@ -931,7 +932,10 @@ static int i2c_device_probe(struct device *dev) if (!client->irq) { int irq = -ENOENT; - if (dev->of_node) { + if (client->flags & I2C_CLIENT_HOST_NOTIFY) { + dev_dbg(dev, "Using Host Notify IRQ\n"); + irq = i2c_smbus_host_notify_to_irq(client); + } else if (dev->of_node) { irq = of_irq_get_byname(dev->of_node, "irq"); if (irq == -EINVAL || irq == -ENODATA) irq = of_irq_get(dev->of_node, 0); @@ -940,14 +944,7 @@ static int i2c_device_probe(struct device *dev) } if (irq == -EPROBE_DEFER) return irq; - /* - * ACPI and OF did not find any useful IRQ, try to see - * if Host Notify can be used. - */ - if (irq < 0) { - dev_dbg(dev, "Using Host Notify IRQ\n"); - irq = i2c_smbus_host_notify_to_irq(client); - } + if (irq < 0) irq = 0; @@ -1339,15 +1336,29 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.fwnode = info->fwnode; i2c_dev_set_name(adap, client); + + if (info->properties) { + status = device_add_properties(&client->dev, info->properties); + if (status) { + dev_err(&adap->dev, + "Failed to add properties to client %s: %d\n", + client->name, status); + goto out_err; + } + } + status = device_register(&client->dev); if (status) - goto out_err; + goto out_free_props; dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); return client; +out_free_props: + if (info->properties) + device_remove_properties(&client->dev); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", @@ -1708,7 +1719,7 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, if (i2c_check_addr_validity(addr, info.flags)) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", - info.addr, node->full_name); + addr, node->full_name); return ERR_PTR(-EINVAL); } @@ -1716,6 +1727,9 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, info.of_node = of_node_get(node); info.archdata = &dev_ad; + if (of_property_read_bool(node, "host-notify")) + info.flags |= I2C_CLIENT_HOST_NOTIFY; + if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; @@ -3633,7 +3647,7 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) int ret; if (!client || !slave_cb) { - WARN(1, "insufficent data\n"); + WARN(1, "insufficient data\n"); return -EINVAL; } diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index 66f323fd3982..6f638bbc922d 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -331,7 +331,7 @@ static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, unsigned long arg) { struct i2c_smbus_ioctl_data data_arg; - union i2c_smbus_data temp; + union i2c_smbus_data temp = {}; int datasize, res; if (copy_from_user(&data_arg, diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 39ea67f9b066..c99a25c075bc 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -10,6 +10,7 @@ menuconfig IDE tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)" depends on HAVE_IDE depends on BLOCK + select BLK_SCSI_REQUEST ---help--- If you say Y here, your kernel will be able to manage ATA/(E)IDE and ATAPI units. The most common cases are IDE hard drives and ATAPI diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index f90ea221f7f2..feb30061123b 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -92,8 +92,9 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, struct request *rq; int error; - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_DRV_PRIV; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_MISC; rq->special = (char *)pc; if (buf && bufflen) { @@ -103,9 +104,9 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, goto put_req; } - memcpy(rq->cmd, pc->c, 12); + memcpy(scsi_req(rq)->cmd, pc->c, 12); if (drive->media == ide_tape) - rq->cmd[13] = REQ_IDETAPE_PC1; + scsi_req(rq)->cmd[13] = REQ_IDETAPE_PC1; error = blk_execute_rq(drive->queue, disk, rq, 0); put_req: blk_put_request(rq); @@ -171,7 +172,8 @@ EXPORT_SYMBOL_GPL(ide_create_request_sense_cmd); void ide_prep_sense(ide_drive_t *drive, struct request *rq) { struct request_sense *sense = &drive->sense_data; - struct request *sense_rq = &drive->sense_rq; + struct request *sense_rq = drive->sense_rq; + struct scsi_request *req = scsi_req(sense_rq); unsigned int cmd_len, sense_len; int err; @@ -191,12 +193,13 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) BUG_ON(sense_len > sizeof(*sense)); - if (rq->cmd_type == REQ_TYPE_ATA_SENSE || drive->sense_rq_armed) + if (ata_sense_request(rq) || drive->sense_rq_armed) return; memset(sense, 0, sizeof(*sense)); blk_rq_init(rq->q, sense_rq); + scsi_req_init(sense_rq); err = blk_rq_map_kern(drive->queue, sense_rq, sense, sense_len, GFP_NOIO); @@ -208,13 +211,14 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) } sense_rq->rq_disk = rq->rq_disk; - sense_rq->cmd[0] = GPCMD_REQUEST_SENSE; - sense_rq->cmd[4] = cmd_len; - sense_rq->cmd_type = REQ_TYPE_ATA_SENSE; + sense_rq->cmd_flags = REQ_OP_DRV_IN; + ide_req(sense_rq)->type = ATA_PRIV_SENSE; sense_rq->rq_flags |= RQF_PREEMPT; + req->cmd[0] = GPCMD_REQUEST_SENSE; + req->cmd[4] = cmd_len; if (drive->media == ide_tape) - sense_rq->cmd[13] = REQ_IDETAPE_PC1; + req->cmd[13] = REQ_IDETAPE_PC1; drive->sense_rq_armed = true; } @@ -229,12 +233,12 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special) return -ENOMEM; } - drive->sense_rq.special = special; + drive->sense_rq->special = special; drive->sense_rq_armed = false; drive->hwif->rq = NULL; - elv_add_request(drive->queue, &drive->sense_rq, ELEVATOR_INSERT_FRONT); + elv_add_request(drive->queue, drive->sense_rq, ELEVATOR_INSERT_FRONT); return 0; } EXPORT_SYMBOL_GPL(ide_queue_sense_rq); @@ -247,14 +251,14 @@ EXPORT_SYMBOL_GPL(ide_queue_sense_rq); void ide_retry_pc(ide_drive_t *drive) { struct request *failed_rq = drive->hwif->rq; - struct request *sense_rq = &drive->sense_rq; + struct request *sense_rq = drive->sense_rq; struct ide_atapi_pc *pc = &drive->request_sense_pc; (void)ide_read_error(drive); /* init pc from sense_rq */ ide_init_pc(pc); - memcpy(pc->c, sense_rq->cmd, 12); + memcpy(pc->c, scsi_req(sense_rq)->cmd, 12); if (drive->media == ide_tape) drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; @@ -286,7 +290,7 @@ int ide_cd_expiry(ide_drive_t *drive) * commands/drives support that. Let ide_timer_expiry keep polling us * for these. */ - switch (rq->cmd[0]) { + switch (scsi_req(rq)->cmd[0]) { case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: @@ -297,7 +301,7 @@ int ide_cd_expiry(ide_drive_t *drive) default: if (!(rq->rq_flags & RQF_QUIET)) printk(KERN_INFO PFX "cmd 0x%x timed out\n", - rq->cmd[0]); + scsi_req(rq)->cmd[0]); wait = 0; break; } @@ -307,15 +311,21 @@ EXPORT_SYMBOL_GPL(ide_cd_expiry); int ide_cd_get_xferlen(struct request *rq) { - switch (rq->cmd_type) { - case REQ_TYPE_FS: + switch (req_op(rq)) { + default: return 32768; - case REQ_TYPE_ATA_SENSE: - case REQ_TYPE_BLOCK_PC: - case REQ_TYPE_ATA_PC: + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: return blk_rq_bytes(rq); - default: - return 0; + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + switch (ide_req(rq)->type) { + case ATA_PRIV_PC: + case ATA_PRIV_SENSE: + return blk_rq_bytes(rq); + default: + return 0; + } } } EXPORT_SYMBOL_GPL(ide_cd_get_xferlen); @@ -374,7 +384,7 @@ int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len, drive->name, __func__, ireason); } - if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC) + if (dev_is_idecd(drive) && ata_pc_request(rq)) rq->rq_flags |= RQF_FAILED; return 1; @@ -420,7 +430,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) ? "write" : "read"); pc->flags |= PC_FLAG_DMA_ERROR; } else - rq->resid_len = 0; + scsi_req(rq)->resid_len = 0; debug_log("%s: DMA finished\n", drive->name); } @@ -436,7 +446,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) local_irq_enable_in_hardirq(); if (drive->media == ide_tape && - (stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE) + (stat & ATA_ERR) && scsi_req(rq)->cmd[0] == REQUEST_SENSE) stat &= ~ATA_ERR; if ((stat & ATA_ERR) || (pc->flags & PC_FLAG_DMA_ERROR)) { @@ -446,7 +456,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (drive->media != ide_tape) pc->rq->errors++; - if (rq->cmd[0] == REQUEST_SENSE) { + if (scsi_req(rq)->cmd[0] == REQUEST_SENSE) { printk(KERN_ERR PFX "%s: I/O error in request " "sense command\n", drive->name); return ide_do_reset(drive); @@ -477,12 +487,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (uptodate == 0) drive->failed_pc = NULL; - if (rq->cmd_type == REQ_TYPE_DRV_PRIV) { + if (ata_misc_request(rq)) { rq->errors = 0; error = 0; } else { - if (rq->cmd_type != REQ_TYPE_FS && uptodate <= 0) { + if (blk_rq_is_passthrough(rq) && uptodate <= 0) { if (rq->errors == 0) rq->errors = -EIO; } @@ -512,7 +522,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) ide_pio_bytes(drive, cmd, write, done); /* Update transferred byte count */ - rq->resid_len -= done; + scsi_req(rq)->resid_len -= done; bcount -= done; @@ -520,7 +530,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) ide_pad_transfer(drive, write, bcount); debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", - rq->cmd[0], done, bcount, rq->resid_len); + rq->cmd[0], done, bcount, scsi_req(rq)->resid_len); /* And set the interrupt handler again */ ide_set_handler(drive, ide_pc_intr, timeout); @@ -603,7 +613,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) if (dev_is_idecd(drive)) { /* ATAPI commands get padded out to 12 bytes minimum */ - cmd_len = COMMAND_SIZE(rq->cmd[0]); + cmd_len = COMMAND_SIZE(scsi_req(rq)->cmd[0]); if (cmd_len < ATAPI_MIN_CDB_BYTES) cmd_len = ATAPI_MIN_CDB_BYTES; @@ -650,7 +660,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) /* Send the actual packet */ if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0) - hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len); + hwif->tp_ops->output_data(drive, NULL, scsi_req(rq)->cmd, cmd_len); /* Begin DMA, if necessary */ if (dev_is_idecd(drive)) { @@ -695,7 +705,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) bytes, 63 * 1024)); /* We haven't transferred any data yet */ - rq->resid_len = bcount; + scsi_req(rq)->resid_len = bcount; if (pc->flags & PC_FLAG_DMA_ERROR) { pc->flags &= ~PC_FLAG_DMA_ERROR; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 9cbd217bc0c9..aef00511ca86 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -121,7 +121,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq) * don't log START_STOP unit with LoEj set, since we cannot * reliably check if drive can auto-close */ - if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) + if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) break; log = 1; break; @@ -163,7 +163,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, * toc has not been recorded yet, it will fail with 05/24/00 (which is a * confusing error) */ - if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP) + if (failed_command && scsi_req(failed_command)->cmd[0] == GPCMD_READ_TOC_PMA_ATIP) if (sense->sense_key == 0x05 && sense->asc == 0x24) return; @@ -176,7 +176,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, if (!sense->valid) break; if (failed_command == NULL || - failed_command->cmd_type != REQ_TYPE_FS) + blk_rq_is_passthrough(failed_command)) break; sector = (sense->information[0] << 24) | (sense->information[1] << 16) | @@ -210,7 +210,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) { /* - * For REQ_TYPE_ATA_SENSE, "rq->special" points to the original + * For ATA_PRIV_SENSE, "rq->special" points to the original * failed request. Also, the sense data should be read * directly from rq which might be different from the original * sense buffer if it got copied during mapping. @@ -219,15 +219,12 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) void *sense = bio_data(rq->bio); if (failed) { - if (failed->sense) { - /* - * Sense is always read into drive->sense_data. - * Copy back if the failed request has its - * sense pointer set. - */ - memcpy(failed->sense, sense, 18); - failed->sense_len = rq->sense_len; - } + /* + * Sense is always read into drive->sense_data, copy back to the + * original request. + */ + memcpy(scsi_req(failed)->sense, sense, 18); + scsi_req(failed)->sense_len = scsi_req(rq)->sense_len; cdrom_analyze_sense_data(drive, failed); if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed))) @@ -285,7 +282,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) "stat 0x%x", rq->cmd[0], rq->cmd_type, err, stat); - if (rq->cmd_type == REQ_TYPE_ATA_SENSE) { + if (ata_sense_request(rq)) { /* * We got an error trying to get sense info from the drive * (probably while trying to recover from a former error). @@ -296,7 +293,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) } /* if we have an error, pass CHECK_CONDITION as the SCSI status byte */ - if (rq->cmd_type == REQ_TYPE_BLOCK_PC && !rq->errors) + if (blk_rq_is_scsi(rq) && !rq->errors) rq->errors = SAM_STAT_CHECK_CONDITION; if (blk_noretry_request(rq)) @@ -304,13 +301,13 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) switch (sense_key) { case NOT_READY: - if (rq->cmd_type == REQ_TYPE_FS && rq_data_dir(rq) == WRITE) { + if (req_op(rq) == REQ_OP_WRITE) { if (ide_cd_breathe(drive, rq)) return 1; } else { cdrom_saw_media_change(drive); - if (rq->cmd_type == REQ_TYPE_FS && + if (!blk_rq_is_passthrough(rq) && !(rq->rq_flags & RQF_QUIET)) printk(KERN_ERR PFX "%s: tray open\n", drive->name); @@ -320,7 +317,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) case UNIT_ATTENTION: cdrom_saw_media_change(drive); - if (rq->cmd_type != REQ_TYPE_FS) + if (blk_rq_is_passthrough(rq)) return 0; /* @@ -338,7 +335,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) * * cdrom_log_sense() knows this! */ - if (rq->cmd[0] == GPCMD_START_STOP_UNIT) + if (scsi_req(rq)->cmd[0] == GPCMD_START_STOP_UNIT) break; /* fall-through */ case DATA_PROTECT: @@ -368,7 +365,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) do_end_request = 1; break; default: - if (rq->cmd_type != REQ_TYPE_FS) + if (blk_rq_is_passthrough(rq)) break; if (err & ~ATA_ABORTED) { /* go to the default handler for other errors */ @@ -379,7 +376,7 @@ static int cdrom_decode_status(ide_drive_t *drive, u8 stat) do_end_request = 1; } - if (rq->cmd_type != REQ_TYPE_FS) { + if (blk_rq_is_passthrough(rq)) { rq->rq_flags |= RQF_FAILED; do_end_request = 1; } @@ -414,7 +411,7 @@ static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) * Some of the trailing request sense fields are optional, * and some drives don't send them. Sigh. */ - if (rq->cmd[0] == GPCMD_REQUEST_SENSE && + if (scsi_req(rq)->cmd[0] == GPCMD_REQUEST_SENSE && cmd->nleft > 0 && cmd->nleft <= 5) cmd->nleft = 0; } @@ -425,12 +422,8 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, req_flags_t rq_flags) { struct cdrom_info *info = drive->driver_data; - struct request_sense local_sense; int retries = 10; - req_flags_t flags = 0; - - if (!sense) - sense = &local_sense; + bool failed; ide_debug_log(IDE_DBG_PC, "cmd[0]: 0x%x, write: 0x%x, timeout: %d, " "rq_flags: 0x%x", @@ -440,12 +433,13 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, do { struct request *rq; int error; + bool delay = false; - rq = blk_get_request(drive->queue, write, __GFP_RECLAIM); - - memcpy(rq->cmd, cmd, BLK_MAX_CDB); - rq->cmd_type = REQ_TYPE_ATA_PC; - rq->sense = sense; + rq = blk_get_request(drive->queue, + write ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + memcpy(scsi_req(rq)->cmd, cmd, BLK_MAX_CDB); + ide_req(rq)->type = ATA_PRIV_PC; rq->rq_flags |= rq_flags; rq->timeout = timeout; if (buffer) { @@ -460,21 +454,21 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, error = blk_execute_rq(drive->queue, info->disk, rq, 0); if (buffer) - *bufflen = rq->resid_len; - - flags = rq->rq_flags; - blk_put_request(rq); + *bufflen = scsi_req(rq)->resid_len; + if (sense) + memcpy(sense, scsi_req(rq)->sense, sizeof(*sense)); /* * FIXME: we should probably abort/retry or something in case of * failure. */ - if (flags & RQF_FAILED) { + failed = (rq->rq_flags & RQF_FAILED) != 0; + if (failed) { /* * The request failed. Retry if it was due to a unit * attention status (usually means media was changed). */ - struct request_sense *reqbuf = sense; + struct request_sense *reqbuf = scsi_req(rq)->sense; if (reqbuf->sense_key == UNIT_ATTENTION) cdrom_saw_media_change(drive); @@ -485,19 +479,20 @@ int ide_cd_queue_pc(ide_drive_t *drive, const unsigned char *cmd, * a disk. Retry, but wait a little to give * the drive time to complete the load. */ - ssleep(2); + delay = true; } else { /* otherwise, don't retry */ retries = 0; } --retries; } - - /* end of retry loop */ - } while ((flags & RQF_FAILED) && retries >= 0); + blk_put_request(rq); + if (delay) + ssleep(2); + } while (failed && retries >= 0); /* return an error if the command failed */ - return (flags & RQF_FAILED) ? -EIO : 0; + return failed ? -EIO : 0; } /* @@ -526,7 +521,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) ide_expiry_t *expiry = NULL; int dma_error = 0, dma, thislen, uptodate = 0; int write = (rq_data_dir(rq) == WRITE) ? 1 : 0, rc = 0; - int sense = (rq->cmd_type == REQ_TYPE_ATA_SENSE); + int sense = ata_sense_request(rq); unsigned int timeout; u16 len; u8 ireason, stat; @@ -569,7 +564,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) ide_read_bcount_and_ireason(drive, &len, &ireason); - thislen = (rq->cmd_type == REQ_TYPE_FS) ? len : cmd->nleft; + thislen = !blk_rq_is_passthrough(rq) ? len : cmd->nleft; if (thislen > len) thislen = len; @@ -578,7 +573,8 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) /* If DRQ is clear, the command has completed. */ if ((stat & ATA_DRQ) == 0) { - if (rq->cmd_type == REQ_TYPE_FS) { + switch (req_op(rq)) { + default: /* * If we're not done reading/writing, complain. * Otherwise, complete the command normally. @@ -592,7 +588,9 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) rq->rq_flags |= RQF_FAILED; uptodate = 0; } - } else if (rq->cmd_type != REQ_TYPE_BLOCK_PC) { + goto out_end; + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: ide_cd_request_sense_fixup(drive, cmd); uptodate = cmd->nleft ? 0 : 1; @@ -608,8 +606,11 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) if (!uptodate) rq->rq_flags |= RQF_FAILED; + goto out_end; + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: + goto out_end; } - goto out_end; } rc = ide_check_ireason(drive, rq, len, ireason, write); @@ -636,12 +637,12 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) len -= blen; if (sense && write == 0) - rq->sense_len += blen; + scsi_req(rq)->sense_len += blen; } /* pad, if necessary */ if (len > 0) { - if (rq->cmd_type != REQ_TYPE_FS || write == 0) + if (blk_rq_is_passthrough(rq) || write == 0) ide_pad_transfer(drive, write, len); else { printk(KERN_ERR PFX "%s: confused, missing data\n", @@ -650,12 +651,18 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) } } - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { + switch (req_op(rq)) { + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: timeout = rq->timeout; - } else { + break; + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + expiry = ide_cd_expiry; + /*FALLTHRU*/ + default: timeout = ATAPI_WAIT_PC; - if (rq->cmd_type != REQ_TYPE_FS) - expiry = ide_cd_expiry; + break; } hwif->expiry = expiry; @@ -663,15 +670,15 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) return ide_started; out_end: - if (rq->cmd_type == REQ_TYPE_BLOCK_PC && rc == 0) { - rq->resid_len = 0; + if (blk_rq_is_scsi(rq) && rc == 0) { + scsi_req(rq)->resid_len = 0; blk_end_request_all(rq, 0); hwif->rq = NULL; } else { if (sense && uptodate) ide_cd_complete_failed_rq(drive, rq); - if (rq->cmd_type == REQ_TYPE_FS) { + if (!blk_rq_is_passthrough(rq)) { if (cmd->nleft == 0) uptodate = 1; } else { @@ -684,10 +691,10 @@ out_end: return ide_stopped; /* make sure it's fully ended */ - if (rq->cmd_type != REQ_TYPE_FS) { - rq->resid_len -= cmd->nbytes - cmd->nleft; + if (blk_rq_is_passthrough(rq)) { + scsi_req(rq)->resid_len -= cmd->nbytes - cmd->nleft; if (uptodate == 0 && (cmd->tf_flags & IDE_TFLAG_WRITE)) - rq->resid_len += cmd->last_xfer_len; + scsi_req(rq)->resid_len += cmd->last_xfer_len; } ide_complete_rq(drive, uptodate ? 0 : -EIO, blk_rq_bytes(rq)); @@ -744,7 +751,7 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq) ide_debug_log(IDE_DBG_PC, "rq->cmd[0]: 0x%x, rq->cmd_type: 0x%x", rq->cmd[0], rq->cmd_type); - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) + if (blk_rq_is_scsi(rq)) rq->rq_flags |= RQF_QUIET; else rq->rq_flags &= ~RQF_FAILED; @@ -786,25 +793,31 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, if (drive->debug_mask & IDE_DBG_RQ) blk_dump_rq_flags(rq, "ide_cd_do_request"); - switch (rq->cmd_type) { - case REQ_TYPE_FS: + switch (req_op(rq)) { + default: if (cdrom_start_rw(drive, rq) == ide_stopped) goto out_end; break; - case REQ_TYPE_ATA_SENSE: - case REQ_TYPE_BLOCK_PC: - case REQ_TYPE_ATA_PC: + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: + handle_pc: if (!rq->timeout) rq->timeout = ATAPI_WAIT_PC; - cdrom_do_block_pc(drive, rq); break; - case REQ_TYPE_DRV_PRIV: - /* right now this can only be a reset... */ - uptodate = 1; - goto out_end; - default: - BUG(); + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + switch (ide_req(rq)->type) { + case ATA_PRIV_MISC: + /* right now this can only be a reset... */ + uptodate = 1; + goto out_end; + case ATA_PRIV_SENSE: + case ATA_PRIV_PC: + goto handle_pc; + default: + BUG(); + } } /* prepare sense request for this command */ @@ -817,7 +830,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, cmd.rq = rq; - if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) { + if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) { ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } @@ -1166,7 +1179,7 @@ void ide_cdrom_update_speed(ide_drive_t *drive, u8 *buf) CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_GENERIC_PACKET | \ CDC_MO_DRIVE | CDC_MRW | CDC_MRW_W | CDC_RAM) -static struct cdrom_device_ops ide_cdrom_dops = { +static const struct cdrom_device_ops ide_cdrom_dops = { .open = ide_cdrom_open_real, .release = ide_cdrom_release_real, .drive_status = ide_cdrom_drive_status, @@ -1312,28 +1325,29 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) int hard_sect = queue_logical_block_size(q); long block = (long)blk_rq_pos(rq) / (hard_sect >> 9); unsigned long blocks = blk_rq_sectors(rq) / (hard_sect >> 9); + struct scsi_request *req = scsi_req(rq); - memset(rq->cmd, 0, BLK_MAX_CDB); + memset(req->cmd, 0, BLK_MAX_CDB); if (rq_data_dir(rq) == READ) - rq->cmd[0] = GPCMD_READ_10; + req->cmd[0] = GPCMD_READ_10; else - rq->cmd[0] = GPCMD_WRITE_10; + req->cmd[0] = GPCMD_WRITE_10; /* * fill in lba */ - rq->cmd[2] = (block >> 24) & 0xff; - rq->cmd[3] = (block >> 16) & 0xff; - rq->cmd[4] = (block >> 8) & 0xff; - rq->cmd[5] = block & 0xff; + req->cmd[2] = (block >> 24) & 0xff; + req->cmd[3] = (block >> 16) & 0xff; + req->cmd[4] = (block >> 8) & 0xff; + req->cmd[5] = block & 0xff; /* * and transfer length */ - rq->cmd[7] = (blocks >> 8) & 0xff; - rq->cmd[8] = blocks & 0xff; - rq->cmd_len = 10; + req->cmd[7] = (blocks >> 8) & 0xff; + req->cmd[8] = blocks & 0xff; + req->cmd_len = 10; return BLKPREP_OK; } @@ -1343,7 +1357,7 @@ static int ide_cdrom_prep_fs(struct request_queue *q, struct request *rq) */ static int ide_cdrom_prep_pc(struct request *rq) { - u8 *c = rq->cmd; + u8 *c = scsi_req(rq)->cmd; /* transform 6-byte read/write commands to the 10-byte version */ if (c[0] == READ_6 || c[0] == WRITE_6) { @@ -1354,7 +1368,7 @@ static int ide_cdrom_prep_pc(struct request *rq) c[2] = 0; c[1] &= 0xe0; c[0] += (READ_10 - READ_6); - rq->cmd_len = 10; + scsi_req(rq)->cmd_len = 10; return BLKPREP_OK; } @@ -1373,9 +1387,9 @@ static int ide_cdrom_prep_pc(struct request *rq) static int ide_cdrom_prep_fn(struct request_queue *q, struct request *rq) { - if (rq->cmd_type == REQ_TYPE_FS) + if (!blk_rq_is_passthrough(rq)) return ide_cdrom_prep_fs(q, rq); - else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) + else if (blk_rq_is_scsi(rq)) return ide_cdrom_prep_pc(rq); return 0; diff --git a/drivers/ide/ide-cd_ioctl.c b/drivers/ide/ide-cd_ioctl.c index f085e3a2e1d6..9fcefbc8425e 100644 --- a/drivers/ide/ide-cd_ioctl.c +++ b/drivers/ide/ide-cd_ioctl.c @@ -303,8 +303,9 @@ int ide_cdrom_reset(struct cdrom_device_info *cdi) struct request *rq; int ret; - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_DRV_PRIV; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_MISC; rq->rq_flags = RQF_QUIET; ret = blk_execute_rq(drive->queue, cd->disk, rq, 0); blk_put_request(rq); diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c index f079ca2f260b..58a6feb74c02 100644 --- a/drivers/ide/ide-cd_verbose.c +++ b/drivers/ide/ide-cd_verbose.c @@ -315,12 +315,12 @@ void ide_cd_log_error(const char *name, struct request *failed_command, while (hi > lo) { mid = (lo + hi) / 2; if (packet_command_texts[mid].packet_command == - failed_command->cmd[0]) { + scsi_req(failed_command)->cmd[0]) { s = packet_command_texts[mid].text; break; } if (packet_command_texts[mid].packet_command > - failed_command->cmd[0]) + scsi_req(failed_command)->cmd[0]) hi = mid; else lo = mid + 1; @@ -329,7 +329,7 @@ void ide_cd_log_error(const char *name, struct request *failed_command, printk(KERN_ERR " The failed \"%s\" packet command " "was: \n \"", s); for (i = 0; i < BLK_MAX_CDB; i++) - printk(KERN_CONT "%02x ", failed_command->cmd[i]); + printk(KERN_CONT "%02x ", scsi_req(failed_command)->cmd[i]); printk(KERN_CONT "\"\n"); } diff --git a/drivers/ide/ide-devsets.c b/drivers/ide/ide-devsets.c index 0dd43b4fcec6..a45dda5386e4 100644 --- a/drivers/ide/ide-devsets.c +++ b/drivers/ide/ide-devsets.c @@ -165,11 +165,12 @@ int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting, if (!(setting->flags & DS_SYNC)) return setting->set(drive, arg); - rq = blk_get_request(q, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_DRV_PRIV; - rq->cmd_len = 5; - rq->cmd[0] = REQ_DEVSET_EXEC; - *(int *)&rq->cmd[1] = arg; + rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_MISC; + scsi_req(rq)->cmd_len = 5; + scsi_req(rq)->cmd[0] = REQ_DEVSET_EXEC; + *(int *)&scsi_req(rq)->cmd[1] = arg; rq->special = setting->set; if (blk_execute_rq(q, NULL, rq, 0)) @@ -183,7 +184,7 @@ ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq) { int err, (*setfunc)(ide_drive_t *, int) = rq->special; - err = setfunc(drive, *(int *)&rq->cmd[1]); + err = setfunc(drive, *(int *)&scsi_req(rq)->cmd[1]); if (err) rq->errors = err; ide_complete_rq(drive, err, blk_rq_bytes(rq)); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 5ceace542b77..186159715b71 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -184,7 +184,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_hwif_t *hwif = drive->hwif; BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); - BUG_ON(rq->cmd_type != REQ_TYPE_FS); + BUG_ON(blk_rq_is_passthrough(rq)); ledtrig_disk_activity(); @@ -452,8 +452,9 @@ static int idedisk_prep_fn(struct request_queue *q, struct request *rq) cmd->valid.out.tf = IDE_VALID_OUT_TF | IDE_VALID_DEVICE; cmd->tf_flags = IDE_TFLAG_DYN; cmd->protocol = ATA_PROT_NODATA; - - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq->cmd_flags &= ~REQ_OP_MASK; + rq->cmd_flags |= REQ_OP_DRV_OUT; + ide_req(rq)->type = ATA_PRIV_TASKFILE; rq->special = cmd; cmd->rq = rq; @@ -477,8 +478,9 @@ static int set_multcount(ide_drive_t *drive, int arg) if (drive->special_flags & IDE_SFLAG_SET_MULTMODE) return -EBUSY; - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_TASKFILE; drive->mult_req = arg; drive->special_flags |= IDE_SFLAG_SET_MULTMODE; diff --git a/drivers/ide/ide-eh.c b/drivers/ide/ide-eh.c index d6da011299f5..cf3af6840368 100644 --- a/drivers/ide/ide-eh.c +++ b/drivers/ide/ide-eh.c @@ -123,8 +123,8 @@ ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat) return ide_stopped; /* retry only "normal" I/O: */ - if (rq->cmd_type != REQ_TYPE_FS) { - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + if (blk_rq_is_passthrough(rq)) { + if (ata_taskfile_request(rq)) { struct ide_cmd *cmd = rq->special; if (cmd) @@ -147,8 +147,8 @@ static inline void ide_complete_drive_reset(ide_drive_t *drive, int err) { struct request *rq = drive->hwif->rq; - if (rq && rq->cmd_type == REQ_TYPE_DRV_PRIV && - rq->cmd[0] == REQ_DRIVE_RESET) { + if (rq && ata_misc_request(rq) && + scsi_req(rq)->cmd[0] == REQ_DRIVE_RESET) { if (err <= 0 && rq->errors == 0) rq->errors = -EIO; ide_complete_rq(drive, err ? err : 0, blk_rq_bytes(rq)); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index f079d8d1d856..a69e8013f1df 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -72,7 +72,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc) drive->failed_pc = NULL; if (pc->c[0] == GPCMD_READ_10 || pc->c[0] == GPCMD_WRITE_10 || - rq->cmd_type == REQ_TYPE_BLOCK_PC) + (req_op(rq) == REQ_OP_SCSI_IN || req_op(rq) == REQ_OP_SCSI_OUT)) uptodate = 1; /* FIXME */ else if (pc->c[0] == GPCMD_REQUEST_SENSE) { @@ -97,7 +97,7 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc) "Aborting request!\n"); } - if (rq->cmd_type == REQ_TYPE_DRV_PRIV) + if (ata_misc_request(rq)) rq->errors = uptodate ? 0 : IDE_DRV_ERROR_GENERAL; return uptodate; @@ -203,7 +203,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, put_unaligned(cpu_to_be16(blocks), (unsigned short *)&pc->c[7]); put_unaligned(cpu_to_be32(block), (unsigned int *) &pc->c[2]); - memcpy(rq->cmd, pc->c, 12); + memcpy(scsi_req(rq)->cmd, pc->c, 12); pc->rq = rq; if (cmd == WRITE) @@ -216,7 +216,7 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, struct ide_atapi_pc *pc, struct request *rq) { ide_init_pc(pc); - memcpy(pc->c, rq->cmd, sizeof(pc->c)); + memcpy(pc->c, scsi_req(rq)->cmd, sizeof(pc->c)); pc->rq = rq; if (blk_rq_bytes(rq)) { pc->flags |= PC_FLAG_DMA_OK; @@ -246,7 +246,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, } else printk(KERN_ERR PFX "%s: I/O error\n", drive->name); - if (rq->cmd_type == REQ_TYPE_DRV_PRIV) { + if (ata_misc_request(rq)) { rq->errors = 0; ide_complete_rq(drive, 0, blk_rq_bytes(rq)); return ide_stopped; @@ -254,8 +254,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, goto out_end; } - switch (rq->cmd_type) { - case REQ_TYPE_FS: + switch (req_op(rq)) { + default: if (((long)blk_rq_pos(rq) % floppy->bs_factor) || (blk_rq_sectors(rq) % floppy->bs_factor)) { printk(KERN_ERR PFX "%s: unsupported r/w rq size\n", @@ -265,16 +265,21 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, pc = &floppy->queued_pc; idefloppy_create_rw_cmd(drive, pc, rq, (unsigned long)block); break; - case REQ_TYPE_DRV_PRIV: - case REQ_TYPE_ATA_SENSE: - pc = (struct ide_atapi_pc *)rq->special; - break; - case REQ_TYPE_BLOCK_PC: + case REQ_OP_SCSI_IN: + case REQ_OP_SCSI_OUT: pc = &floppy->queued_pc; idefloppy_blockpc_cmd(floppy, pc, rq); break; - default: - BUG(); + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: + switch (ide_req(rq)->type) { + case ATA_PRIV_MISC: + case ATA_PRIV_SENSE: + pc = (struct ide_atapi_pc *)rq->special; + break; + default: + BUG(); + } } ide_prep_sense(drive, rq); @@ -286,7 +291,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, cmd.rq = rq; - if (rq->cmd_type == REQ_TYPE_FS || blk_rq_bytes(rq)) { + if (!blk_rq_is_passthrough(rq) || blk_rq_bytes(rq)) { ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } @@ -296,7 +301,7 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, return ide_floppy_issue_pc(drive, &cmd, pc); out_end: drive->failed_pc = NULL; - if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0) + if (blk_rq_is_passthrough(rq) && rq->errors == 0) rq->errors = -EIO; ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); return ide_stopped; diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 201e43fcbc94..043b1fb963cb 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -102,7 +102,7 @@ void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err) drive->dev_flags |= IDE_DFLAG_PARKED; } - if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { + if (rq && ata_taskfile_request(rq)) { struct ide_cmd *orig_cmd = rq->special; if (cmd->tf_flags & IDE_TFLAG_DYN) @@ -135,7 +135,7 @@ EXPORT_SYMBOL(ide_complete_rq); void ide_kill_rq(ide_drive_t *drive, struct request *rq) { - u8 drv_req = (rq->cmd_type == REQ_TYPE_DRV_PRIV) && rq->rq_disk; + u8 drv_req = ata_misc_request(rq) && rq->rq_disk; u8 media = drive->media; drive->failed_pc = NULL; @@ -145,7 +145,7 @@ void ide_kill_rq(ide_drive_t *drive, struct request *rq) } else { if (media == ide_tape) rq->errors = IDE_DRV_ERROR_GENERAL; - else if (rq->cmd_type != REQ_TYPE_FS && rq->errors == 0) + else if (blk_rq_is_passthrough(rq) && rq->errors == 0) rq->errors = -EIO; } @@ -279,7 +279,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq) { - u8 cmd = rq->cmd[0]; + u8 cmd = scsi_req(rq)->cmd[0]; switch (cmd) { case REQ_PARK_HEADS: @@ -340,7 +340,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) if (drive->current_speed == 0xff) ide_config_drive_speed(drive, drive->desired_speed); - if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) + if (ata_taskfile_request(rq)) return execute_drive_cmd(drive, rq); else if (ata_pm_request(rq)) { struct ide_pm_state *pm = rq->special; @@ -353,7 +353,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) pm->pm_step == IDE_PM_COMPLETED) ide_complete_pm_rq(drive, rq); return startstop; - } else if (!rq->rq_disk && rq->cmd_type == REQ_TYPE_DRV_PRIV) + } else if (!rq->rq_disk && ata_misc_request(rq)) /* * TODO: Once all ULDs have been modified to * check for specific op codes rather than @@ -545,6 +545,7 @@ repeat: goto plug_device; } + scsi_req(rq)->resid_len = blk_rq_bytes(rq); hwif->rq = rq; spin_unlock_irq(&hwif->lock); diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index d05db2469209..248a3e0ceb46 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -125,8 +125,9 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) if (NULL == (void *) arg) { struct request *rq; - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_TASKFILE; err = blk_execute_rq(drive->queue, NULL, rq, 0); blk_put_request(rq); @@ -221,10 +222,11 @@ static int generic_drive_reset(ide_drive_t *drive) struct request *rq; int ret = 0; - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_DRV_PRIV; - rq->cmd_len = 1; - rq->cmd[0] = REQ_DRIVE_RESET; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_MISC; + scsi_req(rq)->cmd_len = 1; + scsi_req(rq)->cmd[0] = REQ_DRIVE_RESET; if (blk_execute_rq(drive->queue, NULL, rq, 1)) ret = rq->errors; blk_put_request(rq); diff --git a/drivers/ide/ide-park.c b/drivers/ide/ide-park.c index 2d7dca56dd24..101aed9a61ca 100644 --- a/drivers/ide/ide-park.c +++ b/drivers/ide/ide-park.c @@ -31,10 +31,11 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) } spin_unlock_irq(&hwif->lock); - rq = blk_get_request(q, READ, __GFP_RECLAIM); - rq->cmd[0] = REQ_PARK_HEADS; - rq->cmd_len = 1; - rq->cmd_type = REQ_TYPE_DRV_PRIV; + rq = blk_get_request(q, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + scsi_req(rq)->cmd[0] = REQ_PARK_HEADS; + scsi_req(rq)->cmd_len = 1; + ide_req(rq)->type = ATA_PRIV_MISC; rq->special = &timeout; rc = blk_execute_rq(q, NULL, rq, 1); blk_put_request(rq); @@ -45,13 +46,14 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout) * Make sure that *some* command is sent to the drive after the * timeout has expired, so power management will be reenabled. */ - rq = blk_get_request(q, READ, GFP_NOWAIT); + rq = blk_get_request(q, REQ_OP_DRV_IN, GFP_NOWAIT); + scsi_req_init(rq); if (IS_ERR(rq)) goto out; - rq->cmd[0] = REQ_UNPARK_HEADS; - rq->cmd_len = 1; - rq->cmd_type = REQ_TYPE_DRV_PRIV; + scsi_req(rq)->cmd[0] = REQ_UNPARK_HEADS; + scsi_req(rq)->cmd_len = 1; + ide_req(rq)->type = ATA_PRIV_MISC; elv_add_request(q, rq, ELEVATOR_INSERT_FRONT); out: @@ -64,7 +66,7 @@ ide_startstop_t ide_do_park_unpark(ide_drive_t *drive, struct request *rq) struct ide_taskfile *tf = &cmd.tf; memset(&cmd, 0, sizeof(cmd)); - if (rq->cmd[0] == REQ_PARK_HEADS) { + if (scsi_req(rq)->cmd[0] == REQ_PARK_HEADS) { drive->sleep = *(unsigned long *)rq->special; drive->dev_flags |= IDE_DFLAG_SLEEPING; tf->command = ATA_CMD_IDLEIMMEDIATE; diff --git a/drivers/ide/ide-pm.c b/drivers/ide/ide-pm.c index a015acdffb39..ec951be4b0c8 100644 --- a/drivers/ide/ide-pm.c +++ b/drivers/ide/ide-pm.c @@ -18,8 +18,9 @@ int generic_ide_suspend(struct device *dev, pm_message_t mesg) } memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_ATA_PM_SUSPEND; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_PM_SUSPEND; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_SUSPEND; if (mesg.event == PM_EVENT_PRETHAW) @@ -88,8 +89,9 @@ int generic_ide_resume(struct device *dev) } memset(&rqpm, 0, sizeof(rqpm)); - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_ATA_PM_RESUME; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_PM_RESUME; rq->rq_flags |= RQF_PREEMPT; rq->special = &rqpm; rqpm.pm_step = IDE_PM_START_RESUME; @@ -221,10 +223,10 @@ void ide_complete_pm_rq(ide_drive_t *drive, struct request *rq) #ifdef DEBUG_PM printk("%s: completing PM request, %s\n", drive->name, - (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND) ? "suspend" : "resume"); + (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) ? "suspend" : "resume"); #endif spin_lock_irqsave(q->queue_lock, flags); - if (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND) + if (ide_req(rq)->type == ATA_PRIV_PM_SUSPEND) blk_stop_queue(q); else drive->dev_flags &= ~IDE_DFLAG_BLOCKED; @@ -240,11 +242,13 @@ void ide_check_pm_state(ide_drive_t *drive, struct request *rq) { struct ide_pm_state *pm = rq->special; - if (rq->cmd_type == REQ_TYPE_ATA_PM_SUSPEND && + if (blk_rq_is_private(rq) && + ide_req(rq)->type == ATA_PRIV_PM_SUSPEND && pm->pm_step == IDE_PM_START_SUSPEND) /* Mark drive blocked when starting the suspend sequence. */ drive->dev_flags |= IDE_DFLAG_BLOCKED; - else if (rq->cmd_type == REQ_TYPE_ATA_PM_RESUME && + else if (blk_rq_is_private(rq) && + ide_req(rq)->type == ATA_PRIV_PM_RESUME && pm->pm_step == IDE_PM_START_RESUME) { /* * The first thing we do on wakeup is to wait for BSY bit to diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 330e319419e6..a74ae8df4bb8 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -741,6 +741,14 @@ static void ide_port_tune_devices(ide_hwif_t *hwif) } } +static int ide_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp) +{ + struct ide_request *req = blk_mq_rq_to_pdu(rq); + + req->sreq.sense = req->sense; + return 0; +} + /* * init request queue */ @@ -758,11 +766,18 @@ static int ide_init_queue(ide_drive_t *drive) * limits and LBA48 we could raise it but as yet * do not. */ - - q = blk_init_queue_node(do_ide_request, NULL, hwif_to_node(hwif)); + q = blk_alloc_queue_node(GFP_KERNEL, hwif_to_node(hwif)); if (!q) return 1; + q->request_fn = do_ide_request; + q->init_rq_fn = ide_init_rq; + q->cmd_size = sizeof(struct ide_request); + if (blk_init_allocated_queue(q) < 0) { + blk_cleanup_queue(q); + return 1; + } + q->queuedata = drive; blk_queue_segment_boundary(q, 0xffff); @@ -1131,10 +1146,12 @@ static void ide_port_init_devices_data(ide_hwif_t *hwif) ide_port_for_each_dev(i, drive, hwif) { u8 j = (hwif->index * MAX_DRIVES) + i; u16 *saved_id = drive->id; + struct request *saved_sense_rq = drive->sense_rq; memset(drive, 0, sizeof(*drive)); memset(saved_id, 0, SECTOR_SIZE); drive->id = saved_id; + drive->sense_rq = saved_sense_rq; drive->media = ide_disk; drive->select = (i << 4) | ATA_DEVICE_OBS; @@ -1241,6 +1258,7 @@ static void ide_port_free_devices(ide_hwif_t *hwif) int i; ide_port_for_each_dev(i, drive, hwif) { + kfree(drive->sense_rq); kfree(drive->id); kfree(drive); } @@ -1248,11 +1266,10 @@ static void ide_port_free_devices(ide_hwif_t *hwif) static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) { + ide_drive_t *drive; int i; for (i = 0; i < MAX_DRIVES; i++) { - ide_drive_t *drive; - drive = kzalloc_node(sizeof(*drive), GFP_KERNEL, node); if (drive == NULL) goto out_nomem; @@ -1267,12 +1284,21 @@ static int ide_port_alloc_devices(ide_hwif_t *hwif, int node) */ drive->id = kzalloc_node(SECTOR_SIZE, GFP_KERNEL, node); if (drive->id == NULL) - goto out_nomem; + goto out_free_drive; + + drive->sense_rq = kmalloc(sizeof(struct request) + + sizeof(struct ide_request), GFP_KERNEL); + if (!drive->sense_rq) + goto out_free_id; hwif->devices[i] = drive; } return 0; +out_free_id: + kfree(drive->id); +out_free_drive: + kfree(drive); out_nomem: ide_port_free_devices(hwif); return -ENOMEM; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 9ecf4e35adcd..3c1b7974d66d 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -282,7 +282,7 @@ static void idetape_analyze_error(ide_drive_t *drive) /* correct remaining bytes to transfer */ if (pc->flags & PC_FLAG_DMA_ERROR) - rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); + scsi_req(rq)->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); /* * If error was the result of a zero-length read or write command, @@ -316,7 +316,7 @@ static void idetape_analyze_error(ide_drive_t *drive) pc->flags |= PC_FLAG_ABORT; } if (!(pc->flags & PC_FLAG_ABORT) && - (blk_rq_bytes(rq) - rq->resid_len)) + (blk_rq_bytes(rq) - scsi_req(rq)->resid_len)) pc->retries = IDETAPE_MAX_PC_RETRIES + 1; } } @@ -348,7 +348,7 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) "itself - Aborting request!\n"); } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { unsigned int blocks = - (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size; + (blk_rq_bytes(rq) - scsi_req(rq)->resid_len) / tape->blk_size; tape->avg_size += blocks * tape->blk_size; @@ -560,7 +560,7 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, pc->flags |= PC_FLAG_WRITING; } - memcpy(rq->cmd, pc->c, 12); + memcpy(scsi_req(rq)->cmd, pc->c, 12); } static ide_startstop_t idetape_do_request(ide_drive_t *drive, @@ -570,14 +570,16 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc *pc = NULL; struct ide_cmd cmd; + struct scsi_request *req = scsi_req(rq); u8 stat; ide_debug_log(IDE_DBG_RQ, "cmd: 0x%x, sector: %llu, nr_sectors: %u", - rq->cmd[0], (unsigned long long)blk_rq_pos(rq), + req->cmd[0], (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq)); - BUG_ON(!(rq->cmd_type == REQ_TYPE_DRV_PRIV || - rq->cmd_type == REQ_TYPE_ATA_SENSE)); + BUG_ON(!blk_rq_is_private(rq)); + BUG_ON(ide_req(rq)->type != ATA_PRIV_MISC && + ide_req(rq)->type != ATA_PRIV_SENSE); /* Retry a failed packet command */ if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) { @@ -592,7 +594,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, stat = hwif->tp_ops->read_status(hwif); if ((drive->dev_flags & IDE_DFLAG_DSC_OVERLAP) == 0 && - (rq->cmd[13] & REQ_IDETAPE_PC2) == 0) + (req->cmd[13] & REQ_IDETAPE_PC2) == 0) drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; if (drive->dev_flags & IDE_DFLAG_POST_RESET) { @@ -609,7 +611,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } else if (time_after(jiffies, tape->dsc_timeout)) { printk(KERN_ERR "ide-tape: %s: DSC timeout\n", tape->name); - if (rq->cmd[13] & REQ_IDETAPE_PC2) { + if (req->cmd[13] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } else { @@ -626,23 +628,23 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, tape->postponed_rq = false; } - if (rq->cmd[13] & REQ_IDETAPE_READ) { + if (req->cmd[13] & REQ_IDETAPE_READ) { pc = &tape->queued_pc; ide_tape_create_rw_cmd(tape, pc, rq, READ_6); goto out; } - if (rq->cmd[13] & REQ_IDETAPE_WRITE) { + if (req->cmd[13] & REQ_IDETAPE_WRITE) { pc = &tape->queued_pc; ide_tape_create_rw_cmd(tape, pc, rq, WRITE_6); goto out; } - if (rq->cmd[13] & REQ_IDETAPE_PC1) { + if (req->cmd[13] & REQ_IDETAPE_PC1) { pc = (struct ide_atapi_pc *)rq->special; - rq->cmd[13] &= ~(REQ_IDETAPE_PC1); - rq->cmd[13] |= REQ_IDETAPE_PC2; + req->cmd[13] &= ~(REQ_IDETAPE_PC1); + req->cmd[13] |= REQ_IDETAPE_PC2; goto out; } - if (rq->cmd[13] & REQ_IDETAPE_PC2) { + if (req->cmd[13] & REQ_IDETAPE_PC2) { idetape_media_access_finished(drive); return ide_stopped; } @@ -852,9 +854,10 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) BUG_ON(cmd != REQ_IDETAPE_READ && cmd != REQ_IDETAPE_WRITE); BUG_ON(size < 0 || size % tape->blk_size); - rq = blk_get_request(drive->queue, READ, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_DRV_PRIV; - rq->cmd[13] = cmd; + rq = blk_get_request(drive->queue, REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_MISC; + scsi_req(rq)->cmd[13] = cmd; rq->rq_disk = tape->disk; rq->__sector = tape->first_frame; @@ -868,7 +871,7 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int size) blk_execute_rq(drive->queue, tape->disk, rq, 0); /* calculate the number of transferred bytes and update buffer state */ - size -= rq->resid_len; + size -= scsi_req(rq)->resid_len; tape->cur = tape->buf; if (cmd == REQ_IDETAPE_READ) tape->valid = size; diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index a716693417a3..247b9faccce1 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -428,10 +428,12 @@ int ide_raw_taskfile(ide_drive_t *drive, struct ide_cmd *cmd, u8 *buf, { struct request *rq; int error; - int rw = !(cmd->tf_flags & IDE_TFLAG_WRITE) ? READ : WRITE; - rq = blk_get_request(drive->queue, rw, __GFP_RECLAIM); - rq->cmd_type = REQ_TYPE_ATA_TASKFILE; + rq = blk_get_request(drive->queue, + (cmd->tf_flags & IDE_TFLAG_WRITE) ? + REQ_OP_DRV_OUT : REQ_OP_DRV_IN, __GFP_RECLAIM); + scsi_req_init(rq); + ide_req(rq)->type = ATA_PRIV_TASKFILE; /* * (ks) We transfer currently only whole sectors. diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c index 247853ea1368..c3062b53056f 100644 --- a/drivers/ide/sis5513.c +++ b/drivers/ide/sis5513.c @@ -54,7 +54,7 @@ #define DRV_NAME "sis5513" /* registers layout and init values are chipset family dependent */ - +#undef ATA_16 #define ATA_16 0x01 #define ATA_33 0x02 #define ATA_66 0x03 diff --git a/drivers/iio/accel/st_accel_core.c b/drivers/iio/accel/st_accel_core.c index f6b6d42385e1..784670e2736b 100644 --- a/drivers/iio/accel/st_accel_core.c +++ b/drivers/iio/accel/st_accel_core.c @@ -353,12 +353,12 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { [0] = { .num = ST_ACCEL_FS_AVL_2G, .value = 0x00, - .gain = IIO_G_TO_M_S_2(1024), + .gain = IIO_G_TO_M_S_2(1000), }, [1] = { .num = ST_ACCEL_FS_AVL_6G, .value = 0x01, - .gain = IIO_G_TO_M_S_2(340), + .gain = IIO_G_TO_M_S_2(3000), }, }, }, @@ -366,6 +366,14 @@ static const struct st_sensor_settings st_accel_sensors_settings[] = { .addr = 0x21, .mask = 0x40, }, + /* + * Data Alignment Setting - needs to be set to get + * left-justified data like all other sensors. + */ + .das = { + .addr = 0x21, + .mask = 0x01, + }, .drdy_irq = { .addr = 0x21, .mask_int1 = 0x04, diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 38bc319904c4..9c8b558ba19e 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -561,7 +561,7 @@ config TI_ADS8688 config TI_AM335X_ADC tristate "TI's AM335X ADC driver" - depends on MFD_TI_AM335X_TSCADC + depends on MFD_TI_AM335X_TSCADC && HAS_DMA select IIO_BUFFER select IIO_KFIFO_BUF help diff --git a/drivers/iio/adc/palmas_gpadc.c b/drivers/iio/adc/palmas_gpadc.c index 2bbf0c521beb..7d61b566e148 100644 --- a/drivers/iio/adc/palmas_gpadc.c +++ b/drivers/iio/adc/palmas_gpadc.c @@ -775,7 +775,7 @@ static int palmas_adc_wakeup_reset(struct palmas_gpadc *adc) static int palmas_gpadc_suspend(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; int ret; @@ -798,7 +798,7 @@ static int palmas_gpadc_suspend(struct device *dev) static int palmas_gpadc_resume(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct palmas_gpadc *adc = iio_priv(indio_dev); int wakeup = adc->wakeup1_enable || adc->wakeup2_enable; int ret; diff --git a/drivers/iio/common/st_sensors/st_sensors_buffer.c b/drivers/iio/common/st_sensors/st_sensors_buffer.c index fe7775bb3740..df4045203a07 100644 --- a/drivers/iio/common/st_sensors/st_sensors_buffer.c +++ b/drivers/iio/common/st_sensors/st_sensors_buffer.c @@ -30,7 +30,9 @@ static int st_sensors_get_buffer_element(struct iio_dev *indio_dev, u8 *buf) for_each_set_bit(i, indio_dev->active_scan_mask, num_data_channels) { const struct iio_chan_spec *channel = &indio_dev->channels[i]; - unsigned int bytes_to_read = channel->scan_type.realbits >> 3; + unsigned int bytes_to_read = + DIV_ROUND_UP(channel->scan_type.realbits + + channel->scan_type.shift, 8); unsigned int storage_bytes = channel->scan_type.storagebits >> 3; diff --git a/drivers/iio/common/st_sensors/st_sensors_core.c b/drivers/iio/common/st_sensors/st_sensors_core.c index 975a1f19f747..79c8c7cd70d5 100644 --- a/drivers/iio/common/st_sensors/st_sensors_core.c +++ b/drivers/iio/common/st_sensors/st_sensors_core.c @@ -401,6 +401,15 @@ int st_sensors_init_sensor(struct iio_dev *indio_dev, return err; } + /* set DAS */ + if (sdata->sensor_settings->das.addr) { + err = st_sensors_write_data_with_mask(indio_dev, + sdata->sensor_settings->das.addr, + sdata->sensor_settings->das.mask, 1); + if (err < 0) + return err; + } + if (sdata->int_pin_open_drain) { dev_info(&indio_dev->dev, "set interrupt line to open drain mode\n"); @@ -483,8 +492,10 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev, int err; u8 *outdata; struct st_sensor_data *sdata = iio_priv(indio_dev); - unsigned int byte_for_channel = ch->scan_type.realbits >> 3; + unsigned int byte_for_channel; + byte_for_channel = DIV_ROUND_UP(ch->scan_type.realbits + + ch->scan_type.shift, 8); outdata = kmalloc(byte_for_channel, GFP_KERNEL); if (!outdata) return -ENOMEM; diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index 2d2ee353dde7..a5913e97945e 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -153,7 +153,7 @@ static int quad8_write_raw(struct iio_dev *indio_dev, ior_cfg = val | priv->preset_enable[chan->channel] << 1; /* Load I/O control configuration */ - outb(0x40 | ior_cfg, base_offset); + outb(0x40 | ior_cfg, base_offset + 1); return 0; case IIO_CHAN_INFO_SCALE: @@ -233,7 +233,7 @@ static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, const struct quad8_iio *const priv = iio_priv(indio_dev); return snprintf(buf, PAGE_SIZE, "%u\n", - priv->preset_enable[chan->channel]); + !priv->preset_enable[chan->channel]); } static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, @@ -241,7 +241,7 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, size_t len) { struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; + const int base_offset = priv->base + 2 * chan->channel + 1; bool preset_enable; int ret; unsigned int ior_cfg; @@ -250,6 +250,9 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, if (ret) return ret; + /* Preset enable is active low in Input/Output Control register */ + preset_enable = !preset_enable; + priv->preset_enable[chan->channel] = preset_enable; ior_cfg = priv->ab_enable[chan->channel] | @@ -362,7 +365,7 @@ static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, priv->synchronous_mode[chan->channel] = synchronous_mode; /* Load Index Control configuration to Index Control Register */ - outb(0x40 | idr_cfg, base_offset); + outb(0x60 | idr_cfg, base_offset); return 0; } @@ -444,7 +447,7 @@ static int quad8_set_index_polarity(struct iio_dev *indio_dev, priv->index_polarity[chan->channel] = index_polarity; /* Load Index Control configuration to Index Control Register */ - outb(0x40 | idr_cfg, base_offset); + outb(0x60 | idr_cfg, base_offset); return 0; } diff --git a/drivers/iio/health/afe4403.c b/drivers/iio/health/afe4403.c index 9a081465c42f..6bb23a49e81e 100644 --- a/drivers/iio/health/afe4403.c +++ b/drivers/iio/health/afe4403.c @@ -422,7 +422,7 @@ MODULE_DEVICE_TABLE(of, afe4403_of_match); static int __maybe_unused afe4403_suspend(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); struct afe4403_data *afe = iio_priv(indio_dev); int ret; @@ -443,7 +443,7 @@ static int __maybe_unused afe4403_suspend(struct device *dev) static int __maybe_unused afe4403_resume(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); struct afe4403_data *afe = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/health/afe4404.c b/drivers/iio/health/afe4404.c index 45266404f7e3..964f5231a831 100644 --- a/drivers/iio/health/afe4404.c +++ b/drivers/iio/health/afe4404.c @@ -428,7 +428,7 @@ MODULE_DEVICE_TABLE(of, afe4404_of_match); static int __maybe_unused afe4404_suspend(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); struct afe4404_data *afe = iio_priv(indio_dev); int ret; @@ -449,7 +449,7 @@ static int __maybe_unused afe4404_suspend(struct device *dev) static int __maybe_unused afe4404_resume(struct device *dev) { - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); struct afe4404_data *afe = iio_priv(indio_dev); int ret; diff --git a/drivers/iio/health/max30100.c b/drivers/iio/health/max30100.c index 90ab8a2d2846..183c14329d6e 100644 --- a/drivers/iio/health/max30100.c +++ b/drivers/iio/health/max30100.c @@ -238,7 +238,7 @@ static irqreturn_t max30100_interrupt_handler(int irq, void *private) mutex_lock(&data->lock); - while (cnt || (cnt = max30100_fifo_count(data) > 0)) { + while (cnt || (cnt = max30100_fifo_count(data)) > 0) { ret = max30100_read_measurement(data); if (ret) break; diff --git a/drivers/iio/humidity/dht11.c b/drivers/iio/humidity/dht11.c index 9c47bc98f3ac..2a22ad920333 100644 --- a/drivers/iio/humidity/dht11.c +++ b/drivers/iio/humidity/dht11.c @@ -71,7 +71,8 @@ * a) select an implementation using busy loop polling on those systems * b) use the checksum to do some probabilistic decoding */ -#define DHT11_START_TRANSMISSION 18 /* ms */ +#define DHT11_START_TRANSMISSION_MIN 18000 /* us */ +#define DHT11_START_TRANSMISSION_MAX 20000 /* us */ #define DHT11_MIN_TIMERES 34000 /* ns */ #define DHT11_THRESHOLD 49000 /* ns */ #define DHT11_AMBIG_LOW 23000 /* ns */ @@ -228,7 +229,8 @@ static int dht11_read_raw(struct iio_dev *iio_dev, ret = gpio_direction_output(dht11->gpio, 0); if (ret) goto err; - msleep(DHT11_START_TRANSMISSION); + usleep_range(DHT11_START_TRANSMISSION_MIN, + DHT11_START_TRANSMISSION_MAX); ret = gpio_direction_input(dht11->gpio); if (ret) goto err; diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 5355507f8fa1..c9e319bff58b 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -66,10 +66,8 @@ #define BMI160_REG_DUMMY 0x7F -#define BMI160_ACCEL_PMU_MIN_USLEEP 3200 -#define BMI160_ACCEL_PMU_MAX_USLEEP 3800 -#define BMI160_GYRO_PMU_MIN_USLEEP 55000 -#define BMI160_GYRO_PMU_MAX_USLEEP 80000 +#define BMI160_ACCEL_PMU_MIN_USLEEP 3800 +#define BMI160_GYRO_PMU_MIN_USLEEP 80000 #define BMI160_SOFTRESET_USLEEP 1000 #define BMI160_CHANNEL(_type, _axis, _index) { \ @@ -151,20 +149,9 @@ static struct bmi160_regs bmi160_regs[] = { }, }; -struct bmi160_pmu_time { - unsigned long min; - unsigned long max; -}; - -static struct bmi160_pmu_time bmi160_pmu_time[] = { - [BMI160_ACCEL] = { - .min = BMI160_ACCEL_PMU_MIN_USLEEP, - .max = BMI160_ACCEL_PMU_MAX_USLEEP - }, - [BMI160_GYRO] = { - .min = BMI160_GYRO_PMU_MIN_USLEEP, - .max = BMI160_GYRO_PMU_MIN_USLEEP, - }, +static unsigned long bmi160_pmu_time[] = { + [BMI160_ACCEL] = BMI160_ACCEL_PMU_MIN_USLEEP, + [BMI160_GYRO] = BMI160_GYRO_PMU_MIN_USLEEP, }; struct bmi160_scale { @@ -289,7 +276,7 @@ int bmi160_set_mode(struct bmi160_data *data, enum bmi160_sensor_type t, if (ret < 0) return ret; - usleep_range(bmi160_pmu_time[t].min, bmi160_pmu_time[t].max); + usleep_range(bmi160_pmu_time[t], bmi160_pmu_time[t] + 1000); return 0; } diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c index a144ca3461fc..81bd8e8da4a6 100644 --- a/drivers/iio/light/max44000.c +++ b/drivers/iio/light/max44000.c @@ -113,7 +113,7 @@ static const char max44000_int_time_avail_str[] = "0.100 " "0.025 " "0.00625 " - "0.001625"; + "0.0015625"; /* Available scales (internal to ulux) with pretty manual alignment: */ static const int max44000_scale_avail_ulux_array[] = { diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index e7dcfac877ca..3e70a9c5d79d 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2811,7 +2811,8 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, if (!src_addr || !src_addr->sa_family) { src_addr = (struct sockaddr *) &id->route.addr.src_addr; src_addr->sa_family = dst_addr->sa_family; - if (dst_addr->sa_family == AF_INET6) { + if (IS_ENABLED(CONFIG_IPV6) && + dst_addr->sa_family == AF_INET6) { struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr; struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr; src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id; diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 1e62a5f0cb28..4609b921f899 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -134,6 +134,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, IB_ACCESS_REMOTE_ATOMIC | IB_ACCESS_MW_BIND)); if (access & IB_ACCESS_ON_DEMAND) { + put_pid(umem->pid); ret = ib_umem_odp_get(context, umem); if (ret) { kfree(umem); @@ -149,6 +150,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr, page_list = (struct page **) __get_free_page(GFP_KERNEL); if (!page_list) { + put_pid(umem->pid); kfree(umem); return ERR_PTR(-ENOMEM); } diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h index b9efadfffb4f..e66e75921797 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_cm.h +++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h @@ -55,14 +55,14 @@ #define put_ep(ep) { \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ - ep, atomic_read(&((ep)->kref.refcount))); \ - WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \ + ep, kref_read(&((ep)->kref))); \ + WARN_ON(kref_read(&((ep)->kref)) < 1); \ kref_put(&((ep)->kref), __free_ep); \ } #define get_ep(ep) { \ PDBG("get_ep (via %s:%u) ep %p, refcnt %d\n", __func__, __LINE__, \ - ep, atomic_read(&((ep)->kref.refcount))); \ + ep, kref_read(&((ep)->kref))); \ kref_get(&((ep)->kref)); \ } diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index 9d5fe1853da4..6262dc035f3c 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -1135,16 +1135,7 @@ static int iwch_query_port(struct ib_device *ibdev, memset(props, 0, sizeof(struct ib_port_attr)); props->max_mtu = IB_MTU_4096; - if (netdev->mtu >= 4096) - props->active_mtu = IB_MTU_4096; - else if (netdev->mtu >= 2048) - props->active_mtu = IB_MTU_2048; - else if (netdev->mtu >= 1024) - props->active_mtu = IB_MTU_1024; - else if (netdev->mtu >= 512) - props->active_mtu = IB_MTU_512; - else - props->active_mtu = IB_MTU_256; + props->active_mtu = ib_mtu_int_to_enum(netdev->mtu); if (!netif_carrier_ok(netdev)) props->state = IB_PORT_DOWN; diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c index d939980a708f..a9194db7f9b8 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_qp.c +++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c @@ -961,7 +961,7 @@ int iwch_modify_qp(struct iwch_dev *rhp, struct iwch_qp *qhp, case IWCH_QP_STATE_RTS: switch (attrs->next_state) { case IWCH_QP_STATE_CLOSING: - BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2); + BUG_ON(kref_read(&qhp->ep->com.kref) < 2); qhp->attr.state = IWCH_QP_STATE_CLOSING; if (!internal) { abort=0; diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index f1510cc76d2d..9398143d7c5e 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -1804,20 +1804,21 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb) skb_trim(skb, dlen); mutex_lock(&ep->com.mutex); - /* update RX credits */ - update_rx_credits(ep, dlen); - switch (ep->com.state) { case MPA_REQ_SENT: + update_rx_credits(ep, dlen); ep->rcv_seq += dlen; disconnect = process_mpa_reply(ep, skb); break; case MPA_REQ_WAIT: + update_rx_credits(ep, dlen); ep->rcv_seq += dlen; disconnect = process_mpa_request(ep, skb); break; case FPDU_MODE: { struct c4iw_qp_attributes attrs; + + update_rx_credits(ep, dlen); BUG_ON(!ep->com.qp); if (status) pr_err("%s Unexpected streaming data." \ diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c index 19c6477af19f..bec82a600d77 100644 --- a/drivers/infiniband/hw/cxgb4/cq.c +++ b/drivers/infiniband/hw/cxgb4/cq.c @@ -505,6 +505,15 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe, } /* + * Special cqe for drain WR completions... + */ + if (CQE_OPCODE(hw_cqe) == C4IW_DRAIN_OPCODE) { + *cookie = CQE_DRAIN_COOKIE(hw_cqe); + *cqe = *hw_cqe; + goto skip_cqe; + } + + /* * Gotta tweak READ completions: * 1) the cqe doesn't contain the sq_wptr from the wr. * 2) opcode not reflected from the wr. @@ -753,6 +762,9 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) c4iw_invalidate_mr(qhp->rhp, CQE_WRID_FR_STAG(&cqe)); break; + case C4IW_DRAIN_OPCODE: + wc->opcode = IB_WC_SEND; + break; default: printk(KERN_ERR MOD "Unexpected opcode %d " "in the CQE received for QPID=0x%0x\n", @@ -817,15 +829,8 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc) } } out: - if (wq) { - if (unlikely(qhp->attr.state != C4IW_QP_STATE_RTS)) { - if (t4_sq_empty(wq)) - complete(&qhp->sq_drained); - if (t4_rq_empty(wq)) - complete(&qhp->rq_drained); - } + if (wq) spin_unlock(&qhp->lock); - } return ret; } diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 516b0ae6dc3f..40c0e7b9fc6e 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -846,9 +846,17 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) } } + rdev->free_workq = create_singlethread_workqueue("iw_cxgb4_free"); + if (!rdev->free_workq) { + err = -ENOMEM; + goto err_free_status_page; + } + rdev->status_page->db_off = 0; return 0; +err_free_status_page: + free_page((unsigned long)rdev->status_page); destroy_ocqp_pool: c4iw_ocqp_pool_destroy(rdev); destroy_rqtpool: @@ -862,6 +870,7 @@ destroy_resource: static void c4iw_rdev_close(struct c4iw_rdev *rdev) { + destroy_workqueue(rdev->free_workq); kfree(rdev->wr_log); free_page((unsigned long)rdev->status_page); c4iw_pblpool_destroy(rdev); diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index 4788e1a46fde..d19662f635b1 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -45,6 +45,7 @@ #include <linux/kref.h> #include <linux/timer.h> #include <linux/io.h> +#include <linux/workqueue.h> #include <asm/byteorder.h> @@ -107,6 +108,7 @@ struct c4iw_dev_ucontext { struct list_head qpids; struct list_head cqids; struct mutex lock; + struct kref kref; }; enum c4iw_rdev_flags { @@ -183,6 +185,7 @@ struct c4iw_rdev { atomic_t wr_log_idx; struct wr_log_entry *wr_log; int wr_log_size; + struct workqueue_struct *free_workq; }; static inline int c4iw_fatal_error(struct c4iw_rdev *rdev) @@ -480,8 +483,8 @@ struct c4iw_qp { wait_queue_head_t wait; struct timer_list timer; int sq_sig_all; - struct completion rq_drained; - struct completion sq_drained; + struct work_struct free_work; + struct c4iw_ucontext *ucontext; }; static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp) @@ -495,6 +498,7 @@ struct c4iw_ucontext { u32 key; spinlock_t mmap_lock; struct list_head mmaps; + struct kref kref; }; static inline struct c4iw_ucontext *to_c4iw_ucontext(struct ib_ucontext *c) @@ -502,6 +506,18 @@ static inline struct c4iw_ucontext *to_c4iw_ucontext(struct ib_ucontext *c) return container_of(c, struct c4iw_ucontext, ibucontext); } +void _c4iw_free_ucontext(struct kref *kref); + +static inline void c4iw_put_ucontext(struct c4iw_ucontext *ucontext) +{ + kref_put(&ucontext->kref, _c4iw_free_ucontext); +} + +static inline void c4iw_get_ucontext(struct c4iw_ucontext *ucontext) +{ + kref_get(&ucontext->kref); +} + struct c4iw_mm_entry { struct list_head entry; u64 addr; @@ -615,6 +631,8 @@ static inline int to_ib_qp_state(int c4iw_qp_state) return IB_QPS_ERR; } +#define C4IW_DRAIN_OPCODE FW_RI_SGE_EC_CR_RETURN + static inline u32 c4iw_ib_to_tpt_access(int a) { return (a & IB_ACCESS_REMOTE_WRITE ? FW_RI_MEM_ACCESS_REM_WRITE : 0) | @@ -654,14 +672,14 @@ enum c4iw_mmid_state { #define c4iw_put_ep(ep) { \ PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \ - ep, atomic_read(&((ep)->kref.refcount))); \ - WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \ + ep, kref_read(&((ep)->kref))); \ + WARN_ON(kref_read(&((ep)->kref)) < 1); \ kref_put(&((ep)->kref), _c4iw_free_ep); \ } #define c4iw_get_ep(ep) { \ PDBG("get_ep (via %s:%u) ep %p, refcnt %d\n", __func__, __LINE__, \ - ep, atomic_read(&((ep)->kref.refcount))); \ + ep, kref_read(&((ep)->kref))); \ kref_get(&((ep)->kref)); \ } void _c4iw_free_ep(struct kref *kref); @@ -997,8 +1015,6 @@ extern int c4iw_wr_log; extern int db_fc_threshold; extern int db_coalescing_threshold; extern int use_dsgl; -void c4iw_drain_rq(struct ib_qp *qp); -void c4iw_drain_sq(struct ib_qp *qp); void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey); #endif diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 49b51b7e0fd7..3345e1c312f7 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -93,17 +93,28 @@ static int c4iw_process_mad(struct ib_device *ibdev, int mad_flags, return -ENOSYS; } -static int c4iw_dealloc_ucontext(struct ib_ucontext *context) +void _c4iw_free_ucontext(struct kref *kref) { - struct c4iw_dev *rhp = to_c4iw_dev(context->device); - struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context); + struct c4iw_ucontext *ucontext; + struct c4iw_dev *rhp; struct c4iw_mm_entry *mm, *tmp; - PDBG("%s context %p\n", __func__, context); + ucontext = container_of(kref, struct c4iw_ucontext, kref); + rhp = to_c4iw_dev(ucontext->ibucontext.device); + + PDBG("%s ucontext %p\n", __func__, ucontext); list_for_each_entry_safe(mm, tmp, &ucontext->mmaps, entry) kfree(mm); c4iw_release_dev_ucontext(&rhp->rdev, &ucontext->uctx); kfree(ucontext); +} + +static int c4iw_dealloc_ucontext(struct ib_ucontext *context) +{ + struct c4iw_ucontext *ucontext = to_c4iw_ucontext(context); + + PDBG("%s context %p\n", __func__, context); + c4iw_put_ucontext(ucontext); return 0; } @@ -127,6 +138,7 @@ static struct ib_ucontext *c4iw_alloc_ucontext(struct ib_device *ibdev, c4iw_init_dev_ucontext(&rhp->rdev, &context->uctx); INIT_LIST_HEAD(&context->mmaps); spin_lock_init(&context->mmap_lock); + kref_init(&context->kref); if (udata->outlen < sizeof(uresp) - sizeof(uresp.reserved)) { if (!warned++) @@ -361,16 +373,7 @@ static int c4iw_query_port(struct ib_device *ibdev, u8 port, memset(props, 0, sizeof(struct ib_port_attr)); props->max_mtu = IB_MTU_4096; - if (netdev->mtu >= 4096) - props->active_mtu = IB_MTU_4096; - else if (netdev->mtu >= 2048) - props->active_mtu = IB_MTU_2048; - else if (netdev->mtu >= 1024) - props->active_mtu = IB_MTU_1024; - else if (netdev->mtu >= 512) - props->active_mtu = IB_MTU_512; - else - props->active_mtu = IB_MTU_256; + props->active_mtu = ib_mtu_int_to_enum(netdev->mtu); if (!netif_carrier_ok(netdev)) props->state = IB_PORT_DOWN; @@ -607,8 +610,6 @@ int c4iw_register_device(struct c4iw_dev *dev) dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION; dev->ibdev.get_port_immutable = c4iw_port_immutable; dev->ibdev.get_dev_fw_str = get_dev_fw_str; - dev->ibdev.drain_sq = c4iw_drain_sq; - dev->ibdev.drain_rq = c4iw_drain_rq; dev->ibdev.iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL); if (!dev->ibdev.iwcm) diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index cda5542e13a2..d4fd2f5c8326 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -715,13 +715,32 @@ static int build_inv_stag(union t4_wr *wqe, struct ib_send_wr *wr, u8 *len16) return 0; } -static void _free_qp(struct kref *kref) +static void free_qp_work(struct work_struct *work) +{ + struct c4iw_ucontext *ucontext; + struct c4iw_qp *qhp; + struct c4iw_dev *rhp; + + qhp = container_of(work, struct c4iw_qp, free_work); + ucontext = qhp->ucontext; + rhp = qhp->rhp; + + PDBG("%s qhp %p ucontext %p\n", __func__, qhp, ucontext); + destroy_qp(&rhp->rdev, &qhp->wq, + ucontext ? &ucontext->uctx : &rhp->rdev.uctx); + + if (ucontext) + c4iw_put_ucontext(ucontext); + kfree(qhp); +} + +static void queue_qp_free(struct kref *kref) { struct c4iw_qp *qhp; qhp = container_of(kref, struct c4iw_qp, kref); PDBG("%s qhp %p\n", __func__, qhp); - kfree(qhp); + queue_work(qhp->rhp->rdev.free_workq, &qhp->free_work); } void c4iw_qp_add_ref(struct ib_qp *qp) @@ -733,7 +752,7 @@ void c4iw_qp_add_ref(struct ib_qp *qp) void c4iw_qp_rem_ref(struct ib_qp *qp) { PDBG("%s ib_qp %p\n", __func__, qp); - kref_put(&to_c4iw_qp(qp)->kref, _free_qp); + kref_put(&to_c4iw_qp(qp)->kref, queue_qp_free); } static void add_to_fc_list(struct list_head *head, struct list_head *entry) @@ -776,6 +795,64 @@ static int ring_kernel_rq_db(struct c4iw_qp *qhp, u16 inc) return 0; } +static void complete_sq_drain_wr(struct c4iw_qp *qhp, struct ib_send_wr *wr) +{ + struct t4_cqe cqe = {}; + struct c4iw_cq *schp; + unsigned long flag; + struct t4_cq *cq; + + schp = to_c4iw_cq(qhp->ibqp.send_cq); + cq = &schp->cq; + + cqe.u.drain_cookie = wr->wr_id; + cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | + CQE_OPCODE_V(C4IW_DRAIN_OPCODE) | + CQE_TYPE_V(1) | + CQE_SWCQE_V(1) | + CQE_QPID_V(qhp->wq.sq.qid)); + + spin_lock_irqsave(&schp->lock, flag); + cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); + cq->sw_queue[cq->sw_pidx] = cqe; + t4_swcq_produce(cq); + spin_unlock_irqrestore(&schp->lock, flag); + + spin_lock_irqsave(&schp->comp_handler_lock, flag); + (*schp->ibcq.comp_handler)(&schp->ibcq, + schp->ibcq.cq_context); + spin_unlock_irqrestore(&schp->comp_handler_lock, flag); +} + +static void complete_rq_drain_wr(struct c4iw_qp *qhp, struct ib_recv_wr *wr) +{ + struct t4_cqe cqe = {}; + struct c4iw_cq *rchp; + unsigned long flag; + struct t4_cq *cq; + + rchp = to_c4iw_cq(qhp->ibqp.recv_cq); + cq = &rchp->cq; + + cqe.u.drain_cookie = wr->wr_id; + cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) | + CQE_OPCODE_V(C4IW_DRAIN_OPCODE) | + CQE_TYPE_V(0) | + CQE_SWCQE_V(1) | + CQE_QPID_V(qhp->wq.sq.qid)); + + spin_lock_irqsave(&rchp->lock, flag); + cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen)); + cq->sw_queue[cq->sw_pidx] = cqe; + t4_swcq_produce(cq); + spin_unlock_irqrestore(&rchp->lock, flag); + + spin_lock_irqsave(&rchp->comp_handler_lock, flag); + (*rchp->ibcq.comp_handler)(&rchp->ibcq, + rchp->ibcq.cq_context); + spin_unlock_irqrestore(&rchp->comp_handler_lock, flag); +} + int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { @@ -794,8 +871,8 @@ int c4iw_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, spin_lock_irqsave(&qhp->lock, flag); if (t4_wq_in_error(&qhp->wq)) { spin_unlock_irqrestore(&qhp->lock, flag); - *bad_wr = wr; - return -EINVAL; + complete_sq_drain_wr(qhp, wr); + return err; } num_wrs = t4_sq_avail(&qhp->wq); if (num_wrs == 0) { @@ -937,8 +1014,8 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, spin_lock_irqsave(&qhp->lock, flag); if (t4_wq_in_error(&qhp->wq)) { spin_unlock_irqrestore(&qhp->lock, flag); - *bad_wr = wr; - return -EINVAL; + complete_rq_drain_wr(qhp, wr); + return err; } num_wrs = t4_rq_avail(&qhp->wq); if (num_wrs == 0) { @@ -1503,7 +1580,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, case C4IW_QP_STATE_RTS: switch (attrs->next_state) { case C4IW_QP_STATE_CLOSING: - BUG_ON(atomic_read(&qhp->ep->com.kref.refcount) < 2); + BUG_ON(kref_read(&qhp->ep->com.kref) < 2); t4_set_wq_in_error(&qhp->wq); set_state(qhp, C4IW_QP_STATE_CLOSING); ep = qhp->ep; @@ -1550,7 +1627,12 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp, } break; case C4IW_QP_STATE_CLOSING: - if (!internal) { + + /* + * Allow kernel users to move to ERROR for qp draining. + */ + if (!internal && (qhp->ibqp.uobject || attrs->next_state != + C4IW_QP_STATE_ERROR)) { ret = -EINVAL; goto out; } @@ -1643,7 +1725,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) struct c4iw_dev *rhp; struct c4iw_qp *qhp; struct c4iw_qp_attributes attrs; - struct c4iw_ucontext *ucontext; qhp = to_c4iw_qp(ib_qp); rhp = qhp->rhp; @@ -1663,11 +1744,6 @@ int c4iw_destroy_qp(struct ib_qp *ib_qp) spin_unlock_irq(&rhp->lock); free_ird(rhp, qhp->attr.max_ird); - ucontext = ib_qp->uobject ? - to_c4iw_ucontext(ib_qp->uobject->context) : NULL; - destroy_qp(&rhp->rdev, &qhp->wq, - ucontext ? &ucontext->uctx : &rhp->rdev.uctx); - c4iw_qp_rem_ref(ib_qp); PDBG("%s ib_qp %p qpid 0x%0x\n", __func__, ib_qp, qhp->wq.sq.qid); @@ -1763,11 +1839,10 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, qhp->attr.max_ird = 0; qhp->sq_sig_all = attrs->sq_sig_type == IB_SIGNAL_ALL_WR; spin_lock_init(&qhp->lock); - init_completion(&qhp->sq_drained); - init_completion(&qhp->rq_drained); mutex_init(&qhp->mutex); init_waitqueue_head(&qhp->wait); kref_init(&qhp->kref); + INIT_WORK(&qhp->free_work, free_qp_work); ret = insert_handle(rhp, &rhp->qpidr, qhp, qhp->wq.sq.qid); if (ret) @@ -1854,6 +1929,9 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs, ma_sync_key_mm->len = PAGE_SIZE; insert_mmap(ucontext, ma_sync_key_mm); } + + c4iw_get_ucontext(ucontext); + qhp->ucontext = ucontext; } qhp->ibqp.qp_num = qhp->wq.sq.qid; init_timer(&(qhp->timer)); @@ -1958,40 +2036,3 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0; return 0; } - -static void move_qp_to_err(struct c4iw_qp *qp) -{ - struct c4iw_qp_attributes attrs = { .next_state = C4IW_QP_STATE_ERROR }; - - (void)c4iw_modify_qp(qp->rhp, qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); -} - -void c4iw_drain_sq(struct ib_qp *ibqp) -{ - struct c4iw_qp *qp = to_c4iw_qp(ibqp); - unsigned long flag; - bool need_to_wait; - - move_qp_to_err(qp); - spin_lock_irqsave(&qp->lock, flag); - need_to_wait = !t4_sq_empty(&qp->wq); - spin_unlock_irqrestore(&qp->lock, flag); - - if (need_to_wait) - wait_for_completion(&qp->sq_drained); -} - -void c4iw_drain_rq(struct ib_qp *ibqp) -{ - struct c4iw_qp *qp = to_c4iw_qp(ibqp); - unsigned long flag; - bool need_to_wait; - - move_qp_to_err(qp); - spin_lock_irqsave(&qp->lock, flag); - need_to_wait = !t4_rq_empty(&qp->wq); - spin_unlock_irqrestore(&qp->lock, flag); - - if (need_to_wait) - wait_for_completion(&qp->rq_drained); -} diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h index 862381aa83c8..640d22148a3e 100644 --- a/drivers/infiniband/hw/cxgb4/t4.h +++ b/drivers/infiniband/hw/cxgb4/t4.h @@ -179,6 +179,7 @@ struct t4_cqe { __be32 wrid_hi; __be32 wrid_low; } gen; + u64 drain_cookie; } u; __be64 reserved; __be64 bits_type_ts; @@ -238,6 +239,7 @@ struct t4_cqe { /* generic accessor macros */ #define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi)) #define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low)) +#define CQE_DRAIN_COOKIE(x) ((x)->u.drain_cookie) /* macros for flit 3 of the cqe */ #define CQE_GENBIT_S 63 diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 29e97df9e1a7..4c000d60d5c6 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -100,16 +100,7 @@ static int i40iw_query_port(struct ib_device *ibdev, memset(props, 0, sizeof(*props)); props->max_mtu = IB_MTU_4096; - if (netdev->mtu >= 4096) - props->active_mtu = IB_MTU_4096; - else if (netdev->mtu >= 2048) - props->active_mtu = IB_MTU_2048; - else if (netdev->mtu >= 1024) - props->active_mtu = IB_MTU_1024; - else if (netdev->mtu >= 512) - props->active_mtu = IB_MTU_512; - else - props->active_mtu = IB_MTU_256; + props->active_mtu = ib_mtu_int_to_enum(netdev->mtu); props->lid = 1; if (netif_carrier_ok(iwdev->netdev)) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c8413fc120e6..7031a8dd4d14 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -1682,9 +1682,19 @@ static int __mlx4_ib_create_flow(struct ib_qp *qp, struct ib_flow_attr *flow_att size += ret; } + if (mlx4_is_master(mdev->dev) && flow_type == MLX4_FS_REGULAR && + flow_attr->num_of_specs == 1) { + struct _rule_hw *rule_header = (struct _rule_hw *)(ctrl + 1); + enum ib_flow_spec_type header_spec = + ((union ib_flow_spec *)(flow_attr + 1))->type; + + if (header_spec == IB_FLOW_SPEC_ETH) + mlx4_handle_eth_header_mcast_prio(ctrl, rule_header); + } + ret = mlx4_cmd_imm(mdev->dev, mailbox->dma, reg_id, size >> 2, 0, MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); + MLX4_CMD_NATIVE); if (ret == -ENOMEM) pr_err("mcg table is full. Fail to register network rule.\n"); else if (ret == -ENXIO) @@ -1701,7 +1711,7 @@ static int __mlx4_ib_destroy_flow(struct mlx4_dev *dev, u64 reg_id) int err; err = mlx4_cmd(dev, reg_id, 0, 0, MLX4_QP_FLOW_STEERING_DETACH, MLX4_CMD_TIME_CLASS_A, - MLX4_CMD_WRAPPED); + MLX4_CMD_NATIVE); if (err) pr_err("Fail to detach network rule. registration id = 0x%llx\n", reg_id); diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index aff9fb14768b..5a31f3c6a421 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -478,17 +478,7 @@ static int nes_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr memset(props, 0, sizeof(*props)); props->max_mtu = IB_MTU_4096; - - if (netdev->mtu >= 4096) - props->active_mtu = IB_MTU_4096; - else if (netdev->mtu >= 2048) - props->active_mtu = IB_MTU_2048; - else if (netdev->mtu >= 1024) - props->active_mtu = IB_MTU_1024; - else if (netdev->mtu >= 512) - props->active_mtu = IB_MTU_512; - else - props->active_mtu = IB_MTU_256; + props->active_mtu = ib_mtu_int_to_enum(netdev->mtu); props->lid = 1; props->lmc = 0; diff --git a/drivers/infiniband/hw/qedr/main.c b/drivers/infiniband/hw/qedr/main.c index 7b74d09a8217..3ac8aa5ef37d 100644 --- a/drivers/infiniband/hw/qedr/main.c +++ b/drivers/infiniband/hw/qedr/main.c @@ -576,8 +576,7 @@ static int qedr_set_device_attr(struct qedr_dev *dev) return 0; } -void qedr_unaffiliated_event(void *context, - u8 event_code) +void qedr_unaffiliated_event(void *context, u8 event_code) { pr_err("unaffiliated event not implemented yet\n"); } @@ -792,6 +791,9 @@ static struct qedr_dev *qedr_add(struct qed_dev *cdev, struct pci_dev *pdev, if (device_create_file(&dev->ibdev.dev, qedr_attributes[i])) goto sysfs_err; + if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); + DP_DEBUG(dev, QEDR_MSG_INIT, "qedr driver loaded successfully\n"); return dev; @@ -824,11 +826,10 @@ static void qedr_remove(struct qedr_dev *dev) ib_dealloc_device(&dev->ibdev); } -static int qedr_close(struct qedr_dev *dev) +static void qedr_close(struct qedr_dev *dev) { - qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ERR); - - return 0; + if (test_and_clear_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ERR); } static void qedr_shutdown(struct qedr_dev *dev) @@ -837,6 +838,12 @@ static void qedr_shutdown(struct qedr_dev *dev) qedr_remove(dev); } +static void qedr_open(struct qedr_dev *dev) +{ + if (!test_and_set_bit(QEDR_ENET_STATE_BIT, &dev->enet_state)) + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_PORT_ACTIVE); +} + static void qedr_mac_address_change(struct qedr_dev *dev) { union ib_gid *sgid = &dev->sgid_tbl[0]; @@ -863,7 +870,7 @@ static void qedr_mac_address_change(struct qedr_dev *dev) ether_addr_copy(dev->gsi_ll2_mac_address, dev->ndev->dev_addr); - qedr_ib_dispatch_event(dev, 1, IB_EVENT_GID_CHANGE); + qedr_ib_dispatch_event(dev, QEDR_PORT, IB_EVENT_GID_CHANGE); if (rc) DP_ERR(dev, "Error updating mac filter\n"); @@ -877,7 +884,7 @@ static void qedr_notify(struct qedr_dev *dev, enum qede_roce_event event) { switch (event) { case QEDE_UP: - qedr_ib_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE); + qedr_open(dev); break; case QEDE_DOWN: qedr_close(dev); diff --git a/drivers/infiniband/hw/qedr/qedr.h b/drivers/infiniband/hw/qedr/qedr.h index 620badd7d4fb..bb32e4792ec9 100644 --- a/drivers/infiniband/hw/qedr/qedr.h +++ b/drivers/infiniband/hw/qedr/qedr.h @@ -113,6 +113,8 @@ struct qedr_device_attr { struct qed_rdma_events events; }; +#define QEDR_ENET_STATE_BIT (0) + struct qedr_dev { struct ib_device ibdev; struct qed_dev *cdev; @@ -153,6 +155,8 @@ struct qedr_dev { struct qedr_cq *gsi_sqcq; struct qedr_cq *gsi_rqcq; struct qedr_qp *gsi_qp; + + unsigned long enet_state; }; #define QEDR_MAX_SQ_PBL (0x8000) @@ -188,6 +192,7 @@ struct qedr_dev { #define QEDR_ROCE_MAX_CNQ_SIZE (0x4000) #define QEDR_MAX_PORT (1) +#define QEDR_PORT (1) #define QEDR_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME) @@ -251,9 +256,6 @@ struct qedr_cq { u16 icid; - /* Lock to protect completion handler */ - spinlock_t comp_handler_lock; - /* Lock to protect multiplem CQ's */ spinlock_t cq_lock; u8 arm_flags; diff --git a/drivers/infiniband/hw/qedr/qedr_cm.c b/drivers/infiniband/hw/qedr/qedr_cm.c index 63890ebb72bd..a9a8d8745d2e 100644 --- a/drivers/infiniband/hw/qedr/qedr_cm.c +++ b/drivers/infiniband/hw/qedr/qedr_cm.c @@ -87,11 +87,8 @@ void qedr_ll2_tx_cb(void *_qdev, struct qed_roce_ll2_packet *pkt) qedr_inc_sw_gsi_cons(&qp->sq); spin_unlock_irqrestore(&qp->q_lock, flags); - if (cq->ibcq.comp_handler) { - spin_lock_irqsave(&cq->comp_handler_lock, flags); + if (cq->ibcq.comp_handler) (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); - spin_unlock_irqrestore(&cq->comp_handler_lock, flags); - } } void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, @@ -113,11 +110,8 @@ void qedr_ll2_rx_cb(void *_dev, struct qed_roce_ll2_packet *pkt, spin_unlock_irqrestore(&qp->q_lock, flags); - if (cq->ibcq.comp_handler) { - spin_lock_irqsave(&cq->comp_handler_lock, flags); + if (cq->ibcq.comp_handler) (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context); - spin_unlock_irqrestore(&cq->comp_handler_lock, flags); - } } static void qedr_destroy_gsi_cq(struct qedr_dev *dev, @@ -404,9 +398,9 @@ static inline int qedr_gsi_build_packet(struct qedr_dev *dev, } if (ether_addr_equal(udh.eth.smac_h, udh.eth.dmac_h)) - packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; - else packet->tx_dest = QED_ROCE_LL2_TX_DEST_LB; + else + packet->tx_dest = QED_ROCE_LL2_TX_DEST_NW; packet->roce_mode = roce_mode; memcpy(packet->header.vaddr, ud_header_buffer, header_size); diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 57c8de208077..c7d6c9a783bd 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -471,8 +471,6 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, struct ib_ucontext *context, struct ib_udata *udata) { struct qedr_dev *dev = get_qedr_dev(ibdev); - struct qedr_ucontext *uctx = NULL; - struct qedr_alloc_pd_uresp uresp; struct qedr_pd *pd; u16 pd_id; int rc; @@ -489,21 +487,33 @@ struct ib_pd *qedr_alloc_pd(struct ib_device *ibdev, if (!pd) return ERR_PTR(-ENOMEM); - dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); + rc = dev->ops->rdma_alloc_pd(dev->rdma_ctx, &pd_id); + if (rc) + goto err; - uresp.pd_id = pd_id; pd->pd_id = pd_id; if (udata && context) { + struct qedr_alloc_pd_uresp uresp; + + uresp.pd_id = pd_id; + rc = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); - if (rc) + if (rc) { DP_ERR(dev, "copy error pd_id=0x%x.\n", pd_id); - uctx = get_qedr_ucontext(context); - uctx->pd = pd; - pd->uctx = uctx; + dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd_id); + goto err; + } + + pd->uctx = get_qedr_ucontext(context); + pd->uctx->pd = pd; } return &pd->ibpd; + +err: + kfree(pd); + return ERR_PTR(rc); } int qedr_dealloc_pd(struct ib_pd *ibpd) @@ -1600,7 +1610,7 @@ err0: return ERR_PTR(-EFAULT); } -enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) +static enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) { switch (qp_state) { case QED_ROCE_QP_STATE_RESET: @@ -1621,7 +1631,8 @@ enum ib_qp_state qedr_get_ibqp_state(enum qed_roce_qp_state qp_state) return IB_QPS_ERR; } -enum qed_roce_qp_state qedr_get_state_from_ibqp(enum ib_qp_state qp_state) +static enum qed_roce_qp_state qedr_get_state_from_ibqp( + enum ib_qp_state qp_state) { switch (qp_state) { case IB_QPS_RESET: @@ -1657,7 +1668,7 @@ static int qedr_update_qp_state(struct qedr_dev *dev, int status = 0; if (new_state == qp->state) - return 1; + return 0; switch (qp->state) { case QED_ROCE_QP_STATE_RESET: @@ -1733,6 +1744,14 @@ static int qedr_update_qp_state(struct qedr_dev *dev, /* ERR->XXX */ switch (new_state) { case QED_ROCE_QP_STATE_RESET: + if ((qp->rq.prod != qp->rq.cons) || + (qp->sq.prod != qp->sq.cons)) { + DP_NOTICE(dev, + "Error->Reset with rq/sq not empty rq.prod=%x rq.cons=%x sq.prod=%x sq.cons=%x\n", + qp->rq.prod, qp->rq.cons, qp->sq.prod, + qp->sq.cons); + status = -EINVAL; + } break; default: status = -EINVAL; @@ -1865,7 +1884,6 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, qp_params.sgid.dwords[2], qp_params.sgid.dwords[3]); DP_DEBUG(dev, QEDR_MSG_QP, "remote_mac=[%pM]\n", qp_params.remote_mac_addr); -; qp_params.mtu = qp->mtu; qp_params.lb_indication = false; @@ -2016,7 +2034,7 @@ int qedr_query_qp(struct ib_qp *ibqp, qp_attr->qp_state = qedr_get_ibqp_state(params.state); qp_attr->cur_qp_state = qedr_get_ibqp_state(params.state); - qp_attr->path_mtu = iboe_get_mtu(params.mtu); + qp_attr->path_mtu = ib_mtu_int_to_enum(params.mtu); qp_attr->path_mig_state = IB_MIG_MIGRATED; qp_attr->rq_psn = params.rq_psn; qp_attr->sq_psn = params.sq_psn; @@ -2028,7 +2046,7 @@ int qedr_query_qp(struct ib_qp *ibqp, qp_attr->cap.max_recv_wr = qp->rq.max_wr; qp_attr->cap.max_send_sge = qp->sq.max_sges; qp_attr->cap.max_recv_sge = qp->rq.max_sges; - qp_attr->cap.max_inline_data = qp->max_inline_data; + qp_attr->cap.max_inline_data = ROCE_REQ_MAX_INLINE_DATA_SIZE; qp_init_attr->cap = qp_attr->cap; memcpy(&qp_attr->ah_attr.grh.dgid.raw[0], ¶ms.dgid.bytes[0], @@ -2302,7 +2320,8 @@ int qedr_dereg_mr(struct ib_mr *ib_mr) return rc; } -struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, int max_page_list_len) +static struct qedr_mr *__qedr_alloc_mr(struct ib_pd *ibpd, + int max_page_list_len) { struct qedr_pd *pd = get_qedr_pd(ibpd); struct qedr_dev *dev = get_qedr_dev(ibpd->device); @@ -2704,7 +2723,7 @@ static int qedr_prepare_reg(struct qedr_qp *qp, return 0; } -enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) +static enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) { switch (opcode) { case IB_WR_RDMA_WRITE: @@ -2729,7 +2748,7 @@ enum ib_wc_opcode qedr_ib_to_wc_opcode(enum ib_wr_opcode opcode) } } -inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) +static inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) { int wq_is_full, err_wr, pbl_is_full; struct qedr_dev *dev = qp->dev; @@ -2766,7 +2785,7 @@ inline bool qedr_can_post_send(struct qedr_qp *qp, struct ib_send_wr *wr) return true; } -int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, +static int __qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr) { struct qedr_dev *dev = get_qedr_dev(ibqp->device); @@ -3234,9 +3253,10 @@ static int qedr_poll_cq_req(struct qedr_dev *dev, IB_WC_SUCCESS, 0); break; case RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR: - DP_ERR(dev, - "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", - cq->icid, qp->icid); + if (qp->state != QED_ROCE_QP_STATE_ERR) + DP_ERR(dev, + "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", + cq->icid, qp->icid); cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, IB_WC_WR_FLUSH_ERR, 1); break; diff --git a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c index 80ef3f8998c8..04443242e258 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_sysfs.c @@ -80,7 +80,7 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr, left = PAGE_SIZE; mutex_lock(&us_ibdev->usdev_lock); - if (atomic_read(&us_ibdev->vf_cnt.refcount) > 0) { + if (kref_read(&us_ibdev->vf_cnt) > 0) { char *busname; /* @@ -99,7 +99,7 @@ usnic_ib_show_config(struct device *device, struct device_attribute *attr, PCI_FUNC(us_ibdev->pdev->devfn), netdev_name(us_ibdev->netdev), us_ibdev->ufdev->mac, - atomic_read(&us_ibdev->vf_cnt.refcount)); + kref_read(&us_ibdev->vf_cnt)); UPDATE_PTR_LEFT(n, ptr, left); for (res_type = USNIC_VNIC_RES_TYPE_EOL; @@ -147,7 +147,7 @@ usnic_ib_show_max_vf(struct device *device, struct device_attribute *attr, us_ibdev = container_of(device, struct usnic_ib_dev, ib_dev.dev); return scnprintf(buf, PAGE_SIZE, "%u\n", - atomic_read(&us_ibdev->vf_cnt.refcount)); + kref_read(&us_ibdev->vf_cnt)); } static ssize_t diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index 74819a7951e2..69df8e353123 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -291,11 +291,11 @@ int usnic_ib_query_device(struct ib_device *ibdev, qp_per_vf = max(us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_WQ], us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_RQ]); props->max_qp = qp_per_vf * - atomic_read(&us_ibdev->vf_cnt.refcount); + kref_read(&us_ibdev->vf_cnt); props->device_cap_flags = IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; props->max_cq = us_ibdev->vf_res_cnt[USNIC_VNIC_RES_TYPE_CQ] * - atomic_read(&us_ibdev->vf_cnt.refcount); + kref_read(&us_ibdev->vf_cnt); props->max_pd = USNIC_UIOM_MAX_PD_CNT; props->max_mr = USNIC_UIOM_MAX_MR_CNT; props->local_ca_ack_delay = 0; diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c index 231a1ce1f4be..bd8fbd3d2032 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -1029,7 +1029,7 @@ static int pvrdma_pci_probe(struct pci_dev *pdev, if (ret) { dev_err(&pdev->dev, "failed to allocate interrupts\n"); ret = -ENOMEM; - goto err_netdevice; + goto err_free_cq_ring; } /* Allocate UAR table. */ @@ -1092,8 +1092,6 @@ err_free_uar_table: err_free_intrs: pvrdma_free_irq(dev); pvrdma_disable_msi_all(dev); -err_netdevice: - unregister_netdevice_notifier(&dev->nb_netdev); err_free_cq_ring: pvrdma_page_dir_cleanup(dev, &dev->cq_pdir); err_free_async_ring: diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c index 54891370d18a..c2aa52638dcb 100644 --- a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -306,7 +306,7 @@ struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, union pvrdma_cmd_resp rsp; struct pvrdma_cmd_create_uc *cmd = &req.create_uc; struct pvrdma_cmd_create_uc_resp *resp = &rsp.create_uc_resp; - struct pvrdma_alloc_ucontext_resp uresp; + struct pvrdma_alloc_ucontext_resp uresp = {0}; int ret; void *ptr; diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index d0faca294006..86a6585b847d 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -59,9 +59,11 @@ int mem_check_range(struct rxe_mem *mem, u64 iova, size_t length) case RXE_MEM_TYPE_MR: case RXE_MEM_TYPE_FMR: - return ((iova < mem->iova) || - ((iova + length) > (mem->iova + mem->length))) ? - -EFAULT : 0; + if (iova < mem->iova || + length > mem->length || + iova > mem->iova + mem->length - length) + return -EFAULT; + return 0; default: return -EFAULT; diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 342e78163613..4abdeb359fb4 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -555,7 +555,7 @@ struct rxe_dev *rxe_net_add(struct net_device *ndev) } spin_lock_bh(&dev_list_lock); - list_add_tail(&rxe_dev_list, &rxe->list); + list_add_tail(&rxe->list, &rxe_dev_list); spin_unlock_bh(&dev_list_lock); return rxe; } diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index 486d576e55bc..44b2108253bd 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -813,8 +813,7 @@ void rxe_qp_destroy(struct rxe_qp *qp) del_timer_sync(&qp->rnr_nak_timer); rxe_cleanup_task(&qp->req.task); - if (qp_type(qp) == IB_QPT_RC) - rxe_cleanup_task(&qp->comp.task); + rxe_cleanup_task(&qp->comp.task); /* flush out any receive wr's or pending requests */ __rxe_do_task(&qp->req.task); diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 3435efff8799..5bcf07328972 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -479,7 +479,7 @@ static enum resp_states check_rkey(struct rxe_qp *qp, goto err2; } - resid = mtu; + qp->resp.resid = mtu; } else { if (pktlen != resid) { state = RESPST_ERR_LENGTH; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 86fed1956d7d..30a6985909e0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -651,13 +651,6 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, SHOST_DIX_GUARD_CRC); } - /* - * Limit the sg_tablesize and max_sectors based on the device - * max fastreg page list length. - */ - shost->sg_tablesize = min_t(unsigned short, shost->sg_tablesize, - ib_conn->device->ib_device->attrs.max_fast_reg_page_list_len); - if (iscsi_host_add(shost, ib_conn->device->ib_device->dma_device)) { mutex_unlock(&iser_conn->state_mutex); @@ -679,6 +672,10 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, max_fr_sectors = ((shost->sg_tablesize - 1) * PAGE_SIZE) >> 9; shost->max_sectors = min(iser_max_sectors, max_fr_sectors); + iser_dbg("iser_conn %p, sg_tablesize %u, max_sectors %u\n", + iser_conn, shost->sg_tablesize, + shost->max_sectors); + if (cmds_max > max_cmds) { iser_info("cmds_max changed from %u to %u\n", cmds_max, max_cmds); diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 0be6a7c5ddb5..9d0b22ad58c1 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -496,7 +496,6 @@ struct ib_conn { * @rx_descs: rx buffers array (cyclic buffer) * @num_rx_descs: number of rx descriptors * @scsi_sg_tablesize: scsi host sg_tablesize - * @scsi_max_sectors: scsi host max sectors */ struct iser_conn { struct ib_conn ib_conn; @@ -519,7 +518,6 @@ struct iser_conn { struct iser_rx_desc *rx_descs; u32 num_rx_descs; unsigned short scsi_sg_tablesize; - unsigned int scsi_max_sectors; bool snd_w_inv; }; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 8ae7a3beddb7..6a9d1cb548ee 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -707,18 +707,7 @@ iser_calc_scsi_params(struct iser_conn *iser_conn, sup_sg_tablesize = min_t(unsigned, ISCSI_ISER_MAX_SG_TABLESIZE, device->ib_device->attrs.max_fast_reg_page_list_len); - if (sg_tablesize > sup_sg_tablesize) { - sg_tablesize = sup_sg_tablesize; - iser_conn->scsi_max_sectors = sg_tablesize * SIZE_4K / 512; - } else { - iser_conn->scsi_max_sectors = max_sectors; - } - - iser_conn->scsi_sg_tablesize = sg_tablesize; - - iser_dbg("iser_conn %p, sg_tablesize %u, max_sectors %u\n", - iser_conn, iser_conn->scsi_sg_tablesize, - iser_conn->scsi_max_sectors); + iser_conn->scsi_sg_tablesize = min(sg_tablesize, sup_sg_tablesize); } /** diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 7866cb0a8f00..36529e390e48 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -371,6 +371,7 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, struct srp_fr_desc *d; struct ib_mr *mr; int i, ret = -EINVAL; + enum ib_mr_type mr_type; if (pool_size <= 0) goto err; @@ -384,9 +385,13 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, spin_lock_init(&pool->lock); INIT_LIST_HEAD(&pool->free_list); + if (device->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG) + mr_type = IB_MR_TYPE_SG_GAPS; + else + mr_type = IB_MR_TYPE_MEM_REG; + for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { - mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, - max_page_list_len); + mr = ib_alloc_mr(pd, mr_type, max_page_list_len); if (IS_ERR(mr)) { ret = PTR_ERR(mr); if (ret == -ENOMEM) @@ -3695,6 +3700,12 @@ static int __init srp_init_module(void) indirect_sg_entries = cmd_sg_entries; } + if (indirect_sg_entries > SG_MAX_SEGMENTS) { + pr_warn("Clamping indirect_sg_entries to %u\n", + SG_MAX_SEGMENTS); + indirect_sg_entries = SG_MAX_SEGMENTS; + } + srp_remove_wq = create_workqueue("srp_remove"); if (!srp_remove_wq) { ret = -ENOMEM; diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f3135ae22df4..abd18f31b24f 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -22,7 +22,6 @@ #include <linux/sched.h> #include <linux/slab.h> #include <linux/mm.h> -#include <linux/miscdevice.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/init.h> diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 6d9499658671..c7d5b2b643d1 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1377,6 +1377,12 @@ static int xpad_init_input(struct usb_xpad *xpad) input_dev->name = xpad->name; input_dev->phys = xpad->phys; usb_to_input_id(xpad->udev, &input_dev->id); + + if (xpad->xtype == XTYPE_XBOX360W) { + /* x360w controllers and the receiver have different ids */ + input_dev->id.product = 0x02a1; + } + input_dev->dev.parent = &xpad->intf->dev; input_set_drvdata(input_dev, xpad); diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index a8b0a2eec344..7fed92fb8cc1 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -136,7 +136,6 @@ static const struct i2c_device_id adxl34x_id[] = { MODULE_DEVICE_TABLE(i2c, adxl34x_id); -#ifdef CONFIG_OF static const struct of_device_id adxl34x_of_id[] = { /* * The ADXL346 is backward-compatible with the ADXL345. Differences are @@ -153,13 +152,12 @@ static const struct of_device_id adxl34x_of_id[] = { }; MODULE_DEVICE_TABLE(of, adxl34x_of_id); -#endif static struct i2c_driver adxl34x_driver = { .driver = { .name = "adxl34x", .pm = &adxl34x_i2c_pm, - .of_match_table = of_match_ptr(adxl34x_of_id), + .of_match_table = adxl34x_of_id, }, .probe = adxl34x_i2c_probe, .remove = adxl34x_i2c_remove, diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 92595b98e7ed..022be0e22eba 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -263,13 +263,21 @@ static int uinput_create_device(struct uinput_device *udev) return -EINVAL; } - if (test_bit(ABS_MT_SLOT, dev->absbit)) { - nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; - error = input_mt_init_slots(dev, nslot, 0); - if (error) + if (test_bit(EV_ABS, dev->evbit)) { + input_alloc_absinfo(dev); + if (!dev->absinfo) { + error = -EINVAL; goto fail1; - } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { - input_set_events_per_packet(dev, 60); + } + + if (test_bit(ABS_MT_SLOT, dev->absbit)) { + nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1; + error = input_mt_init_slots(dev, nslot, 0); + if (error) + goto fail1; + } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { + input_set_events_per_packet(dev, 60); + } } if (test_bit(EV_FF, dev->evbit) && !udev->ff_effects_max) { diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index cde6f4bd8ea2..6d279aa27cb9 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -114,7 +114,7 @@ enum SS4_PACKET_ID { (_b[1] & 0x7F) \ ) -#define SS4_TS_Y_V2(_b) (s8)( \ +#define SS4_TS_Y_V2(_b) -(s8)( \ ((_b[3] & 0x01) << 7) | \ (_b[2] & 0x7F) \ ) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index fa598f7f4372..1e1d0ad406f2 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1231,6 +1231,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, { "ELAN0100", 0 }, { "ELAN0600", 0 }, + { "ELAN0605", 0 }, { "ELAN1000", 0 }, { } }; diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index aa7c5da60800..cb2bf203f4ca 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -29,7 +29,7 @@ * after soft reset, we should wait for 1 ms * before the device becomes operational */ -#define SOFT_RESET_DELAY_MS 3 +#define SOFT_RESET_DELAY_US 3000 /* and after hard reset, we should wait for max 500ms */ #define HARD_RESET_DELAY_MS 500 @@ -311,7 +311,7 @@ static int synaptics_i2c_reset_config(struct i2c_client *client) if (ret) { dev_err(&client->dev, "Unable to reset device\n"); } else { - msleep(SOFT_RESET_DELAY_MS); + usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100); ret = synaptics_i2c_config(client); if (ret) dev_err(&client->dev, "Unable to config device\n"); diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index 30cc627a4f45..bb7762bf2879 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -41,13 +41,20 @@ config RMI4_SMB config RMI4_F03 bool "RMI4 Function 03 (PS2 Guest)" - depends on RMI4_CORE && SERIO + depends on RMI4_CORE help Say Y here if you want to add support for RMI4 function 03. Function 03 provides PS2 guest support for RMI4 devices. This includes support for TrackPoints on TouchPads. +config RMI4_F03_SERIO + tristate + depends on RMI4_CORE + depends on RMI4_F03 + default RMI4_CORE + select SERIO + config RMI4_2D_SENSOR bool depends on RMI4_CORE diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 11447ab1055c..bf5c36e229ba 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -901,7 +901,7 @@ void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake) data->enabled = true; if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) { retval = disable_irq_wake(irq); - if (!retval) + if (retval) dev_warn(&rmi_dev->dev, "Failed to disable irq for wake: %d\n", retval); @@ -936,7 +936,7 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake) disable_irq(irq); if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) { retval = enable_irq_wake(irq); - if (!retval) + if (retval) dev_warn(&rmi_dev->dev, "Failed to enable irq for wake: %d\n", retval); diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 77551f522202..a7618776705a 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -211,6 +211,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), + DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), + }, + }, { } }; diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 02aec284deca..3e6003d32e56 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -914,9 +914,9 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev) case QUEUE_HEADER_NORMAL: report_count = ts->buf[FW_HDR_COUNT]; - if (report_count > 3) { + if (report_count == 0 || report_count > 3) { dev_err(&client->dev, - "too large report count: %*ph\n", + "bad report count: %*ph\n", HEADER_SIZE, ts->buf); break; } diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 83cf11312fd9..c9d1c91e1887 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -682,7 +682,7 @@ static int wm97xx_probe(struct device *dev) } platform_set_drvdata(wm->battery_dev, wm); wm->battery_dev->dev.parent = dev; - wm->battery_dev->dev.platform_data = pdata->batt_pdata; + wm->battery_dev->dev.platform_data = pdata ? pdata->batt_pdata : NULL; ret = platform_device_add(wm->battery_dev); if (ret < 0) goto batt_reg_err; diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 8ee54d71c7eb..37e204f3d9be 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -352,9 +352,6 @@ config MTK_IOMMU_V1 select IOMMU_API select MEMORY select MTK_SMI - select COMMON_CLK_MT2701_MMSYS - select COMMON_CLK_MT2701_IMGSYS - select COMMON_CLK_MT2701_VDECSYS help Support for the M4U on certain Mediatek SoCs. M4U generation 1 HW is Multimedia Memory Managememt Unit. This option enables remapping of diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 019e02707cd5..1b5b8c5361c5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -112,7 +112,7 @@ static struct timer_list queue_timer; * Domain for untranslated devices - only allocated * if iommu=pt passed on kernel cmd line. */ -static const struct iommu_ops amd_iommu_ops; +const struct iommu_ops amd_iommu_ops; static ATOMIC_NOTIFIER_HEAD(ppr_notifier); int amd_iommu_max_glx_val = -1; @@ -445,6 +445,7 @@ static void init_iommu_group(struct device *dev) static int iommu_init_device(struct device *dev) { struct iommu_dev_data *dev_data; + struct amd_iommu *iommu; int devid; if (dev->archdata.iommu) @@ -454,6 +455,8 @@ static int iommu_init_device(struct device *dev) if (devid < 0) return devid; + iommu = amd_iommu_rlookup_table[devid]; + dev_data = find_dev_data(devid); if (!dev_data) return -ENOMEM; @@ -469,8 +472,7 @@ static int iommu_init_device(struct device *dev) dev->archdata.iommu = dev_data; - iommu_device_link(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev, - dev); + iommu_device_link(&iommu->iommu, dev); return 0; } @@ -495,13 +497,16 @@ static void iommu_ignore_device(struct device *dev) static void iommu_uninit_device(struct device *dev) { - int devid; struct iommu_dev_data *dev_data; + struct amd_iommu *iommu; + int devid; devid = get_device_id(dev); if (devid < 0) return; + iommu = amd_iommu_rlookup_table[devid]; + dev_data = search_dev_data(devid); if (!dev_data) return; @@ -509,8 +514,7 @@ static void iommu_uninit_device(struct device *dev) if (dev_data->domain) detach_device(dev); - iommu_device_unlink(amd_iommu_rlookup_table[dev_data->devid]->iommu_dev, - dev); + iommu_device_unlink(&iommu->iommu, dev); iommu_group_remove_device(dev); @@ -1023,7 +1027,7 @@ again: next_tail = (tail + sizeof(*cmd)) % CMD_BUFFER_SIZE; left = (head - next_tail) % CMD_BUFFER_SIZE; - if (left <= 2) { + if (left <= 0x20) { struct iommu_cmd sync_cmd; int ret; @@ -3161,9 +3165,10 @@ static bool amd_iommu_capable(enum iommu_cap cap) return false; } -static void amd_iommu_get_dm_regions(struct device *dev, - struct list_head *head) +static void amd_iommu_get_resv_regions(struct device *dev, + struct list_head *head) { + struct iommu_resv_region *region; struct unity_map_entry *entry; int devid; @@ -3172,41 +3177,56 @@ static void amd_iommu_get_dm_regions(struct device *dev, return; list_for_each_entry(entry, &amd_iommu_unity_map, list) { - struct iommu_dm_region *region; + size_t length; + int prot = 0; if (devid < entry->devid_start || devid > entry->devid_end) continue; - region = kzalloc(sizeof(*region), GFP_KERNEL); + length = entry->address_end - entry->address_start; + if (entry->prot & IOMMU_PROT_IR) + prot |= IOMMU_READ; + if (entry->prot & IOMMU_PROT_IW) + prot |= IOMMU_WRITE; + + region = iommu_alloc_resv_region(entry->address_start, + length, prot, + IOMMU_RESV_DIRECT); if (!region) { pr_err("Out of memory allocating dm-regions for %s\n", dev_name(dev)); return; } - - region->start = entry->address_start; - region->length = entry->address_end - entry->address_start; - if (entry->prot & IOMMU_PROT_IR) - region->prot |= IOMMU_READ; - if (entry->prot & IOMMU_PROT_IW) - region->prot |= IOMMU_WRITE; - list_add_tail(®ion->list, head); } + + region = iommu_alloc_resv_region(MSI_RANGE_START, + MSI_RANGE_END - MSI_RANGE_START + 1, + 0, IOMMU_RESV_RESERVED); + if (!region) + return; + list_add_tail(®ion->list, head); + + region = iommu_alloc_resv_region(HT_RANGE_START, + HT_RANGE_END - HT_RANGE_START + 1, + 0, IOMMU_RESV_RESERVED); + if (!region) + return; + list_add_tail(®ion->list, head); } -static void amd_iommu_put_dm_regions(struct device *dev, +static void amd_iommu_put_resv_regions(struct device *dev, struct list_head *head) { - struct iommu_dm_region *entry, *next; + struct iommu_resv_region *entry, *next; list_for_each_entry_safe(entry, next, head, list) kfree(entry); } -static void amd_iommu_apply_dm_region(struct device *dev, +static void amd_iommu_apply_resv_region(struct device *dev, struct iommu_domain *domain, - struct iommu_dm_region *region) + struct iommu_resv_region *region) { struct dma_ops_domain *dma_dom = to_dma_ops_domain(to_pdomain(domain)); unsigned long start, end; @@ -3217,7 +3237,7 @@ static void amd_iommu_apply_dm_region(struct device *dev, WARN_ON_ONCE(reserve_iova(&dma_dom->iovad, start, end) == NULL); } -static const struct iommu_ops amd_iommu_ops = { +const struct iommu_ops amd_iommu_ops = { .capable = amd_iommu_capable, .domain_alloc = amd_iommu_domain_alloc, .domain_free = amd_iommu_domain_free, @@ -3230,9 +3250,9 @@ static const struct iommu_ops amd_iommu_ops = { .add_device = amd_iommu_add_device, .remove_device = amd_iommu_remove_device, .device_group = amd_iommu_device_group, - .get_dm_regions = amd_iommu_get_dm_regions, - .put_dm_regions = amd_iommu_put_dm_regions, - .apply_dm_region = amd_iommu_apply_dm_region, + .get_resv_regions = amd_iommu_get_resv_regions, + .put_resv_regions = amd_iommu_put_resv_regions, + .apply_resv_region = amd_iommu_apply_resv_region, .pgsize_bitmap = AMD_IOMMU_PGSIZES, }; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 6799cf9713f7..04cdac7ab3e3 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -94,6 +94,8 @@ * out of it. */ +extern const struct iommu_ops amd_iommu_ops; + /* * structure describing one IOMMU in the ACPI table. Typically followed by one * or more ivhd_entrys. @@ -1635,9 +1637,10 @@ static int iommu_init_pci(struct amd_iommu *iommu) amd_iommu_erratum_746_workaround(iommu); amd_iommu_ats_write_check_workaround(iommu); - iommu->iommu_dev = iommu_device_create(&iommu->dev->dev, iommu, - amd_iommu_groups, "ivhd%d", - iommu->index); + iommu_device_sysfs_add(&iommu->iommu, &iommu->dev->dev, + amd_iommu_groups, "ivhd%d", iommu->index); + iommu_device_set_ops(&iommu->iommu, &amd_iommu_ops); + iommu_device_register(&iommu->iommu); return pci_enable_device(iommu->dev); } @@ -2230,7 +2233,7 @@ static int __init early_amd_iommu_init(void) */ ret = check_ivrs_checksum(ivrs_base); if (ret) - return ret; + goto out; amd_iommu_target_ivhd_type = get_highest_supported_ivhd_type(ivrs_base); DUMP_printk("Using IVHD type %#x\n", amd_iommu_target_ivhd_type); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 0d91785ebdc3..af00f381a7b1 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -535,8 +535,8 @@ struct amd_iommu { /* if one, we need to send a completion wait command */ bool need_sync; - /* IOMMU sysfs device */ - struct device *iommu_dev; + /* Handle for IOMMU core code */ + struct iommu_device iommu; /* * We can't rely on the BIOS to restore all values on reinit, so we diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 4d6ec444a9d6..5806a6acc94e 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -269,9 +269,6 @@ #define STRTAB_STE_1_SHCFG_INCOMING 1UL #define STRTAB_STE_1_SHCFG_SHIFT 44 -#define STRTAB_STE_1_PRIVCFG_UNPRIV 2UL -#define STRTAB_STE_1_PRIVCFG_SHIFT 48 - #define STRTAB_STE_2_S2VMID_SHIFT 0 #define STRTAB_STE_2_S2VMID_MASK 0xffffUL #define STRTAB_STE_2_VTCR_SHIFT 32 @@ -412,6 +409,9 @@ /* High-level queue structures */ #define ARM_SMMU_POLL_TIMEOUT_US 100 +#define MSI_IOVA_BASE 0x8000000 +#define MSI_IOVA_LENGTH 0x100000 + static bool disable_bypass; module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO); MODULE_PARM_DESC(disable_bypass, @@ -616,6 +616,9 @@ struct arm_smmu_device { unsigned int sid_bits; struct arm_smmu_strtab_cfg strtab_cfg; + + /* IOMMU core code handle */ + struct iommu_device iommu; }; /* SMMU private data for each master */ @@ -1042,13 +1045,8 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, } } - /* Nuke the existing Config, as we're going to rewrite it */ - val &= ~(STRTAB_STE_0_CFG_MASK << STRTAB_STE_0_CFG_SHIFT); - - if (ste->valid) - val |= STRTAB_STE_0_V; - else - val &= ~STRTAB_STE_0_V; + /* Nuke the existing STE_0 value, as we're going to rewrite it */ + val = ste->valid ? STRTAB_STE_0_V : 0; if (ste->bypass) { val |= disable_bypass ? STRTAB_STE_0_CFG_ABORT @@ -1073,9 +1071,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, #ifdef CONFIG_PCI_ATS STRTAB_STE_1_EATS_TRANS << STRTAB_STE_1_EATS_SHIFT | #endif - STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT | - STRTAB_STE_1_PRIVCFG_UNPRIV << - STRTAB_STE_1_PRIVCFG_SHIFT); + STRTAB_STE_1_STRW_NSEL1 << STRTAB_STE_1_STRW_SHIFT); if (smmu->features & ARM_SMMU_FEAT_STALLS) dst[1] |= cpu_to_le64(STRTAB_STE_1_S1STALLD); @@ -1083,7 +1079,6 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_device *smmu, u32 sid, val |= (ste->s1_cfg->cdptr_dma & STRTAB_STE_0_S1CTXPTR_MASK << STRTAB_STE_0_S1CTXPTR_SHIFT) | STRTAB_STE_0_CFG_S1_TRANS; - } if (ste->s2_cfg) { @@ -1372,8 +1367,6 @@ static bool arm_smmu_capable(enum iommu_cap cap) switch (cap) { case IOMMU_CAP_CACHE_COHERENCY: return true; - case IOMMU_CAP_INTR_REMAP: - return true; /* MSIs are just memory writes */ case IOMMU_CAP_NOEXEC: return true; default: @@ -1795,8 +1788,10 @@ static int arm_smmu_add_device(struct device *dev) } group = iommu_group_get_for_dev(dev); - if (!IS_ERR(group)) + if (!IS_ERR(group)) { iommu_group_put(group); + iommu_device_link(&smmu->iommu, dev); + } return PTR_ERR_OR_ZERO(group); } @@ -1805,14 +1800,17 @@ static void arm_smmu_remove_device(struct device *dev) { struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct arm_smmu_master_data *master; + struct arm_smmu_device *smmu; if (!fwspec || fwspec->ops != &arm_smmu_ops) return; master = fwspec->iommu_priv; + smmu = master->smmu; if (master && master->ste.valid) arm_smmu_detach_dev(dev); iommu_group_remove_device(dev); + iommu_device_unlink(&smmu->iommu, dev); kfree(master); iommu_fwspec_free(dev); } @@ -1883,6 +1881,29 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) return iommu_fwspec_add_ids(dev, args->args, 1); } +static void arm_smmu_get_resv_regions(struct device *dev, + struct list_head *head) +{ + struct iommu_resv_region *region; + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; + + region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, + prot, IOMMU_RESV_MSI); + if (!region) + return; + + list_add_tail(®ion->list, head); +} + +static void arm_smmu_put_resv_regions(struct device *dev, + struct list_head *head) +{ + struct iommu_resv_region *entry, *next; + + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); +} + static struct iommu_ops arm_smmu_ops = { .capable = arm_smmu_capable, .domain_alloc = arm_smmu_domain_alloc, @@ -1898,6 +1919,8 @@ static struct iommu_ops arm_smmu_ops = { .domain_get_attr = arm_smmu_domain_get_attr, .domain_set_attr = arm_smmu_domain_set_attr, .of_xlate = arm_smmu_of_xlate, + .get_resv_regions = arm_smmu_get_resv_regions, + .put_resv_regions = arm_smmu_put_resv_regions, .pgsize_bitmap = -1UL, /* Restricted during device attach */ }; @@ -1983,17 +2006,9 @@ static int arm_smmu_init_strtab_2lvl(struct arm_smmu_device *smmu) u32 size, l1size; struct arm_smmu_strtab_cfg *cfg = &smmu->strtab_cfg; - /* - * If we can resolve everything with a single L2 table, then we - * just need a single L1 descriptor. Otherwise, calculate the L1 - * size, capped to the SIDSIZE. - */ - if (smmu->sid_bits < STRTAB_SPLIT) { - size = 0; - } else { - size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3); - size = min(size, smmu->sid_bits - STRTAB_SPLIT); - } + /* Calculate the L1 size, capped to the SIDSIZE. */ + size = STRTAB_L1_SZ_SHIFT - (ilog2(STRTAB_L1_DESC_DWORDS) + 3); + size = min(size, smmu->sid_bits - STRTAB_SPLIT); cfg->num_l1_ents = 1 << size; size += STRTAB_SPLIT; @@ -2504,6 +2519,13 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) smmu->ssid_bits = reg >> IDR1_SSID_SHIFT & IDR1_SSID_MASK; smmu->sid_bits = reg >> IDR1_SID_SHIFT & IDR1_SID_MASK; + /* + * If the SMMU supports fewer bits than would fill a single L2 stream + * table, use a linear table instead. + */ + if (smmu->sid_bits <= STRTAB_SPLIT) + smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB; + /* IDR5 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5); @@ -2613,6 +2635,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) { int irq, ret; struct resource *res; + resource_size_t ioaddr; struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; bool bypass; @@ -2630,6 +2653,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) dev_err(dev, "MMIO region too small (%pr)\n", res); return -EINVAL; } + ioaddr = res->start; smmu->base = devm_ioremap_resource(dev, res); if (IS_ERR(smmu->base)) @@ -2682,7 +2706,15 @@ static int arm_smmu_device_probe(struct platform_device *pdev) return ret; /* And we're up. Go go go! */ - iommu_register_instance(dev->fwnode, &arm_smmu_ops); + ret = iommu_device_sysfs_add(&smmu->iommu, dev, NULL, + "smmu3.%pa", &ioaddr); + if (ret) + return ret; + + iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops); + iommu_device_set_fwnode(&smmu->iommu, dev->fwnode); + + ret = iommu_device_register(&smmu->iommu); #ifdef CONFIG_PCI if (pci_bus_type.iommu_ops != &arm_smmu_ops) { diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index a60cded8a6ed..abf6496843a6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -24,6 +24,7 @@ * - v7/v8 long-descriptor format * - Non-secure access to the SMMU * - Context fault reporting + * - Extended Stream ID (16 bit) */ #define pr_fmt(fmt) "arm-smmu: " fmt @@ -87,6 +88,7 @@ #define sCR0_CLIENTPD (1 << 0) #define sCR0_GFRE (1 << 1) #define sCR0_GFIE (1 << 2) +#define sCR0_EXIDENABLE (1 << 3) #define sCR0_GCFGFRE (1 << 4) #define sCR0_GCFGFIE (1 << 5) #define sCR0_USFCFG (1 << 10) @@ -126,6 +128,7 @@ #define ID0_NUMIRPT_MASK 0xff #define ID0_NUMSIDB_SHIFT 9 #define ID0_NUMSIDB_MASK 0xf +#define ID0_EXIDS (1 << 8) #define ID0_NUMSMRG_SHIFT 0 #define ID0_NUMSMRG_MASK 0xff @@ -169,6 +172,7 @@ #define ARM_SMMU_GR0_S2CR(n) (0xc00 + ((n) << 2)) #define S2CR_CBNDX_SHIFT 0 #define S2CR_CBNDX_MASK 0xff +#define S2CR_EXIDVALID (1 << 10) #define S2CR_TYPE_SHIFT 16 #define S2CR_TYPE_MASK 0x3 enum arm_smmu_s2cr_type { @@ -260,6 +264,7 @@ enum arm_smmu_s2cr_privcfg { #define TTBCR2_SEP_SHIFT 15 #define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) +#define TTBCR2_AS (1 << 4) #define TTBRn_ASID_SHIFT 48 @@ -281,6 +286,9 @@ enum arm_smmu_s2cr_privcfg { #define FSYNR0_WNR (1 << 4) +#define MSI_IOVA_BASE 0x8000000 +#define MSI_IOVA_LENGTH 0x100000 + static int force_stage; module_param(force_stage, int, S_IRUGO); MODULE_PARM_DESC(force_stage, @@ -351,6 +359,7 @@ struct arm_smmu_device { #define ARM_SMMU_FEAT_FMT_AARCH64_64K (1 << 9) #define ARM_SMMU_FEAT_FMT_AARCH32_L (1 << 10) #define ARM_SMMU_FEAT_FMT_AARCH32_S (1 << 11) +#define ARM_SMMU_FEAT_EXIDS (1 << 12) u32 features; #define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0) @@ -380,6 +389,9 @@ struct arm_smmu_device { unsigned int *irqs; u32 cavium_id_base; /* Specific to Cavium */ + + /* IOMMU core code handle */ + struct iommu_device iommu; }; enum arm_smmu_context_fmt { @@ -778,6 +790,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain, reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr; reg2 = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32; reg2 |= TTBCR2_SEP_UPSTREAM; + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64) + reg2 |= TTBCR2_AS; } if (smmu->version > ARM_SMMU_V1) writel_relaxed(reg2, cb_base + ARM_SMMU_CB_TTBCR2); @@ -1048,7 +1062,7 @@ static void arm_smmu_write_smr(struct arm_smmu_device *smmu, int idx) struct arm_smmu_smr *smr = smmu->smrs + idx; u32 reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT; - if (smr->valid) + if (!(smmu->features & ARM_SMMU_FEAT_EXIDS) && smr->valid) reg |= SMR_VALID; writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_SMR(idx)); } @@ -1060,6 +1074,9 @@ static void arm_smmu_write_s2cr(struct arm_smmu_device *smmu, int idx) (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT | (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT; + if (smmu->features & ARM_SMMU_FEAT_EXIDS && smmu->smrs && + smmu->smrs[idx].valid) + reg |= S2CR_EXIDVALID; writel_relaxed(reg, ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_S2CR(idx)); } @@ -1070,6 +1087,34 @@ static void arm_smmu_write_sme(struct arm_smmu_device *smmu, int idx) arm_smmu_write_smr(smmu, idx); } +/* + * The width of SMR's mask field depends on sCR0_EXIDENABLE, so this function + * should be called after sCR0 is written. + */ +static void arm_smmu_test_smr_masks(struct arm_smmu_device *smmu) +{ + void __iomem *gr0_base = ARM_SMMU_GR0(smmu); + u32 smr; + + if (!smmu->smrs) + return; + + /* + * SMR.ID bits may not be preserved if the corresponding MASK + * bits are set, so check each one separately. We can reject + * masters later if they try to claim IDs outside these masks. + */ + smr = smmu->streamid_mask << SMR_ID_SHIFT; + writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); + smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); + smmu->streamid_mask = smr >> SMR_ID_SHIFT; + + smr = smmu->streamid_mask << SMR_MASK_SHIFT; + writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); + smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); + smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT; +} + static int arm_smmu_find_sme(struct arm_smmu_device *smmu, u16 id, u16 mask) { struct arm_smmu_smr *smrs = smmu->smrs; @@ -1214,7 +1259,7 @@ static int arm_smmu_domain_add_master(struct arm_smmu_domain *smmu_domain, continue; s2cr[idx].type = type; - s2cr[idx].privcfg = S2CR_PRIVCFG_UNPRIV; + s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT; s2cr[idx].cbndx = cbndx; arm_smmu_write_s2cr(smmu, idx); } @@ -1371,8 +1416,6 @@ static bool arm_smmu_capable(enum iommu_cap cap) * requests. */ return true; - case IOMMU_CAP_INTR_REMAP: - return true; /* MSIs are just memory writes */ case IOMMU_CAP_NOEXEC: return true; default: @@ -1444,6 +1487,8 @@ static int arm_smmu_add_device(struct device *dev) if (ret) goto out_free; + iommu_device_link(&smmu->iommu, dev); + return 0; out_free: @@ -1456,10 +1501,17 @@ out_free: static void arm_smmu_remove_device(struct device *dev) { struct iommu_fwspec *fwspec = dev->iommu_fwspec; + struct arm_smmu_master_cfg *cfg; + struct arm_smmu_device *smmu; + if (!fwspec || fwspec->ops != &arm_smmu_ops) return; + cfg = fwspec->iommu_priv; + smmu = cfg->smmu; + + iommu_device_unlink(&smmu->iommu, dev); arm_smmu_master_free_smes(fwspec); iommu_group_remove_device(dev); kfree(fwspec->iommu_priv); @@ -1549,6 +1601,29 @@ static int arm_smmu_of_xlate(struct device *dev, struct of_phandle_args *args) return iommu_fwspec_add_ids(dev, &fwid, 1); } +static void arm_smmu_get_resv_regions(struct device *dev, + struct list_head *head) +{ + struct iommu_resv_region *region; + int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; + + region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH, + prot, IOMMU_RESV_MSI); + if (!region) + return; + + list_add_tail(®ion->list, head); +} + +static void arm_smmu_put_resv_regions(struct device *dev, + struct list_head *head) +{ + struct iommu_resv_region *entry, *next; + + list_for_each_entry_safe(entry, next, head, list) + kfree(entry); +} + static struct iommu_ops arm_smmu_ops = { .capable = arm_smmu_capable, .domain_alloc = arm_smmu_domain_alloc, @@ -1564,6 +1639,8 @@ static struct iommu_ops arm_smmu_ops = { .domain_get_attr = arm_smmu_domain_get_attr, .domain_set_attr = arm_smmu_domain_set_attr, .of_xlate = arm_smmu_of_xlate, + .get_resv_regions = arm_smmu_get_resv_regions, + .put_resv_regions = arm_smmu_put_resv_regions, .pgsize_bitmap = -1UL, /* Restricted during device attach */ }; @@ -1648,6 +1725,9 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) if (smmu->features & ARM_SMMU_FEAT_VMID16) reg |= sCR0_VMID16EN; + if (smmu->features & ARM_SMMU_FEAT_EXIDS) + reg |= sCR0_EXIDENABLE; + /* Push the button */ __arm_smmu_tlb_sync(smmu); writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0); @@ -1735,11 +1815,14 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) "\t(IDR0.CTTW overridden by FW configuration)\n"); /* Max. number of entries we have for stream matching/indexing */ - size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK); + if (smmu->version == ARM_SMMU_V2 && id & ID0_EXIDS) { + smmu->features |= ARM_SMMU_FEAT_EXIDS; + size = 1 << 16; + } else { + size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK); + } smmu->streamid_mask = size - 1; if (id & ID0_SMS) { - u32 smr; - smmu->features |= ARM_SMMU_FEAT_STREAM_MATCH; size = (id >> ID0_NUMSMRG_SHIFT) & ID0_NUMSMRG_MASK; if (size == 0) { @@ -1748,21 +1831,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENODEV; } - /* - * SMR.ID bits may not be preserved if the corresponding MASK - * bits are set, so check each one separately. We can reject - * masters later if they try to claim IDs outside these masks. - */ - smr = smmu->streamid_mask << SMR_ID_SHIFT; - writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); - smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); - smmu->streamid_mask = smr >> SMR_ID_SHIFT; - - smr = smmu->streamid_mask << SMR_MASK_SHIFT; - writel_relaxed(smr, gr0_base + ARM_SMMU_GR0_SMR(0)); - smr = readl_relaxed(gr0_base + ARM_SMMU_GR0_SMR(0)); - smmu->smr_mask_mask = smr >> SMR_MASK_SHIFT; - /* Zero-initialised to mark as invalid */ smmu->smrs = devm_kcalloc(smmu->dev, size, sizeof(*smmu->smrs), GFP_KERNEL); @@ -1770,8 +1838,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) return -ENOMEM; dev_notice(smmu->dev, - "\tstream matching with %lu register groups, mask 0x%x", - size, smmu->smr_mask_mask); + "\tstream matching with %lu register groups", size); } /* s2cr->type == 0 means translation, so initialise explicitly */ smmu->s2crs = devm_kmalloc_array(smmu->dev, size, sizeof(*smmu->s2crs), @@ -2011,6 +2078,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev, static int arm_smmu_device_probe(struct platform_device *pdev) { struct resource *res; + resource_size_t ioaddr; struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; int num_irqs, i, err; @@ -2031,6 +2099,7 @@ static int arm_smmu_device_probe(struct platform_device *pdev) return err; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ioaddr = res->start; smmu->base = devm_ioremap_resource(dev, res); if (IS_ERR(smmu->base)) return PTR_ERR(smmu->base); @@ -2091,9 +2160,25 @@ static int arm_smmu_device_probe(struct platform_device *pdev) } } - iommu_register_instance(dev->fwnode, &arm_smmu_ops); + err = iommu_device_sysfs_add(&smmu->iommu, smmu->dev, NULL, + "smmu.%pa", &ioaddr); + if (err) { + dev_err(dev, "Failed to register iommu in sysfs\n"); + return err; + } + + iommu_device_set_ops(&smmu->iommu, &arm_smmu_ops); + iommu_device_set_fwnode(&smmu->iommu, dev->fwnode); + + err = iommu_device_register(&smmu->iommu); + if (err) { + dev_err(dev, "Failed to register iommu\n"); + return err; + } + platform_set_drvdata(pdev, smmu); arm_smmu_device_reset(smmu); + arm_smmu_test_smr_masks(smmu); /* Oh, for a proper bus abstraction */ if (!iommu_present(&platform_bus_type)) diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 2db0d641cf45..48d36ce59efb 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -37,15 +37,50 @@ struct iommu_dma_msi_page { phys_addr_t phys; }; +enum iommu_dma_cookie_type { + IOMMU_DMA_IOVA_COOKIE, + IOMMU_DMA_MSI_COOKIE, +}; + struct iommu_dma_cookie { - struct iova_domain iovad; - struct list_head msi_page_list; - spinlock_t msi_lock; + enum iommu_dma_cookie_type type; + union { + /* Full allocator for IOMMU_DMA_IOVA_COOKIE */ + struct iova_domain iovad; + /* Trivial linear page allocator for IOMMU_DMA_MSI_COOKIE */ + dma_addr_t msi_iova; + }; + struct list_head msi_page_list; + spinlock_t msi_lock; }; +static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie) +{ + if (cookie->type == IOMMU_DMA_IOVA_COOKIE) + return cookie->iovad.granule; + return PAGE_SIZE; +} + static inline struct iova_domain *cookie_iovad(struct iommu_domain *domain) { - return &((struct iommu_dma_cookie *)domain->iova_cookie)->iovad; + struct iommu_dma_cookie *cookie = domain->iova_cookie; + + if (cookie->type == IOMMU_DMA_IOVA_COOKIE) + return &cookie->iovad; + return NULL; +} + +static struct iommu_dma_cookie *cookie_alloc(enum iommu_dma_cookie_type type) +{ + struct iommu_dma_cookie *cookie; + + cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + if (cookie) { + spin_lock_init(&cookie->msi_lock); + INIT_LIST_HEAD(&cookie->msi_page_list); + cookie->type = type; + } + return cookie; } int iommu_dma_init(void) @@ -62,25 +97,53 @@ int iommu_dma_init(void) */ int iommu_get_dma_cookie(struct iommu_domain *domain) { + if (domain->iova_cookie) + return -EEXIST; + + domain->iova_cookie = cookie_alloc(IOMMU_DMA_IOVA_COOKIE); + if (!domain->iova_cookie) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL(iommu_get_dma_cookie); + +/** + * iommu_get_msi_cookie - Acquire just MSI remapping resources + * @domain: IOMMU domain to prepare + * @base: Start address of IOVA region for MSI mappings + * + * Users who manage their own IOVA allocation and do not want DMA API support, + * but would still like to take advantage of automatic MSI remapping, can use + * this to initialise their own domain appropriately. Users should reserve a + * contiguous IOVA region, starting at @base, large enough to accommodate the + * number of PAGE_SIZE mappings necessary to cover every MSI doorbell address + * used by the devices attached to @domain. + */ +int iommu_get_msi_cookie(struct iommu_domain *domain, dma_addr_t base) +{ struct iommu_dma_cookie *cookie; + if (domain->type != IOMMU_DOMAIN_UNMANAGED) + return -EINVAL; + if (domain->iova_cookie) return -EEXIST; - cookie = kzalloc(sizeof(*cookie), GFP_KERNEL); + cookie = cookie_alloc(IOMMU_DMA_MSI_COOKIE); if (!cookie) return -ENOMEM; - spin_lock_init(&cookie->msi_lock); - INIT_LIST_HEAD(&cookie->msi_page_list); + cookie->msi_iova = base; domain->iova_cookie = cookie; return 0; } -EXPORT_SYMBOL(iommu_get_dma_cookie); +EXPORT_SYMBOL(iommu_get_msi_cookie); /** * iommu_put_dma_cookie - Release a domain's DMA mapping resources - * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() + * @domain: IOMMU domain previously prepared by iommu_get_dma_cookie() or + * iommu_get_msi_cookie() * * IOMMU drivers should normally call this from their domain_free callback. */ @@ -92,7 +155,7 @@ void iommu_put_dma_cookie(struct iommu_domain *domain) if (!cookie) return; - if (cookie->iovad.granule) + if (cookie->type == IOMMU_DMA_IOVA_COOKIE && cookie->iovad.granule) put_iova_domain(&cookie->iovad); list_for_each_entry_safe(msi, tmp, &cookie->msi_page_list, list) { @@ -137,11 +200,13 @@ static void iova_reserve_pci_windows(struct pci_dev *dev, int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, u64 size, struct device *dev) { - struct iova_domain *iovad = cookie_iovad(domain); + struct iommu_dma_cookie *cookie = domain->iova_cookie; + struct iova_domain *iovad = &cookie->iovad; unsigned long order, base_pfn, end_pfn; + bool pci = dev && dev_is_pci(dev); - if (!iovad) - return -ENODEV; + if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE) + return -EINVAL; /* Use the smallest supported page size for IOVA granularity */ order = __ffs(domain->pgsize_bitmap); @@ -161,19 +226,31 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, end_pfn = min_t(unsigned long, end_pfn, domain->geometry.aperture_end >> order); } + /* + * PCI devices may have larger DMA masks, but still prefer allocating + * within a 32-bit mask to avoid DAC addressing. Such limitations don't + * apply to the typical platform device, so for those we may as well + * leave the cache limit at the top of their range to save an rb_last() + * traversal on every allocation. + */ + if (pci) + end_pfn &= DMA_BIT_MASK(32) >> order; - /* All we can safely do with an existing domain is enlarge it */ + /* start_pfn is always nonzero for an already-initialised domain */ if (iovad->start_pfn) { if (1UL << order != iovad->granule || - base_pfn != iovad->start_pfn || - end_pfn < iovad->dma_32bit_pfn) { + base_pfn != iovad->start_pfn) { pr_warn("Incompatible range for DMA domain\n"); return -EFAULT; } - iovad->dma_32bit_pfn = end_pfn; + /* + * If we have devices with different DMA masks, move the free + * area cache limit down for the benefit of the smaller one. + */ + iovad->dma_32bit_pfn = min(end_pfn, iovad->dma_32bit_pfn); } else { init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn); - if (dev && dev_is_pci(dev)) + if (pci) iova_reserve_pci_windows(to_pci_dev(dev), iovad); } return 0; @@ -181,16 +258,22 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base, EXPORT_SYMBOL(iommu_dma_init_domain); /** - * dma_direction_to_prot - Translate DMA API directions to IOMMU API page flags + * dma_info_to_prot - Translate DMA API directions and attributes to IOMMU API + * page flags. * @dir: Direction of DMA transfer * @coherent: Is the DMA master cache-coherent? + * @attrs: DMA attributes for the mapping * * Return: corresponding IOMMU API page protection flags */ -int dma_direction_to_prot(enum dma_data_direction dir, bool coherent) +int dma_info_to_prot(enum dma_data_direction dir, bool coherent, + unsigned long attrs) { int prot = coherent ? IOMMU_CACHE : 0; + if (attrs & DMA_ATTR_PRIVILEGED) + prot |= IOMMU_PRIV; + switch (dir) { case DMA_BIDIRECTIONAL: return prot | IOMMU_READ | IOMMU_WRITE; @@ -204,19 +287,28 @@ int dma_direction_to_prot(enum dma_data_direction dir, bool coherent) } static struct iova *__alloc_iova(struct iommu_domain *domain, size_t size, - dma_addr_t dma_limit) + dma_addr_t dma_limit, struct device *dev) { struct iova_domain *iovad = cookie_iovad(domain); unsigned long shift = iova_shift(iovad); unsigned long length = iova_align(iovad, size) >> shift; + struct iova *iova = NULL; if (domain->geometry.force_aperture) dma_limit = min(dma_limit, domain->geometry.aperture_end); + + /* Try to get PCI devices a SAC address */ + if (dma_limit > DMA_BIT_MASK(32) && dev_is_pci(dev)) + iova = alloc_iova(iovad, length, DMA_BIT_MASK(32) >> shift, + true); /* * Enforce size-alignment to be safe - there could perhaps be an * attribute to control this per-device, or at least per-domain... */ - return alloc_iova(iovad, length, dma_limit >> shift, true); + if (!iova) + iova = alloc_iova(iovad, length, dma_limit >> shift, true); + + return iova; } /* The IOVA allocator knows what we mapped, so just unmap whatever that was */ @@ -369,7 +461,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, if (!pages) return NULL; - iova = __alloc_iova(domain, size, dev->coherent_dma_mask); + iova = __alloc_iova(domain, size, dev->coherent_dma_mask, dev); if (!iova) goto out_free_pages; @@ -440,7 +532,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, struct iova_domain *iovad = cookie_iovad(domain); size_t iova_off = iova_offset(iovad, phys); size_t len = iova_align(iovad, size + iova_off); - struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev)); + struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev), dev); if (!iova) return DMA_ERROR_CODE; @@ -598,7 +690,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, prev = s; } - iova = __alloc_iova(domain, iova_len, dma_get_mask(dev)); + iova = __alloc_iova(domain, iova_len, dma_get_mask(dev), dev); if (!iova) goto out_restore_sg; @@ -633,7 +725,7 @@ dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, size_t size, enum dma_data_direction dir, unsigned long attrs) { return __iommu_dma_map(dev, phys, size, - dma_direction_to_prot(dir, false) | IOMMU_MMIO); + dma_info_to_prot(dir, false, attrs) | IOMMU_MMIO); } void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, @@ -642,16 +734,6 @@ void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); } -int iommu_dma_supported(struct device *dev, u64 mask) -{ - /* - * 'Special' IOMMUs which don't have the same addressing capability - * as the CPU will have to wait until we have some way to query that - * before they'll be able to use this framework. - */ - return 1; -} - int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return dma_addr == DMA_ERROR_CODE; @@ -662,11 +744,12 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, { struct iommu_dma_cookie *cookie = domain->iova_cookie; struct iommu_dma_msi_page *msi_page; - struct iova_domain *iovad = &cookie->iovad; + struct iova_domain *iovad = cookie_iovad(domain); struct iova *iova; int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO; + size_t size = cookie_msi_granule(cookie); - msi_addr &= ~(phys_addr_t)iova_mask(iovad); + msi_addr &= ~(phys_addr_t)(size - 1); list_for_each_entry(msi_page, &cookie->msi_page_list, list) if (msi_page->phys == msi_addr) return msi_page; @@ -675,13 +758,18 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, if (!msi_page) return NULL; - iova = __alloc_iova(domain, iovad->granule, dma_get_mask(dev)); - if (!iova) - goto out_free_page; - msi_page->phys = msi_addr; - msi_page->iova = iova_dma_addr(iovad, iova); - if (iommu_map(domain, msi_page->iova, msi_addr, iovad->granule, prot)) + if (iovad) { + iova = __alloc_iova(domain, size, dma_get_mask(dev), dev); + if (!iova) + goto out_free_page; + msi_page->iova = iova_dma_addr(iovad, iova); + } else { + msi_page->iova = cookie->msi_iova; + cookie->msi_iova += size; + } + + if (iommu_map(domain, msi_page->iova, msi_addr, size, prot)) goto out_free_iova; INIT_LIST_HEAD(&msi_page->list); @@ -689,7 +777,10 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev, return msi_page; out_free_iova: - __free_iova(iovad, iova); + if (iovad) + __free_iova(iovad, iova); + else + cookie->msi_iova -= size; out_free_page: kfree(msi_page); return NULL; @@ -730,7 +821,7 @@ void iommu_dma_map_msi_msg(int irq, struct msi_msg *msg) msg->data = ~0U; } else { msg->address_hi = upper_32_bits(msi_page->iova); - msg->address_lo &= iova_mask(&cookie->iovad); + msg->address_lo &= cookie_msi_granule(cookie) - 1; msg->address_lo += lower_32_bits(msi_page->iova); } } diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index a88576d50740..d9c0decfc91a 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -74,6 +74,8 @@ static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)]; static int alloc_iommu(struct dmar_drhd_unit *drhd); static void free_iommu(struct intel_iommu *iommu); +extern const struct iommu_ops intel_iommu_ops; + static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd) { /* @@ -903,8 +905,10 @@ int __init detect_intel_iommu(void) x86_init.iommu.iommu_init = intel_iommu_init; #endif - acpi_put_table(dmar_tbl); - dmar_tbl = NULL; + if (dmar_tbl) { + acpi_put_table(dmar_tbl); + dmar_tbl = NULL; + } up_write(&dmar_global_lock); return ret ? 1 : -ENODEV; @@ -1076,14 +1080,17 @@ static int alloc_iommu(struct dmar_drhd_unit *drhd) raw_spin_lock_init(&iommu->register_lock); if (intel_iommu_enabled) { - iommu->iommu_dev = iommu_device_create(NULL, iommu, - intel_iommu_groups, - "%s", iommu->name); + err = iommu_device_sysfs_add(&iommu->iommu, NULL, + intel_iommu_groups, + "%s", iommu->name); + if (err) + goto err_unmap; - if (IS_ERR(iommu->iommu_dev)) { - err = PTR_ERR(iommu->iommu_dev); + iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops); + + err = iommu_device_register(&iommu->iommu); + if (err) goto err_unmap; - } } drhd->iommu = iommu; @@ -1101,7 +1108,8 @@ error: static void free_iommu(struct intel_iommu *iommu) { - iommu_device_destroy(iommu->iommu_dev); + iommu_device_sysfs_remove(&iommu->iommu); + iommu_device_unregister(&iommu->iommu); if (iommu->irq) { if (iommu->pr_irq) { diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 57ba0d3091ea..a7e0821c9967 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -276,6 +276,8 @@ struct sysmmu_drvdata { struct list_head owner_node; /* node for owner controllers list */ phys_addr_t pgtable; /* assigned page table structure */ unsigned int version; /* our version */ + + struct iommu_device iommu; /* IOMMU core handle */ }; static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom) @@ -381,13 +383,14 @@ static void show_fault_information(struct sysmmu_drvdata *data, { sysmmu_pte_t *ent; - dev_err(data->sysmmu, "%s FAULT occurred at %#x (page table base: %pa)\n", - finfo->name, fault_addr, &data->pgtable); + dev_err(data->sysmmu, "%s: %s FAULT occurred at %#x\n", + dev_name(data->master), finfo->name, fault_addr); + dev_dbg(data->sysmmu, "Page table base: %pa\n", &data->pgtable); ent = section_entry(phys_to_virt(data->pgtable), fault_addr); - dev_err(data->sysmmu, "\tLv1 entry: %#x\n", *ent); + dev_dbg(data->sysmmu, "\tLv1 entry: %#x\n", *ent); if (lv1ent_page(ent)) { ent = page_entry(ent, fault_addr); - dev_err(data->sysmmu, "\t Lv2 entry: %#x\n", *ent); + dev_dbg(data->sysmmu, "\t Lv2 entry: %#x\n", *ent); } } @@ -611,6 +614,18 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) data->sysmmu = dev; spin_lock_init(&data->lock); + ret = iommu_device_sysfs_add(&data->iommu, &pdev->dev, NULL, + dev_name(data->sysmmu)); + if (ret) + return ret; + + iommu_device_set_ops(&data->iommu, &exynos_iommu_ops); + iommu_device_set_fwnode(&data->iommu, &dev->of_node->fwnode); + + ret = iommu_device_register(&data->iommu); + if (ret) + return ret; + platform_set_drvdata(pdev, data); __sysmmu_get_version(data); @@ -628,8 +643,6 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) pm_runtime_enable(dev); - of_iommu_set_ops(dev->of_node, &exynos_iommu_ops); - return 0; } @@ -743,6 +756,8 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) DMA_TO_DEVICE); /* For mapping page table entries we rely on dma == phys */ BUG_ON(handle != virt_to_phys(domain->pgtable)); + if (dma_mapping_error(dma_dev, handle)) + goto err_lv2ent; spin_lock_init(&domain->lock); spin_lock_init(&domain->pgtablelock); @@ -754,6 +769,8 @@ static struct iommu_domain *exynos_iommu_domain_alloc(unsigned type) return &domain->domain; +err_lv2ent: + free_pages((unsigned long)domain->lv2entcnt, 1); err_counter: free_pages((unsigned long)domain->pgtable, 2); err_dma_cookie: @@ -897,6 +914,7 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain, } if (lv1ent_fault(sent)) { + dma_addr_t handle; sysmmu_pte_t *pent; bool need_flush_flpd_cache = lv1ent_zero(sent); @@ -908,7 +926,12 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain, update_pte(sent, mk_lv1ent_page(virt_to_phys(pent))); kmemleak_ignore(pent); *pgcounter = NUM_LV2ENTRIES; - dma_map_single(dma_dev, pent, LV2TABLE_SIZE, DMA_TO_DEVICE); + handle = dma_map_single(dma_dev, pent, LV2TABLE_SIZE, + DMA_TO_DEVICE); + if (dma_mapping_error(dma_dev, handle)) { + kmem_cache_free(lv2table_kmem_cache, pent); + return ERR_PTR(-EADDRINUSE); + } /* * If pre-fetched SLPD is a faulty SLPD in zero_l2_table, @@ -1231,9 +1254,21 @@ static int exynos_iommu_add_device(struct device *dev) static void exynos_iommu_remove_device(struct device *dev) { + struct exynos_iommu_owner *owner = dev->archdata.iommu; + if (!has_sysmmu(dev)) return; + if (owner->domain) { + struct iommu_group *group = iommu_group_get(dev); + + if (group) { + WARN_ON(owner->domain != + iommu_group_default_domain(group)); + exynos_iommu_detach_device(owner->domain, dev); + iommu_group_put(group); + } + } iommu_group_remove_device(dev); } @@ -1242,7 +1277,7 @@ static int exynos_iommu_of_xlate(struct device *dev, { struct exynos_iommu_owner *owner = dev->archdata.iommu; struct platform_device *sysmmu = of_find_device_by_node(spec->np); - struct sysmmu_drvdata *data; + struct sysmmu_drvdata *data, *entry; if (!sysmmu) return -ENODEV; @@ -1261,6 +1296,10 @@ static int exynos_iommu_of_xlate(struct device *dev, dev->archdata.iommu = owner; } + list_for_each_entry(entry, &owner->controllers, owner_node) + if (entry == data) + return 0; + list_add_tail(&data->owner_node, &owner->controllers); data->master = dev; diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index c66c273dfd8a..f5e02f8e7371 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -440,6 +440,7 @@ struct dmar_rmrr_unit { u64 end_address; /* reserved end address */ struct dmar_dev_scope *devices; /* target devices */ int devices_cnt; /* target device count */ + struct iommu_resv_region *resv; /* reserved region handle */ }; struct dmar_atsr_unit { @@ -547,7 +548,7 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); static DEFINE_SPINLOCK(device_domain_lock); static LIST_HEAD(device_domain_list); -static const struct iommu_ops intel_iommu_ops; +const struct iommu_ops intel_iommu_ops; static bool translation_pre_enabled(struct intel_iommu *iommu) { @@ -1144,7 +1145,7 @@ static void dma_pte_free_level(struct dmar_domain *domain, int level, if (!dma_pte_present(pte) || dma_pte_superpage(pte)) goto next; - level_pfn = pfn & level_mask(level - 1); + level_pfn = pfn & level_mask(level); level_pte = phys_to_virt(dma_pte_addr(pte)); if (level > 2) @@ -2037,6 +2038,25 @@ static int domain_context_mapping_one(struct dmar_domain *domain, if (context_present(context)) goto out_unlock; + /* + * For kdump cases, old valid entries may be cached due to the + * in-flight DMA and copied pgtable, but there is no unmapping + * behaviour for them, thus we need an explicit cache flush for + * the newly-mapped device. For kdump, at this point, the device + * is supposed to finish reset at its driver probe stage, so no + * in-flight DMA will exist, and we don't need to worry anymore + * hereafter. + */ + if (context_copied(context)) { + u16 did_old = context_domain_id(context); + + if (did_old >= 0 && did_old < cap_ndoms(iommu->cap)) + iommu->flush.flush_context(iommu, did_old, + (((u16)bus) << 8) | devfn, + DMA_CCMD_MASK_NOBIT, + DMA_CCMD_DEVICE_INVL); + } + pgd = domain->pgd; context_clear_entry(context); @@ -3306,13 +3326,14 @@ static int __init init_dmars(void) iommu_identity_mapping |= IDENTMAP_GFX; #endif + check_tylersburg_isoch(); + if (iommu_identity_mapping) { ret = si_domain_init(hw_pass_through); if (ret) goto free_iommu; } - check_tylersburg_isoch(); /* * If we copied translations from a previous kernel in the kdump @@ -4227,27 +4248,40 @@ static inline void init_iommu_pm_ops(void) {} int __init dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg) { struct acpi_dmar_reserved_memory *rmrr; + int prot = DMA_PTE_READ|DMA_PTE_WRITE; struct dmar_rmrr_unit *rmrru; + size_t length; rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL); if (!rmrru) - return -ENOMEM; + goto out; rmrru->hdr = header; rmrr = (struct acpi_dmar_reserved_memory *)header; rmrru->base_address = rmrr->base_address; rmrru->end_address = rmrr->end_address; + + length = rmrr->end_address - rmrr->base_address + 1; + rmrru->resv = iommu_alloc_resv_region(rmrr->base_address, length, prot, + IOMMU_RESV_DIRECT); + if (!rmrru->resv) + goto free_rmrru; + rmrru->devices = dmar_alloc_dev_scope((void *)(rmrr + 1), ((void *)rmrr) + rmrr->header.length, &rmrru->devices_cnt); - if (rmrru->devices_cnt && rmrru->devices == NULL) { - kfree(rmrru); - return -ENOMEM; - } + if (rmrru->devices_cnt && rmrru->devices == NULL) + goto free_all; list_add(&rmrru->list, &dmar_rmrr_units); return 0; +free_all: + kfree(rmrru->resv); +free_rmrru: + kfree(rmrru); +out: + return -ENOMEM; } static struct dmar_atsr_unit *dmar_find_atsr(struct acpi_dmar_atsr *atsr) @@ -4461,6 +4495,7 @@ static void intel_iommu_free_dmars(void) list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) { list_del(&rmrru->list); dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt); + kfree(rmrru->resv); kfree(rmrru); } @@ -4834,10 +4869,13 @@ int __init intel_iommu_init(void) init_iommu_pm_ops(); - for_each_active_iommu(iommu, drhd) - iommu->iommu_dev = iommu_device_create(NULL, iommu, - intel_iommu_groups, - "%s", iommu->name); + for_each_active_iommu(iommu, drhd) { + iommu_device_sysfs_add(&iommu->iommu, NULL, + intel_iommu_groups, + "%s", iommu->name); + iommu_device_set_ops(&iommu->iommu, &intel_iommu_ops); + iommu_device_register(&iommu->iommu); + } bus_set_iommu(&pci_bus_type, &intel_iommu_ops); bus_register_notifier(&pci_bus_type, &device_nb); @@ -5159,7 +5197,7 @@ static int intel_iommu_add_device(struct device *dev) if (!iommu) return -ENODEV; - iommu_device_link(iommu->iommu_dev, dev); + iommu_device_link(&iommu->iommu, dev); group = iommu_group_get_for_dev(dev); @@ -5181,10 +5219,68 @@ static void intel_iommu_remove_device(struct device *dev) iommu_group_remove_device(dev); - iommu_device_unlink(iommu->iommu_dev, dev); + iommu_device_unlink(&iommu->iommu, dev); +} + +static void intel_iommu_get_resv_regions(struct device *device, + struct list_head *head) +{ + struct iommu_resv_region *reg; + struct dmar_rmrr_unit *rmrr; + struct device *i_dev; + int i; + + rcu_read_lock(); + for_each_rmrr_units(rmrr) { + for_each_active_dev_scope(rmrr->devices, rmrr->devices_cnt, + i, i_dev) { + if (i_dev != device) + continue; + + list_add_tail(&rmrr->resv->list, head); + } + } + rcu_read_unlock(); + + reg = iommu_alloc_resv_region(IOAPIC_RANGE_START, + IOAPIC_RANGE_END - IOAPIC_RANGE_START + 1, + 0, IOMMU_RESV_RESERVED); + if (!reg) + return; + list_add_tail(®->list, head); +} + +static void intel_iommu_put_resv_regions(struct device *dev, + struct list_head *head) +{ + struct iommu_resv_region *entry, *next; + + list_for_each_entry_safe(entry, next, head, list) { + if (entry->type == IOMMU_RESV_RESERVED) + kfree(entry); + } } #ifdef CONFIG_INTEL_IOMMU_SVM +#define MAX_NR_PASID_BITS (20) +static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) +{ + /* + * Convert ecap_pss to extend context entry pts encoding, also + * respect the soft pasid_max value set by the iommu. + * - number of PASID bits = ecap_pss + 1 + * - number of PASID table entries = 2^(pts + 5) + * Therefore, pts = ecap_pss - 4 + * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15 + */ + if (ecap_pss(iommu->ecap) < 5) + return 0; + + /* pasid_max is encoded as actual number of entries not the bits */ + return find_first_bit((unsigned long *)&iommu->pasid_max, + MAX_NR_PASID_BITS) - 5; +} + int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) { struct device_domain_info *info; @@ -5217,7 +5313,9 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd if (!(ctx_lo & CONTEXT_PASIDE)) { context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); - context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | ecap_pss(iommu->ecap); + context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | + intel_iommu_get_pts(iommu); + wmb(); /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both * extended to permit requests-with-PASID if the PASIDE bit @@ -5292,20 +5390,22 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) } #endif /* CONFIG_INTEL_IOMMU_SVM */ -static const struct iommu_ops intel_iommu_ops = { - .capable = intel_iommu_capable, - .domain_alloc = intel_iommu_domain_alloc, - .domain_free = intel_iommu_domain_free, - .attach_dev = intel_iommu_attach_device, - .detach_dev = intel_iommu_detach_device, - .map = intel_iommu_map, - .unmap = intel_iommu_unmap, - .map_sg = default_iommu_map_sg, - .iova_to_phys = intel_iommu_iova_to_phys, - .add_device = intel_iommu_add_device, - .remove_device = intel_iommu_remove_device, - .device_group = pci_device_group, - .pgsize_bitmap = INTEL_IOMMU_PGSIZES, +const struct iommu_ops intel_iommu_ops = { + .capable = intel_iommu_capable, + .domain_alloc = intel_iommu_domain_alloc, + .domain_free = intel_iommu_domain_free, + .attach_dev = intel_iommu_attach_device, + .detach_dev = intel_iommu_detach_device, + .map = intel_iommu_map, + .unmap = intel_iommu_unmap, + .map_sg = default_iommu_map_sg, + .iova_to_phys = intel_iommu_iova_to_phys, + .add_device = intel_iommu_add_device, + .remove_device = intel_iommu_remove_device, + .get_resv_regions = intel_iommu_get_resv_regions, + .put_resv_regions = intel_iommu_put_resv_regions, + .device_group = pci_device_group, + .pgsize_bitmap = INTEL_IOMMU_PGSIZES, }; static void quirk_iommu_g4x_gfx(struct pci_dev *dev) diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 0769276c0537..1c049e2e12bf 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -265,7 +265,9 @@ static arm_v7s_iopte arm_v7s_prot_to_pte(int prot, int lvl, if (!(prot & IOMMU_MMIO)) pte |= ARM_V7S_ATTR_TEX(1); if (ap) { - pte |= ARM_V7S_PTE_AF | ARM_V7S_PTE_AP_UNPRIV; + pte |= ARM_V7S_PTE_AF; + if (!(prot & IOMMU_PRIV)) + pte |= ARM_V7S_PTE_AP_UNPRIV; if (!(prot & IOMMU_WRITE)) pte |= ARM_V7S_PTE_AP_RDONLY; } @@ -288,6 +290,8 @@ static int arm_v7s_pte_to_prot(arm_v7s_iopte pte, int lvl) if (!(attr & ARM_V7S_PTE_AP_RDONLY)) prot |= IOMMU_WRITE; + if (!(attr & ARM_V7S_PTE_AP_UNPRIV)) + prot |= IOMMU_PRIV; if ((attr & (ARM_V7S_TEX_MASK << ARM_V7S_TEX_SHIFT)) == 0) prot |= IOMMU_MMIO; else if (pte & ARM_V7S_ATTR_C) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index a40ce3406fef..feacc54bec68 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -350,11 +350,14 @@ static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data, if (data->iop.fmt == ARM_64_LPAE_S1 || data->iop.fmt == ARM_32_LPAE_S1) { - pte = ARM_LPAE_PTE_AP_UNPRIV | ARM_LPAE_PTE_nG; + pte = ARM_LPAE_PTE_nG; if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ)) pte |= ARM_LPAE_PTE_AP_RDONLY; + if (!(prot & IOMMU_PRIV)) + pte |= ARM_LPAE_PTE_AP_UNPRIV; + if (prot & IOMMU_MMIO) pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV << ARM_LPAE_PTE_ATTRINDX_SHIFT); diff --git a/drivers/iommu/iommu-sysfs.c b/drivers/iommu/iommu-sysfs.c index 39b2d9127dbf..c58351ed61c1 100644 --- a/drivers/iommu/iommu-sysfs.c +++ b/drivers/iommu/iommu-sysfs.c @@ -50,85 +50,76 @@ static int __init iommu_dev_init(void) postcore_initcall(iommu_dev_init); /* - * Create an IOMMU device and return a pointer to it. IOMMU specific - * attributes can be provided as an attribute group, allowing a unique - * namespace per IOMMU type. + * Init the struct device for the IOMMU. IOMMU specific attributes can + * be provided as an attribute group, allowing a unique namespace per + * IOMMU type. */ -struct device *iommu_device_create(struct device *parent, void *drvdata, - const struct attribute_group **groups, - const char *fmt, ...) +int iommu_device_sysfs_add(struct iommu_device *iommu, + struct device *parent, + const struct attribute_group **groups, + const char *fmt, ...) { - struct device *dev; va_list vargs; int ret; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return ERR_PTR(-ENOMEM); + device_initialize(&iommu->dev); - device_initialize(dev); - - dev->class = &iommu_class; - dev->parent = parent; - dev->groups = groups; - dev_set_drvdata(dev, drvdata); + iommu->dev.class = &iommu_class; + iommu->dev.parent = parent; + iommu->dev.groups = groups; va_start(vargs, fmt); - ret = kobject_set_name_vargs(&dev->kobj, fmt, vargs); + ret = kobject_set_name_vargs(&iommu->dev.kobj, fmt, vargs); va_end(vargs); if (ret) goto error; - ret = device_add(dev); + ret = device_add(&iommu->dev); if (ret) goto error; - return dev; + return 0; error: - put_device(dev); - return ERR_PTR(ret); + put_device(&iommu->dev); + return ret; } -void iommu_device_destroy(struct device *dev) +void iommu_device_sysfs_remove(struct iommu_device *iommu) { - if (!dev || IS_ERR(dev)) - return; - - device_unregister(dev); + device_unregister(&iommu->dev); } - /* * IOMMU drivers can indicate a device is managed by a given IOMMU using * this interface. A link to the device will be created in the "devices" * directory of the IOMMU device in sysfs and an "iommu" link will be * created under the linked device, pointing back at the IOMMU device. */ -int iommu_device_link(struct device *dev, struct device *link) +int iommu_device_link(struct iommu_device *iommu, struct device *link) { int ret; - if (!dev || IS_ERR(dev)) + if (!iommu || IS_ERR(iommu)) return -ENODEV; - ret = sysfs_add_link_to_group(&dev->kobj, "devices", + ret = sysfs_add_link_to_group(&iommu->dev.kobj, "devices", &link->kobj, dev_name(link)); if (ret) return ret; - ret = sysfs_create_link_nowarn(&link->kobj, &dev->kobj, "iommu"); + ret = sysfs_create_link_nowarn(&link->kobj, &iommu->dev.kobj, "iommu"); if (ret) - sysfs_remove_link_from_group(&dev->kobj, "devices", + sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link)); return ret; } -void iommu_device_unlink(struct device *dev, struct device *link) +void iommu_device_unlink(struct iommu_device *iommu, struct device *link) { - if (!dev || IS_ERR(dev)) + if (!iommu || IS_ERR(iommu)) return; sysfs_remove_link(&link->kobj, "iommu"); - sysfs_remove_link_from_group(&dev->kobj, "devices", dev_name(link)); + sysfs_remove_link_from_group(&iommu->dev.kobj, "devices", dev_name(link)); } diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index dbe7f653bb7c..8ea14f41a979 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -55,7 +55,7 @@ struct iommu_group { struct iommu_domain *domain; }; -struct iommu_device { +struct group_device { struct list_head list; struct device *dev; char *name; @@ -68,6 +68,12 @@ struct iommu_group_attribute { const char *buf, size_t count); }; +static const char * const iommu_group_resv_type_string[] = { + [IOMMU_RESV_DIRECT] = "direct", + [IOMMU_RESV_RESERVED] = "reserved", + [IOMMU_RESV_MSI] = "msi", +}; + #define IOMMU_GROUP_ATTR(_name, _mode, _show, _store) \ struct iommu_group_attribute iommu_group_attr_##_name = \ __ATTR(_name, _mode, _show, _store) @@ -77,6 +83,25 @@ struct iommu_group_attribute iommu_group_attr_##_name = \ #define to_iommu_group(_kobj) \ container_of(_kobj, struct iommu_group, kobj) +static LIST_HEAD(iommu_device_list); +static DEFINE_SPINLOCK(iommu_device_lock); + +int iommu_device_register(struct iommu_device *iommu) +{ + spin_lock(&iommu_device_lock); + list_add_tail(&iommu->list, &iommu_device_list); + spin_unlock(&iommu_device_lock); + + return 0; +} + +void iommu_device_unregister(struct iommu_device *iommu) +{ + spin_lock(&iommu_device_lock); + list_del(&iommu->list); + spin_unlock(&iommu_device_lock); +} + static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus, unsigned type); static int __iommu_attach_device(struct iommu_domain *domain, @@ -133,8 +158,131 @@ static ssize_t iommu_group_show_name(struct iommu_group *group, char *buf) return sprintf(buf, "%s\n", group->name); } +/** + * iommu_insert_resv_region - Insert a new region in the + * list of reserved regions. + * @new: new region to insert + * @regions: list of regions + * + * The new element is sorted by address with respect to the other + * regions of the same type. In case it overlaps with another + * region of the same type, regions are merged. In case it + * overlaps with another region of different type, regions are + * not merged. + */ +static int iommu_insert_resv_region(struct iommu_resv_region *new, + struct list_head *regions) +{ + struct iommu_resv_region *region; + phys_addr_t start = new->start; + phys_addr_t end = new->start + new->length - 1; + struct list_head *pos = regions->next; + + while (pos != regions) { + struct iommu_resv_region *entry = + list_entry(pos, struct iommu_resv_region, list); + phys_addr_t a = entry->start; + phys_addr_t b = entry->start + entry->length - 1; + int type = entry->type; + + if (end < a) { + goto insert; + } else if (start > b) { + pos = pos->next; + } else if ((start >= a) && (end <= b)) { + if (new->type == type) + goto done; + else + pos = pos->next; + } else { + if (new->type == type) { + phys_addr_t new_start = min(a, start); + phys_addr_t new_end = max(b, end); + + list_del(&entry->list); + entry->start = new_start; + entry->length = new_end - new_start + 1; + iommu_insert_resv_region(entry, regions); + } else { + pos = pos->next; + } + } + } +insert: + region = iommu_alloc_resv_region(new->start, new->length, + new->prot, new->type); + if (!region) + return -ENOMEM; + + list_add_tail(®ion->list, pos); +done: + return 0; +} + +static int +iommu_insert_device_resv_regions(struct list_head *dev_resv_regions, + struct list_head *group_resv_regions) +{ + struct iommu_resv_region *entry; + int ret = 0; + + list_for_each_entry(entry, dev_resv_regions, list) { + ret = iommu_insert_resv_region(entry, group_resv_regions); + if (ret) + break; + } + return ret; +} + +int iommu_get_group_resv_regions(struct iommu_group *group, + struct list_head *head) +{ + struct group_device *device; + int ret = 0; + + mutex_lock(&group->mutex); + list_for_each_entry(device, &group->devices, list) { + struct list_head dev_resv_regions; + + INIT_LIST_HEAD(&dev_resv_regions); + iommu_get_resv_regions(device->dev, &dev_resv_regions); + ret = iommu_insert_device_resv_regions(&dev_resv_regions, head); + iommu_put_resv_regions(device->dev, &dev_resv_regions); + if (ret) + break; + } + mutex_unlock(&group->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(iommu_get_group_resv_regions); + +static ssize_t iommu_group_show_resv_regions(struct iommu_group *group, + char *buf) +{ + struct iommu_resv_region *region, *next; + struct list_head group_resv_regions; + char *str = buf; + + INIT_LIST_HEAD(&group_resv_regions); + iommu_get_group_resv_regions(group, &group_resv_regions); + + list_for_each_entry_safe(region, next, &group_resv_regions, list) { + str += sprintf(str, "0x%016llx 0x%016llx %s\n", + (long long int)region->start, + (long long int)(region->start + + region->length - 1), + iommu_group_resv_type_string[region->type]); + kfree(region); + } + + return (str - buf); +} + static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); +static IOMMU_GROUP_ATTR(reserved_regions, 0444, + iommu_group_show_resv_regions, NULL); + static void iommu_group_release(struct kobject *kobj) { struct iommu_group *group = to_iommu_group(kobj); @@ -212,6 +360,11 @@ struct iommu_group *iommu_group_alloc(void) */ kobject_put(&group->kobj); + ret = iommu_group_create_file(group, + &iommu_group_attr_reserved_regions); + if (ret) + return ERR_PTR(ret); + pr_debug("Allocated group %d\n", group->id); return group; @@ -318,7 +471,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, struct device *dev) { struct iommu_domain *domain = group->default_domain; - struct iommu_dm_region *entry; + struct iommu_resv_region *entry; struct list_head mappings; unsigned long pg_size; int ret = 0; @@ -331,18 +484,21 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, pg_size = 1UL << __ffs(domain->pgsize_bitmap); INIT_LIST_HEAD(&mappings); - iommu_get_dm_regions(dev, &mappings); + iommu_get_resv_regions(dev, &mappings); /* We need to consider overlapping regions for different devices */ list_for_each_entry(entry, &mappings, list) { dma_addr_t start, end, addr; - if (domain->ops->apply_dm_region) - domain->ops->apply_dm_region(dev, domain, entry); + if (domain->ops->apply_resv_region) + domain->ops->apply_resv_region(dev, domain, entry); start = ALIGN(entry->start, pg_size); end = ALIGN(entry->start + entry->length, pg_size); + if (entry->type != IOMMU_RESV_DIRECT) + continue; + for (addr = start; addr < end; addr += pg_size) { phys_addr_t phys_addr; @@ -358,7 +514,7 @@ static int iommu_group_create_direct_mappings(struct iommu_group *group, } out: - iommu_put_dm_regions(dev, &mappings); + iommu_put_resv_regions(dev, &mappings); return ret; } @@ -374,7 +530,7 @@ out: int iommu_group_add_device(struct iommu_group *group, struct device *dev) { int ret, i = 0; - struct iommu_device *device; + struct group_device *device; device = kzalloc(sizeof(*device), GFP_KERNEL); if (!device) @@ -383,36 +539,30 @@ int iommu_group_add_device(struct iommu_group *group, struct device *dev) device->dev = dev; ret = sysfs_create_link(&dev->kobj, &group->kobj, "iommu_group"); - if (ret) { - kfree(device); - return ret; - } + if (ret) + goto err_free_device; device->name = kasprintf(GFP_KERNEL, "%s", kobject_name(&dev->kobj)); rename: if (!device->name) { - sysfs_remove_link(&dev->kobj, "iommu_group"); - kfree(device); - return -ENOMEM; + ret = -ENOMEM; + goto err_remove_link; } ret = sysfs_create_link_nowarn(group->devices_kobj, &dev->kobj, device->name); if (ret) { - kfree(device->name); if (ret == -EEXIST && i >= 0) { /* * Account for the slim chance of collision * and append an instance to the name. */ + kfree(device->name); device->name = kasprintf(GFP_KERNEL, "%s.%d", kobject_name(&dev->kobj), i++); goto rename; } - - sysfs_remove_link(&dev->kobj, "iommu_group"); - kfree(device); - return ret; + goto err_free_name; } kobject_get(group->devices_kobj); @@ -424,8 +574,10 @@ rename: mutex_lock(&group->mutex); list_add_tail(&device->list, &group->devices); if (group->domain) - __iommu_attach_device(group->domain, dev); + ret = __iommu_attach_device(group->domain, dev); mutex_unlock(&group->mutex); + if (ret) + goto err_put_group; /* Notify any listeners about change to group. */ blocking_notifier_call_chain(&group->notifier, @@ -436,6 +588,21 @@ rename: pr_info("Adding device %s to group %d\n", dev_name(dev), group->id); return 0; + +err_put_group: + mutex_lock(&group->mutex); + list_del(&device->list); + mutex_unlock(&group->mutex); + dev->iommu_group = NULL; + kobject_put(group->devices_kobj); +err_free_name: + kfree(device->name); +err_remove_link: + sysfs_remove_link(&dev->kobj, "iommu_group"); +err_free_device: + kfree(device); + pr_err("Failed to add device %s to group %d: %d\n", dev_name(dev), group->id, ret); + return ret; } EXPORT_SYMBOL_GPL(iommu_group_add_device); @@ -449,7 +616,7 @@ EXPORT_SYMBOL_GPL(iommu_group_add_device); void iommu_group_remove_device(struct device *dev) { struct iommu_group *group = dev->iommu_group; - struct iommu_device *tmp_device, *device = NULL; + struct group_device *tmp_device, *device = NULL; pr_info("Removing device %s from group %d\n", dev_name(dev), group->id); @@ -484,7 +651,7 @@ EXPORT_SYMBOL_GPL(iommu_group_remove_device); static int iommu_group_device_count(struct iommu_group *group) { - struct iommu_device *entry; + struct group_device *entry; int ret = 0; list_for_each_entry(entry, &group->devices, list) @@ -507,7 +674,7 @@ static int iommu_group_device_count(struct iommu_group *group) static int __iommu_group_for_each_dev(struct iommu_group *group, void *data, int (*fn)(struct device *, void *)) { - struct iommu_device *device; + struct group_device *device; int ret = 0; list_for_each_entry(device, &group->devices, list) { @@ -1559,20 +1726,38 @@ int iommu_domain_set_attr(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_domain_set_attr); -void iommu_get_dm_regions(struct device *dev, struct list_head *list) +void iommu_get_resv_regions(struct device *dev, struct list_head *list) { const struct iommu_ops *ops = dev->bus->iommu_ops; - if (ops && ops->get_dm_regions) - ops->get_dm_regions(dev, list); + if (ops && ops->get_resv_regions) + ops->get_resv_regions(dev, list); } -void iommu_put_dm_regions(struct device *dev, struct list_head *list) +void iommu_put_resv_regions(struct device *dev, struct list_head *list) { const struct iommu_ops *ops = dev->bus->iommu_ops; - if (ops && ops->put_dm_regions) - ops->put_dm_regions(dev, list); + if (ops && ops->put_resv_regions) + ops->put_resv_regions(dev, list); +} + +struct iommu_resv_region *iommu_alloc_resv_region(phys_addr_t start, + size_t length, + int prot, int type) +{ + struct iommu_resv_region *region; + + region = kzalloc(sizeof(*region), GFP_KERNEL); + if (!region) + return NULL; + + INIT_LIST_HEAD(®ion->list); + region->start = start; + region->length = length; + region->prot = prot; + region->type = type; + return region; } /* Request that a device is direct mapped by the IOMMU */ @@ -1628,43 +1813,18 @@ out: return ret; } -struct iommu_instance { - struct list_head list; - struct fwnode_handle *fwnode; - const struct iommu_ops *ops; -}; -static LIST_HEAD(iommu_instance_list); -static DEFINE_SPINLOCK(iommu_instance_lock); - -void iommu_register_instance(struct fwnode_handle *fwnode, - const struct iommu_ops *ops) +const struct iommu_ops *iommu_ops_from_fwnode(struct fwnode_handle *fwnode) { - struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - - if (WARN_ON(!iommu)) - return; - - of_node_get(to_of_node(fwnode)); - INIT_LIST_HEAD(&iommu->list); - iommu->fwnode = fwnode; - iommu->ops = ops; - spin_lock(&iommu_instance_lock); - list_add_tail(&iommu->list, &iommu_instance_list); - spin_unlock(&iommu_instance_lock); -} - -const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode) -{ - struct iommu_instance *instance; const struct iommu_ops *ops = NULL; + struct iommu_device *iommu; - spin_lock(&iommu_instance_lock); - list_for_each_entry(instance, &iommu_instance_list, list) - if (instance->fwnode == fwnode) { - ops = instance->ops; + spin_lock(&iommu_device_lock); + list_for_each_entry(iommu, &iommu_device_list, list) + if (iommu->fwnode == fwnode) { + ops = iommu->ops; break; } - spin_unlock(&iommu_instance_lock); + spin_unlock(&iommu_device_lock); return ops; } @@ -1714,13 +1874,14 @@ int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids) fwspec = krealloc(dev->iommu_fwspec, size, GFP_KERNEL); if (!fwspec) return -ENOMEM; + + dev->iommu_fwspec = fwspec; } for (i = 0; i < num_ids; i++) fwspec->ids[fwspec->num_ids + i] = ids[i]; fwspec->num_ids += num_ids; - dev->iommu_fwspec = fwspec; return 0; } EXPORT_SYMBOL_GPL(iommu_fwspec_add_ids); diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index 080beca0197d..b7268a14184f 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -62,7 +62,7 @@ __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn) else { struct rb_node *prev_node = rb_prev(iovad->cached32_node); struct iova *curr_iova = - container_of(iovad->cached32_node, struct iova, node); + rb_entry(iovad->cached32_node, struct iova, node); *limit_pfn = curr_iova->pfn_lo - 1; return prev_node; } @@ -86,11 +86,11 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free) if (!iovad->cached32_node) return; curr = iovad->cached32_node; - cached_iova = container_of(curr, struct iova, node); + cached_iova = rb_entry(curr, struct iova, node); if (free->pfn_lo >= cached_iova->pfn_lo) { struct rb_node *node = rb_next(&free->node); - struct iova *iova = container_of(node, struct iova, node); + struct iova *iova = rb_entry(node, struct iova, node); /* only cache if it's below 32bit pfn */ if (node && iova->pfn_lo < iovad->dma_32bit_pfn) @@ -125,7 +125,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain *iovad, curr = __get_cached_rbnode(iovad, &limit_pfn); prev = curr; while (curr) { - struct iova *curr_iova = container_of(curr, struct iova, node); + struct iova *curr_iova = rb_entry(curr, struct iova, node); if (limit_pfn < curr_iova->pfn_lo) goto move_left; @@ -171,8 +171,7 @@ move_left: /* Figure out where to put new node */ while (*entry) { - struct iova *this = container_of(*entry, - struct iova, node); + struct iova *this = rb_entry(*entry, struct iova, node); parent = *entry; if (new->pfn_lo < this->pfn_lo) @@ -201,7 +200,7 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova) struct rb_node **new = &(root->rb_node), *parent = NULL; /* Figure out where to put new node */ while (*new) { - struct iova *this = container_of(*new, struct iova, node); + struct iova *this = rb_entry(*new, struct iova, node); parent = *new; @@ -311,7 +310,7 @@ private_find_iova(struct iova_domain *iovad, unsigned long pfn) assert_spin_locked(&iovad->iova_rbtree_lock); while (node) { - struct iova *iova = container_of(node, struct iova, node); + struct iova *iova = rb_entry(node, struct iova, node); /* If pfn falls within iova's range, return iova */ if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) { @@ -463,7 +462,7 @@ void put_iova_domain(struct iova_domain *iovad) spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); node = rb_first(&iovad->rbroot); while (node) { - struct iova *iova = container_of(node, struct iova, node); + struct iova *iova = rb_entry(node, struct iova, node); rb_erase(node, &iovad->rbroot); free_iova_mem(iova); @@ -477,7 +476,7 @@ static int __is_range_overlap(struct rb_node *node, unsigned long pfn_lo, unsigned long pfn_hi) { - struct iova *iova = container_of(node, struct iova, node); + struct iova *iova = rb_entry(node, struct iova, node); if ((pfn_lo <= iova->pfn_hi) && (pfn_hi >= iova->pfn_lo)) return 1; @@ -541,7 +540,7 @@ reserve_iova(struct iova_domain *iovad, spin_lock_irqsave(&iovad->iova_rbtree_lock, flags); for (node = rb_first(&iovad->rbroot); node; node = rb_next(node)) { if (__is_range_overlap(node, pfn_lo, pfn_hi)) { - iova = container_of(node, struct iova, node); + iova = rb_entry(node, struct iova, node); __adjust_overlap_range(iova, &pfn_lo, &pfn_hi); if ((pfn_lo >= iova->pfn_lo) && (pfn_hi <= iova->pfn_hi)) @@ -578,7 +577,7 @@ copy_reserved_iova(struct iova_domain *from, struct iova_domain *to) spin_lock_irqsave(&from->iova_rbtree_lock, flags); for (node = rb_first(&from->rbroot); node; node = rb_next(node)) { - struct iova *iova = container_of(node, struct iova, node); + struct iova *iova = rb_entry(node, struct iova, node); struct iova *new_iova; new_iova = reserve_iova(to, iova->pfn_lo, iova->pfn_hi); diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index ace331da6459..b7e14ee863f9 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -313,6 +313,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain) domain->cfg.ias = 32; domain->cfg.oas = 40; domain->cfg.tlb = &ipmmu_gather_ops; + domain->io_domain.geometry.aperture_end = DMA_BIT_MASK(32); + domain->io_domain.geometry.force_aperture = true; /* * TODO: Add support for coherent walk through CCI with DVM and remove * cache handling. For now, delegate it to the io-pgtable code. diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index b09692bb5b0a..d0448353d501 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -371,6 +371,58 @@ static int msm_iommu_domain_config(struct msm_priv *priv) return 0; } +/* Must be called under msm_iommu_lock */ +static struct msm_iommu_dev *find_iommu_for_dev(struct device *dev) +{ + struct msm_iommu_dev *iommu, *ret = NULL; + struct msm_iommu_ctx_dev *master; + + list_for_each_entry(iommu, &qcom_iommu_devices, dev_node) { + master = list_first_entry(&iommu->ctx_list, + struct msm_iommu_ctx_dev, + list); + if (master->of_node == dev->of_node) { + ret = iommu; + break; + } + } + + return ret; +} + +static int msm_iommu_add_device(struct device *dev) +{ + struct msm_iommu_dev *iommu; + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&msm_iommu_lock, flags); + + iommu = find_iommu_for_dev(dev); + if (iommu) + iommu_device_link(&iommu->iommu, dev); + else + ret = -ENODEV; + + spin_unlock_irqrestore(&msm_iommu_lock, flags); + + return ret; +} + +static void msm_iommu_remove_device(struct device *dev) +{ + struct msm_iommu_dev *iommu; + unsigned long flags; + + spin_lock_irqsave(&msm_iommu_lock, flags); + + iommu = find_iommu_for_dev(dev); + if (iommu) + iommu_device_unlink(&iommu->iommu, dev); + + spin_unlock_irqrestore(&msm_iommu_lock, flags); +} + static int msm_iommu_attach_dev(struct iommu_domain *domain, struct device *dev) { int ret = 0; @@ -646,6 +698,8 @@ static struct iommu_ops msm_iommu_ops = { .unmap = msm_iommu_unmap, .map_sg = default_iommu_map_sg, .iova_to_phys = msm_iommu_iova_to_phys, + .add_device = msm_iommu_add_device, + .remove_device = msm_iommu_remove_device, .pgsize_bitmap = MSM_IOMMU_PGSIZES, .of_xlate = qcom_iommu_of_xlate, }; @@ -653,6 +707,7 @@ static struct iommu_ops msm_iommu_ops = { static int msm_iommu_probe(struct platform_device *pdev) { struct resource *r; + resource_size_t ioaddr; struct msm_iommu_dev *iommu; int ret, par, val; @@ -696,6 +751,7 @@ static int msm_iommu_probe(struct platform_device *pdev) ret = PTR_ERR(iommu->base); goto fail; } + ioaddr = r->start; iommu->irq = platform_get_irq(pdev, 0); if (iommu->irq < 0) { @@ -737,7 +793,22 @@ static int msm_iommu_probe(struct platform_device *pdev) } list_add(&iommu->dev_node, &qcom_iommu_devices); - of_iommu_set_ops(pdev->dev.of_node, &msm_iommu_ops); + + ret = iommu_device_sysfs_add(&iommu->iommu, iommu->dev, NULL, + "msm-smmu.%pa", &ioaddr); + if (ret) { + pr_err("Could not add msm-smmu at %pa to sysfs\n", &ioaddr); + goto fail; + } + + iommu_device_set_ops(&iommu->iommu, &msm_iommu_ops); + iommu_device_set_fwnode(&iommu->iommu, &pdev->dev.of_node->fwnode); + + ret = iommu_device_register(&iommu->iommu); + if (ret) { + pr_err("Could not register msm-smmu at %pa\n", &ioaddr); + goto fail; + } pr_info("device mapped at %p, irq %d with %d ctx banks\n", iommu->base, iommu->irq, iommu->ncb); diff --git a/drivers/iommu/msm_iommu.h b/drivers/iommu/msm_iommu.h index 4ca25d50d679..ae92d2779c42 100644 --- a/drivers/iommu/msm_iommu.h +++ b/drivers/iommu/msm_iommu.h @@ -19,6 +19,7 @@ #define MSM_IOMMU_H #include <linux/interrupt.h> +#include <linux/iommu.h> #include <linux/clk.h> /* Sharability attributes of MSM IOMMU mappings */ @@ -68,6 +69,8 @@ struct msm_iommu_dev { struct list_head dom_node; struct list_head ctx_list; DECLARE_BITMAP(context_map, IOMMU_MAX_CBS); + + struct iommu_device iommu; }; /** diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 1479c76ece9e..5d14cd15198d 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -360,11 +360,15 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, static int mtk_iommu_add_device(struct device *dev) { + struct mtk_iommu_data *data; struct iommu_group *group; if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return -ENODEV; /* Not a iommu client device */ + data = dev->iommu_fwspec->iommu_priv; + iommu_device_link(&data->iommu, dev); + group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) return PTR_ERR(group); @@ -375,9 +379,14 @@ static int mtk_iommu_add_device(struct device *dev) static void mtk_iommu_remove_device(struct device *dev) { + struct mtk_iommu_data *data; + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return; + data = dev->iommu_fwspec->iommu_priv; + iommu_device_unlink(&data->iommu, dev); + iommu_group_remove_device(dev); iommu_fwspec_free(dev); } @@ -497,6 +506,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) struct mtk_iommu_data *data; struct device *dev = &pdev->dev; struct resource *res; + resource_size_t ioaddr; struct component_match *match = NULL; void *protect; int i, larb_nr, ret; @@ -519,6 +529,7 @@ static int mtk_iommu_probe(struct platform_device *pdev) data->base = devm_ioremap_resource(dev, res); if (IS_ERR(data->base)) return PTR_ERR(data->base); + ioaddr = res->start; data->irq = platform_get_irq(pdev, 0); if (data->irq < 0) @@ -567,6 +578,18 @@ static int mtk_iommu_probe(struct platform_device *pdev) if (ret) return ret; + ret = iommu_device_sysfs_add(&data->iommu, dev, NULL, + "mtk-iommu.%pa", &ioaddr); + if (ret) + return ret; + + iommu_device_set_ops(&data->iommu, &mtk_iommu_ops); + iommu_device_set_fwnode(&data->iommu, &pdev->dev.of_node->fwnode); + + ret = iommu_device_register(&data->iommu); + if (ret) + return ret; + if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &mtk_iommu_ops); @@ -577,6 +600,9 @@ static int mtk_iommu_remove(struct platform_device *pdev) { struct mtk_iommu_data *data = platform_get_drvdata(pdev); + iommu_device_sysfs_remove(&data->iommu); + iommu_device_unregister(&data->iommu); + if (iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, NULL); @@ -655,7 +681,6 @@ static int mtk_iommu_init_fn(struct device_node *np) return ret; } - of_iommu_set_ops(np, &mtk_iommu_ops); return 0; } diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index 50177f738e4e..2a28eadeea0e 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h @@ -47,6 +47,8 @@ struct mtk_iommu_data { struct iommu_group *m4u_group; struct mtk_smi_iommu smi_imu; /* SMI larb iommu info */ bool enable_4GB; + + struct iommu_device iommu; }; static inline int compare_of(struct device *dev, void *data) diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 0f57ddc4ecc2..2683e9fc0dcf 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -127,7 +127,7 @@ static const struct iommu_ops "iommu-map-mask", &iommu_spec.np, iommu_spec.args)) return NULL; - ops = of_iommu_get_ops(iommu_spec.np); + ops = iommu_ops_from_fwnode(&iommu_spec.np->fwnode); if (!ops || !ops->of_xlate || iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) || ops->of_xlate(&pdev->dev, &iommu_spec)) @@ -157,7 +157,7 @@ const struct iommu_ops *of_iommu_configure(struct device *dev, "#iommu-cells", idx, &iommu_spec)) { np = iommu_spec.np; - ops = of_iommu_get_ops(np); + ops = iommu_ops_from_fwnode(&np->fwnode); if (!ops || !ops->of_xlate || iommu_fwspec_init(dev, &np->fwnode, ops) || diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig index ae96731cd2fb..125528f39e92 100644 --- a/drivers/irqchip/Kconfig +++ b/drivers/irqchip/Kconfig @@ -283,3 +283,12 @@ config EZNPS_GIC config STM32_EXTI bool select IRQ_DOMAIN + +config QCOM_IRQ_COMBINER + bool "QCOM IRQ combiner support" + depends on ARCH_QCOM && ACPI + select IRQ_DOMAIN + select IRQ_DOMAIN_HIERARCHY + help + Say yes here to add support for the IRQ combiner devices embedded + in Qualcomm Technologies chips. diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 0e55d94065bf..152bc40b6762 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_ATH79) += irq-ath79-misc.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o +obj-$(CONFIG_ARCH_GEMINI) += irq-gemini.o obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o @@ -75,3 +76,4 @@ obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o +obj-$(CONFIG_QCOM_IRQ_COMBINER) += qcom-irq-combiner.o diff --git a/drivers/irqchip/irq-gemini.c b/drivers/irqchip/irq-gemini.c new file mode 100644 index 000000000000..495224c743ee --- /dev/null +++ b/drivers/irqchip/irq-gemini.c @@ -0,0 +1,185 @@ +/* + * irqchip for the Cortina Systems Gemini Copyright (C) 2017 Linus + * Walleij <linus.walleij@linaro.org> + * + * Based on arch/arm/mach-gemini/irq.c + * Copyright (C) 2001-2006 Storlink, Corp. + * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt> + */ +#include <linux/bitops.h> +#include <linux/irq.h> +#include <linux/io.h> +#include <linux/irqchip.h> +#include <linux/irqchip/versatile-fpga.h> +#include <linux/irqdomain.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/cpu.h> + +#include <asm/exception.h> +#include <asm/mach/irq.h> + +#define GEMINI_NUM_IRQS 32 + +#define GEMINI_IRQ_SOURCE(base_addr) (base_addr + 0x00) +#define GEMINI_IRQ_MASK(base_addr) (base_addr + 0x04) +#define GEMINI_IRQ_CLEAR(base_addr) (base_addr + 0x08) +#define GEMINI_IRQ_MODE(base_addr) (base_addr + 0x0C) +#define GEMINI_IRQ_POLARITY(base_addr) (base_addr + 0x10) +#define GEMINI_IRQ_STATUS(base_addr) (base_addr + 0x14) +#define GEMINI_FIQ_SOURCE(base_addr) (base_addr + 0x20) +#define GEMINI_FIQ_MASK(base_addr) (base_addr + 0x24) +#define GEMINI_FIQ_CLEAR(base_addr) (base_addr + 0x28) +#define GEMINI_FIQ_MODE(base_addr) (base_addr + 0x2C) +#define GEMINI_FIQ_POLARITY(base_addr) (base_addr + 0x30) +#define GEMINI_FIQ_STATUS(base_addr) (base_addr + 0x34) + +/** + * struct gemini_irq_data - irq data container for the Gemini IRQ controller + * @base: memory offset in virtual memory + * @chip: chip container for this instance + * @domain: IRQ domain for this instance + */ +struct gemini_irq_data { + void __iomem *base; + struct irq_chip chip; + struct irq_domain *domain; +}; + +static void gemini_irq_mask(struct irq_data *d) +{ + struct gemini_irq_data *g = irq_data_get_irq_chip_data(d); + unsigned int mask; + + mask = readl(GEMINI_IRQ_MASK(g->base)); + mask &= ~BIT(irqd_to_hwirq(d)); + writel(mask, GEMINI_IRQ_MASK(g->base)); +} + +static void gemini_irq_unmask(struct irq_data *d) +{ + struct gemini_irq_data *g = irq_data_get_irq_chip_data(d); + unsigned int mask; + + mask = readl(GEMINI_IRQ_MASK(g->base)); + mask |= BIT(irqd_to_hwirq(d)); + writel(mask, GEMINI_IRQ_MASK(g->base)); +} + +static void gemini_irq_ack(struct irq_data *d) +{ + struct gemini_irq_data *g = irq_data_get_irq_chip_data(d); + + writel(BIT(irqd_to_hwirq(d)), GEMINI_IRQ_CLEAR(g->base)); +} + +static int gemini_irq_set_type(struct irq_data *d, unsigned int trigger) +{ + struct gemini_irq_data *g = irq_data_get_irq_chip_data(d); + int offset = irqd_to_hwirq(d); + u32 mode, polarity; + + mode = readl(GEMINI_IRQ_MODE(g->base)); + polarity = readl(GEMINI_IRQ_POLARITY(g->base)); + + if (trigger & (IRQ_TYPE_LEVEL_HIGH)) { + irq_set_handler_locked(d, handle_level_irq); + /* Disable edge detection */ + mode &= ~BIT(offset); + polarity &= ~BIT(offset); + } else if (trigger & IRQ_TYPE_EDGE_RISING) { + irq_set_handler_locked(d, handle_edge_irq); + mode |= BIT(offset); + polarity |= BIT(offset); + } else if (trigger & IRQ_TYPE_EDGE_FALLING) { + irq_set_handler_locked(d, handle_edge_irq); + mode |= BIT(offset); + polarity &= ~BIT(offset); + } else { + irq_set_handler_locked(d, handle_bad_irq); + pr_warn("GEMINI IRQ: no supported trigger selected for line %d\n", + offset); + } + + writel(mode, GEMINI_IRQ_MODE(g->base)); + writel(polarity, GEMINI_IRQ_POLARITY(g->base)); + + return 0; +} + +static struct irq_chip gemini_irq_chip = { + .name = "GEMINI", + .irq_ack = gemini_irq_ack, + .irq_mask = gemini_irq_mask, + .irq_unmask = gemini_irq_unmask, + .irq_set_type = gemini_irq_set_type, +}; + +/* Local static for the IRQ entry call */ +static struct gemini_irq_data girq; + +asmlinkage void __exception_irq_entry gemini_irqchip_handle_irq(struct pt_regs *regs) +{ + struct gemini_irq_data *g = &girq; + int irq; + u32 status; + + while ((status = readl(GEMINI_IRQ_STATUS(g->base)))) { + irq = ffs(status) - 1; + handle_domain_irq(g->domain, irq, regs); + } +} + +static int gemini_irqdomain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct gemini_irq_data *g = d->host_data; + + irq_set_chip_data(irq, g); + /* All IRQs should set up their type, flags as bad by default */ + irq_set_chip_and_handler(irq, &gemini_irq_chip, handle_bad_irq); + irq_set_probe(irq); + + return 0; +} + +static void gemini_irqdomain_unmap(struct irq_domain *d, unsigned int irq) +{ + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); +} + +static const struct irq_domain_ops gemini_irqdomain_ops = { + .map = gemini_irqdomain_map, + .unmap = gemini_irqdomain_unmap, + .xlate = irq_domain_xlate_onetwocell, +}; + +int __init gemini_of_init_irq(struct device_node *node, + struct device_node *parent) +{ + struct gemini_irq_data *g = &girq; + + /* + * Disable the idle handler by default since it is buggy + * For more info see arch/arm/mach-gemini/idle.c + */ + cpu_idle_poll_ctrl(true); + + g->base = of_iomap(node, 0); + WARN(!g->base, "unable to map gemini irq registers\n"); + + /* Disable all interrupts */ + writel(0, GEMINI_IRQ_MASK(g->base)); + writel(0, GEMINI_FIQ_MASK(g->base)); + + g->domain = irq_domain_add_simple(node, GEMINI_NUM_IRQS, 0, + &gemini_irqdomain_ops, g); + set_handle_irq(gemini_irqchip_handle_irq); + + return 0; +} +IRQCHIP_DECLARE(gemini, "cortina,gemini-interrupt-controller", + gemini_of_init_irq); diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index 69b040f47d56..23201004fd7a 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -161,7 +161,7 @@ struct its_cmd_desc { struct its_device *dev; u32 phys_id; u32 event_id; - } its_mapvi_cmd; + } its_mapti_cmd; struct { struct its_device *dev; @@ -193,58 +193,56 @@ struct its_cmd_block { typedef struct its_collection *(*its_cmd_builder_t)(struct its_cmd_block *, struct its_cmd_desc *); +static void its_mask_encode(u64 *raw_cmd, u64 val, int h, int l) +{ + u64 mask = GENMASK_ULL(h, l); + *raw_cmd &= ~mask; + *raw_cmd |= (val << l) & mask; +} + static void its_encode_cmd(struct its_cmd_block *cmd, u8 cmd_nr) { - cmd->raw_cmd[0] &= ~0xffULL; - cmd->raw_cmd[0] |= cmd_nr; + its_mask_encode(&cmd->raw_cmd[0], cmd_nr, 7, 0); } static void its_encode_devid(struct its_cmd_block *cmd, u32 devid) { - cmd->raw_cmd[0] &= BIT_ULL(32) - 1; - cmd->raw_cmd[0] |= ((u64)devid) << 32; + its_mask_encode(&cmd->raw_cmd[0], devid, 63, 32); } static void its_encode_event_id(struct its_cmd_block *cmd, u32 id) { - cmd->raw_cmd[1] &= ~0xffffffffULL; - cmd->raw_cmd[1] |= id; + its_mask_encode(&cmd->raw_cmd[1], id, 31, 0); } static void its_encode_phys_id(struct its_cmd_block *cmd, u32 phys_id) { - cmd->raw_cmd[1] &= 0xffffffffULL; - cmd->raw_cmd[1] |= ((u64)phys_id) << 32; + its_mask_encode(&cmd->raw_cmd[1], phys_id, 63, 32); } static void its_encode_size(struct its_cmd_block *cmd, u8 size) { - cmd->raw_cmd[1] &= ~0x1fULL; - cmd->raw_cmd[1] |= size & 0x1f; + its_mask_encode(&cmd->raw_cmd[1], size, 4, 0); } static void its_encode_itt(struct its_cmd_block *cmd, u64 itt_addr) { - cmd->raw_cmd[2] &= ~0xffffffffffffULL; - cmd->raw_cmd[2] |= itt_addr & 0xffffffffff00ULL; + its_mask_encode(&cmd->raw_cmd[2], itt_addr >> 8, 50, 8); } static void its_encode_valid(struct its_cmd_block *cmd, int valid) { - cmd->raw_cmd[2] &= ~(1ULL << 63); - cmd->raw_cmd[2] |= ((u64)!!valid) << 63; + its_mask_encode(&cmd->raw_cmd[2], !!valid, 63, 63); } static void its_encode_target(struct its_cmd_block *cmd, u64 target_addr) { - cmd->raw_cmd[2] &= ~(0xffffffffULL << 16); - cmd->raw_cmd[2] |= (target_addr & (0xffffffffULL << 16)); + its_mask_encode(&cmd->raw_cmd[2], target_addr >> 16, 50, 16); } static void its_encode_collection(struct its_cmd_block *cmd, u16 col) { - cmd->raw_cmd[2] &= ~0xffffULL; - cmd->raw_cmd[2] |= col; + its_mask_encode(&cmd->raw_cmd[2], col, 15, 0); } static inline void its_fixup_cmd(struct its_cmd_block *cmd) @@ -289,18 +287,18 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd, return desc->its_mapc_cmd.col; } -static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd, +static struct its_collection *its_build_mapti_cmd(struct its_cmd_block *cmd, struct its_cmd_desc *desc) { struct its_collection *col; - col = dev_event_to_col(desc->its_mapvi_cmd.dev, - desc->its_mapvi_cmd.event_id); + col = dev_event_to_col(desc->its_mapti_cmd.dev, + desc->its_mapti_cmd.event_id); - its_encode_cmd(cmd, GITS_CMD_MAPVI); - its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id); - its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id); - its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id); + its_encode_cmd(cmd, GITS_CMD_MAPTI); + its_encode_devid(cmd, desc->its_mapti_cmd.dev->device_id); + its_encode_event_id(cmd, desc->its_mapti_cmd.event_id); + its_encode_phys_id(cmd, desc->its_mapti_cmd.phys_id); its_encode_collection(cmd, col->col_id); its_fixup_cmd(cmd); @@ -413,6 +411,12 @@ static struct its_cmd_block *its_allocate_entry(struct its_node *its) if (its->cmd_write == (its->cmd_base + ITS_CMD_QUEUE_NR_ENTRIES)) its->cmd_write = its->cmd_base; + /* Clear command */ + cmd->raw_cmd[0] = 0; + cmd->raw_cmd[1] = 0; + cmd->raw_cmd[2] = 0; + cmd->raw_cmd[3] = 0; + return cmd; } @@ -531,15 +535,15 @@ static void its_send_mapc(struct its_node *its, struct its_collection *col, its_send_single_command(its, its_build_mapc_cmd, &desc); } -static void its_send_mapvi(struct its_device *dev, u32 irq_id, u32 id) +static void its_send_mapti(struct its_device *dev, u32 irq_id, u32 id) { struct its_cmd_desc desc; - desc.its_mapvi_cmd.dev = dev; - desc.its_mapvi_cmd.phys_id = irq_id; - desc.its_mapvi_cmd.event_id = id; + desc.its_mapti_cmd.dev = dev; + desc.its_mapti_cmd.phys_id = irq_id; + desc.its_mapti_cmd.event_id = id; - its_send_single_command(dev->its, its_build_mapvi_cmd, &desc); + its_send_single_command(dev->its, its_build_mapti_cmd, &desc); } static void its_send_movi(struct its_device *dev, @@ -824,7 +828,7 @@ static int __init its_alloc_lpi_tables(void) static const char *its_base_type_string[] = { [GITS_BASER_TYPE_DEVICE] = "Devices", [GITS_BASER_TYPE_VCPU] = "Virtual CPUs", - [GITS_BASER_TYPE_CPU] = "Physical CPUs", + [GITS_BASER_TYPE_RESERVED3] = "Reserved (3)", [GITS_BASER_TYPE_COLLECTION] = "Interrupt Collections", [GITS_BASER_TYPE_RESERVED5] = "Reserved (5)", [GITS_BASER_TYPE_RESERVED6] = "Reserved (6)", @@ -960,7 +964,7 @@ static bool its_parse_baser_device(struct its_node *its, struct its_baser *baser u32 psz, u32 *order) { u64 esz = GITS_BASER_ENTRY_SIZE(its_read_baser(its, baser)); - u64 val = GITS_BASER_InnerShareable | GITS_BASER_WaWb; + u64 val = GITS_BASER_InnerShareable | GITS_BASER_RaWaWb; u32 ids = its->device_ids; u32 new_order = *order; bool indirect = false; @@ -1025,7 +1029,7 @@ static int its_alloc_tables(struct its_node *its) u64 typer = gic_read_typer(its->base + GITS_TYPER); u32 ids = GITS_TYPER_DEVBITS(typer); u64 shr = GITS_BASER_InnerShareable; - u64 cache = GITS_BASER_WaWb; + u64 cache = GITS_BASER_RaWaWb; u32 psz = SZ_64K; int err, i; @@ -1122,7 +1126,7 @@ static void its_cpu_init_lpis(void) /* set PROPBASE */ val = (page_to_phys(gic_rdists->prop_page) | GICR_PROPBASER_InnerShareable | - GICR_PROPBASER_WaWb | + GICR_PROPBASER_RaWaWb | ((LPI_NRBITS - 1) & GICR_PROPBASER_IDBITS_MASK)); gicr_write_propbaser(val, rbase + GICR_PROPBASER); @@ -1147,7 +1151,7 @@ static void its_cpu_init_lpis(void) /* set PENDBASE */ val = (page_to_phys(pend_page) | GICR_PENDBASER_InnerShareable | - GICR_PENDBASER_WaWb); + GICR_PENDBASER_RaWaWb); gicr_write_pendbaser(val, rbase + GICR_PENDBASER); tmp = gicr_read_pendbaser(rbase + GICR_PENDBASER); @@ -1498,7 +1502,7 @@ static void its_irq_domain_activate(struct irq_domain *domain, its_dev->event_map.col_map[event] = cpumask_first(cpu_mask); /* Map the GIC IRQ and event to the device */ - its_send_mapvi(its_dev, d->hwirq, event); + its_send_mapti(its_dev, d->hwirq, event); } static void its_irq_domain_deactivate(struct irq_domain *domain, @@ -1642,6 +1646,7 @@ static int its_init_domain(struct fwnode_handle *handle, struct its_node *its) inner_domain->parent = its_parent; inner_domain->bus_token = DOMAIN_BUS_NEXUS; + inner_domain->flags |= IRQ_DOMAIN_FLAG_MSI_REMAP; info->ops = &its_msi_domain_ops; info->data = its; inner_domain->host_data = info; @@ -1693,7 +1698,8 @@ static int __init its_probe_one(struct resource *res, its->ite_size = ((gic_read_typer(its_base + GITS_TYPER) >> 4) & 0xf) + 1; its->numa_node = numa_node; - its->cmd_base = kzalloc(ITS_CMD_QUEUE_SZ, GFP_KERNEL); + its->cmd_base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + get_order(ITS_CMD_QUEUE_SZ)); if (!its->cmd_base) { err = -ENOMEM; goto out_free_its; @@ -1711,7 +1717,7 @@ static int __init its_probe_one(struct resource *res, goto out_free_tables; baser = (virt_to_phys(its->cmd_base) | - GITS_CBASER_WaWb | + GITS_CBASER_RaWaWb | GITS_CBASER_InnerShareable | (ITS_CMD_QUEUE_SZ / SZ_4K - 1) | GITS_CBASER_VALID); @@ -1751,7 +1757,7 @@ static int __init its_probe_one(struct resource *res, out_free_tables: its_free_tables(its); out_free_cmd: - kfree(its->cmd_base); + free_pages((unsigned long)its->cmd_base, get_order(ITS_CMD_QUEUE_SZ)); out_free_its: kfree(its); out_unmap: diff --git a/drivers/irqchip/irq-keystone.c b/drivers/irqchip/irq-keystone.c index 54a5e870a8f5..efbcf8435185 100644 --- a/drivers/irqchip/irq-keystone.c +++ b/drivers/irqchip/irq-keystone.c @@ -19,9 +19,9 @@ #include <linux/bitops.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/interrupt.h> #include <linux/irqdomain.h> #include <linux/irqchip.h> -#include <linux/irqchip/chained_irq.h> #include <linux/of.h> #include <linux/of_platform.h> #include <linux/mfd/syscon.h> @@ -39,6 +39,7 @@ struct keystone_irq_device { struct irq_domain *irqd; struct regmap *devctrl_regs; u32 devctrl_offset; + raw_spinlock_t wa_lock; }; static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq) @@ -83,17 +84,15 @@ static void keystone_irq_ack(struct irq_data *d) /* nothing to do here */ } -static void keystone_irq_handler(struct irq_desc *desc) +static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq) { - unsigned int irq = irq_desc_get_irq(desc); - struct keystone_irq_device *kirq = irq_desc_get_handler_data(desc); + struct keystone_irq_device *kirq = keystone_irq; + unsigned long wa_lock_flags; unsigned long pending; int src, virq; dev_dbg(kirq->dev, "start irq %d\n", irq); - chained_irq_enter(irq_desc_get_chip(desc), desc); - pending = keystone_irq_readl(kirq); keystone_irq_writel(kirq, pending); @@ -111,13 +110,15 @@ static void keystone_irq_handler(struct irq_desc *desc) if (!virq) dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n", src, virq); + raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags); generic_handle_irq(virq); + raw_spin_unlock_irqrestore(&kirq->wa_lock, + wa_lock_flags); } } - chained_irq_exit(irq_desc_get_chip(desc), desc); - dev_dbg(kirq->dev, "end irq %d\n", irq); + return IRQ_HANDLED; } static int keystone_irq_map(struct irq_domain *h, unsigned int virq, @@ -182,9 +183,16 @@ static int keystone_irq_probe(struct platform_device *pdev) return -ENODEV; } + raw_spin_lock_init(&kirq->wa_lock); + platform_set_drvdata(pdev, kirq); - irq_set_chained_handler_and_data(kirq->irq, keystone_irq_handler, kirq); + ret = request_irq(kirq->irq, keystone_irq_handler, + 0, dev_name(dev), kirq); + if (ret) { + irq_domain_remove(kirq->irqd); + return ret; + } /* clear all source bits */ keystone_irq_writel(kirq, ~0x0); @@ -199,6 +207,8 @@ static int keystone_irq_remove(struct platform_device *pdev) struct keystone_irq_device *kirq = platform_get_drvdata(pdev); int hwirq; + free_irq(kirq->irq, kirq); + for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++) irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq)); diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index c01c09e9916d..11d12bccc4e7 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -968,6 +968,34 @@ static struct irq_domain_ops gic_ipi_domain_ops = { .match = gic_ipi_domain_match, }; +static void __init gic_map_single_int(struct device_node *node, + unsigned int irq) +{ + unsigned int linux_irq; + struct irq_fwspec local_int_fwspec = { + .fwnode = &node->fwnode, + .param_count = 3, + .param = { + [0] = GIC_LOCAL, + [1] = irq, + [2] = IRQ_TYPE_NONE, + }, + }; + + if (!gic_local_irq_is_routable(irq)) + return; + + linux_irq = irq_create_fwspec_mapping(&local_int_fwspec); + WARN_ON(!linux_irq); +} + +static void __init gic_map_interrupts(struct device_node *node) +{ + gic_map_single_int(node, GIC_LOCAL_INT_TIMER); + gic_map_single_int(node, GIC_LOCAL_INT_PERFCTR); + gic_map_single_int(node, GIC_LOCAL_INT_FDC); +} + static void __init __gic_init(unsigned long gic_base_addr, unsigned long gic_addrspace_size, unsigned int cpu_vec, unsigned int irqbase, @@ -1067,6 +1095,7 @@ static void __init __gic_init(unsigned long gic_base_addr, } gic_basic_init(); + gic_map_interrupts(node); } void __init gic_init(unsigned long gic_base_addr, diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c index 17304705f2cf..05fa9f7af53c 100644 --- a/drivers/irqchip/irq-mxs.c +++ b/drivers/irqchip/irq-mxs.c @@ -131,12 +131,16 @@ static struct irq_chip mxs_icoll_chip = { .irq_ack = icoll_ack_irq, .irq_mask = icoll_mask_irq, .irq_unmask = icoll_unmask_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, }; static struct irq_chip asm9260_icoll_chip = { .irq_ack = icoll_ack_irq, .irq_mask = asm9260_mask_irq, .irq_unmask = asm9260_unmask_irq, + .flags = IRQCHIP_MASK_ON_SUSPEND | + IRQCHIP_SKIP_SET_WAKE, }; asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs) diff --git a/drivers/irqchip/qcom-irq-combiner.c b/drivers/irqchip/qcom-irq-combiner.c new file mode 100644 index 000000000000..226558698344 --- /dev/null +++ b/drivers/irqchip/qcom-irq-combiner.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver for interrupt combiners in the Top-level Control and Status + * Registers (TCSR) hardware block in Qualcomm Technologies chips. + * An interrupt combiner in this block combines a set of interrupts by + * OR'ing the individual interrupt signals into a summary interrupt + * signal routed to a parent interrupt controller, and provides read- + * only, 32-bit registers to query the status of individual interrupts. + * The status bit for IRQ n is bit (n % 32) within register (n / 32) + * of the given combiner. Thus, each combiner can be described as a set + * of register offsets and the number of IRQs managed. + */ + +#define pr_fmt(fmt) "QCOM80B1:" fmt + +#include <linux/acpi.h> +#include <linux/irqchip/chained_irq.h> +#include <linux/irqdomain.h> +#include <linux/platform_device.h> + +#define REG_SIZE 32 + +struct combiner_reg { + void __iomem *addr; + unsigned long enabled; +}; + +struct combiner { + struct irq_domain *domain; + int parent_irq; + u32 nirqs; + u32 nregs; + struct combiner_reg regs[0]; +}; + +static inline int irq_nr(u32 reg, u32 bit) +{ + return reg * REG_SIZE + bit; +} + +/* + * Handler for the cascaded IRQ. + */ +static void combiner_handle_irq(struct irq_desc *desc) +{ + struct combiner *combiner = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); + u32 reg; + + chained_irq_enter(chip, desc); + + for (reg = 0; reg < combiner->nregs; reg++) { + int virq; + int hwirq; + u32 bit; + u32 status; + + bit = readl_relaxed(combiner->regs[reg].addr); + status = bit & combiner->regs[reg].enabled; + if (!status) + pr_warn_ratelimited("Unexpected IRQ on CPU%d: (%08x %08lx %p)\n", + smp_processor_id(), bit, + combiner->regs[reg].enabled, + combiner->regs[reg].addr); + + while (status) { + bit = __ffs(status); + status &= ~(1 << bit); + hwirq = irq_nr(reg, bit); + virq = irq_find_mapping(combiner->domain, hwirq); + if (virq > 0) + generic_handle_irq(virq); + + } + } + + chained_irq_exit(chip, desc); +} + +static void combiner_irq_chip_mask_irq(struct irq_data *data) +{ + struct combiner *combiner = irq_data_get_irq_chip_data(data); + struct combiner_reg *reg = combiner->regs + data->hwirq / REG_SIZE; + + clear_bit(data->hwirq % REG_SIZE, ®->enabled); +} + +static void combiner_irq_chip_unmask_irq(struct irq_data *data) +{ + struct combiner *combiner = irq_data_get_irq_chip_data(data); + struct combiner_reg *reg = combiner->regs + data->hwirq / REG_SIZE; + + set_bit(data->hwirq % REG_SIZE, ®->enabled); +} + +static struct irq_chip irq_chip = { + .irq_mask = combiner_irq_chip_mask_irq, + .irq_unmask = combiner_irq_chip_unmask_irq, + .name = "qcom-irq-combiner" +}; + +static int combiner_irq_map(struct irq_domain *domain, unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_and_handler(irq, &irq_chip, handle_level_irq); + irq_set_chip_data(irq, domain->host_data); + irq_set_noprobe(irq); + return 0; +} + +static void combiner_irq_unmap(struct irq_domain *domain, unsigned int irq) +{ + irq_domain_reset_irq_data(irq_get_irq_data(irq)); +} + +static int combiner_irq_translate(struct irq_domain *d, struct irq_fwspec *fws, + unsigned long *hwirq, unsigned int *type) +{ + struct combiner *combiner = d->host_data; + + if (is_acpi_node(fws->fwnode)) { + if (WARN_ON((fws->param_count != 2) || + (fws->param[0] >= combiner->nirqs) || + (fws->param[1] & IORESOURCE_IRQ_LOWEDGE) || + (fws->param[1] & IORESOURCE_IRQ_HIGHEDGE))) + return -EINVAL; + + *hwirq = fws->param[0]; + *type = fws->param[1]; + return 0; + } + + return -EINVAL; +} + +static const struct irq_domain_ops domain_ops = { + .map = combiner_irq_map, + .unmap = combiner_irq_unmap, + .translate = combiner_irq_translate +}; + +static acpi_status count_registers_cb(struct acpi_resource *ares, void *context) +{ + int *count = context; + + if (ares->type == ACPI_RESOURCE_TYPE_GENERIC_REGISTER) + ++(*count); + return AE_OK; +} + +static int count_registers(struct platform_device *pdev) +{ + acpi_handle ahandle = ACPI_HANDLE(&pdev->dev); + acpi_status status; + int count = 0; + + if (!acpi_has_method(ahandle, METHOD_NAME__CRS)) + return -EINVAL; + + status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, + count_registers_cb, &count); + if (ACPI_FAILURE(status)) + return -EINVAL; + return count; +} + +struct get_registers_context { + struct device *dev; + struct combiner *combiner; + int err; +}; + +static acpi_status get_registers_cb(struct acpi_resource *ares, void *context) +{ + struct get_registers_context *ctx = context; + struct acpi_resource_generic_register *reg; + phys_addr_t paddr; + void __iomem *vaddr; + + if (ares->type != ACPI_RESOURCE_TYPE_GENERIC_REGISTER) + return AE_OK; + + reg = &ares->data.generic_reg; + paddr = reg->address; + if ((reg->space_id != ACPI_SPACE_MEM) || + (reg->bit_offset != 0) || + (reg->bit_width > REG_SIZE)) { + dev_err(ctx->dev, "Bad register resource @%pa\n", &paddr); + ctx->err = -EINVAL; + return AE_ERROR; + } + + vaddr = devm_ioremap(ctx->dev, reg->address, REG_SIZE); + if (!vaddr) { + dev_err(ctx->dev, "Can't map register @%pa\n", &paddr); + ctx->err = -ENOMEM; + return AE_ERROR; + } + + ctx->combiner->regs[ctx->combiner->nregs].addr = vaddr; + ctx->combiner->nirqs += reg->bit_width; + ctx->combiner->nregs++; + return AE_OK; +} + +static int get_registers(struct platform_device *pdev, struct combiner *comb) +{ + acpi_handle ahandle = ACPI_HANDLE(&pdev->dev); + acpi_status status; + struct get_registers_context ctx; + + if (!acpi_has_method(ahandle, METHOD_NAME__CRS)) + return -EINVAL; + + ctx.dev = &pdev->dev; + ctx.combiner = comb; + ctx.err = 0; + + status = acpi_walk_resources(ahandle, METHOD_NAME__CRS, + get_registers_cb, &ctx); + if (ACPI_FAILURE(status)) + return ctx.err; + return 0; +} + +static int __init combiner_probe(struct platform_device *pdev) +{ + struct combiner *combiner; + size_t alloc_sz; + u32 nregs; + int err; + + nregs = count_registers(pdev); + if (nregs <= 0) { + dev_err(&pdev->dev, "Error reading register resources\n"); + return -EINVAL; + } + + alloc_sz = sizeof(*combiner) + sizeof(struct combiner_reg) * nregs; + combiner = devm_kzalloc(&pdev->dev, alloc_sz, GFP_KERNEL); + if (!combiner) + return -ENOMEM; + + err = get_registers(pdev, combiner); + if (err < 0) + return err; + + combiner->parent_irq = platform_get_irq(pdev, 0); + if (combiner->parent_irq <= 0) { + dev_err(&pdev->dev, "Error getting IRQ resource\n"); + return -EPROBE_DEFER; + } + + combiner->domain = irq_domain_create_linear(pdev->dev.fwnode, combiner->nirqs, + &domain_ops, combiner); + if (!combiner->domain) + /* Errors printed by irq_domain_create_linear */ + return -ENODEV; + + irq_set_chained_handler_and_data(combiner->parent_irq, + combiner_handle_irq, combiner); + + dev_info(&pdev->dev, "Initialized with [p=%d,n=%d,r=%p]\n", + combiner->parent_irq, combiner->nirqs, combiner->regs[0].addr); + return 0; +} + +static const struct acpi_device_id qcom_irq_combiner_ids[] = { + { "QCOM80B1", }, + { } +}; + +static struct platform_driver qcom_irq_combiner_probe = { + .driver = { + .name = "qcom-irq-combiner", + .acpi_match_table = ACPI_PTR(qcom_irq_combiner_ids), + }, + .probe = combiner_probe, +}; + +static int __init register_qcom_irq_combiner(void) +{ + return platform_driver_register(&qcom_irq_combiner_probe); +} +device_initcall(register_qcom_irq_combiner); diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 1a1d99704fe6..296f1411fe84 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -11297,7 +11297,8 @@ static void mixer_notify_update(PLCI *plci, byte others) ((CAPI_MSG *) msg)->header.ncci = 0; ((CAPI_MSG *) msg)->info.facility_req.Selector = SELECTOR_LINE_INTERCONNECT; ((CAPI_MSG *) msg)->info.facility_req.structs[0] = 3; - PUT_WORD(&(((CAPI_MSG *) msg)->info.facility_req.structs[1]), LI_REQ_SILENT_UPDATE); + ((CAPI_MSG *) msg)->info.facility_req.structs[1] = LI_REQ_SILENT_UPDATE & 0xff; + ((CAPI_MSG *) msg)->info.facility_req.structs[2] = LI_REQ_SILENT_UPDATE >> 8; ((CAPI_MSG *) msg)->info.facility_req.structs[3] = 0; w = api_put(notify_plci->appl, (CAPI_MSG *) msg); if (w != _QUEUE_FULL) diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 9cb4b621fbc3..b324474c0c12 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -203,7 +203,7 @@ mISDNStackd(void *data) { struct mISDNstack *st = data; #ifdef MISDN_MSG_STATS - cputime_t utime, stime; + u64 utime, stime; #endif int err = 0; @@ -308,7 +308,7 @@ mISDNStackd(void *data) st->stopped_cnt); task_cputime(st->thread, &utime, &stime); printk(KERN_DEBUG - "mISDNStackd daemon for %s utime(%ld) stime(%ld)\n", + "mISDNStackd daemon for %s utime(%llu) stime(%llu)\n", dev_name(&st->dev->dev), utime, stime); printk(KERN_DEBUG "mISDNStackd daemon for %s nvcsw(%ld) nivcsw(%ld)\n", diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index c621cbbb5768..275f467956ee 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -29,6 +29,15 @@ config LEDS_CLASS_FLASH for the flash related features of a LED device. It can be built as a module. +config LEDS_BRIGHTNESS_HW_CHANGED + bool "LED Class brightness_hw_changed attribute support" + depends on LEDS_CLASS + help + This option enables support for the brightness_hw_changed attribute + for led sysfs class devices under /sys/class/leds. + + See Documentation/ABI/testing/sysfs-class-led for details. + comment "LED drivers" config LEDS_88PM860X diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 326ee6e925a2..f2b0a80a62b4 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -103,6 +103,68 @@ static const struct attribute_group *led_groups[] = { NULL, }; +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED +static ssize_t brightness_hw_changed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + + if (led_cdev->brightness_hw_changed == -1) + return -ENODATA; + + return sprintf(buf, "%u\n", led_cdev->brightness_hw_changed); +} + +static DEVICE_ATTR_RO(brightness_hw_changed); + +static int led_add_brightness_hw_changed(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev; + int ret; + + ret = device_create_file(dev, &dev_attr_brightness_hw_changed); + if (ret) { + dev_err(dev, "Error creating brightness_hw_changed\n"); + return ret; + } + + led_cdev->brightness_hw_changed_kn = + sysfs_get_dirent(dev->kobj.sd, "brightness_hw_changed"); + if (!led_cdev->brightness_hw_changed_kn) { + dev_err(dev, "Error getting brightness_hw_changed kn\n"); + device_remove_file(dev, &dev_attr_brightness_hw_changed); + return -ENXIO; + } + + return 0; +} + +static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev) +{ + sysfs_put(led_cdev->brightness_hw_changed_kn); + device_remove_file(led_cdev->dev, &dev_attr_brightness_hw_changed); +} + +void led_classdev_notify_brightness_hw_changed(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + if (WARN_ON(!led_cdev->brightness_hw_changed_kn)) + return; + + led_cdev->brightness_hw_changed = brightness; + sysfs_notify_dirent(led_cdev->brightness_hw_changed_kn); +} +EXPORT_SYMBOL_GPL(led_classdev_notify_brightness_hw_changed); +#else +static int led_add_brightness_hw_changed(struct led_classdev *led_cdev) +{ + return 0; +} +static void led_remove_brightness_hw_changed(struct led_classdev *led_cdev) +{ +} +#endif + /** * led_classdev_suspend - suspend an led_classdev. * @led_cdev: the led_classdev to suspend. @@ -204,10 +266,21 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) dev_warn(parent, "Led %s renamed to %s due to name collision", led_cdev->name, dev_name(led_cdev->dev)); + if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) { + ret = led_add_brightness_hw_changed(led_cdev); + if (ret) { + device_unregister(led_cdev->dev); + return ret; + } + } + led_cdev->work_flags = 0; #ifdef CONFIG_LEDS_TRIGGERS init_rwsem(&led_cdev->trigger_lock); #endif +#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED + led_cdev->brightness_hw_changed = -1; +#endif mutex_init(&led_cdev->led_access); /* add to the list of leds */ down_write(&leds_list_lock); @@ -256,6 +329,9 @@ void led_classdev_unregister(struct led_classdev *led_cdev) flush_work(&led_cdev->set_brightness_work); + if (led_cdev->flags & LED_BRIGHT_HW_CHANGED) + led_remove_brightness_hw_changed(led_cdev); + device_unregister(led_cdev->dev); down_write(&leds_list_lock); diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c index bf23ba191ad0..45296aaca9da 100644 --- a/drivers/leds/leds-ktd2692.c +++ b/drivers/leds/leds-ktd2692.c @@ -270,15 +270,15 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev, return -ENXIO; led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS); - if (IS_ERR(led->ctrl_gpio)) { - ret = PTR_ERR(led->ctrl_gpio); + ret = PTR_ERR_OR_ZERO(led->ctrl_gpio); + if (ret) { dev_err(dev, "cannot get ctrl-gpios %d\n", ret); return ret; } led->aux_gpio = devm_gpiod_get(dev, "aux", GPIOD_ASIS); - if (IS_ERR(led->aux_gpio)) { - ret = PTR_ERR(led->aux_gpio); + ret = PTR_ERR_OR_ZERO(led->aux_gpio); + if (ret) { dev_err(dev, "cannot get aux-gpios %d\n", ret); return ret; } diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c index c9f386213e9e..e6f2f8b9f09a 100644 --- a/drivers/leds/trigger/ledtrig-heartbeat.c +++ b/drivers/leds/trigger/ledtrig-heartbeat.c @@ -43,6 +43,9 @@ static void led_heartbeat_function(unsigned long data) return; } + if (test_and_clear_bit(LED_BLINK_BRIGHTNESS_CHANGE, &led_cdev->work_flags)) + led_cdev->blink_brightness = led_cdev->new_blink_brightness; + /* acts like an actual heart beat -- ie thump-thump-pause... */ switch (heartbeat_data->phase) { case 0: @@ -59,26 +62,26 @@ static void led_heartbeat_function(unsigned long data) delay = msecs_to_jiffies(70); heartbeat_data->phase++; if (!heartbeat_data->invert) - brightness = led_cdev->max_brightness; + brightness = led_cdev->blink_brightness; break; case 1: delay = heartbeat_data->period / 4 - msecs_to_jiffies(70); heartbeat_data->phase++; if (heartbeat_data->invert) - brightness = led_cdev->max_brightness; + brightness = led_cdev->blink_brightness; break; case 2: delay = msecs_to_jiffies(70); heartbeat_data->phase++; if (!heartbeat_data->invert) - brightness = led_cdev->max_brightness; + brightness = led_cdev->blink_brightness; break; default: delay = heartbeat_data->period - heartbeat_data->period / 4 - msecs_to_jiffies(70); heartbeat_data->phase = 0; if (heartbeat_data->invert) - brightness = led_cdev->max_brightness; + brightness = led_cdev->blink_brightness; break; } @@ -133,7 +136,10 @@ static void heartbeat_trig_activate(struct led_classdev *led_cdev) setup_timer(&heartbeat_data->timer, led_heartbeat_function, (unsigned long) led_cdev); heartbeat_data->phase = 0; + if (!led_cdev->blink_brightness) + led_cdev->blink_brightness = led_cdev->max_brightness; led_heartbeat_function(heartbeat_data->timer.data); + set_bit(LED_BLINK_SW, &led_cdev->work_flags); led_cdev->activated = true; } @@ -145,6 +151,7 @@ static void heartbeat_trig_deactivate(struct led_classdev *led_cdev) del_timer_sync(&heartbeat_data->timer); device_remove_file(led_cdev->dev, &dev_attr_invert); kfree(heartbeat_data); + clear_bit(LED_BLINK_SW, &led_cdev->work_flags); led_cdev->activated = false; } } diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig index 2f5d5f4a4c75..052714106b7b 100644 --- a/drivers/lightnvm/Kconfig +++ b/drivers/lightnvm/Kconfig @@ -26,15 +26,6 @@ config NVM_DEBUG It is required to create/remove targets without IOCTLs. -config NVM_GENNVM - tristate "General Non-Volatile Memory Manager for Open-Channel SSDs" - ---help--- - Non-volatile memory media manager for Open-Channel SSDs that implements - physical media metadata management and block provisioning API. - - This is the standard media manager for using Open-Channel SSDs, and - required for targets to be instantiated. - config NVM_RRPC tristate "Round-robin Hybrid Open-Channel SSD target" ---help--- diff --git a/drivers/lightnvm/Makefile b/drivers/lightnvm/Makefile index a7a0a22cf1a5..b2a39e2d2895 100644 --- a/drivers/lightnvm/Makefile +++ b/drivers/lightnvm/Makefile @@ -2,6 +2,5 @@ # Makefile for Open-Channel SSDs. # -obj-$(CONFIG_NVM) := core.o sysblk.o -obj-$(CONFIG_NVM_GENNVM) += gennvm.o +obj-$(CONFIG_NVM) := core.o obj-$(CONFIG_NVM_RRPC) += rrpc.o diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index 02240a0b39c9..5262ba66a7a7 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -29,10 +29,483 @@ static LIST_HEAD(nvm_tgt_types); static DECLARE_RWSEM(nvm_tgtt_lock); -static LIST_HEAD(nvm_mgrs); static LIST_HEAD(nvm_devices); static DECLARE_RWSEM(nvm_lock); +/* Map between virtual and physical channel and lun */ +struct nvm_ch_map { + int ch_off; + int nr_luns; + int *lun_offs; +}; + +struct nvm_dev_map { + struct nvm_ch_map *chnls; + int nr_chnls; +}; + +struct nvm_area { + struct list_head list; + sector_t begin; + sector_t end; /* end is excluded */ +}; + +static struct nvm_target *nvm_find_target(struct nvm_dev *dev, const char *name) +{ + struct nvm_target *tgt; + + list_for_each_entry(tgt, &dev->targets, list) + if (!strcmp(name, tgt->disk->disk_name)) + return tgt; + + return NULL; +} + +static int nvm_reserve_luns(struct nvm_dev *dev, int lun_begin, int lun_end) +{ + int i; + + for (i = lun_begin; i <= lun_end; i++) { + if (test_and_set_bit(i, dev->lun_map)) { + pr_err("nvm: lun %d already allocated\n", i); + goto err; + } + } + + return 0; +err: + while (--i > lun_begin) + clear_bit(i, dev->lun_map); + + return -EBUSY; +} + +static void nvm_release_luns_err(struct nvm_dev *dev, int lun_begin, + int lun_end) +{ + int i; + + for (i = lun_begin; i <= lun_end; i++) + WARN_ON(!test_and_clear_bit(i, dev->lun_map)); +} + +static void nvm_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev) +{ + struct nvm_dev *dev = tgt_dev->parent; + struct nvm_dev_map *dev_map = tgt_dev->map; + int i, j; + + for (i = 0; i < dev_map->nr_chnls; i++) { + struct nvm_ch_map *ch_map = &dev_map->chnls[i]; + int *lun_offs = ch_map->lun_offs; + int ch = i + ch_map->ch_off; + + for (j = 0; j < ch_map->nr_luns; j++) { + int lun = j + lun_offs[j]; + int lunid = (ch * dev->geo.luns_per_chnl) + lun; + + WARN_ON(!test_and_clear_bit(lunid, dev->lun_map)); + } + + kfree(ch_map->lun_offs); + } + + kfree(dev_map->chnls); + kfree(dev_map); + + kfree(tgt_dev->luns); + kfree(tgt_dev); +} + +static struct nvm_tgt_dev *nvm_create_tgt_dev(struct nvm_dev *dev, + int lun_begin, int lun_end) +{ + struct nvm_tgt_dev *tgt_dev = NULL; + struct nvm_dev_map *dev_rmap = dev->rmap; + struct nvm_dev_map *dev_map; + struct ppa_addr *luns; + int nr_luns = lun_end - lun_begin + 1; + int luns_left = nr_luns; + int nr_chnls = nr_luns / dev->geo.luns_per_chnl; + int nr_chnls_mod = nr_luns % dev->geo.luns_per_chnl; + int bch = lun_begin / dev->geo.luns_per_chnl; + int blun = lun_begin % dev->geo.luns_per_chnl; + int lunid = 0; + int lun_balanced = 1; + int prev_nr_luns; + int i, j; + + nr_chnls = nr_luns / dev->geo.luns_per_chnl; + nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1; + + dev_map = kmalloc(sizeof(struct nvm_dev_map), GFP_KERNEL); + if (!dev_map) + goto err_dev; + + dev_map->chnls = kcalloc(nr_chnls, sizeof(struct nvm_ch_map), + GFP_KERNEL); + if (!dev_map->chnls) + goto err_chnls; + + luns = kcalloc(nr_luns, sizeof(struct ppa_addr), GFP_KERNEL); + if (!luns) + goto err_luns; + + prev_nr_luns = (luns_left > dev->geo.luns_per_chnl) ? + dev->geo.luns_per_chnl : luns_left; + for (i = 0; i < nr_chnls; i++) { + struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[i + bch]; + int *lun_roffs = ch_rmap->lun_offs; + struct nvm_ch_map *ch_map = &dev_map->chnls[i]; + int *lun_offs; + int luns_in_chnl = (luns_left > dev->geo.luns_per_chnl) ? + dev->geo.luns_per_chnl : luns_left; + + if (lun_balanced && prev_nr_luns != luns_in_chnl) + lun_balanced = 0; + + ch_map->ch_off = ch_rmap->ch_off = bch; + ch_map->nr_luns = luns_in_chnl; + + lun_offs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL); + if (!lun_offs) + goto err_ch; + + for (j = 0; j < luns_in_chnl; j++) { + luns[lunid].ppa = 0; + luns[lunid].g.ch = i; + luns[lunid++].g.lun = j; + + lun_offs[j] = blun; + lun_roffs[j + blun] = blun; + } + + ch_map->lun_offs = lun_offs; + + /* when starting a new channel, lun offset is reset */ + blun = 0; + luns_left -= luns_in_chnl; + } + + dev_map->nr_chnls = nr_chnls; + + tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL); + if (!tgt_dev) + goto err_ch; + + memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo)); + /* Target device only owns a portion of the physical device */ + tgt_dev->geo.nr_chnls = nr_chnls; + tgt_dev->geo.nr_luns = nr_luns; + tgt_dev->geo.luns_per_chnl = (lun_balanced) ? prev_nr_luns : -1; + tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun; + tgt_dev->q = dev->q; + tgt_dev->map = dev_map; + tgt_dev->luns = luns; + memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id)); + + tgt_dev->parent = dev; + + return tgt_dev; +err_ch: + while (--i > 0) + kfree(dev_map->chnls[i].lun_offs); + kfree(luns); +err_luns: + kfree(dev_map->chnls); +err_chnls: + kfree(dev_map); +err_dev: + return tgt_dev; +} + +static const struct block_device_operations nvm_fops = { + .owner = THIS_MODULE, +}; + +static int nvm_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) +{ + struct nvm_ioctl_create_simple *s = &create->conf.s; + struct request_queue *tqueue; + struct gendisk *tdisk; + struct nvm_tgt_type *tt; + struct nvm_target *t; + struct nvm_tgt_dev *tgt_dev; + void *targetdata; + + tt = nvm_find_target_type(create->tgttype, 1); + if (!tt) { + pr_err("nvm: target type %s not found\n", create->tgttype); + return -EINVAL; + } + + mutex_lock(&dev->mlock); + t = nvm_find_target(dev, create->tgtname); + if (t) { + pr_err("nvm: target name already exists.\n"); + mutex_unlock(&dev->mlock); + return -EINVAL; + } + mutex_unlock(&dev->mlock); + + if (nvm_reserve_luns(dev, s->lun_begin, s->lun_end)) + return -ENOMEM; + + t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL); + if (!t) + goto err_reserve; + + tgt_dev = nvm_create_tgt_dev(dev, s->lun_begin, s->lun_end); + if (!tgt_dev) { + pr_err("nvm: could not create target device\n"); + goto err_t; + } + + tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node); + if (!tqueue) + goto err_dev; + blk_queue_make_request(tqueue, tt->make_rq); + + tdisk = alloc_disk(0); + if (!tdisk) + goto err_queue; + + sprintf(tdisk->disk_name, "%s", create->tgtname); + tdisk->flags = GENHD_FL_EXT_DEVT; + tdisk->major = 0; + tdisk->first_minor = 0; + tdisk->fops = &nvm_fops; + tdisk->queue = tqueue; + + targetdata = tt->init(tgt_dev, tdisk); + if (IS_ERR(targetdata)) + goto err_init; + + tdisk->private_data = targetdata; + tqueue->queuedata = targetdata; + + blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect); + + set_capacity(tdisk, tt->capacity(targetdata)); + add_disk(tdisk); + + if (tt->sysfs_init && tt->sysfs_init(tdisk)) + goto err_sysfs; + + t->type = tt; + t->disk = tdisk; + t->dev = tgt_dev; + + mutex_lock(&dev->mlock); + list_add_tail(&t->list, &dev->targets); + mutex_unlock(&dev->mlock); + + return 0; +err_sysfs: + if (tt->exit) + tt->exit(targetdata); +err_init: + put_disk(tdisk); +err_queue: + blk_cleanup_queue(tqueue); +err_dev: + nvm_remove_tgt_dev(tgt_dev); +err_t: + kfree(t); +err_reserve: + nvm_release_luns_err(dev, s->lun_begin, s->lun_end); + return -ENOMEM; +} + +static void __nvm_remove_target(struct nvm_target *t) +{ + struct nvm_tgt_type *tt = t->type; + struct gendisk *tdisk = t->disk; + struct request_queue *q = tdisk->queue; + + del_gendisk(tdisk); + blk_cleanup_queue(q); + + if (tt->sysfs_exit) + tt->sysfs_exit(tdisk); + + if (tt->exit) + tt->exit(tdisk->private_data); + + nvm_remove_tgt_dev(t->dev); + put_disk(tdisk); + + list_del(&t->list); + kfree(t); +} + +/** + * nvm_remove_tgt - Removes a target from the media manager + * @dev: device + * @remove: ioctl structure with target name to remove. + * + * Returns: + * 0: on success + * 1: on not found + * <0: on error + */ +static int nvm_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) +{ + struct nvm_target *t; + + mutex_lock(&dev->mlock); + t = nvm_find_target(dev, remove->tgtname); + if (!t) { + mutex_unlock(&dev->mlock); + return 1; + } + __nvm_remove_target(t); + mutex_unlock(&dev->mlock); + + return 0; +} + +static int nvm_register_map(struct nvm_dev *dev) +{ + struct nvm_dev_map *rmap; + int i, j; + + rmap = kmalloc(sizeof(struct nvm_dev_map), GFP_KERNEL); + if (!rmap) + goto err_rmap; + + rmap->chnls = kcalloc(dev->geo.nr_chnls, sizeof(struct nvm_ch_map), + GFP_KERNEL); + if (!rmap->chnls) + goto err_chnls; + + for (i = 0; i < dev->geo.nr_chnls; i++) { + struct nvm_ch_map *ch_rmap; + int *lun_roffs; + int luns_in_chnl = dev->geo.luns_per_chnl; + + ch_rmap = &rmap->chnls[i]; + + ch_rmap->ch_off = -1; + ch_rmap->nr_luns = luns_in_chnl; + + lun_roffs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL); + if (!lun_roffs) + goto err_ch; + + for (j = 0; j < luns_in_chnl; j++) + lun_roffs[j] = -1; + + ch_rmap->lun_offs = lun_roffs; + } + + dev->rmap = rmap; + + return 0; +err_ch: + while (--i >= 0) + kfree(rmap->chnls[i].lun_offs); +err_chnls: + kfree(rmap); +err_rmap: + return -ENOMEM; +} + +static void nvm_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) +{ + struct nvm_dev_map *dev_map = tgt_dev->map; + struct nvm_ch_map *ch_map = &dev_map->chnls[p->g.ch]; + int lun_off = ch_map->lun_offs[p->g.lun]; + + p->g.ch += ch_map->ch_off; + p->g.lun += lun_off; +} + +static void nvm_map_to_tgt(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) +{ + struct nvm_dev *dev = tgt_dev->parent; + struct nvm_dev_map *dev_rmap = dev->rmap; + struct nvm_ch_map *ch_rmap = &dev_rmap->chnls[p->g.ch]; + int lun_roff = ch_rmap->lun_offs[p->g.lun]; + + p->g.ch -= ch_rmap->ch_off; + p->g.lun -= lun_roff; +} + +static void nvm_ppa_tgt_to_dev(struct nvm_tgt_dev *tgt_dev, + struct ppa_addr *ppa_list, int nr_ppas) +{ + int i; + + for (i = 0; i < nr_ppas; i++) { + nvm_map_to_dev(tgt_dev, &ppa_list[i]); + ppa_list[i] = generic_to_dev_addr(tgt_dev, ppa_list[i]); + } +} + +static void nvm_ppa_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, + struct ppa_addr *ppa_list, int nr_ppas) +{ + int i; + + for (i = 0; i < nr_ppas; i++) { + ppa_list[i] = dev_to_generic_addr(tgt_dev, ppa_list[i]); + nvm_map_to_tgt(tgt_dev, &ppa_list[i]); + } +} + +static void nvm_rq_tgt_to_dev(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) +{ + if (rqd->nr_ppas == 1) { + nvm_ppa_tgt_to_dev(tgt_dev, &rqd->ppa_addr, 1); + return; + } + + nvm_ppa_tgt_to_dev(tgt_dev, rqd->ppa_list, rqd->nr_ppas); +} + +static void nvm_rq_dev_to_tgt(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) +{ + if (rqd->nr_ppas == 1) { + nvm_ppa_dev_to_tgt(tgt_dev, &rqd->ppa_addr, 1); + return; + } + + nvm_ppa_dev_to_tgt(tgt_dev, rqd->ppa_list, rqd->nr_ppas); +} + +void nvm_part_to_tgt(struct nvm_dev *dev, sector_t *entries, + int len) +{ + struct nvm_geo *geo = &dev->geo; + struct nvm_dev_map *dev_rmap = dev->rmap; + u64 i; + + for (i = 0; i < len; i++) { + struct nvm_ch_map *ch_rmap; + int *lun_roffs; + struct ppa_addr gaddr; + u64 pba = le64_to_cpu(entries[i]); + int off; + u64 diff; + + if (!pba) + continue; + + gaddr = linear_to_generic_addr(geo, pba); + ch_rmap = &dev_rmap->chnls[gaddr.g.ch]; + lun_roffs = ch_rmap->lun_offs; + + off = gaddr.g.ch * geo->luns_per_chnl + gaddr.g.lun; + + diff = ((ch_rmap->ch_off * geo->luns_per_chnl) + + (lun_roffs[gaddr.g.lun])) * geo->sec_per_lun; + + entries[i] -= cpu_to_le64(diff); + } +} +EXPORT_SYMBOL(nvm_part_to_tgt); + struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock) { struct nvm_tgt_type *tmp, *tt = NULL; @@ -92,78 +565,6 @@ void nvm_dev_dma_free(struct nvm_dev *dev, void *addr, dma_addr_t dma_handler) } EXPORT_SYMBOL(nvm_dev_dma_free); -static struct nvmm_type *nvm_find_mgr_type(const char *name) -{ - struct nvmm_type *mt; - - list_for_each_entry(mt, &nvm_mgrs, list) - if (!strcmp(name, mt->name)) - return mt; - - return NULL; -} - -static struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev) -{ - struct nvmm_type *mt; - int ret; - - lockdep_assert_held(&nvm_lock); - - list_for_each_entry(mt, &nvm_mgrs, list) { - if (strncmp(dev->sb.mmtype, mt->name, NVM_MMTYPE_LEN)) - continue; - - ret = mt->register_mgr(dev); - if (ret < 0) { - pr_err("nvm: media mgr failed to init (%d) on dev %s\n", - ret, dev->name); - return NULL; /* initialization failed */ - } else if (ret > 0) - return mt; - } - - return NULL; -} - -int nvm_register_mgr(struct nvmm_type *mt) -{ - struct nvm_dev *dev; - int ret = 0; - - down_write(&nvm_lock); - if (nvm_find_mgr_type(mt->name)) { - ret = -EEXIST; - goto finish; - } else { - list_add(&mt->list, &nvm_mgrs); - } - - /* try to register media mgr if any device have none configured */ - list_for_each_entry(dev, &nvm_devices, devices) { - if (dev->mt) - continue; - - dev->mt = nvm_init_mgr(dev); - } -finish: - up_write(&nvm_lock); - - return ret; -} -EXPORT_SYMBOL(nvm_register_mgr); - -void nvm_unregister_mgr(struct nvmm_type *mt) -{ - if (!mt) - return; - - down_write(&nvm_lock); - list_del(&mt->list); - up_write(&nvm_lock); -} -EXPORT_SYMBOL(nvm_unregister_mgr); - static struct nvm_dev *nvm_find_nvm_dev(const char *name) { struct nvm_dev *dev; @@ -175,53 +576,6 @@ static struct nvm_dev *nvm_find_nvm_dev(const char *name) return NULL; } -static void nvm_tgt_generic_to_addr_mode(struct nvm_tgt_dev *tgt_dev, - struct nvm_rq *rqd) -{ - struct nvm_dev *dev = tgt_dev->parent; - int i; - - if (rqd->nr_ppas > 1) { - for (i = 0; i < rqd->nr_ppas; i++) { - rqd->ppa_list[i] = dev->mt->trans_ppa(tgt_dev, - rqd->ppa_list[i], TRANS_TGT_TO_DEV); - rqd->ppa_list[i] = generic_to_dev_addr(dev, - rqd->ppa_list[i]); - } - } else { - rqd->ppa_addr = dev->mt->trans_ppa(tgt_dev, rqd->ppa_addr, - TRANS_TGT_TO_DEV); - rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); - } -} - -int nvm_set_bb_tbl(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, - int type) -{ - struct nvm_rq rqd; - int ret; - - if (nr_ppas > dev->ops->max_phys_sect) { - pr_err("nvm: unable to update all sysblocks atomically\n"); - return -EINVAL; - } - - memset(&rqd, 0, sizeof(struct nvm_rq)); - - nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1); - nvm_generic_to_addr_mode(dev, &rqd); - - ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); - nvm_free_rqd_ppalist(dev, &rqd); - if (ret) { - pr_err("nvm: sysblk failed bb mark\n"); - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(nvm_set_bb_tbl); - int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, int nr_ppas, int type) { @@ -237,12 +591,12 @@ int nvm_set_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, memset(&rqd, 0, sizeof(struct nvm_rq)); nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1); - nvm_tgt_generic_to_addr_mode(tgt_dev, &rqd); + nvm_rq_tgt_to_dev(tgt_dev, &rqd); ret = dev->ops->set_bb_tbl(dev, &rqd.ppa_addr, rqd.nr_ppas, type); nvm_free_rqd_ppalist(dev, &rqd); if (ret) { - pr_err("nvm: sysblk failed bb mark\n"); + pr_err("nvm: failed bb mark\n"); return -EINVAL; } @@ -262,15 +616,42 @@ int nvm_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) { struct nvm_dev *dev = tgt_dev->parent; - return dev->mt->submit_io(tgt_dev, rqd); + if (!dev->ops->submit_io) + return -ENODEV; + + nvm_rq_tgt_to_dev(tgt_dev, rqd); + + rqd->dev = tgt_dev; + return dev->ops->submit_io(dev, rqd); } EXPORT_SYMBOL(nvm_submit_io); -int nvm_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p, int flags) +int nvm_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *ppas, int flags) { struct nvm_dev *dev = tgt_dev->parent; + struct nvm_rq rqd; + int ret; + + if (!dev->ops->erase_block) + return 0; + + nvm_map_to_dev(tgt_dev, ppas); + + memset(&rqd, 0, sizeof(struct nvm_rq)); + + ret = nvm_set_rqd_ppalist(dev, &rqd, ppas, 1, 1); + if (ret) + return ret; + + nvm_rq_tgt_to_dev(tgt_dev, &rqd); + + rqd.flags = flags; + + ret = dev->ops->erase_block(dev, &rqd); - return dev->mt->erase_blk(tgt_dev, p, flags); + nvm_free_rqd_ppalist(dev, &rqd); + + return ret; } EXPORT_SYMBOL(nvm_erase_blk); @@ -289,46 +670,67 @@ EXPORT_SYMBOL(nvm_get_l2p_tbl); int nvm_get_area(struct nvm_tgt_dev *tgt_dev, sector_t *lba, sector_t len) { struct nvm_dev *dev = tgt_dev->parent; + struct nvm_geo *geo = &dev->geo; + struct nvm_area *area, *prev, *next; + sector_t begin = 0; + sector_t max_sectors = (geo->sec_size * dev->total_secs) >> 9; - return dev->mt->get_area(dev, lba, len); -} -EXPORT_SYMBOL(nvm_get_area); + if (len > max_sectors) + return -EINVAL; -void nvm_put_area(struct nvm_tgt_dev *tgt_dev, sector_t lba) -{ - struct nvm_dev *dev = tgt_dev->parent; + area = kmalloc(sizeof(struct nvm_area), GFP_KERNEL); + if (!area) + return -ENOMEM; - dev->mt->put_area(dev, lba); -} -EXPORT_SYMBOL(nvm_put_area); + prev = NULL; -void nvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd) -{ - int i; + spin_lock(&dev->lock); + list_for_each_entry(next, &dev->area_list, list) { + if (begin + len > next->begin) { + begin = next->end; + prev = next; + continue; + } + break; + } - if (rqd->nr_ppas > 1) { - for (i = 0; i < rqd->nr_ppas; i++) - rqd->ppa_list[i] = dev_to_generic_addr(dev, - rqd->ppa_list[i]); - } else { - rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr); + if ((begin + len) > max_sectors) { + spin_unlock(&dev->lock); + kfree(area); + return -EINVAL; } + + area->begin = *lba = begin; + area->end = begin + len; + + if (prev) /* insert into sorted order */ + list_add(&area->list, &prev->list); + else + list_add(&area->list, &dev->area_list); + spin_unlock(&dev->lock); + + return 0; } -EXPORT_SYMBOL(nvm_addr_to_generic_mode); +EXPORT_SYMBOL(nvm_get_area); -void nvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd) +void nvm_put_area(struct nvm_tgt_dev *tgt_dev, sector_t begin) { - int i; + struct nvm_dev *dev = tgt_dev->parent; + struct nvm_area *area; - if (rqd->nr_ppas > 1) { - for (i = 0; i < rqd->nr_ppas; i++) - rqd->ppa_list[i] = generic_to_dev_addr(dev, - rqd->ppa_list[i]); - } else { - rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr); + spin_lock(&dev->lock); + list_for_each_entry(area, &dev->area_list, list) { + if (area->begin != begin) + continue; + + list_del(&area->list); + spin_unlock(&dev->lock); + kfree(area); + return; } + spin_unlock(&dev->lock); } -EXPORT_SYMBOL(nvm_generic_to_addr_mode); +EXPORT_SYMBOL(nvm_put_area); int nvm_set_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd, const struct ppa_addr *ppas, int nr_ppas, int vblk) @@ -380,149 +782,19 @@ void nvm_free_rqd_ppalist(struct nvm_dev *dev, struct nvm_rq *rqd) } EXPORT_SYMBOL(nvm_free_rqd_ppalist); -int nvm_erase_ppa(struct nvm_dev *dev, struct ppa_addr *ppas, int nr_ppas, - int flags) +void nvm_end_io(struct nvm_rq *rqd) { - struct nvm_rq rqd; - int ret; + struct nvm_tgt_dev *tgt_dev = rqd->dev; - if (!dev->ops->erase_block) - return 0; + /* Convert address space */ + if (tgt_dev) + nvm_rq_dev_to_tgt(tgt_dev, rqd); - memset(&rqd, 0, sizeof(struct nvm_rq)); - - ret = nvm_set_rqd_ppalist(dev, &rqd, ppas, nr_ppas, 1); - if (ret) - return ret; - - nvm_generic_to_addr_mode(dev, &rqd); - - rqd.flags = flags; - - ret = dev->ops->erase_block(dev, &rqd); - - nvm_free_rqd_ppalist(dev, &rqd); - - return ret; -} -EXPORT_SYMBOL(nvm_erase_ppa); - -void nvm_end_io(struct nvm_rq *rqd, int error) -{ - rqd->error = error; - rqd->end_io(rqd); + if (rqd->end_io) + rqd->end_io(rqd); } EXPORT_SYMBOL(nvm_end_io); -static void nvm_end_io_sync(struct nvm_rq *rqd) -{ - struct completion *waiting = rqd->wait; - - rqd->wait = NULL; - - complete(waiting); -} - -static int __nvm_submit_ppa(struct nvm_dev *dev, struct nvm_rq *rqd, int opcode, - int flags, void *buf, int len) -{ - DECLARE_COMPLETION_ONSTACK(wait); - struct bio *bio; - int ret; - unsigned long hang_check; - - bio = bio_map_kern(dev->q, buf, len, GFP_KERNEL); - if (IS_ERR_OR_NULL(bio)) - return -ENOMEM; - - nvm_generic_to_addr_mode(dev, rqd); - - rqd->dev = NULL; - rqd->opcode = opcode; - rqd->flags = flags; - rqd->bio = bio; - rqd->wait = &wait; - rqd->end_io = nvm_end_io_sync; - - ret = dev->ops->submit_io(dev, rqd); - if (ret) { - bio_put(bio); - return ret; - } - - /* Prevent hang_check timer from firing at us during very long I/O */ - hang_check = sysctl_hung_task_timeout_secs; - if (hang_check) - while (!wait_for_completion_io_timeout(&wait, - hang_check * (HZ/2))) - ; - else - wait_for_completion_io(&wait); - - return rqd->error; -} - -/** - * nvm_submit_ppa_list - submit user-defined ppa list to device. The user must - * take to free ppa list if necessary. - * @dev: device - * @ppa_list: user created ppa_list - * @nr_ppas: length of ppa_list - * @opcode: device opcode - * @flags: device flags - * @buf: data buffer - * @len: data buffer length - */ -int nvm_submit_ppa_list(struct nvm_dev *dev, struct ppa_addr *ppa_list, - int nr_ppas, int opcode, int flags, void *buf, int len) -{ - struct nvm_rq rqd; - - if (dev->ops->max_phys_sect < nr_ppas) - return -EINVAL; - - memset(&rqd, 0, sizeof(struct nvm_rq)); - - rqd.nr_ppas = nr_ppas; - if (nr_ppas > 1) - rqd.ppa_list = ppa_list; - else - rqd.ppa_addr = ppa_list[0]; - - return __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len); -} -EXPORT_SYMBOL(nvm_submit_ppa_list); - -/** - * nvm_submit_ppa - submit PPAs to device. PPAs will automatically be unfolded - * as single, dual, quad plane PPAs depending on device type. - * @dev: device - * @ppa: user created ppa_list - * @nr_ppas: length of ppa_list - * @opcode: device opcode - * @flags: device flags - * @buf: data buffer - * @len: data buffer length - */ -int nvm_submit_ppa(struct nvm_dev *dev, struct ppa_addr *ppa, int nr_ppas, - int opcode, int flags, void *buf, int len) -{ - struct nvm_rq rqd; - int ret; - - memset(&rqd, 0, sizeof(struct nvm_rq)); - ret = nvm_set_rqd_ppalist(dev, &rqd, ppa, nr_ppas, 1); - if (ret) - return ret; - - ret = __nvm_submit_ppa(dev, &rqd, opcode, flags, buf, len); - - nvm_free_rqd_ppalist(dev, &rqd); - - return ret; -} -EXPORT_SYMBOL(nvm_submit_ppa); - /* * folds a bad block list from its plane representation to its virtual * block representation. The fold is done in place and reduced size is @@ -559,21 +831,14 @@ int nvm_bb_tbl_fold(struct nvm_dev *dev, u8 *blks, int nr_blks) } EXPORT_SYMBOL(nvm_bb_tbl_fold); -int nvm_get_bb_tbl(struct nvm_dev *dev, struct ppa_addr ppa, u8 *blks) -{ - ppa = generic_to_dev_addr(dev, ppa); - - return dev->ops->get_bb_tbl(dev, ppa, blks); -} -EXPORT_SYMBOL(nvm_get_bb_tbl); - int nvm_get_tgt_bb_tbl(struct nvm_tgt_dev *tgt_dev, struct ppa_addr ppa, u8 *blks) { struct nvm_dev *dev = tgt_dev->parent; - ppa = dev->mt->trans_ppa(tgt_dev, ppa, TRANS_TGT_TO_DEV); - return nvm_get_bb_tbl(dev, ppa, blks); + nvm_ppa_tgt_to_dev(tgt_dev, &ppa, 1); + + return dev->ops->get_bb_tbl(dev, ppa, blks); } EXPORT_SYMBOL(nvm_get_tgt_bb_tbl); @@ -627,7 +892,7 @@ static int nvm_init_mlc_tbl(struct nvm_dev *dev, struct nvm_id_group *grp) static int nvm_core_init(struct nvm_dev *dev) { struct nvm_id *id = &dev->identity; - struct nvm_id_group *grp = &id->groups[0]; + struct nvm_id_group *grp = &id->grp; struct nvm_geo *geo = &dev->geo; int ret; @@ -691,36 +956,31 @@ static int nvm_core_init(struct nvm_dev *dev) goto err_fmtype; } + INIT_LIST_HEAD(&dev->area_list); + INIT_LIST_HEAD(&dev->targets); mutex_init(&dev->mlock); spin_lock_init(&dev->lock); - blk_queue_logical_block_size(dev->q, geo->sec_size); + ret = nvm_register_map(dev); + if (ret) + goto err_fmtype; + blk_queue_logical_block_size(dev->q, geo->sec_size); return 0; err_fmtype: kfree(dev->lun_map); return ret; } -static void nvm_free_mgr(struct nvm_dev *dev) -{ - if (!dev->mt) - return; - - dev->mt->unregister_mgr(dev); - dev->mt = NULL; -} - void nvm_free(struct nvm_dev *dev) { if (!dev) return; - nvm_free_mgr(dev); - if (dev->dma_pool) dev->ops->destroy_dma_pool(dev->dma_pool); + kfree(dev->rmap); kfree(dev->lptbl); kfree(dev->lun_map); kfree(dev); @@ -731,28 +991,19 @@ static int nvm_init(struct nvm_dev *dev) struct nvm_geo *geo = &dev->geo; int ret = -EINVAL; - if (!dev->q || !dev->ops) - return ret; - if (dev->ops->identity(dev, &dev->identity)) { pr_err("nvm: device could not be identified\n"); goto err; } - pr_debug("nvm: ver:%x nvm_vendor:%x groups:%u\n", - dev->identity.ver_id, dev->identity.vmnt, - dev->identity.cgrps); + pr_debug("nvm: ver:%x nvm_vendor:%x\n", + dev->identity.ver_id, dev->identity.vmnt); if (dev->identity.ver_id != 1) { pr_err("nvm: device not supported by kernel."); goto err; } - if (dev->identity.cgrps != 1) { - pr_err("nvm: only one group configuration supported."); - goto err; - } - ret = nvm_core_init(dev); if (ret) { pr_err("nvm: could not initialize core structures.\n"); @@ -779,49 +1030,50 @@ int nvm_register(struct nvm_dev *dev) { int ret; - ret = nvm_init(dev); - if (ret) - goto err_init; + if (!dev->q || !dev->ops) + return -EINVAL; if (dev->ops->max_phys_sect > 256) { pr_info("nvm: max sectors supported is 256.\n"); - ret = -EINVAL; - goto err_init; + return -EINVAL; } if (dev->ops->max_phys_sect > 1) { dev->dma_pool = dev->ops->create_dma_pool(dev, "ppalist"); if (!dev->dma_pool) { pr_err("nvm: could not create dma pool\n"); - ret = -ENOMEM; - goto err_init; + return -ENOMEM; } } - if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) { - ret = nvm_get_sysblock(dev, &dev->sb); - if (!ret) - pr_err("nvm: device not initialized.\n"); - else if (ret < 0) - pr_err("nvm: err (%d) on device initialization\n", ret); - } + ret = nvm_init(dev); + if (ret) + goto err_init; /* register device with a supported media manager */ down_write(&nvm_lock); - if (ret > 0) - dev->mt = nvm_init_mgr(dev); list_add(&dev->devices, &nvm_devices); up_write(&nvm_lock); return 0; err_init: - kfree(dev->lun_map); + dev->ops->destroy_dma_pool(dev->dma_pool); return ret; } EXPORT_SYMBOL(nvm_register); void nvm_unregister(struct nvm_dev *dev) { + struct nvm_target *t, *tmp; + + mutex_lock(&dev->mlock); + list_for_each_entry_safe(t, tmp, &dev->targets, list) { + if (t->dev->parent != dev) + continue; + __nvm_remove_target(t); + } + mutex_unlock(&dev->mlock); + down_write(&nvm_lock); list_del(&dev->devices); up_write(&nvm_lock); @@ -844,24 +1096,24 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create) return -EINVAL; } - if (!dev->mt) { - pr_info("nvm: device has no media manager registered.\n"); - return -ENODEV; - } - if (create->conf.type != NVM_CONFIG_TYPE_SIMPLE) { pr_err("nvm: config type not valid\n"); return -EINVAL; } s = &create->conf.s; - if (s->lun_begin > s->lun_end || s->lun_end > dev->geo.nr_luns) { + if (s->lun_begin == -1 && s->lun_end == -1) { + s->lun_begin = 0; + s->lun_end = dev->geo.nr_luns - 1; + } + + if (s->lun_begin > s->lun_end || s->lun_end >= dev->geo.nr_luns) { pr_err("nvm: lun out of bound (%u:%u > %u)\n", - s->lun_begin, s->lun_end, dev->geo.nr_luns); + s->lun_begin, s->lun_end, dev->geo.nr_luns - 1); return -EINVAL; } - return dev->mt->create_tgt(dev, create); + return nvm_create_tgt(dev, create); } static long nvm_ioctl_info(struct file *file, void __user *arg) @@ -923,16 +1175,14 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg) struct nvm_ioctl_device_info *info = &devices->info[i]; sprintf(info->devname, "%s", dev->name); - if (dev->mt) { - info->bmversion[0] = dev->mt->version[0]; - info->bmversion[1] = dev->mt->version[1]; - info->bmversion[2] = dev->mt->version[2]; - sprintf(info->bmname, "%s", dev->mt->name); - } else { - sprintf(info->bmname, "none"); - } + /* kept for compatibility */ + info->bmversion[0] = 1; + info->bmversion[1] = 0; + info->bmversion[2] = 0; + sprintf(info->bmname, "%s", "gennvm"); i++; + if (i > 31) { pr_err("nvm: max 31 devices can be reported.\n"); break; @@ -994,7 +1244,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) } list_for_each_entry(dev, &nvm_devices, devices) { - ret = dev->mt->remove_tgt(dev, &remove); + ret = nvm_remove_tgt(dev, &remove); if (!ret) break; } @@ -1002,47 +1252,7 @@ static long nvm_ioctl_dev_remove(struct file *file, void __user *arg) return ret; } -static void nvm_setup_nvm_sb_info(struct nvm_sb_info *info) -{ - info->seqnr = 1; - info->erase_cnt = 0; - info->version = 1; -} - -static long __nvm_ioctl_dev_init(struct nvm_ioctl_dev_init *init) -{ - struct nvm_dev *dev; - struct nvm_sb_info info; - int ret; - - down_write(&nvm_lock); - dev = nvm_find_nvm_dev(init->dev); - up_write(&nvm_lock); - if (!dev) { - pr_err("nvm: device not found\n"); - return -EINVAL; - } - - nvm_setup_nvm_sb_info(&info); - - strncpy(info.mmtype, init->mmtype, NVM_MMTYPE_LEN); - info.fs_ppa.ppa = -1; - - if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) { - ret = nvm_init_sysblock(dev, &info); - if (ret) - return ret; - } - - memcpy(&dev->sb, &info, sizeof(struct nvm_sb_info)); - - down_write(&nvm_lock); - dev->mt = nvm_init_mgr(dev); - up_write(&nvm_lock); - - return 0; -} - +/* kept for compatibility reasons */ static long nvm_ioctl_dev_init(struct file *file, void __user *arg) { struct nvm_ioctl_dev_init init; @@ -1058,15 +1268,13 @@ static long nvm_ioctl_dev_init(struct file *file, void __user *arg) return -EINVAL; } - init.dev[DISK_NAME_LEN - 1] = '\0'; - - return __nvm_ioctl_dev_init(&init); + return 0; } +/* Kept for compatibility reasons */ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg) { struct nvm_ioctl_dev_factory fact; - struct nvm_dev *dev; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -1079,19 +1287,6 @@ static long nvm_ioctl_dev_factory(struct file *file, void __user *arg) if (fact.flags & ~(NVM_FACTORY_NR_BITS - 1)) return -EINVAL; - down_write(&nvm_lock); - dev = nvm_find_nvm_dev(fact.dev); - up_write(&nvm_lock); - if (!dev) { - pr_err("nvm: device not found\n"); - return -EINVAL; - } - - nvm_free_mgr(dev); - - if (dev->identity.cap & NVM_ID_DCAP_BBLKMGMT) - return nvm_dev_factory(dev, fact.flags); - return 0; } diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c deleted file mode 100644 index ca7880082d80..000000000000 --- a/drivers/lightnvm/gennvm.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * Copyright (C) 2015 Matias Bjorling <m@bjorling.me> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - * Implementation of a general nvm manager for Open-Channel SSDs. - */ - -#include "gennvm.h" - -static struct nvm_target *gen_find_target(struct gen_dev *gn, const char *name) -{ - struct nvm_target *tgt; - - list_for_each_entry(tgt, &gn->targets, list) - if (!strcmp(name, tgt->disk->disk_name)) - return tgt; - - return NULL; -} - -static const struct block_device_operations gen_fops = { - .owner = THIS_MODULE, -}; - -static int gen_reserve_luns(struct nvm_dev *dev, struct nvm_target *t, - int lun_begin, int lun_end) -{ - int i; - - for (i = lun_begin; i <= lun_end; i++) { - if (test_and_set_bit(i, dev->lun_map)) { - pr_err("nvm: lun %d already allocated\n", i); - goto err; - } - } - - return 0; - -err: - while (--i > lun_begin) - clear_bit(i, dev->lun_map); - - return -EBUSY; -} - -static void gen_release_luns_err(struct nvm_dev *dev, int lun_begin, - int lun_end) -{ - int i; - - for (i = lun_begin; i <= lun_end; i++) - WARN_ON(!test_and_clear_bit(i, dev->lun_map)); -} - -static void gen_remove_tgt_dev(struct nvm_tgt_dev *tgt_dev) -{ - struct nvm_dev *dev = tgt_dev->parent; - struct gen_dev_map *dev_map = tgt_dev->map; - int i, j; - - for (i = 0; i < dev_map->nr_chnls; i++) { - struct gen_ch_map *ch_map = &dev_map->chnls[i]; - int *lun_offs = ch_map->lun_offs; - int ch = i + ch_map->ch_off; - - for (j = 0; j < ch_map->nr_luns; j++) { - int lun = j + lun_offs[j]; - int lunid = (ch * dev->geo.luns_per_chnl) + lun; - - WARN_ON(!test_and_clear_bit(lunid, dev->lun_map)); - } - - kfree(ch_map->lun_offs); - } - - kfree(dev_map->chnls); - kfree(dev_map); - kfree(tgt_dev->luns); - kfree(tgt_dev); -} - -static struct nvm_tgt_dev *gen_create_tgt_dev(struct nvm_dev *dev, - int lun_begin, int lun_end) -{ - struct nvm_tgt_dev *tgt_dev = NULL; - struct gen_dev_map *dev_rmap = dev->rmap; - struct gen_dev_map *dev_map; - struct ppa_addr *luns; - int nr_luns = lun_end - lun_begin + 1; - int luns_left = nr_luns; - int nr_chnls = nr_luns / dev->geo.luns_per_chnl; - int nr_chnls_mod = nr_luns % dev->geo.luns_per_chnl; - int bch = lun_begin / dev->geo.luns_per_chnl; - int blun = lun_begin % dev->geo.luns_per_chnl; - int lunid = 0; - int lun_balanced = 1; - int prev_nr_luns; - int i, j; - - nr_chnls = nr_luns / dev->geo.luns_per_chnl; - nr_chnls = (nr_chnls_mod == 0) ? nr_chnls : nr_chnls + 1; - - dev_map = kmalloc(sizeof(struct gen_dev_map), GFP_KERNEL); - if (!dev_map) - goto err_dev; - - dev_map->chnls = kcalloc(nr_chnls, sizeof(struct gen_ch_map), - GFP_KERNEL); - if (!dev_map->chnls) - goto err_chnls; - - luns = kcalloc(nr_luns, sizeof(struct ppa_addr), GFP_KERNEL); - if (!luns) - goto err_luns; - - prev_nr_luns = (luns_left > dev->geo.luns_per_chnl) ? - dev->geo.luns_per_chnl : luns_left; - for (i = 0; i < nr_chnls; i++) { - struct gen_ch_map *ch_rmap = &dev_rmap->chnls[i + bch]; - int *lun_roffs = ch_rmap->lun_offs; - struct gen_ch_map *ch_map = &dev_map->chnls[i]; - int *lun_offs; - int luns_in_chnl = (luns_left > dev->geo.luns_per_chnl) ? - dev->geo.luns_per_chnl : luns_left; - - if (lun_balanced && prev_nr_luns != luns_in_chnl) - lun_balanced = 0; - - ch_map->ch_off = ch_rmap->ch_off = bch; - ch_map->nr_luns = luns_in_chnl; - - lun_offs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL); - if (!lun_offs) - goto err_ch; - - for (j = 0; j < luns_in_chnl; j++) { - luns[lunid].ppa = 0; - luns[lunid].g.ch = i; - luns[lunid++].g.lun = j; - - lun_offs[j] = blun; - lun_roffs[j + blun] = blun; - } - - ch_map->lun_offs = lun_offs; - - /* when starting a new channel, lun offset is reset */ - blun = 0; - luns_left -= luns_in_chnl; - } - - dev_map->nr_chnls = nr_chnls; - - tgt_dev = kmalloc(sizeof(struct nvm_tgt_dev), GFP_KERNEL); - if (!tgt_dev) - goto err_ch; - - memcpy(&tgt_dev->geo, &dev->geo, sizeof(struct nvm_geo)); - /* Target device only owns a portion of the physical device */ - tgt_dev->geo.nr_chnls = nr_chnls; - tgt_dev->geo.nr_luns = nr_luns; - tgt_dev->geo.luns_per_chnl = (lun_balanced) ? prev_nr_luns : -1; - tgt_dev->total_secs = nr_luns * tgt_dev->geo.sec_per_lun; - tgt_dev->q = dev->q; - tgt_dev->map = dev_map; - tgt_dev->luns = luns; - memcpy(&tgt_dev->identity, &dev->identity, sizeof(struct nvm_id)); - - tgt_dev->parent = dev; - - return tgt_dev; -err_ch: - while (--i > 0) - kfree(dev_map->chnls[i].lun_offs); - kfree(luns); -err_luns: - kfree(dev_map->chnls); -err_chnls: - kfree(dev_map); -err_dev: - return tgt_dev; -} - -static int gen_create_tgt(struct nvm_dev *dev, struct nvm_ioctl_create *create) -{ - struct gen_dev *gn = dev->mp; - struct nvm_ioctl_create_simple *s = &create->conf.s; - struct request_queue *tqueue; - struct gendisk *tdisk; - struct nvm_tgt_type *tt; - struct nvm_target *t; - struct nvm_tgt_dev *tgt_dev; - void *targetdata; - - tt = nvm_find_target_type(create->tgttype, 1); - if (!tt) { - pr_err("nvm: target type %s not found\n", create->tgttype); - return -EINVAL; - } - - mutex_lock(&gn->lock); - t = gen_find_target(gn, create->tgtname); - if (t) { - pr_err("nvm: target name already exists.\n"); - mutex_unlock(&gn->lock); - return -EINVAL; - } - mutex_unlock(&gn->lock); - - t = kmalloc(sizeof(struct nvm_target), GFP_KERNEL); - if (!t) - return -ENOMEM; - - if (gen_reserve_luns(dev, t, s->lun_begin, s->lun_end)) - goto err_t; - - tgt_dev = gen_create_tgt_dev(dev, s->lun_begin, s->lun_end); - if (!tgt_dev) { - pr_err("nvm: could not create target device\n"); - goto err_reserve; - } - - tqueue = blk_alloc_queue_node(GFP_KERNEL, dev->q->node); - if (!tqueue) - goto err_dev; - blk_queue_make_request(tqueue, tt->make_rq); - - tdisk = alloc_disk(0); - if (!tdisk) - goto err_queue; - - sprintf(tdisk->disk_name, "%s", create->tgtname); - tdisk->flags = GENHD_FL_EXT_DEVT; - tdisk->major = 0; - tdisk->first_minor = 0; - tdisk->fops = &gen_fops; - tdisk->queue = tqueue; - - targetdata = tt->init(tgt_dev, tdisk); - if (IS_ERR(targetdata)) - goto err_init; - - tdisk->private_data = targetdata; - tqueue->queuedata = targetdata; - - blk_queue_max_hw_sectors(tqueue, 8 * dev->ops->max_phys_sect); - - set_capacity(tdisk, tt->capacity(targetdata)); - add_disk(tdisk); - - t->type = tt; - t->disk = tdisk; - t->dev = tgt_dev; - - mutex_lock(&gn->lock); - list_add_tail(&t->list, &gn->targets); - mutex_unlock(&gn->lock); - - return 0; -err_init: - put_disk(tdisk); -err_queue: - blk_cleanup_queue(tqueue); -err_dev: - kfree(tgt_dev); -err_reserve: - gen_release_luns_err(dev, s->lun_begin, s->lun_end); -err_t: - kfree(t); - return -ENOMEM; -} - -static void __gen_remove_target(struct nvm_target *t) -{ - struct nvm_tgt_type *tt = t->type; - struct gendisk *tdisk = t->disk; - struct request_queue *q = tdisk->queue; - - del_gendisk(tdisk); - blk_cleanup_queue(q); - - if (tt->exit) - tt->exit(tdisk->private_data); - - gen_remove_tgt_dev(t->dev); - put_disk(tdisk); - - list_del(&t->list); - kfree(t); -} - -/** - * gen_remove_tgt - Removes a target from the media manager - * @dev: device - * @remove: ioctl structure with target name to remove. - * - * Returns: - * 0: on success - * 1: on not found - * <0: on error - */ -static int gen_remove_tgt(struct nvm_dev *dev, struct nvm_ioctl_remove *remove) -{ - struct gen_dev *gn = dev->mp; - struct nvm_target *t; - - if (!gn) - return 1; - - mutex_lock(&gn->lock); - t = gen_find_target(gn, remove->tgtname); - if (!t) { - mutex_unlock(&gn->lock); - return 1; - } - __gen_remove_target(t); - mutex_unlock(&gn->lock); - - return 0; -} - -static int gen_get_area(struct nvm_dev *dev, sector_t *lba, sector_t len) -{ - struct nvm_geo *geo = &dev->geo; - struct gen_dev *gn = dev->mp; - struct gen_area *area, *prev, *next; - sector_t begin = 0; - sector_t max_sectors = (geo->sec_size * dev->total_secs) >> 9; - - if (len > max_sectors) - return -EINVAL; - - area = kmalloc(sizeof(struct gen_area), GFP_KERNEL); - if (!area) - return -ENOMEM; - - prev = NULL; - - spin_lock(&dev->lock); - list_for_each_entry(next, &gn->area_list, list) { - if (begin + len > next->begin) { - begin = next->end; - prev = next; - continue; - } - break; - } - - if ((begin + len) > max_sectors) { - spin_unlock(&dev->lock); - kfree(area); - return -EINVAL; - } - - area->begin = *lba = begin; - area->end = begin + len; - - if (prev) /* insert into sorted order */ - list_add(&area->list, &prev->list); - else - list_add(&area->list, &gn->area_list); - spin_unlock(&dev->lock); - - return 0; -} - -static void gen_put_area(struct nvm_dev *dev, sector_t begin) -{ - struct gen_dev *gn = dev->mp; - struct gen_area *area; - - spin_lock(&dev->lock); - list_for_each_entry(area, &gn->area_list, list) { - if (area->begin != begin) - continue; - - list_del(&area->list); - spin_unlock(&dev->lock); - kfree(area); - return; - } - spin_unlock(&dev->lock); -} - -static void gen_free(struct nvm_dev *dev) -{ - kfree(dev->mp); - kfree(dev->rmap); - dev->mp = NULL; -} - -static int gen_register(struct nvm_dev *dev) -{ - struct gen_dev *gn; - struct gen_dev_map *dev_rmap; - int i, j; - - if (!try_module_get(THIS_MODULE)) - return -ENODEV; - - gn = kzalloc(sizeof(struct gen_dev), GFP_KERNEL); - if (!gn) - goto err_gn; - - dev_rmap = kmalloc(sizeof(struct gen_dev_map), GFP_KERNEL); - if (!dev_rmap) - goto err_rmap; - - dev_rmap->chnls = kcalloc(dev->geo.nr_chnls, sizeof(struct gen_ch_map), - GFP_KERNEL); - if (!dev_rmap->chnls) - goto err_chnls; - - for (i = 0; i < dev->geo.nr_chnls; i++) { - struct gen_ch_map *ch_rmap; - int *lun_roffs; - int luns_in_chnl = dev->geo.luns_per_chnl; - - ch_rmap = &dev_rmap->chnls[i]; - - ch_rmap->ch_off = -1; - ch_rmap->nr_luns = luns_in_chnl; - - lun_roffs = kcalloc(luns_in_chnl, sizeof(int), GFP_KERNEL); - if (!lun_roffs) - goto err_ch; - - for (j = 0; j < luns_in_chnl; j++) - lun_roffs[j] = -1; - - ch_rmap->lun_offs = lun_roffs; - } - - gn->dev = dev; - gn->nr_luns = dev->geo.nr_luns; - INIT_LIST_HEAD(&gn->area_list); - mutex_init(&gn->lock); - INIT_LIST_HEAD(&gn->targets); - dev->mp = gn; - dev->rmap = dev_rmap; - - return 1; -err_ch: - while (--i >= 0) - kfree(dev_rmap->chnls[i].lun_offs); -err_chnls: - kfree(dev_rmap); -err_rmap: - gen_free(dev); -err_gn: - module_put(THIS_MODULE); - return -ENOMEM; -} - -static void gen_unregister(struct nvm_dev *dev) -{ - struct gen_dev *gn = dev->mp; - struct nvm_target *t, *tmp; - - mutex_lock(&gn->lock); - list_for_each_entry_safe(t, tmp, &gn->targets, list) { - if (t->dev->parent != dev) - continue; - __gen_remove_target(t); - } - mutex_unlock(&gn->lock); - - gen_free(dev); - module_put(THIS_MODULE); -} - -static int gen_map_to_dev(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) -{ - struct gen_dev_map *dev_map = tgt_dev->map; - struct gen_ch_map *ch_map = &dev_map->chnls[p->g.ch]; - int lun_off = ch_map->lun_offs[p->g.lun]; - struct nvm_dev *dev = tgt_dev->parent; - struct gen_dev_map *dev_rmap = dev->rmap; - struct gen_ch_map *ch_rmap; - int lun_roff; - - p->g.ch += ch_map->ch_off; - p->g.lun += lun_off; - - ch_rmap = &dev_rmap->chnls[p->g.ch]; - lun_roff = ch_rmap->lun_offs[p->g.lun]; - - if (unlikely(ch_rmap->ch_off < 0 || lun_roff < 0)) { - pr_err("nvm: corrupted device partition table\n"); - return -EINVAL; - } - - return 0; -} - -static int gen_map_to_tgt(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p) -{ - struct nvm_dev *dev = tgt_dev->parent; - struct gen_dev_map *dev_rmap = dev->rmap; - struct gen_ch_map *ch_rmap = &dev_rmap->chnls[p->g.ch]; - int lun_roff = ch_rmap->lun_offs[p->g.lun]; - - p->g.ch -= ch_rmap->ch_off; - p->g.lun -= lun_roff; - - return 0; -} - -static int gen_trans_rq(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd, - int flag) -{ - gen_trans_fn *f; - int i; - int ret = 0; - - f = (flag == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt; - - if (rqd->nr_ppas == 1) - return f(tgt_dev, &rqd->ppa_addr); - - for (i = 0; i < rqd->nr_ppas; i++) { - ret = f(tgt_dev, &rqd->ppa_list[i]); - if (ret) - goto out; - } - -out: - return ret; -} - -static void gen_end_io(struct nvm_rq *rqd) -{ - struct nvm_tgt_dev *tgt_dev = rqd->dev; - struct nvm_tgt_instance *ins = rqd->ins; - - /* Convert address space */ - if (tgt_dev) - gen_trans_rq(tgt_dev, rqd, TRANS_DEV_TO_TGT); - - ins->tt->end_io(rqd); -} - -static int gen_submit_io(struct nvm_tgt_dev *tgt_dev, struct nvm_rq *rqd) -{ - struct nvm_dev *dev = tgt_dev->parent; - - if (!dev->ops->submit_io) - return -ENODEV; - - /* Convert address space */ - gen_trans_rq(tgt_dev, rqd, TRANS_TGT_TO_DEV); - nvm_generic_to_addr_mode(dev, rqd); - - rqd->dev = tgt_dev; - rqd->end_io = gen_end_io; - return dev->ops->submit_io(dev, rqd); -} - -static int gen_erase_blk(struct nvm_tgt_dev *tgt_dev, struct ppa_addr *p, - int flags) -{ - /* Convert address space */ - gen_map_to_dev(tgt_dev, p); - - return nvm_erase_ppa(tgt_dev->parent, p, 1, flags); -} - -static struct ppa_addr gen_trans_ppa(struct nvm_tgt_dev *tgt_dev, - struct ppa_addr p, int direction) -{ - gen_trans_fn *f; - struct ppa_addr ppa = p; - - f = (direction == TRANS_TGT_TO_DEV) ? gen_map_to_dev : gen_map_to_tgt; - f(tgt_dev, &ppa); - - return ppa; -} - -static void gen_part_to_tgt(struct nvm_dev *dev, sector_t *entries, - int len) -{ - struct nvm_geo *geo = &dev->geo; - struct gen_dev_map *dev_rmap = dev->rmap; - u64 i; - - for (i = 0; i < len; i++) { - struct gen_ch_map *ch_rmap; - int *lun_roffs; - struct ppa_addr gaddr; - u64 pba = le64_to_cpu(entries[i]); - int off; - u64 diff; - - if (!pba) - continue; - - gaddr = linear_to_generic_addr(geo, pba); - ch_rmap = &dev_rmap->chnls[gaddr.g.ch]; - lun_roffs = ch_rmap->lun_offs; - - off = gaddr.g.ch * geo->luns_per_chnl + gaddr.g.lun; - - diff = ((ch_rmap->ch_off * geo->luns_per_chnl) + - (lun_roffs[gaddr.g.lun])) * geo->sec_per_lun; - - entries[i] -= cpu_to_le64(diff); - } -} - -static struct nvmm_type gen = { - .name = "gennvm", - .version = {0, 1, 0}, - - .register_mgr = gen_register, - .unregister_mgr = gen_unregister, - - .create_tgt = gen_create_tgt, - .remove_tgt = gen_remove_tgt, - - .submit_io = gen_submit_io, - .erase_blk = gen_erase_blk, - - .get_area = gen_get_area, - .put_area = gen_put_area, - - .trans_ppa = gen_trans_ppa, - .part_to_tgt = gen_part_to_tgt, -}; - -static int __init gen_module_init(void) -{ - return nvm_register_mgr(&gen); -} - -static void gen_module_exit(void) -{ - nvm_unregister_mgr(&gen); -} - -module_init(gen_module_init); -module_exit(gen_module_exit); -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("General media manager for Open-Channel SSDs"); diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h deleted file mode 100644 index 6a4b3f368848..000000000000 --- a/drivers/lightnvm/gennvm.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright: Matias Bjorling <mb@bjorling.me> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#ifndef GENNVM_H_ -#define GENNVM_H_ - -#include <linux/module.h> -#include <linux/vmalloc.h> - -#include <linux/lightnvm.h> - -struct gen_dev { - struct nvm_dev *dev; - - int nr_luns; - struct list_head area_list; - - struct mutex lock; - struct list_head targets; -}; - -/* Map between virtual and physical channel and lun */ -struct gen_ch_map { - int ch_off; - int nr_luns; - int *lun_offs; -}; - -struct gen_dev_map { - struct gen_ch_map *chnls; - int nr_chnls; -}; - -struct gen_area { - struct list_head list; - sector_t begin; - sector_t end; /* end is excluded */ -}; - -static inline void *ch_map_to_lun_offs(struct gen_ch_map *ch_map) -{ - return ch_map + 1; -} - -typedef int (gen_trans_fn)(struct nvm_tgt_dev *, struct ppa_addr *); - -#define gen_for_each_lun(bm, lun, i) \ - for ((i) = 0, lun = &(bm)->luns[0]; \ - (i) < (bm)->nr_luns; (i)++, lun = &(bm)->luns[(i)]) - -#endif /* GENNVM_H_ */ diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c index 9fb7de395915..e00b1d7b976f 100644 --- a/drivers/lightnvm/rrpc.c +++ b/drivers/lightnvm/rrpc.c @@ -779,7 +779,7 @@ static void rrpc_end_io_write(struct rrpc *rrpc, struct rrpc_rq *rrqd, static void rrpc_end_io(struct nvm_rq *rqd) { - struct rrpc *rrpc = container_of(rqd->ins, struct rrpc, instance); + struct rrpc *rrpc = rqd->private; struct nvm_tgt_dev *dev = rrpc->dev; struct rrpc_rq *rrqd = nvm_rq_to_pdu(rqd); uint8_t npages = rqd->nr_ppas; @@ -972,8 +972,9 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio, bio_get(bio); rqd->bio = bio; - rqd->ins = &rrpc->instance; + rqd->private = rrpc; rqd->nr_ppas = nr_pages; + rqd->end_io = rrpc_end_io; rrq->flags = flags; err = nvm_submit_io(dev, rqd); @@ -1532,7 +1533,6 @@ static void *rrpc_init(struct nvm_tgt_dev *dev, struct gendisk *tdisk) if (!rrpc) return ERR_PTR(-ENOMEM); - rrpc->instance.tt = &tt_rrpc; rrpc->dev = dev; rrpc->disk = tdisk; @@ -1611,7 +1611,6 @@ static struct nvm_tgt_type tt_rrpc = { .make_rq = rrpc_make_rq, .capacity = rrpc_capacity, - .end_io = rrpc_end_io, .init = rrpc_init, .exit = rrpc_exit, diff --git a/drivers/lightnvm/rrpc.h b/drivers/lightnvm/rrpc.h index 94e4d73116b2..fdb6ff902903 100644 --- a/drivers/lightnvm/rrpc.h +++ b/drivers/lightnvm/rrpc.h @@ -102,9 +102,6 @@ struct rrpc_lun { }; struct rrpc { - /* instance must be kept in top to resolve rrpc in unprep */ - struct nvm_tgt_instance instance; - struct nvm_tgt_dev *dev; struct gendisk *disk; diff --git a/drivers/lightnvm/sysblk.c b/drivers/lightnvm/sysblk.c deleted file mode 100644 index 12002bf4efc2..000000000000 --- a/drivers/lightnvm/sysblk.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Copyright (C) 2015 Matias Bjorling. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include <linux/lightnvm.h> - -#define MAX_SYSBLKS 3 /* remember to update mapping scheme on change */ -#define MAX_BLKS_PR_SYSBLK 2 /* 2 blks with 256 pages and 3000 erases - * enables ~1.5M updates per sysblk unit - */ - -struct sysblk_scan { - /* A row is a collection of flash blocks for a system block. */ - int nr_rows; - int row; - int act_blk[MAX_SYSBLKS]; - - int nr_ppas; - struct ppa_addr ppas[MAX_SYSBLKS * MAX_BLKS_PR_SYSBLK];/* all sysblks */ -}; - -static inline int scan_ppa_idx(int row, int blkid) -{ - return (row * MAX_BLKS_PR_SYSBLK) + blkid; -} - -static void nvm_sysblk_to_cpu(struct nvm_sb_info *info, - struct nvm_system_block *sb) -{ - info->seqnr = be32_to_cpu(sb->seqnr); - info->erase_cnt = be32_to_cpu(sb->erase_cnt); - info->version = be16_to_cpu(sb->version); - strncpy(info->mmtype, sb->mmtype, NVM_MMTYPE_LEN); - info->fs_ppa.ppa = be64_to_cpu(sb->fs_ppa); -} - -static void nvm_cpu_to_sysblk(struct nvm_system_block *sb, - struct nvm_sb_info *info) -{ - sb->magic = cpu_to_be32(NVM_SYSBLK_MAGIC); - sb->seqnr = cpu_to_be32(info->seqnr); - sb->erase_cnt = cpu_to_be32(info->erase_cnt); - sb->version = cpu_to_be16(info->version); - strncpy(sb->mmtype, info->mmtype, NVM_MMTYPE_LEN); - sb->fs_ppa = cpu_to_be64(info->fs_ppa.ppa); -} - -static int nvm_setup_sysblks(struct nvm_dev *dev, struct ppa_addr *sysblk_ppas) -{ - struct nvm_geo *geo = &dev->geo; - int nr_rows = min_t(int, MAX_SYSBLKS, geo->nr_chnls); - int i; - - for (i = 0; i < nr_rows; i++) - sysblk_ppas[i].ppa = 0; - - /* if possible, place sysblk at first channel, middle channel and last - * channel of the device. If not, create only one or two sys blocks - */ - switch (geo->nr_chnls) { - case 2: - sysblk_ppas[1].g.ch = 1; - /* fall-through */ - case 1: - sysblk_ppas[0].g.ch = 0; - break; - default: - sysblk_ppas[0].g.ch = 0; - sysblk_ppas[1].g.ch = geo->nr_chnls / 2; - sysblk_ppas[2].g.ch = geo->nr_chnls - 1; - break; - } - - return nr_rows; -} - -static void nvm_setup_sysblk_scan(struct nvm_dev *dev, struct sysblk_scan *s, - struct ppa_addr *sysblk_ppas) -{ - memset(s, 0, sizeof(struct sysblk_scan)); - s->nr_rows = nvm_setup_sysblks(dev, sysblk_ppas); -} - -static int sysblk_get_free_blks(struct nvm_dev *dev, struct ppa_addr ppa, - u8 *blks, int nr_blks, - struct sysblk_scan *s) -{ - struct ppa_addr *sppa; - int i, blkid = 0; - - nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); - if (nr_blks < 0) - return nr_blks; - - for (i = 0; i < nr_blks; i++) { - if (blks[i] == NVM_BLK_T_HOST) - return -EEXIST; - - if (blks[i] != NVM_BLK_T_FREE) - continue; - - sppa = &s->ppas[scan_ppa_idx(s->row, blkid)]; - sppa->g.ch = ppa.g.ch; - sppa->g.lun = ppa.g.lun; - sppa->g.blk = i; - s->nr_ppas++; - blkid++; - - pr_debug("nvm: use (%u %u %u) as sysblk\n", - sppa->g.ch, sppa->g.lun, sppa->g.blk); - if (blkid > MAX_BLKS_PR_SYSBLK - 1) - return 0; - } - - pr_err("nvm: sysblk failed get sysblk\n"); - return -EINVAL; -} - -static int sysblk_get_host_blks(struct nvm_dev *dev, struct ppa_addr ppa, - u8 *blks, int nr_blks, - struct sysblk_scan *s) -{ - int i, nr_sysblk = 0; - - nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); - if (nr_blks < 0) - return nr_blks; - - for (i = 0; i < nr_blks; i++) { - if (blks[i] != NVM_BLK_T_HOST) - continue; - - if (s->nr_ppas == MAX_BLKS_PR_SYSBLK * MAX_SYSBLKS) { - pr_err("nvm: too many host blks\n"); - return -EINVAL; - } - - ppa.g.blk = i; - - s->ppas[scan_ppa_idx(s->row, nr_sysblk)] = ppa; - s->nr_ppas++; - nr_sysblk++; - } - - return 0; -} - -static int nvm_get_all_sysblks(struct nvm_dev *dev, struct sysblk_scan *s, - struct ppa_addr *ppas, int get_free) -{ - struct nvm_geo *geo = &dev->geo; - int i, nr_blks, ret = 0; - u8 *blks; - - s->nr_ppas = 0; - nr_blks = geo->blks_per_lun * geo->plane_mode; - - blks = kmalloc(nr_blks, GFP_KERNEL); - if (!blks) - return -ENOMEM; - - for (i = 0; i < s->nr_rows; i++) { - s->row = i; - - ret = nvm_get_bb_tbl(dev, ppas[i], blks); - if (ret) { - pr_err("nvm: failed bb tbl for ppa (%u %u)\n", - ppas[i].g.ch, - ppas[i].g.blk); - goto err_get; - } - - if (get_free) - ret = sysblk_get_free_blks(dev, ppas[i], blks, nr_blks, - s); - else - ret = sysblk_get_host_blks(dev, ppas[i], blks, nr_blks, - s); - - if (ret) - goto err_get; - } - -err_get: - kfree(blks); - return ret; -} - -/* - * scans a block for latest sysblk. - * Returns: - * 0 - newer sysblk not found. PPA is updated to latest page. - * 1 - newer sysblk found and stored in *cur. PPA is updated to - * next valid page. - * <0- error. - */ -static int nvm_scan_block(struct nvm_dev *dev, struct ppa_addr *ppa, - struct nvm_system_block *sblk) -{ - struct nvm_geo *geo = &dev->geo; - struct nvm_system_block *cur; - int pg, ret, found = 0; - - /* the full buffer for a flash page is allocated. Only the first of it - * contains the system block information - */ - cur = kmalloc(geo->pfpg_size, GFP_KERNEL); - if (!cur) - return -ENOMEM; - - /* perform linear scan through the block */ - for (pg = 0; pg < dev->lps_per_blk; pg++) { - ppa->g.pg = ppa_to_slc(dev, pg); - - ret = nvm_submit_ppa(dev, ppa, 1, NVM_OP_PREAD, NVM_IO_SLC_MODE, - cur, geo->pfpg_size); - if (ret) { - if (ret == NVM_RSP_ERR_EMPTYPAGE) { - pr_debug("nvm: sysblk scan empty ppa (%u %u %u %u)\n", - ppa->g.ch, - ppa->g.lun, - ppa->g.blk, - ppa->g.pg); - break; - } - pr_err("nvm: read failed (%x) for ppa (%u %u %u %u)", - ret, - ppa->g.ch, - ppa->g.lun, - ppa->g.blk, - ppa->g.pg); - break; /* if we can't read a page, continue to the - * next blk - */ - } - - if (be32_to_cpu(cur->magic) != NVM_SYSBLK_MAGIC) { - pr_debug("nvm: scan break for ppa (%u %u %u %u)\n", - ppa->g.ch, - ppa->g.lun, - ppa->g.blk, - ppa->g.pg); - break; /* last valid page already found */ - } - - if (be32_to_cpu(cur->seqnr) < be32_to_cpu(sblk->seqnr)) - continue; - - memcpy(sblk, cur, sizeof(struct nvm_system_block)); - found = 1; - } - - kfree(cur); - - return found; -} - -static int nvm_sysblk_set_bb_tbl(struct nvm_dev *dev, struct sysblk_scan *s, - int type) -{ - return nvm_set_bb_tbl(dev, s->ppas, s->nr_ppas, type); -} - -static int nvm_write_and_verify(struct nvm_dev *dev, struct nvm_sb_info *info, - struct sysblk_scan *s) -{ - struct nvm_geo *geo = &dev->geo; - struct nvm_system_block nvmsb; - void *buf; - int i, sect, ret = 0; - struct ppa_addr *ppas; - - nvm_cpu_to_sysblk(&nvmsb, info); - - buf = kzalloc(geo->pfpg_size, GFP_KERNEL); - if (!buf) - return -ENOMEM; - memcpy(buf, &nvmsb, sizeof(struct nvm_system_block)); - - ppas = kcalloc(geo->sec_per_pg, sizeof(struct ppa_addr), GFP_KERNEL); - if (!ppas) { - ret = -ENOMEM; - goto err; - } - - /* Write and verify */ - for (i = 0; i < s->nr_rows; i++) { - ppas[0] = s->ppas[scan_ppa_idx(i, s->act_blk[i])]; - - pr_debug("nvm: writing sysblk to ppa (%u %u %u %u)\n", - ppas[0].g.ch, - ppas[0].g.lun, - ppas[0].g.blk, - ppas[0].g.pg); - - /* Expand to all sectors within a flash page */ - if (geo->sec_per_pg > 1) { - for (sect = 1; sect < geo->sec_per_pg; sect++) { - ppas[sect].ppa = ppas[0].ppa; - ppas[sect].g.sec = sect; - } - } - - ret = nvm_submit_ppa(dev, ppas, geo->sec_per_pg, NVM_OP_PWRITE, - NVM_IO_SLC_MODE, buf, geo->pfpg_size); - if (ret) { - pr_err("nvm: sysblk failed program (%u %u %u)\n", - ppas[0].g.ch, - ppas[0].g.lun, - ppas[0].g.blk); - break; - } - - ret = nvm_submit_ppa(dev, ppas, geo->sec_per_pg, NVM_OP_PREAD, - NVM_IO_SLC_MODE, buf, geo->pfpg_size); - if (ret) { - pr_err("nvm: sysblk failed read (%u %u %u)\n", - ppas[0].g.ch, - ppas[0].g.lun, - ppas[0].g.blk); - break; - } - - if (memcmp(buf, &nvmsb, sizeof(struct nvm_system_block))) { - pr_err("nvm: sysblk failed verify (%u %u %u)\n", - ppas[0].g.ch, - ppas[0].g.lun, - ppas[0].g.blk); - ret = -EINVAL; - break; - } - } - - kfree(ppas); -err: - kfree(buf); - - return ret; -} - -static int nvm_prepare_new_sysblks(struct nvm_dev *dev, struct sysblk_scan *s) -{ - int i, ret; - unsigned long nxt_blk; - struct ppa_addr *ppa; - - for (i = 0; i < s->nr_rows; i++) { - nxt_blk = (s->act_blk[i] + 1) % MAX_BLKS_PR_SYSBLK; - ppa = &s->ppas[scan_ppa_idx(i, nxt_blk)]; - ppa->g.pg = ppa_to_slc(dev, 0); - - ret = nvm_erase_ppa(dev, ppa, 1, 0); - if (ret) - return ret; - - s->act_blk[i] = nxt_blk; - } - - return 0; -} - -int nvm_get_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info) -{ - struct ppa_addr sysblk_ppas[MAX_SYSBLKS]; - struct sysblk_scan s; - struct nvm_system_block *cur; - int i, j, found = 0; - int ret = -ENOMEM; - - /* - * 1. setup sysblk locations - * 2. get bad block list - * 3. filter on host-specific (type 3) - * 4. iterate through all and find the highest seq nr. - * 5. return superblock information - */ - - if (!dev->ops->get_bb_tbl) - return -EINVAL; - - nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); - - mutex_lock(&dev->mlock); - ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0); - if (ret) - goto err_sysblk; - - /* no sysblocks initialized */ - if (!s.nr_ppas) - goto err_sysblk; - - cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL); - if (!cur) - goto err_sysblk; - - /* find the latest block across all sysblocks */ - for (i = 0; i < s.nr_rows; i++) { - for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) { - struct ppa_addr ppa = s.ppas[scan_ppa_idx(i, j)]; - - ret = nvm_scan_block(dev, &ppa, cur); - if (ret > 0) - found = 1; - else if (ret < 0) - break; - } - } - - nvm_sysblk_to_cpu(info, cur); - - kfree(cur); -err_sysblk: - mutex_unlock(&dev->mlock); - - if (found) - return 1; - return ret; -} - -int nvm_update_sysblock(struct nvm_dev *dev, struct nvm_sb_info *new) -{ - /* 1. for each latest superblock - * 2. if room - * a. write new flash page entry with the updated information - * 3. if no room - * a. find next available block on lun (linear search) - * if none, continue to next lun - * if none at all, report error. also report that it wasn't - * possible to write to all superblocks. - * c. write data to block. - */ - struct ppa_addr sysblk_ppas[MAX_SYSBLKS]; - struct sysblk_scan s; - struct nvm_system_block *cur; - int i, j, ppaidx, found = 0; - int ret = -ENOMEM; - - if (!dev->ops->get_bb_tbl) - return -EINVAL; - - nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); - - mutex_lock(&dev->mlock); - ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0); - if (ret) - goto err_sysblk; - - cur = kzalloc(sizeof(struct nvm_system_block), GFP_KERNEL); - if (!cur) - goto err_sysblk; - - /* Get the latest sysblk for each sysblk row */ - for (i = 0; i < s.nr_rows; i++) { - found = 0; - for (j = 0; j < MAX_BLKS_PR_SYSBLK; j++) { - ppaidx = scan_ppa_idx(i, j); - ret = nvm_scan_block(dev, &s.ppas[ppaidx], cur); - if (ret > 0) { - s.act_blk[i] = j; - found = 1; - } else if (ret < 0) - break; - } - } - - if (!found) { - pr_err("nvm: no valid sysblks found to update\n"); - ret = -EINVAL; - goto err_cur; - } - - /* - * All sysblocks found. Check that they have same page id in their flash - * blocks - */ - for (i = 1; i < s.nr_rows; i++) { - struct ppa_addr l = s.ppas[scan_ppa_idx(0, s.act_blk[0])]; - struct ppa_addr r = s.ppas[scan_ppa_idx(i, s.act_blk[i])]; - - if (l.g.pg != r.g.pg) { - pr_err("nvm: sysblks not on same page. Previous update failed.\n"); - ret = -EINVAL; - goto err_cur; - } - } - - /* - * Check that there haven't been another update to the seqnr since we - * began - */ - if ((new->seqnr - 1) != be32_to_cpu(cur->seqnr)) { - pr_err("nvm: seq is not sequential\n"); - ret = -EINVAL; - goto err_cur; - } - - /* - * When all pages in a block has been written, a new block is selected - * and writing is performed on the new block. - */ - if (s.ppas[scan_ppa_idx(0, s.act_blk[0])].g.pg == - dev->lps_per_blk - 1) { - ret = nvm_prepare_new_sysblks(dev, &s); - if (ret) - goto err_cur; - } - - ret = nvm_write_and_verify(dev, new, &s); -err_cur: - kfree(cur); -err_sysblk: - mutex_unlock(&dev->mlock); - - return ret; -} - -int nvm_init_sysblock(struct nvm_dev *dev, struct nvm_sb_info *info) -{ - struct nvm_geo *geo = &dev->geo; - struct ppa_addr sysblk_ppas[MAX_SYSBLKS]; - struct sysblk_scan s; - int ret; - - /* - * 1. select master blocks and select first available blks - * 2. get bad block list - * 3. mark MAX_SYSBLKS block as host-based device allocated. - * 4. write and verify data to block - */ - - if (!dev->ops->get_bb_tbl || !dev->ops->set_bb_tbl) - return -EINVAL; - - if (!(geo->mccap & NVM_ID_CAP_SLC) || !dev->lps_per_blk) { - pr_err("nvm: memory does not support SLC access\n"); - return -EINVAL; - } - - /* Index all sysblocks and mark them as host-driven */ - nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); - - mutex_lock(&dev->mlock); - ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 1); - if (ret) - goto err_mark; - - ret = nvm_sysblk_set_bb_tbl(dev, &s, NVM_BLK_T_HOST); - if (ret) - goto err_mark; - - /* Write to the first block of each row */ - ret = nvm_write_and_verify(dev, info, &s); -err_mark: - mutex_unlock(&dev->mlock); - return ret; -} - -static int factory_nblks(int nblks) -{ - /* Round up to nearest BITS_PER_LONG */ - return (nblks + (BITS_PER_LONG - 1)) & ~(BITS_PER_LONG - 1); -} - -static unsigned int factory_blk_offset(struct nvm_geo *geo, struct ppa_addr ppa) -{ - int nblks = factory_nblks(geo->blks_per_lun); - - return ((ppa.g.ch * geo->luns_per_chnl * nblks) + (ppa.g.lun * nblks)) / - BITS_PER_LONG; -} - -static int nvm_factory_blks(struct nvm_dev *dev, struct ppa_addr ppa, - u8 *blks, int nr_blks, - unsigned long *blk_bitmap, int flags) -{ - int i, lunoff; - - nr_blks = nvm_bb_tbl_fold(dev, blks, nr_blks); - if (nr_blks < 0) - return nr_blks; - - lunoff = factory_blk_offset(&dev->geo, ppa); - - /* non-set bits correspond to the block must be erased */ - for (i = 0; i < nr_blks; i++) { - switch (blks[i]) { - case NVM_BLK_T_FREE: - if (flags & NVM_FACTORY_ERASE_ONLY_USER) - set_bit(i, &blk_bitmap[lunoff]); - break; - case NVM_BLK_T_HOST: - if (!(flags & NVM_FACTORY_RESET_HOST_BLKS)) - set_bit(i, &blk_bitmap[lunoff]); - break; - case NVM_BLK_T_GRWN_BAD: - if (!(flags & NVM_FACTORY_RESET_GRWN_BBLKS)) - set_bit(i, &blk_bitmap[lunoff]); - break; - default: - set_bit(i, &blk_bitmap[lunoff]); - break; - } - } - - return 0; -} - -static int nvm_fact_get_blks(struct nvm_dev *dev, struct ppa_addr *erase_list, - int max_ppas, unsigned long *blk_bitmap) -{ - struct nvm_geo *geo = &dev->geo; - struct ppa_addr ppa; - int ch, lun, blkid, idx, done = 0, ppa_cnt = 0; - unsigned long *offset; - - while (!done) { - done = 1; - nvm_for_each_lun_ppa(geo, ppa, ch, lun) { - idx = factory_blk_offset(geo, ppa); - offset = &blk_bitmap[idx]; - - blkid = find_first_zero_bit(offset, geo->blks_per_lun); - if (blkid >= geo->blks_per_lun) - continue; - set_bit(blkid, offset); - - ppa.g.blk = blkid; - pr_debug("nvm: erase ppa (%u %u %u)\n", - ppa.g.ch, - ppa.g.lun, - ppa.g.blk); - - erase_list[ppa_cnt] = ppa; - ppa_cnt++; - done = 0; - - if (ppa_cnt == max_ppas) - return ppa_cnt; - } - } - - return ppa_cnt; -} - -static int nvm_fact_select_blks(struct nvm_dev *dev, unsigned long *blk_bitmap, - int flags) -{ - struct nvm_geo *geo = &dev->geo; - struct ppa_addr ppa; - int ch, lun, nr_blks, ret = 0; - u8 *blks; - - nr_blks = geo->blks_per_lun * geo->plane_mode; - blks = kmalloc(nr_blks, GFP_KERNEL); - if (!blks) - return -ENOMEM; - - nvm_for_each_lun_ppa(geo, ppa, ch, lun) { - ret = nvm_get_bb_tbl(dev, ppa, blks); - if (ret) - pr_err("nvm: failed bb tbl for ch%u lun%u\n", - ppa.g.ch, ppa.g.blk); - - ret = nvm_factory_blks(dev, ppa, blks, nr_blks, blk_bitmap, - flags); - if (ret) - break; - } - - kfree(blks); - return ret; -} - -int nvm_dev_factory(struct nvm_dev *dev, int flags) -{ - struct nvm_geo *geo = &dev->geo; - struct ppa_addr *ppas; - int ppa_cnt, ret = -ENOMEM; - int max_ppas = dev->ops->max_phys_sect / geo->nr_planes; - struct ppa_addr sysblk_ppas[MAX_SYSBLKS]; - struct sysblk_scan s; - unsigned long *blk_bitmap; - - blk_bitmap = kzalloc(factory_nblks(geo->blks_per_lun) * geo->nr_luns, - GFP_KERNEL); - if (!blk_bitmap) - return ret; - - ppas = kcalloc(max_ppas, sizeof(struct ppa_addr), GFP_KERNEL); - if (!ppas) - goto err_blks; - - /* create list of blks to be erased */ - ret = nvm_fact_select_blks(dev, blk_bitmap, flags); - if (ret) - goto err_ppas; - - /* continue to erase until list of blks until empty */ - while ((ppa_cnt = - nvm_fact_get_blks(dev, ppas, max_ppas, blk_bitmap)) > 0) - nvm_erase_ppa(dev, ppas, ppa_cnt, 0); - - /* mark host reserved blocks free */ - if (flags & NVM_FACTORY_RESET_HOST_BLKS) { - nvm_setup_sysblk_scan(dev, &s, sysblk_ppas); - mutex_lock(&dev->mlock); - ret = nvm_get_all_sysblks(dev, &s, sysblk_ppas, 0); - if (!ret) - ret = nvm_sysblk_set_bb_tbl(dev, &s, NVM_BLK_T_FREE); - mutex_unlock(&dev->mlock); - } -err_ppas: - kfree(ppas); -err_blks: - kfree(blk_bitmap); - return ret; -} -EXPORT_SYMBOL(nvm_dev_factory); diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 775527135b93..e199fd6c71ce 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -52,8 +52,8 @@ struct rackmeter_dma { struct rackmeter_cpu { struct delayed_work sniffer; struct rackmeter *rm; - cputime64_t prev_wall; - cputime64_t prev_idle; + u64 prev_wall; + u64 prev_idle; int zero; } ____cacheline_aligned; @@ -81,7 +81,7 @@ static int rackmeter_ignore_nice; /* This is copied from cpufreq_ondemand, maybe we should put it in * a common header somewhere */ -static inline cputime64_t get_cpu_idle_time(unsigned int cpu) +static inline u64 get_cpu_idle_time(unsigned int cpu) { u64 retval; @@ -217,23 +217,23 @@ static void rackmeter_do_timer(struct work_struct *work) container_of(work, struct rackmeter_cpu, sniffer.work); struct rackmeter *rm = rcpu->rm; unsigned int cpu = smp_processor_id(); - cputime64_t cur_jiffies, total_idle_ticks; - unsigned int total_ticks, idle_ticks; + u64 cur_nsecs, total_idle_nsecs; + u64 total_nsecs, idle_nsecs; int i, offset, load, cumm, pause; - cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); - total_ticks = (unsigned int) (cur_jiffies - rcpu->prev_wall); - rcpu->prev_wall = cur_jiffies; + cur_nsecs = jiffies64_to_nsecs(get_jiffies_64()); + total_nsecs = cur_nsecs - rcpu->prev_wall; + rcpu->prev_wall = cur_nsecs; - total_idle_ticks = get_cpu_idle_time(cpu); - idle_ticks = (unsigned int) (total_idle_ticks - rcpu->prev_idle); - idle_ticks = min(idle_ticks, total_ticks); - rcpu->prev_idle = total_idle_ticks; + total_idle_nsecs = get_cpu_idle_time(cpu); + idle_nsecs = total_idle_nsecs - rcpu->prev_idle; + idle_nsecs = min(idle_nsecs, total_nsecs); + rcpu->prev_idle = total_idle_nsecs; /* We do a very dumb calculation to update the LEDs for now, * we'll do better once we have actual PWM implemented */ - load = (9 * (total_ticks - idle_ticks)) / total_ticks; + load = div64_u64(9 * (total_nsecs - idle_nsecs), total_nsecs); offset = cpu << 3; cumm = 0; @@ -278,7 +278,7 @@ static void rackmeter_init_cpu_sniffer(struct rackmeter *rm) continue; rcpu = &rm->cpu[cpu]; rcpu->prev_idle = get_cpu_idle_time(cpu); - rcpu->prev_wall = jiffies64_to_cputime64(get_jiffies_64()); + rcpu->prev_wall = jiffies64_to_nsecs(get_jiffies_64()); schedule_delayed_work_on(cpu, &rm->cpu[cpu].sniffer, msecs_to_jiffies(CPU_SAMPLING_RATE)); } diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 76d20875503c..709c9cc34369 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -666,7 +666,7 @@ static inline struct search *search_alloc(struct bio *bio, s->iop.write_prio = 0; s->iop.error = 0; s->iop.flags = 0; - s->iop.flush_journal = (bio->bi_opf & (REQ_PREFLUSH|REQ_FUA)) != 0; + s->iop.flush_journal = op_is_flush(bio->bi_opf); s->iop.wq = bcache_wq; return s; @@ -1009,7 +1009,7 @@ static int cached_dev_congested(void *data, int bits) struct request_queue *q = bdev_get_queue(dc->bdev); int ret = 0; - if (bdi_congested(&q->backing_dev_info, bits)) + if (bdi_congested(q->backing_dev_info, bits)) return 1; if (cached_dev_get(dc)) { @@ -1018,7 +1018,7 @@ static int cached_dev_congested(void *data, int bits) for_each_cache(ca, d->c, i) { q = bdev_get_queue(ca->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); } cached_dev_put(dc); @@ -1032,7 +1032,7 @@ void bch_cached_dev_request_init(struct cached_dev *dc) struct gendisk *g = dc->disk.disk; g->queue->make_request_fn = cached_dev_make_request; - g->queue->backing_dev_info.congested_fn = cached_dev_congested; + g->queue->backing_dev_info->congested_fn = cached_dev_congested; dc->disk.cache_miss = cached_dev_cache_miss; dc->disk.ioctl = cached_dev_ioctl; } @@ -1125,7 +1125,7 @@ static int flash_dev_congested(void *data, int bits) for_each_cache(ca, d->c, i) { q = bdev_get_queue(ca->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); } return ret; @@ -1136,7 +1136,7 @@ void bch_flash_dev_request_init(struct bcache_device *d) struct gendisk *g = d->disk; g->queue->make_request_fn = flash_dev_make_request; - g->queue->backing_dev_info.congested_fn = flash_dev_congested; + g->queue->backing_dev_info->congested_fn = flash_dev_congested; d->cache_miss = flash_dev_cache_miss; d->ioctl = flash_dev_ioctl; } diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 3a19cbc8b230..85e3f21c2514 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -807,7 +807,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, blk_queue_make_request(q, NULL); d->disk->queue = q; q->queuedata = d; - q->backing_dev_info.congested_data = d; + q->backing_dev_info->congested_data = d; q->limits.max_hw_sectors = UINT_MAX; q->limits.max_sectors = UINT_MAX; q->limits.max_segment_size = UINT_MAX; @@ -1132,9 +1132,9 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size) set_capacity(dc->disk.disk, dc->bdev->bd_part->nr_sects - dc->sb.data_offset); - dc->disk.disk->queue->backing_dev_info.ra_pages = - max(dc->disk.disk->queue->backing_dev_info.ra_pages, - q->backing_dev_info.ra_pages); + dc->disk.disk->queue->backing_dev_info->ra_pages = + max(dc->disk.disk->queue->backing_dev_info->ra_pages, + q->backing_dev_info->ra_pages); bch_cached_dev_request_init(dc); bch_cached_dev_writeback_init(dc); diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 84d2f0e4c754..d36d427a9efb 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -794,7 +794,7 @@ static void __wait_for_free_buffer(struct dm_bufio_client *c) DECLARE_WAITQUEUE(wait, current); add_wait_queue(&c->free_buffer_wait, &wait); - set_task_state(current, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); dm_bufio_unlock(c); io_schedule(); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index e04c61e0839e..894bc14469c8 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -787,8 +787,7 @@ static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio) struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size); spin_lock_irqsave(&cache->lock, flags); - if (cache->need_tick_bio && - !(bio->bi_opf & (REQ_FUA | REQ_PREFLUSH)) && + if (cache->need_tick_bio && !op_is_flush(bio->bi_opf) && bio_op(bio) != REQ_OP_DISCARD) { pb->tick = true; cache->need_tick_bio = false; @@ -828,11 +827,6 @@ static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio) return to_oblock(block_nr); } -static int bio_triggers_commit(struct cache *cache, struct bio *bio) -{ - return bio->bi_opf & (REQ_PREFLUSH | REQ_FUA); -} - /* * You must increment the deferred set whilst the prison cell is held. To * encourage this, we ask for 'cell' to be passed in. @@ -884,7 +878,7 @@ static void issue(struct cache *cache, struct bio *bio) { unsigned long flags; - if (!bio_triggers_commit(cache, bio)) { + if (!op_is_flush(bio->bi_opf)) { accounted_request(cache, bio); return; } @@ -1069,8 +1063,7 @@ static void dec_io_migrations(struct cache *cache) static bool discard_or_flush(struct bio *bio) { - return bio_op(bio) == REQ_OP_DISCARD || - bio->bi_opf & (REQ_PREFLUSH | REQ_FUA); + return bio_op(bio) == REQ_OP_DISCARD || op_is_flush(bio->bi_opf); } static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell) @@ -2291,7 +2284,7 @@ static void do_waker(struct work_struct *ws) static int is_congested(struct dm_dev *dev, int bdi_bits) { struct request_queue *q = bdev_get_queue(dev->bdev); - return bdi_congested(&q->backing_dev_info, bdi_bits); + return bdi_congested(q->backing_dev_info, bdi_bits); } static int cache_is_congested(struct dm_target_callbacks *cb, int bdi_bits) diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 40ceba1fe8be..136fda3ff9e5 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -92,7 +92,6 @@ struct mapped_device { * io objects are allocated from here. */ mempool_t *io_pool; - mempool_t *rq_pool; struct bio_set *bs; diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 7c6c57216bf2..1cb2ca9dfae3 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -1210,14 +1210,14 @@ continue_locked: spin_unlock_irq(&cc->write_thread_wait.lock); if (unlikely(kthread_should_stop())) { - set_task_state(current, TASK_RUNNING); + set_current_state(TASK_RUNNING); remove_wait_queue(&cc->write_thread_wait, &wait); break; } schedule(); - set_task_state(current, TASK_RUNNING); + set_current_state(TASK_RUNNING); spin_lock_irq(&cc->write_thread_wait.lock); __remove_wait_queue(&cc->write_thread_wait, &wait); goto continue_locked; @@ -1534,18 +1534,18 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string return PTR_ERR(key); } - rcu_read_lock(); + down_read(&key->sem); ukp = user_key_payload(key); if (!ukp) { - rcu_read_unlock(); + up_read(&key->sem); key_put(key); kzfree(new_key_string); return -EKEYREVOKED; } if (cc->key_size != ukp->datalen) { - rcu_read_unlock(); + up_read(&key->sem); key_put(key); kzfree(new_key_string); return -EINVAL; @@ -1553,7 +1553,7 @@ static int crypt_set_keyring_key(struct crypt_config *cc, const char *key_string memcpy(cc->key, ukp->data, cc->key_size); - rcu_read_unlock(); + up_read(&key->sem); key_put(key); /* clear the flag since following operations may invalidate previously valid key */ diff --git a/drivers/md/dm-era-target.c b/drivers/md/dm-era-target.c index bf2b2676cb8a..9fab33b113c4 100644 --- a/drivers/md/dm-era-target.c +++ b/drivers/md/dm-era-target.c @@ -1379,7 +1379,7 @@ static void stop_worker(struct era *era) static int dev_is_congested(struct dm_dev *dev, int bdi_bits) { struct request_queue *q = bdev_get_queue(dev->bdev); - return bdi_congested(&q->backing_dev_info, bdi_bits); + return bdi_congested(q->backing_dev_info, bdi_bits); } static int era_is_congested(struct dm_target_callbacks *cb, int bdi_bits) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 6400cffb986d..7f223dbed49f 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -92,12 +92,6 @@ struct multipath { unsigned queue_mode; - /* - * We must use a mempool of dm_mpath_io structs so that we - * can resubmit bios on error. - */ - mempool_t *mpio_pool; - struct mutex work_mutex; struct work_struct trigger_event; @@ -115,8 +109,6 @@ struct dm_mpath_io { typedef int (*action_fn) (struct pgpath *pgpath); -static struct kmem_cache *_mpio_cache; - static struct workqueue_struct *kmultipathd, *kmpath_handlerd; static void trigger_event(struct work_struct *work); static void activate_path(struct work_struct *work); @@ -209,7 +201,6 @@ static struct multipath *alloc_multipath(struct dm_target *ti) init_waitqueue_head(&m->pg_init_wait); mutex_init(&m->work_mutex); - m->mpio_pool = NULL; m->queue_mode = DM_TYPE_NONE; m->ti = ti; @@ -229,16 +220,7 @@ static int alloc_multipath_stage2(struct dm_target *ti, struct multipath *m) m->queue_mode = DM_TYPE_MQ_REQUEST_BASED; else m->queue_mode = DM_TYPE_REQUEST_BASED; - } - - if (m->queue_mode == DM_TYPE_REQUEST_BASED) { - unsigned min_ios = dm_get_reserved_rq_based_ios(); - - m->mpio_pool = mempool_create_slab_pool(min_ios, _mpio_cache); - if (!m->mpio_pool) - return -ENOMEM; - } - else if (m->queue_mode == DM_TYPE_BIO_BASED) { + } else if (m->queue_mode == DM_TYPE_BIO_BASED) { INIT_WORK(&m->process_queued_bios, process_queued_bios); /* * bio-based doesn't support any direct scsi_dh management; @@ -263,7 +245,6 @@ static void free_multipath(struct multipath *m) kfree(m->hw_handler_name); kfree(m->hw_handler_params); - mempool_destroy(m->mpio_pool); kfree(m); } @@ -272,38 +253,6 @@ static struct dm_mpath_io *get_mpio(union map_info *info) return info->ptr; } -static struct dm_mpath_io *set_mpio(struct multipath *m, union map_info *info) -{ - struct dm_mpath_io *mpio; - - if (!m->mpio_pool) { - /* Use blk-mq pdu memory requested via per_io_data_size */ - mpio = get_mpio(info); - memset(mpio, 0, sizeof(*mpio)); - return mpio; - } - - mpio = mempool_alloc(m->mpio_pool, GFP_ATOMIC); - if (!mpio) - return NULL; - - memset(mpio, 0, sizeof(*mpio)); - info->ptr = mpio; - - return mpio; -} - -static void clear_request_fn_mpio(struct multipath *m, union map_info *info) -{ - /* Only needed for non blk-mq (.request_fn) multipath */ - if (m->mpio_pool) { - struct dm_mpath_io *mpio = info->ptr; - - info->ptr = NULL; - mempool_free(mpio, m->mpio_pool); - } -} - static size_t multipath_per_bio_data_size(void) { return sizeof(struct dm_mpath_io) + sizeof(struct dm_bio_details); @@ -427,7 +376,7 @@ static struct pgpath *choose_pgpath(struct multipath *m, size_t nr_bytes) unsigned long flags; struct priority_group *pg; struct pgpath *pgpath; - bool bypassed = true; + unsigned bypassed = 1; if (!atomic_read(&m->nr_valid_paths)) { clear_bit(MPATHF_QUEUE_IO, &m->flags); @@ -466,7 +415,7 @@ check_current_pg: */ do { list_for_each_entry(pg, &m->priority_groups, list) { - if (pg->bypassed == bypassed) + if (pg->bypassed == !!bypassed) continue; pgpath = choose_path_in_pg(m, pg, nr_bytes); if (!IS_ERR_OR_NULL(pgpath)) { @@ -530,16 +479,17 @@ static bool must_push_back_bio(struct multipath *m) /* * Map cloned requests (request-based multipath) */ -static int __multipath_map(struct dm_target *ti, struct request *clone, - union map_info *map_context, - struct request *rq, struct request **__clone) +static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, + union map_info *map_context, + struct request **__clone) { struct multipath *m = ti->private; int r = DM_MAPIO_REQUEUE; - size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq); + size_t nr_bytes = blk_rq_bytes(rq); struct pgpath *pgpath; struct block_device *bdev; - struct dm_mpath_io *mpio; + struct dm_mpath_io *mpio = get_mpio(map_context); + struct request *clone; /* Do we need to select a new pgpath? */ pgpath = lockless_dereference(m->current_pgpath); @@ -556,42 +506,23 @@ static int __multipath_map(struct dm_target *ti, struct request *clone, return r; } - mpio = set_mpio(m, map_context); - if (!mpio) - /* ENOMEM, requeue */ - return r; - + memset(mpio, 0, sizeof(*mpio)); mpio->pgpath = pgpath; mpio->nr_bytes = nr_bytes; bdev = pgpath->path.dev->bdev; - if (clone) { - /* - * Old request-based interface: allocated clone is passed in. - * Used by: .request_fn stacked on .request_fn path(s). - */ - clone->q = bdev_get_queue(bdev); - clone->rq_disk = bdev->bd_disk; - clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; - } else { - /* - * blk-mq request-based interface; used by both: - * .request_fn stacked on blk-mq path(s) and - * blk-mq stacked on blk-mq path(s). - */ - clone = blk_mq_alloc_request(bdev_get_queue(bdev), - rq_data_dir(rq), BLK_MQ_REQ_NOWAIT); - if (IS_ERR(clone)) { - /* EBUSY, ENODEV or EWOULDBLOCK: requeue */ - clear_request_fn_mpio(m, map_context); - return r; - } - clone->bio = clone->biotail = NULL; - clone->rq_disk = bdev->bd_disk; - clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; - *__clone = clone; + clone = blk_get_request(bdev_get_queue(bdev), + rq->cmd_flags | REQ_NOMERGE, + GFP_ATOMIC); + if (IS_ERR(clone)) { + /* EBUSY, ENODEV or EWOULDBLOCK: requeue */ + return r; } + clone->bio = clone->biotail = NULL; + clone->rq_disk = bdev->bd_disk; + clone->cmd_flags |= REQ_FAILFAST_TRANSPORT; + *__clone = clone; if (pgpath->pg->ps.type->start_io) pgpath->pg->ps.type->start_io(&pgpath->pg->ps, @@ -600,22 +531,9 @@ static int __multipath_map(struct dm_target *ti, struct request *clone, return DM_MAPIO_REMAPPED; } -static int multipath_map(struct dm_target *ti, struct request *clone, - union map_info *map_context) -{ - return __multipath_map(ti, clone, map_context, NULL, NULL); -} - -static int multipath_clone_and_map(struct dm_target *ti, struct request *rq, - union map_info *map_context, - struct request **clone) -{ - return __multipath_map(ti, NULL, map_context, rq, clone); -} - static void multipath_release_clone(struct request *clone) { - blk_mq_free_request(clone); + blk_put_request(clone); } /* @@ -1187,7 +1105,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned argc, char **argv) ti->num_write_same_bios = 1; if (m->queue_mode == DM_TYPE_BIO_BASED) ti->per_io_data_size = multipath_per_bio_data_size(); - else if (m->queue_mode == DM_TYPE_MQ_REQUEST_BASED) + else ti->per_io_data_size = sizeof(struct dm_mpath_io); return 0; @@ -1610,7 +1528,6 @@ static int multipath_end_io(struct dm_target *ti, struct request *clone, if (ps->type->end_io) ps->type->end_io(ps, &pgpath->path, mpio->nr_bytes); } - clear_request_fn_mpio(m, map_context); return r; } @@ -2060,7 +1977,6 @@ static struct target_type multipath_target = { .module = THIS_MODULE, .ctr = multipath_ctr, .dtr = multipath_dtr, - .map_rq = multipath_map, .clone_and_map_rq = multipath_clone_and_map, .release_clone_rq = multipath_release_clone, .rq_end_io = multipath_end_io, @@ -2080,11 +1996,6 @@ static int __init dm_multipath_init(void) { int r; - /* allocate a slab for the dm_mpath_ios */ - _mpio_cache = KMEM_CACHE(dm_mpath_io, 0); - if (!_mpio_cache) - return -ENOMEM; - r = dm_register_target(&multipath_target); if (r < 0) { DMERR("request-based register failed %d", r); @@ -2120,8 +2031,6 @@ bad_alloc_kmpath_handlerd: bad_alloc_kmultipathd: dm_unregister_target(&multipath_target); bad_register_target: - kmem_cache_destroy(_mpio_cache); - return r; } @@ -2131,7 +2040,6 @@ static void __exit dm_multipath_exit(void) destroy_workqueue(kmultipathd); dm_unregister_target(&multipath_target); - kmem_cache_destroy(_mpio_cache); } module_init(dm_multipath_init); diff --git a/drivers/md/dm-rq.c b/drivers/md/dm-rq.c index 9d7275fb541a..67d76f21fecd 100644 --- a/drivers/md/dm-rq.c +++ b/drivers/md/dm-rq.c @@ -109,28 +109,6 @@ void dm_stop_queue(struct request_queue *q) dm_mq_stop_queue(q); } -static struct dm_rq_target_io *alloc_old_rq_tio(struct mapped_device *md, - gfp_t gfp_mask) -{ - return mempool_alloc(md->io_pool, gfp_mask); -} - -static void free_old_rq_tio(struct dm_rq_target_io *tio) -{ - mempool_free(tio, tio->md->io_pool); -} - -static struct request *alloc_old_clone_request(struct mapped_device *md, - gfp_t gfp_mask) -{ - return mempool_alloc(md->rq_pool, gfp_mask); -} - -static void free_old_clone_request(struct mapped_device *md, struct request *rq) -{ - mempool_free(rq, md->rq_pool); -} - /* * Partial completion handling for request-based dm */ @@ -185,7 +163,7 @@ static void end_clone_bio(struct bio *clone) static struct dm_rq_target_io *tio_from_request(struct request *rq) { - return (rq->q->mq_ops ? blk_mq_rq_to_pdu(rq) : rq->special); + return blk_mq_rq_to_pdu(rq); } static void rq_end_stats(struct mapped_device *md, struct request *orig) @@ -233,31 +211,6 @@ static void rq_completed(struct mapped_device *md, int rw, bool run_queue) dm_put(md); } -static void free_rq_clone(struct request *clone) -{ - struct dm_rq_target_io *tio = clone->end_io_data; - struct mapped_device *md = tio->md; - - blk_rq_unprep_clone(clone); - - /* - * It is possible for a clone_old_rq() allocated clone to - * get passed in -- it may not yet have a request_queue. - * This is known to occur if the error target replaces - * a multipath target that has a request_fn queue stacked - * on blk-mq queue(s). - */ - if (clone->q && clone->q->mq_ops) - /* stacked on blk-mq queue(s) */ - tio->ti->type->release_clone_rq(clone); - else if (!md->queue->mq_ops) - /* request_fn queue stacked on request_fn queue(s) */ - free_old_clone_request(md, clone); - - if (!md->queue->mq_ops) - free_old_rq_tio(tio); -} - /* * Complete the clone and the original request. * Must be called without clone's queue lock held, @@ -270,20 +223,9 @@ static void dm_end_request(struct request *clone, int error) struct mapped_device *md = tio->md; struct request *rq = tio->orig; - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - rq->errors = clone->errors; - rq->resid_len = clone->resid_len; - - if (rq->sense) - /* - * We are using the sense buffer of the original - * request. - * So setting the length of the sense data is enough. - */ - rq->sense_len = clone->sense_len; - } + blk_rq_unprep_clone(clone); + tio->ti->type->release_clone_rq(clone); - free_rq_clone(clone); rq_end_stats(md, rq); if (!rq->q->mq_ops) blk_end_request_all(rq, error); @@ -292,22 +234,6 @@ static void dm_end_request(struct request *clone, int error) rq_completed(md, rw, true); } -static void dm_unprep_request(struct request *rq) -{ - struct dm_rq_target_io *tio = tio_from_request(rq); - struct request *clone = tio->clone; - - if (!rq->q->mq_ops) { - rq->special = NULL; - rq->rq_flags &= ~RQF_DONTPREP; - } - - if (clone) - free_rq_clone(clone); - else if (!tio->md->queue->mq_ops) - free_old_rq_tio(tio); -} - /* * Requeue the original request of a clone. */ @@ -346,7 +272,10 @@ static void dm_requeue_original_request(struct dm_rq_target_io *tio, bool delay_ int rw = rq_data_dir(rq); rq_end_stats(md, rq); - dm_unprep_request(rq); + if (tio->clone) { + blk_rq_unprep_clone(tio->clone); + tio->ti->type->release_clone_rq(tio->clone); + } if (!rq->q->mq_ops) dm_old_requeue_request(rq); @@ -401,14 +330,11 @@ static void dm_softirq_done(struct request *rq) if (!clone) { rq_end_stats(tio->md, rq); rw = rq_data_dir(rq); - if (!rq->q->mq_ops) { + if (!rq->q->mq_ops) blk_end_request_all(rq, tio->error); - rq_completed(tio->md, rw, false); - free_old_rq_tio(tio); - } else { + else blk_mq_end_request(rq, tio->error); - rq_completed(tio->md, rw, false); - } + rq_completed(tio->md, rw, false); return; } @@ -452,16 +378,6 @@ static void end_clone_request(struct request *clone, int error) { struct dm_rq_target_io *tio = clone->end_io_data; - if (!clone->q->mq_ops) { - /* - * For just cleaning up the information of the queue in which - * the clone was dispatched. - * The clone is *NOT* freed actually here because it is alloced - * from dm own mempool (RQF_ALLOCED isn't set). - */ - __blk_put_request(clone->q, clone); - } - /* * Actual request completion is done in a softirq context which doesn't * hold the clone's queue lock. Otherwise, deadlock could occur because: @@ -511,9 +427,6 @@ static int setup_clone(struct request *clone, struct request *rq, if (r) return r; - clone->cmd = rq->cmd; - clone->cmd_len = rq->cmd_len; - clone->sense = rq->sense; clone->end_io = end_clone_request; clone->end_io_data = tio; @@ -522,28 +435,6 @@ static int setup_clone(struct request *clone, struct request *rq, return 0; } -static struct request *clone_old_rq(struct request *rq, struct mapped_device *md, - struct dm_rq_target_io *tio, gfp_t gfp_mask) -{ - /* - * Create clone for use with .request_fn request_queue - */ - struct request *clone; - - clone = alloc_old_clone_request(md, gfp_mask); - if (!clone) - return NULL; - - blk_rq_init(NULL, clone); - if (setup_clone(clone, rq, tio, gfp_mask)) { - /* -ENOMEM */ - free_old_clone_request(md, clone); - return NULL; - } - - return clone; -} - static void map_tio_request(struct kthread_work *work); static void init_tio(struct dm_rq_target_io *tio, struct request *rq, @@ -565,60 +456,6 @@ static void init_tio(struct dm_rq_target_io *tio, struct request *rq, kthread_init_work(&tio->work, map_tio_request); } -static struct dm_rq_target_io *dm_old_prep_tio(struct request *rq, - struct mapped_device *md, - gfp_t gfp_mask) -{ - struct dm_rq_target_io *tio; - int srcu_idx; - struct dm_table *table; - - tio = alloc_old_rq_tio(md, gfp_mask); - if (!tio) - return NULL; - - init_tio(tio, rq, md); - - table = dm_get_live_table(md, &srcu_idx); - /* - * Must clone a request if this .request_fn DM device - * is stacked on .request_fn device(s). - */ - if (!dm_table_all_blk_mq_devices(table)) { - if (!clone_old_rq(rq, md, tio, gfp_mask)) { - dm_put_live_table(md, srcu_idx); - free_old_rq_tio(tio); - return NULL; - } - } - dm_put_live_table(md, srcu_idx); - - return tio; -} - -/* - * Called with the queue lock held. - */ -static int dm_old_prep_fn(struct request_queue *q, struct request *rq) -{ - struct mapped_device *md = q->queuedata; - struct dm_rq_target_io *tio; - - if (unlikely(rq->special)) { - DMWARN("Already has something in rq->special."); - return BLKPREP_KILL; - } - - tio = dm_old_prep_tio(rq, md, GFP_ATOMIC); - if (!tio) - return BLKPREP_DEFER; - - rq->special = tio; - rq->rq_flags |= RQF_DONTPREP; - - return BLKPREP_OK; -} - /* * Returns: * DM_MAPIO_* : the request has been processed as indicated @@ -633,31 +470,18 @@ static int map_request(struct dm_rq_target_io *tio) struct request *rq = tio->orig; struct request *clone = NULL; - if (tio->clone) { - clone = tio->clone; - r = ti->type->map_rq(ti, clone, &tio->info); - if (r == DM_MAPIO_DELAY_REQUEUE) - return DM_MAPIO_REQUEUE; /* .request_fn requeue is always immediate */ - } else { - r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone); - if (r < 0) { - /* The target wants to complete the I/O */ - dm_kill_unmapped_request(rq, r); - return r; - } - if (r == DM_MAPIO_REMAPPED && - setup_clone(clone, rq, tio, GFP_ATOMIC)) { - /* -ENOMEM */ - ti->type->release_clone_rq(clone); - return DM_MAPIO_REQUEUE; - } - } - + r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone); switch (r) { case DM_MAPIO_SUBMITTED: /* The target has taken the I/O to submit by itself later */ break; case DM_MAPIO_REMAPPED: + if (setup_clone(clone, rq, tio, GFP_ATOMIC)) { + /* -ENOMEM */ + ti->type->release_clone_rq(clone); + return DM_MAPIO_REQUEUE; + } + /* The target has remapped the I/O so dispatch it */ trace_block_rq_remap(clone->q, clone, disk_devt(dm_disk(md)), blk_rq_pos(rq)); @@ -716,6 +540,29 @@ static void dm_start_request(struct mapped_device *md, struct request *orig) dm_get(md); } +static int __dm_rq_init_rq(struct mapped_device *md, struct request *rq) +{ + struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); + + /* + * Must initialize md member of tio, otherwise it won't + * be available in dm_mq_queue_rq. + */ + tio->md = md; + + if (md->init_tio_pdu) { + /* target-specific per-io data is immediately after the tio */ + tio->info.ptr = tio + 1; + } + + return 0; +} + +static int dm_rq_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp) +{ + return __dm_rq_init_rq(q->rq_alloc_data, rq); +} + static void map_tio_request(struct kthread_work *work) { struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work); @@ -779,6 +626,10 @@ static void dm_old_request_fn(struct request_queue *q) int srcu_idx; struct dm_table *map = dm_get_live_table(md, &srcu_idx); + if (unlikely(!map)) { + dm_put_live_table(md, srcu_idx); + return; + } ti = dm_table_find_target(map, pos); dm_put_live_table(md, srcu_idx); } @@ -810,6 +661,7 @@ static void dm_old_request_fn(struct request_queue *q) dm_start_request(md, rq); tio = tio_from_request(rq); + init_tio(tio, rq, md); /* Establish tio->ti before queuing work (map_tio_request) */ tio->ti = ti; kthread_queue_work(&md->kworker, &tio->work); @@ -820,10 +672,23 @@ static void dm_old_request_fn(struct request_queue *q) /* * Fully initialize a .request_fn request-based queue. */ -int dm_old_init_request_queue(struct mapped_device *md) +int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t) { + struct dm_target *immutable_tgt; + /* Fully initialize the queue */ - if (!blk_init_allocated_queue(md->queue, dm_old_request_fn, NULL)) + md->queue->cmd_size = sizeof(struct dm_rq_target_io); + md->queue->rq_alloc_data = md; + md->queue->request_fn = dm_old_request_fn; + md->queue->init_rq_fn = dm_rq_init_rq; + + immutable_tgt = dm_table_get_immutable_target(t); + if (immutable_tgt && immutable_tgt->per_io_data_size) { + /* any target-specific per-io data is immediately after the tio */ + md->queue->cmd_size += immutable_tgt->per_io_data_size; + md->init_tio_pdu = true; + } + if (blk_init_allocated_queue(md->queue) < 0) return -EINVAL; /* disable dm_old_request_fn's merge heuristic by default */ @@ -831,7 +696,6 @@ int dm_old_init_request_queue(struct mapped_device *md) dm_init_normal_md_queue(md); blk_queue_softirq_done(md->queue, dm_softirq_done); - blk_queue_prep_rq(md->queue, dm_old_prep_fn); /* Initialize the request-based DM worker thread */ kthread_init_worker(&md->kworker); @@ -852,21 +716,7 @@ static int dm_mq_init_request(void *data, struct request *rq, unsigned int hctx_idx, unsigned int request_idx, unsigned int numa_node) { - struct mapped_device *md = data; - struct dm_rq_target_io *tio = blk_mq_rq_to_pdu(rq); - - /* - * Must initialize md member of tio, otherwise it won't - * be available in dm_mq_queue_rq. - */ - tio->md = md; - - if (md->init_tio_pdu) { - /* target-specific per-io data is immediately after the tio */ - tio->info.ptr = tio + 1; - } - - return 0; + return __dm_rq_init_rq(data, rq); } static int dm_mq_queue_rq(struct blk_mq_hw_ctx *hctx, diff --git a/drivers/md/dm-rq.h b/drivers/md/dm-rq.h index 4da06cae7bad..f0020d21b95f 100644 --- a/drivers/md/dm-rq.h +++ b/drivers/md/dm-rq.h @@ -48,7 +48,7 @@ struct dm_rq_clone_bio_info { bool dm_use_blk_mq_default(void); bool dm_use_blk_mq(struct mapped_device *md); -int dm_old_init_request_queue(struct mapped_device *md); +int dm_old_init_request_queue(struct mapped_device *md, struct dm_table *t); int dm_mq_init_request_queue(struct mapped_device *md, struct dm_table *t); void dm_mq_cleanup_mapped_device(struct mapped_device *md); diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 0a427de23ed2..3ad16d9c9d5a 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -1750,7 +1750,7 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits) char b[BDEVNAME_SIZE]; if (likely(q)) - r |= bdi_congested(&q->backing_dev_info, bdi_bits); + r |= bdi_congested(q->backing_dev_info, bdi_bits); else DMWARN_LIMIT("%s: any_congested: nonexistent device %s", dm_device_name(t->md), diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 710ae28fd618..43d3445b121d 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c @@ -131,12 +131,6 @@ static int io_err_map(struct dm_target *tt, struct bio *bio) return -EIO; } -static int io_err_map_rq(struct dm_target *ti, struct request *clone, - union map_info *map_context) -{ - return -EIO; -} - static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq, union map_info *map_context, struct request **clone) @@ -161,7 +155,6 @@ static struct target_type error_target = { .ctr = io_err_ctr, .dtr = io_err_dtr, .map = io_err_map, - .map_rq = io_err_map_rq, .clone_and_map_rq = io_err_clone_and_map_rq, .release_clone_rq = io_err_release_clone_rq, .direct_access = io_err_direct_access, diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index d1c05c12a9db..2b266a2b5035 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -699,7 +699,7 @@ static void remap_to_origin(struct thin_c *tc, struct bio *bio) static int bio_triggers_commit(struct thin_c *tc, struct bio *bio) { - return (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) && + return op_is_flush(bio->bi_opf) && dm_thin_changed_this_transaction(tc->td); } @@ -870,8 +870,7 @@ static void __inc_remap_and_issue_cell(void *context, struct bio *bio; while ((bio = bio_list_pop(&cell->bios))) { - if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) || - bio_op(bio) == REQ_OP_DISCARD) + if (op_is_flush(bio->bi_opf) || bio_op(bio) == REQ_OP_DISCARD) bio_list_add(&info->defer_bios, bio); else { inc_all_io_entry(info->tc->pool, bio); @@ -1716,9 +1715,8 @@ static void __remap_and_issue_shared_cell(void *context, struct bio *bio; while ((bio = bio_list_pop(&cell->bios))) { - if ((bio_data_dir(bio) == WRITE) || - (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) || - bio_op(bio) == REQ_OP_DISCARD)) + if (bio_data_dir(bio) == WRITE || op_is_flush(bio->bi_opf) || + bio_op(bio) == REQ_OP_DISCARD) bio_list_add(&info->defer_bios, bio); else { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));; @@ -2635,8 +2633,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_SUBMITTED; } - if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA) || - bio_op(bio) == REQ_OP_DISCARD) { + if (op_is_flush(bio->bi_opf) || bio_op(bio) == REQ_OP_DISCARD) { thin_defer_bio_with_throttle(tc, bio); return DM_MAPIO_SUBMITTED; } @@ -2714,7 +2711,7 @@ static int pool_is_congested(struct dm_target_callbacks *cb, int bdi_bits) return 1; q = bdev_get_queue(pt->data_dev->bdev); - return bdi_congested(&q->backing_dev_info, bdi_bits); + return bdi_congested(q->backing_dev_info, bdi_bits); } static void requeue_bios(struct pool *pool) diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 3086da5664f3..5bd9ab06a562 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -91,7 +91,6 @@ static int dm_numa_node = DM_NUMA_NODE; */ struct dm_md_mempools { mempool_t *io_pool; - mempool_t *rq_pool; struct bio_set *bs; }; @@ -466,13 +465,16 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, if (r > 0) { /* - * Target determined this ioctl is being issued against - * a logical partition of the parent bdev; so extra - * validation is needed. + * Target determined this ioctl is being issued against a + * subset of the parent bdev; require extra privileges. */ - r = scsi_verify_blk_ioctl(NULL, cmd); - if (r) + if (!capable(CAP_SYS_RAWIO)) { + DMWARN_LIMIT( + "%s: sending ioctl %x to DM device without required privilege.", + current->comm, cmd); + r = -ENOIOCTLCMD; goto out; + } } r = __blkdev_driver_ioctl(bdev, mode, cmd, arg); @@ -1314,7 +1316,7 @@ static int dm_any_congested(void *congested_data, int bdi_bits) * With request-based DM we only need to check the * top-level queue for congestion. */ - r = md->queue->backing_dev_info.wb.state & bdi_bits; + r = md->queue->backing_dev_info->wb.state & bdi_bits; } else { map = dm_get_live_table_fast(md); if (map) @@ -1397,7 +1399,7 @@ void dm_init_md_queue(struct mapped_device *md) * - must do so here (in alloc_dev callchain) before queue is used */ md->queue->queuedata = md; - md->queue->backing_dev_info.congested_data = md; + md->queue->backing_dev_info->congested_data = md; } void dm_init_normal_md_queue(struct mapped_device *md) @@ -1408,7 +1410,7 @@ void dm_init_normal_md_queue(struct mapped_device *md) /* * Initialize aspects of queue that aren't relevant for blk-mq */ - md->queue->backing_dev_info.congested_fn = dm_any_congested; + md->queue->backing_dev_info->congested_fn = dm_any_congested; blk_queue_bounce_limit(md->queue, BLK_BOUNCE_ANY); } @@ -1419,7 +1421,6 @@ static void cleanup_mapped_device(struct mapped_device *md) if (md->kworker_task) kthread_stop(md->kworker_task); mempool_destroy(md->io_pool); - mempool_destroy(md->rq_pool); if (md->bs) bioset_free(md->bs); @@ -1595,12 +1596,10 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t) goto out; } - BUG_ON(!p || md->io_pool || md->rq_pool || md->bs); + BUG_ON(!p || md->io_pool || md->bs); md->io_pool = p->io_pool; p->io_pool = NULL; - md->rq_pool = p->rq_pool; - p->rq_pool = NULL; md->bs = p->bs; p->bs = NULL; @@ -1777,7 +1776,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t) switch (type) { case DM_TYPE_REQUEST_BASED: - r = dm_old_init_request_queue(md); + r = dm_old_init_request_queue(md, t); if (r) { DMERR("Cannot initialize queue for request-based mapped device"); return r; @@ -2493,7 +2492,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t unsigned integrity, unsigned per_io_data_size) { struct dm_md_mempools *pools = kzalloc_node(sizeof(*pools), GFP_KERNEL, md->numa_node_id); - struct kmem_cache *cachep = NULL; unsigned int pool_size = 0; unsigned int front_pad; @@ -2503,20 +2501,16 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t switch (type) { case DM_TYPE_BIO_BASED: case DM_TYPE_DAX_BIO_BASED: - cachep = _io_cache; pool_size = dm_get_reserved_bio_based_ios(); front_pad = roundup(per_io_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone); + + pools->io_pool = mempool_create_slab_pool(pool_size, _io_cache); + if (!pools->io_pool) + goto out; break; case DM_TYPE_REQUEST_BASED: - cachep = _rq_tio_cache; - pool_size = dm_get_reserved_rq_based_ios(); - pools->rq_pool = mempool_create_slab_pool(pool_size, _rq_cache); - if (!pools->rq_pool) - goto out; - /* fall through to setup remaining rq-based pools */ case DM_TYPE_MQ_REQUEST_BASED: - if (!pool_size) - pool_size = dm_get_reserved_rq_based_ios(); + pool_size = dm_get_reserved_rq_based_ios(); front_pad = offsetof(struct dm_rq_clone_bio_info, clone); /* per_io_data_size is used for blk-mq pdu at queue allocation */ break; @@ -2524,12 +2518,6 @@ struct dm_md_mempools *dm_alloc_md_mempools(struct mapped_device *md, unsigned t BUG(); } - if (cachep) { - pools->io_pool = mempool_create_slab_pool(pool_size, cachep); - if (!pools->io_pool) - goto out; - } - pools->bs = bioset_create_nobvec(pool_size, front_pad); if (!pools->bs) goto out; @@ -2551,7 +2539,6 @@ void dm_free_md_mempools(struct dm_md_mempools *pools) return; mempool_destroy(pools->io_pool); - mempool_destroy(pools->rq_pool); if (pools->bs) bioset_free(pools->bs); diff --git a/drivers/md/dm.h b/drivers/md/dm.h index f0aad08b9654..f298b01f7ab3 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -95,8 +95,7 @@ int dm_setup_md_queue(struct mapped_device *md, struct dm_table *t); /* * To check whether the target type is request-based or not (bio-based). */ -#define dm_target_request_based(t) (((t)->type->map_rq != NULL) || \ - ((t)->type->clone_and_map_rq != NULL)) +#define dm_target_request_based(t) ((t)->type->clone_and_map_rq != NULL) /* * To check whether the target type is a hybrid (capable of being diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 5975c9915684..f1c7bbac31a5 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -62,7 +62,7 @@ static int linear_congested(struct mddev *mddev, int bits) for (i = 0; i < mddev->raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); } return ret; diff --git a/drivers/md/md.c b/drivers/md/md.c index 82821ee0d57f..ba485dcf1064 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5291,6 +5291,11 @@ int md_run(struct mddev *mddev) if (start_readonly && mddev->ro == 0) mddev->ro = 2; /* read-only, but switch on first write */ + /* + * NOTE: some pers->run(), for example r5l_recovery_log(), wakes + * up mddev->thread. It is important to initialize critical + * resources for mddev->thread BEFORE calling pers->run(). + */ err = pers->run(mddev); if (err) pr_warn("md: pers->run() failed ...\n"); @@ -5341,8 +5346,8 @@ int md_run(struct mddev *mddev) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mddev->queue); else queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, mddev->queue); - mddev->queue->backing_dev_info.congested_data = mddev; - mddev->queue->backing_dev_info.congested_fn = md_congested; + mddev->queue->backing_dev_info->congested_data = mddev; + mddev->queue->backing_dev_info->congested_fn = md_congested; } if (pers->sync_request) { if (mddev->kobj.sd && @@ -5699,7 +5704,7 @@ static int do_md_stop(struct mddev *mddev, int mode, __md_stop_writes(mddev); __md_stop(mddev); - mddev->queue->backing_dev_info.congested_fn = NULL; + mddev->queue->backing_dev_info->congested_fn = NULL; /* tell userspace to handle 'inactive' */ sysfs_notify_dirent_safe(mddev->sysfs_state); diff --git a/drivers/md/md.h b/drivers/md/md.h index e38936d05df1..2a514036a83d 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -212,6 +212,7 @@ extern int rdev_clear_badblocks(struct md_rdev *rdev, sector_t s, int sectors, int is_new); struct md_cluster_info; +/* change UNSUPPORTED_MDDEV_FLAGS for each array type if new flag is added */ enum mddev_flags { MD_ARRAY_FIRST_USE, /* First use of array, needs initialization */ MD_CLOSING, /* If set, we are closing the array, do not open @@ -702,4 +703,11 @@ static inline int mddev_is_clustered(struct mddev *mddev) { return mddev->cluster_info && mddev->bitmap_info.nodes > 1; } + +/* clear unsupported mddev_flags */ +static inline void mddev_clear_unsupported_flags(struct mddev *mddev, + unsigned long unsupported_flags) +{ + mddev->flags &= ~unsupported_flags; +} #endif /* _MD_MD_H */ diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index aa8c4e5c1ee2..d457afa672d5 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -169,7 +169,7 @@ static int multipath_congested(struct mddev *mddev, int bits) if (rdev && !test_bit(Faulty, &rdev->flags)) { struct request_queue *q = bdev_get_queue(rdev->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); /* Just like multipath_map, we just check the * first available device */ diff --git a/drivers/md/persistent-data/dm-block-manager.c b/drivers/md/persistent-data/dm-block-manager.c index a6dde7cab458..758d90cc2733 100644 --- a/drivers/md/persistent-data/dm-block-manager.c +++ b/drivers/md/persistent-data/dm-block-manager.c @@ -120,7 +120,7 @@ static int __check_holder(struct block_lock *lock) static void __wait(struct waiter *w) { for (;;) { - set_task_state(current, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); if (!w->task) break; @@ -128,7 +128,7 @@ static void __wait(struct waiter *w) schedule(); } - set_task_state(current, TASK_RUNNING); + set_current_state(TASK_RUNNING); } static void __wake_waiter(struct waiter *w) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index a162fedeb51a..d6585239bff2 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -26,6 +26,11 @@ #include "raid0.h" #include "raid5.h" +#define UNSUPPORTED_MDDEV_FLAGS \ + ((1L << MD_HAS_JOURNAL) | \ + (1L << MD_JOURNAL_CLEAN) | \ + (1L << MD_FAILFAST_SUPPORTED)) + static int raid0_congested(struct mddev *mddev, int bits) { struct r0conf *conf = mddev->private; @@ -36,7 +41,7 @@ static int raid0_congested(struct mddev *mddev, int bits) for (i = 0; i < raid_disks && !ret ; i++) { struct request_queue *q = bdev_get_queue(devlist[i]->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); } return ret; } @@ -415,8 +420,8 @@ static int raid0_run(struct mddev *mddev) */ int stripe = mddev->raid_disks * (mddev->chunk_sectors << 9) / PAGE_SIZE; - if (mddev->queue->backing_dev_info.ra_pages < 2* stripe) - mddev->queue->backing_dev_info.ra_pages = 2* stripe; + if (mddev->queue->backing_dev_info->ra_pages < 2* stripe) + mddev->queue->backing_dev_info->ra_pages = 2* stripe; } dump_zones(mddev); @@ -539,8 +544,7 @@ static void *raid0_takeover_raid45(struct mddev *mddev) mddev->delta_disks = -1; /* make sure it will be not marked as dirty */ mddev->recovery_cp = MaxSector; - clear_bit(MD_HAS_JOURNAL, &mddev->flags); - clear_bit(MD_JOURNAL_CLEAN, &mddev->flags); + mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS); create_strip_zones(mddev, &priv_conf); @@ -583,7 +587,7 @@ static void *raid0_takeover_raid10(struct mddev *mddev) mddev->degraded = 0; /* make sure it will be not marked as dirty */ mddev->recovery_cp = MaxSector; - clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags); + mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS); create_strip_zones(mddev, &priv_conf); return priv_conf; @@ -626,7 +630,7 @@ static void *raid0_takeover_raid1(struct mddev *mddev) mddev->raid_disks = 1; /* make sure it will be not marked as dirty */ mddev->recovery_cp = MaxSector; - clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags); + mddev_clear_unsupported_flags(mddev, UNSUPPORTED_MDDEV_FLAGS); create_strip_zones(mddev, &priv_conf); return priv_conf; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index a1f3fbed9100..830ff2b20346 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -42,6 +42,10 @@ #include "raid1.h" #include "bitmap.h" +#define UNSUPPORTED_MDDEV_FLAGS \ + ((1L << MD_HAS_JOURNAL) | \ + (1L << MD_JOURNAL_CLEAN)) + /* * Number of guaranteed r1bios in case of extreme VM load: */ @@ -740,9 +744,9 @@ static int raid1_congested(struct mddev *mddev, int bits) * non-congested targets, it can be removed */ if ((bits & (1 << WB_async_congested)) || 1) - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); else - ret &= bdi_congested(&q->backing_dev_info, bits); + ret &= bdi_congested(q->backing_dev_info, bits); } } rcu_read_unlock(); @@ -1066,20 +1070,106 @@ static void raid1_unplug(struct blk_plug_cb *cb, bool from_schedule) kfree(plug); } -static void raid1_make_request(struct mddev *mddev, struct bio * bio) +static void raid1_read_request(struct mddev *mddev, struct bio *bio, + struct r1bio *r1_bio) { struct r1conf *conf = mddev->private; struct raid1_info *mirror; - struct r1bio *r1_bio; struct bio *read_bio; - int i, disks; - struct bitmap *bitmap; - unsigned long flags; + struct bitmap *bitmap = mddev->bitmap; const int op = bio_op(bio); - const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_opf & REQ_SYNC); - const unsigned long do_flush_fua = (bio->bi_opf & - (REQ_PREFLUSH | REQ_FUA)); + int sectors_handled; + int max_sectors; + int rdisk; + + wait_barrier(conf, bio); + +read_again: + rdisk = read_balance(conf, r1_bio, &max_sectors); + + if (rdisk < 0) { + /* couldn't find anywhere to read from */ + raid_end_bio_io(r1_bio); + return; + } + mirror = conf->mirrors + rdisk; + + if (test_bit(WriteMostly, &mirror->rdev->flags) && + bitmap) { + /* + * Reading from a write-mostly device must take care not to + * over-take any writes that are 'behind' + */ + raid1_log(mddev, "wait behind writes"); + wait_event(bitmap->behind_wait, + atomic_read(&bitmap->behind_writes) == 0); + } + r1_bio->read_disk = rdisk; + r1_bio->start_next_window = 0; + + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); + bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector, + max_sectors); + + r1_bio->bios[rdisk] = read_bio; + + read_bio->bi_iter.bi_sector = r1_bio->sector + + mirror->rdev->data_offset; + read_bio->bi_bdev = mirror->rdev->bdev; + read_bio->bi_end_io = raid1_end_read_request; + bio_set_op_attrs(read_bio, op, do_sync); + if (test_bit(FailFast, &mirror->rdev->flags) && + test_bit(R1BIO_FailFast, &r1_bio->state)) + read_bio->bi_opf |= MD_FAILFAST; + read_bio->bi_private = r1_bio; + + if (mddev->gendisk) + trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev), + read_bio, disk_devt(mddev->gendisk), + r1_bio->sector); + + if (max_sectors < r1_bio->sectors) { + /* + * could not read all from this device, so we will need another + * r1_bio. + */ + sectors_handled = (r1_bio->sector + max_sectors + - bio->bi_iter.bi_sector); + r1_bio->sectors = max_sectors; + spin_lock_irq(&conf->device_lock); + if (bio->bi_phys_segments == 0) + bio->bi_phys_segments = 2; + else + bio->bi_phys_segments++; + spin_unlock_irq(&conf->device_lock); + + /* + * Cannot call generic_make_request directly as that will be + * queued in __make_request and subsequent mempool_alloc might + * block waiting for it. So hand bio over to raid1d. + */ + reschedule_retry(r1_bio); + + r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); + + r1_bio->master_bio = bio; + r1_bio->sectors = bio_sectors(bio) - sectors_handled; + r1_bio->state = 0; + r1_bio->mddev = mddev; + r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled; + goto read_again; + } else + generic_make_request(read_bio); +} + +static void raid1_write_request(struct mddev *mddev, struct bio *bio, + struct r1bio *r1_bio) +{ + struct r1conf *conf = mddev->private; + int i, disks; + struct bitmap *bitmap = mddev->bitmap; + unsigned long flags; struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid1_plug_cb *plug = NULL; @@ -1096,15 +1186,15 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio) md_write_start(mddev, bio); /* wait on superblock update early */ - if (bio_data_dir(bio) == WRITE && - ((bio_end_sector(bio) > mddev->suspend_lo && + if ((bio_end_sector(bio) > mddev->suspend_lo && bio->bi_iter.bi_sector < mddev->suspend_hi) || (mddev_is_clustered(mddev) && md_cluster_ops->area_resyncing(mddev, WRITE, - bio->bi_iter.bi_sector, bio_end_sector(bio))))) { - /* As the suspend_* range is controlled by - * userspace, we want an interruptible - * wait. + bio->bi_iter.bi_sector, bio_end_sector(bio)))) { + + /* + * As the suspend_* range is controlled by userspace, we want + * an interruptible wait. */ DEFINE_WAIT(w); for (;;) { @@ -1115,128 +1205,15 @@ static void raid1_make_request(struct mddev *mddev, struct bio * bio) bio->bi_iter.bi_sector >= mddev->suspend_hi || (mddev_is_clustered(mddev) && !md_cluster_ops->area_resyncing(mddev, WRITE, - bio->bi_iter.bi_sector, bio_end_sector(bio)))) + bio->bi_iter.bi_sector, + bio_end_sector(bio)))) break; schedule(); } finish_wait(&conf->wait_barrier, &w); } - start_next_window = wait_barrier(conf, bio); - bitmap = mddev->bitmap; - - /* - * make_request() can abort the operation when read-ahead is being - * used and no empty request is available. - * - */ - r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); - - r1_bio->master_bio = bio; - r1_bio->sectors = bio_sectors(bio); - r1_bio->state = 0; - r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_iter.bi_sector; - - /* We might need to issue multiple reads to different - * devices if there are bad blocks around, so we keep - * track of the number of reads in bio->bi_phys_segments. - * If this is 0, there is only one r1_bio and no locking - * will be needed when requests complete. If it is - * non-zero, then it is the number of not-completed requests. - */ - bio->bi_phys_segments = 0; - bio_clear_flag(bio, BIO_SEG_VALID); - - if (rw == READ) { - /* - * read balancing logic: - */ - int rdisk; - -read_again: - rdisk = read_balance(conf, r1_bio, &max_sectors); - - if (rdisk < 0) { - /* couldn't find anywhere to read from */ - raid_end_bio_io(r1_bio); - return; - } - mirror = conf->mirrors + rdisk; - - if (test_bit(WriteMostly, &mirror->rdev->flags) && - bitmap) { - /* Reading from a write-mostly device must - * take care not to over-take any writes - * that are 'behind' - */ - raid1_log(mddev, "wait behind writes"); - wait_event(bitmap->behind_wait, - atomic_read(&bitmap->behind_writes) == 0); - } - r1_bio->read_disk = rdisk; - r1_bio->start_next_window = 0; - - read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector, - max_sectors); - - r1_bio->bios[rdisk] = read_bio; - - read_bio->bi_iter.bi_sector = r1_bio->sector + - mirror->rdev->data_offset; - read_bio->bi_bdev = mirror->rdev->bdev; - read_bio->bi_end_io = raid1_end_read_request; - bio_set_op_attrs(read_bio, op, do_sync); - if (test_bit(FailFast, &mirror->rdev->flags) && - test_bit(R1BIO_FailFast, &r1_bio->state)) - read_bio->bi_opf |= MD_FAILFAST; - read_bio->bi_private = r1_bio; - - if (mddev->gendisk) - trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev), - read_bio, disk_devt(mddev->gendisk), - r1_bio->sector); - - if (max_sectors < r1_bio->sectors) { - /* could not read all from this device, so we will - * need another r1_bio. - */ - - sectors_handled = (r1_bio->sector + max_sectors - - bio->bi_iter.bi_sector); - r1_bio->sectors = max_sectors; - spin_lock_irq(&conf->device_lock); - if (bio->bi_phys_segments == 0) - bio->bi_phys_segments = 2; - else - bio->bi_phys_segments++; - spin_unlock_irq(&conf->device_lock); - /* Cannot call generic_make_request directly - * as that will be queued in __make_request - * and subsequent mempool_alloc might block waiting - * for it. So hand bio over to raid1d. - */ - reschedule_retry(r1_bio); - - r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); - - r1_bio->master_bio = bio; - r1_bio->sectors = bio_sectors(bio) - sectors_handled; - r1_bio->state = 0; - r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_iter.bi_sector + - sectors_handled; - goto read_again; - } else - generic_make_request(read_bio); - return; - } - - /* - * WRITE: - */ if (conf->pending_count >= max_queued_requests) { md_wakeup_thread(mddev->thread); raid1_log(mddev, "wait queued"); @@ -1280,8 +1257,7 @@ read_again: int bad_sectors; int is_bad; - is_bad = is_badblock(rdev, r1_bio->sector, - max_sectors, + is_bad = is_badblock(rdev, r1_bio->sector, max_sectors, &first_bad, &bad_sectors); if (is_bad < 0) { /* mustn't write here until the bad block is @@ -1370,7 +1346,8 @@ read_again: continue; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors); + bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, + max_sectors); if (first_clone) { /* do behind I/O ? @@ -1408,7 +1385,8 @@ read_again: conf->mirrors[i].rdev->data_offset); mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; - bio_set_op_attrs(mbio, op, do_flush_fua | do_sync); + mbio->bi_opf = bio_op(bio) | + (bio->bi_opf & (REQ_SYNC | REQ_PREFLUSH | REQ_FUA)); if (test_bit(FailFast, &conf->mirrors[i].rdev->flags) && !test_bit(WriteMostly, &conf->mirrors[i].rdev->flags) && conf->raid_disks - mddev->degraded > 1) @@ -1464,6 +1442,40 @@ read_again: wake_up(&conf->wait_barrier); } +static void raid1_make_request(struct mddev *mddev, struct bio *bio) +{ + struct r1conf *conf = mddev->private; + struct r1bio *r1_bio; + + /* + * make_request() can abort the operation when read-ahead is being + * used and no empty request is available. + * + */ + r1_bio = mempool_alloc(conf->r1bio_pool, GFP_NOIO); + + r1_bio->master_bio = bio; + r1_bio->sectors = bio_sectors(bio); + r1_bio->state = 0; + r1_bio->mddev = mddev; + r1_bio->sector = bio->bi_iter.bi_sector; + + /* + * We might need to issue multiple reads to different devices if there + * are bad blocks around, so we keep track of the number of reads in + * bio->bi_phys_segments. If this is 0, there is only one r1_bio and + * no locking will be needed when requests complete. If it is + * non-zero, then it is the number of not-completed requests. + */ + bio->bi_phys_segments = 0; + bio_clear_flag(bio, BIO_SEG_VALID); + + if (bio_data_dir(bio) == READ) + raid1_read_request(mddev, bio, r1_bio); + else + raid1_write_request(mddev, bio, r1_bio); +} + static void raid1_status(struct seq_file *seq, struct mddev *mddev) { struct r1conf *conf = mddev->private; @@ -3246,8 +3258,8 @@ static void *raid1_takeover(struct mddev *mddev) if (!IS_ERR(conf)) { /* Array must appear to be quiesced */ conf->array_frozen = 1; - clear_bit(MD_HAS_JOURNAL, &mddev->flags); - clear_bit(MD_JOURNAL_CLEAN, &mddev->flags); + mddev_clear_unsupported_flags(mddev, + UNSUPPORTED_MDDEV_FLAGS); } return conf; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index ab5e86209322..6bc5c2a85160 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -860,7 +860,7 @@ static int raid10_congested(struct mddev *mddev, int bits) if (rdev && !test_bit(Faulty, &rdev->flags)) { struct request_queue *q = bdev_get_queue(rdev->bdev); - ret |= bdi_congested(&q->backing_dev_info, bits); + ret |= bdi_congested(q->backing_dev_info, bits); } } rcu_read_unlock(); @@ -1087,23 +1087,122 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) kfree(plug); } -static void __make_request(struct mddev *mddev, struct bio *bio) +static void raid10_read_request(struct mddev *mddev, struct bio *bio, + struct r10bio *r10_bio) { struct r10conf *conf = mddev->private; - struct r10bio *r10_bio; struct bio *read_bio; + const int op = bio_op(bio); + const unsigned long do_sync = (bio->bi_opf & REQ_SYNC); + int sectors_handled; + int max_sectors; + sector_t sectors; + struct md_rdev *rdev; + int slot; + + /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. + * Continue immediately if no resync is active currently. + */ + wait_barrier(conf); + + sectors = bio_sectors(bio); + while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + bio->bi_iter.bi_sector < conf->reshape_progress && + bio->bi_iter.bi_sector + sectors > conf->reshape_progress) { + /* + * IO spans the reshape position. Need to wait for reshape to + * pass + */ + raid10_log(conf->mddev, "wait reshape"); + allow_barrier(conf); + wait_event(conf->wait_barrier, + conf->reshape_progress <= bio->bi_iter.bi_sector || + conf->reshape_progress >= bio->bi_iter.bi_sector + + sectors); + wait_barrier(conf); + } + +read_again: + rdev = read_balance(conf, r10_bio, &max_sectors); + if (!rdev) { + raid_end_bio_io(r10_bio); + return; + } + slot = r10_bio->read_slot; + + read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); + bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector, + max_sectors); + + r10_bio->devs[slot].bio = read_bio; + r10_bio->devs[slot].rdev = rdev; + + read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + + choose_data_offset(r10_bio, rdev); + read_bio->bi_bdev = rdev->bdev; + read_bio->bi_end_io = raid10_end_read_request; + bio_set_op_attrs(read_bio, op, do_sync); + if (test_bit(FailFast, &rdev->flags) && + test_bit(R10BIO_FailFast, &r10_bio->state)) + read_bio->bi_opf |= MD_FAILFAST; + read_bio->bi_private = r10_bio; + + if (mddev->gendisk) + trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev), + read_bio, disk_devt(mddev->gendisk), + r10_bio->sector); + if (max_sectors < r10_bio->sectors) { + /* + * Could not read all from this device, so we will need another + * r10_bio. + */ + sectors_handled = (r10_bio->sector + max_sectors + - bio->bi_iter.bi_sector); + r10_bio->sectors = max_sectors; + spin_lock_irq(&conf->device_lock); + if (bio->bi_phys_segments == 0) + bio->bi_phys_segments = 2; + else + bio->bi_phys_segments++; + spin_unlock_irq(&conf->device_lock); + /* + * Cannot call generic_make_request directly as that will be + * queued in __generic_make_request and subsequent + * mempool_alloc might block waiting for it. so hand bio over + * to raid10d. + */ + reschedule_retry(r10_bio); + + r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); + + r10_bio->master_bio = bio; + r10_bio->sectors = bio_sectors(bio) - sectors_handled; + r10_bio->state = 0; + r10_bio->mddev = mddev; + r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled; + goto read_again; + } else + generic_make_request(read_bio); + return; +} + +static void raid10_write_request(struct mddev *mddev, struct bio *bio, + struct r10bio *r10_bio) +{ + struct r10conf *conf = mddev->private; int i; const int op = bio_op(bio); - const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_opf & REQ_SYNC); const unsigned long do_fua = (bio->bi_opf & REQ_FUA); unsigned long flags; struct md_rdev *blocked_rdev; struct blk_plug_cb *cb; struct raid10_plug_cb *plug = NULL; + sector_t sectors; int sectors_handled; int max_sectors; - int sectors; md_write_start(mddev, bio); @@ -1118,8 +1217,9 @@ static void __make_request(struct mddev *mddev, struct bio *bio) while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && bio->bi_iter.bi_sector < conf->reshape_progress && bio->bi_iter.bi_sector + sectors > conf->reshape_progress) { - /* IO spans the reshape position. Need to wait for - * reshape to pass + /* + * IO spans the reshape position. Need to wait for reshape to + * pass */ raid10_log(conf->mddev, "wait reshape"); allow_barrier(conf); @@ -1129,8 +1229,8 @@ static void __make_request(struct mddev *mddev, struct bio *bio) sectors); wait_barrier(conf); } + if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && - bio_data_dir(bio) == WRITE && (mddev->reshape_backwards ? (bio->bi_iter.bi_sector < conf->reshape_safe && bio->bi_iter.bi_sector + sectors > conf->reshape_progress) @@ -1148,98 +1248,6 @@ static void __make_request(struct mddev *mddev, struct bio *bio) conf->reshape_safe = mddev->reshape_position; } - r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); - - r10_bio->master_bio = bio; - r10_bio->sectors = sectors; - - r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_iter.bi_sector; - r10_bio->state = 0; - - /* We might need to issue multiple reads to different - * devices if there are bad blocks around, so we keep - * track of the number of reads in bio->bi_phys_segments. - * If this is 0, there is only one r10_bio and no locking - * will be needed when the request completes. If it is - * non-zero, then it is the number of not-completed requests. - */ - bio->bi_phys_segments = 0; - bio_clear_flag(bio, BIO_SEG_VALID); - - if (rw == READ) { - /* - * read balancing logic: - */ - struct md_rdev *rdev; - int slot; - -read_again: - rdev = read_balance(conf, r10_bio, &max_sectors); - if (!rdev) { - raid_end_bio_io(r10_bio); - return; - } - slot = r10_bio->read_slot; - - read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector, - max_sectors); - - r10_bio->devs[slot].bio = read_bio; - r10_bio->devs[slot].rdev = rdev; - - read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + - choose_data_offset(r10_bio, rdev); - read_bio->bi_bdev = rdev->bdev; - read_bio->bi_end_io = raid10_end_read_request; - bio_set_op_attrs(read_bio, op, do_sync); - if (test_bit(FailFast, &rdev->flags) && - test_bit(R10BIO_FailFast, &r10_bio->state)) - read_bio->bi_opf |= MD_FAILFAST; - read_bio->bi_private = r10_bio; - - if (mddev->gendisk) - trace_block_bio_remap(bdev_get_queue(read_bio->bi_bdev), - read_bio, disk_devt(mddev->gendisk), - r10_bio->sector); - if (max_sectors < r10_bio->sectors) { - /* Could not read all from this device, so we will - * need another r10_bio. - */ - sectors_handled = (r10_bio->sector + max_sectors - - bio->bi_iter.bi_sector); - r10_bio->sectors = max_sectors; - spin_lock_irq(&conf->device_lock); - if (bio->bi_phys_segments == 0) - bio->bi_phys_segments = 2; - else - bio->bi_phys_segments++; - spin_unlock_irq(&conf->device_lock); - /* Cannot call generic_make_request directly - * as that will be queued in __generic_make_request - * and subsequent mempool_alloc might block - * waiting for it. so hand bio over to raid10d. - */ - reschedule_retry(r10_bio); - - r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); - - r10_bio->master_bio = bio; - r10_bio->sectors = bio_sectors(bio) - sectors_handled; - r10_bio->state = 0; - r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_iter.bi_sector + - sectors_handled; - goto read_again; - } else - generic_make_request(read_bio); - return; - } - - /* - * WRITE: - */ if (conf->pending_count >= max_queued_requests) { md_wakeup_thread(mddev->thread); raid10_log(mddev, "wait queued"); @@ -1300,8 +1308,7 @@ retry_write: int bad_sectors; int is_bad; - is_bad = is_badblock(rdev, dev_sector, - max_sectors, + is_bad = is_badblock(rdev, dev_sector, max_sectors, &first_bad, &bad_sectors); if (is_bad < 0) { /* Mustn't write here until the bad block @@ -1405,8 +1412,7 @@ retry_write: r10_bio->devs[i].bio = mbio; mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+ - choose_data_offset(r10_bio, - rdev)); + choose_data_offset(r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; bio_set_op_attrs(mbio, op, do_sync | do_fua); @@ -1457,8 +1463,7 @@ retry_write: r10_bio->devs[i].repl_bio = mbio; mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr + - choose_data_offset( - r10_bio, rdev)); + choose_data_offset(r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; mbio->bi_end_io = raid10_end_write_request; bio_set_op_attrs(mbio, op, do_sync | do_fua); @@ -1503,6 +1508,36 @@ retry_write: one_write_done(r10_bio); } +static void __make_request(struct mddev *mddev, struct bio *bio) +{ + struct r10conf *conf = mddev->private; + struct r10bio *r10_bio; + + r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO); + + r10_bio->master_bio = bio; + r10_bio->sectors = bio_sectors(bio); + + r10_bio->mddev = mddev; + r10_bio->sector = bio->bi_iter.bi_sector; + r10_bio->state = 0; + + /* + * We might need to issue multiple reads to different devices if there + * are bad blocks around, so we keep track of the number of reads in + * bio->bi_phys_segments. If this is 0, there is only one r10_bio and + * no locking will be needed when the request completes. If it is + * non-zero, then it is the number of not-completed requests. + */ + bio->bi_phys_segments = 0; + bio_clear_flag(bio, BIO_SEG_VALID); + + if (bio_data_dir(bio) == READ) + raid10_read_request(mddev, bio, r10_bio); + else + raid10_write_request(mddev, bio, r10_bio); +} + static void raid10_make_request(struct mddev *mddev, struct bio *bio) { struct r10conf *conf = mddev->private; @@ -3806,8 +3841,8 @@ static int raid10_run(struct mddev *mddev) * maybe... */ stripe /= conf->geo.near_copies; - if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) - mddev->queue->backing_dev_info.ra_pages = 2 * stripe; + if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe) + mddev->queue->backing_dev_info->ra_pages = 2 * stripe; } if (md_integrity_register(mddev)) @@ -4608,8 +4643,8 @@ static void end_reshape(struct r10conf *conf) int stripe = conf->geo.raid_disks * ((conf->mddev->chunk_sectors << 9) / PAGE_SIZE); stripe /= conf->geo.near_copies; - if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) - conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; + if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe) + conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe; } conf->fullsync = 0; } diff --git a/drivers/md/raid5-cache.c b/drivers/md/raid5-cache.c index d7bfb6fc8aef..302dea3296ba 100644 --- a/drivers/md/raid5-cache.c +++ b/drivers/md/raid5-cache.c @@ -162,6 +162,8 @@ struct r5l_log { /* to submit async io_units, to fulfill ordering of flush */ struct work_struct deferred_io_work; + /* to disable write back during in degraded mode */ + struct work_struct disable_writeback_work; }; /* @@ -611,6 +613,21 @@ static void r5l_submit_io_async(struct work_struct *work) r5l_do_submit_io(log, io); } +static void r5c_disable_writeback_async(struct work_struct *work) +{ + struct r5l_log *log = container_of(work, struct r5l_log, + disable_writeback_work); + struct mddev *mddev = log->rdev->mddev; + + if (log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH) + return; + pr_info("md/raid:%s: Disabling writeback cache for degraded array.\n", + mdname(mddev)); + mddev_suspend(mddev); + log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH; + mddev_resume(mddev); +} + static void r5l_submit_current_io(struct r5l_log *log) { struct r5l_io_unit *io = log->current_io; @@ -1393,8 +1410,6 @@ static void r5l_do_reclaim(struct r5l_log *log) next_checkpoint = r5c_calculate_new_cp(conf); spin_unlock_irq(&log->io_list_lock); - BUG_ON(reclaimable < 0); - if (reclaimable == 0 || !write_super) return; @@ -1682,8 +1697,7 @@ out: static struct stripe_head * r5c_recovery_alloc_stripe(struct r5conf *conf, - sector_t stripe_sect, - sector_t log_start) + sector_t stripe_sect) { struct stripe_head *sh; @@ -1692,7 +1706,6 @@ r5c_recovery_alloc_stripe(struct r5conf *conf, return NULL; /* no more stripe available */ r5l_recovery_reset_stripe(sh); - sh->log_start = log_start; return sh; } @@ -1862,7 +1875,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, stripe_sect); if (!sh) { - sh = r5c_recovery_alloc_stripe(conf, stripe_sect, ctx->pos); + sh = r5c_recovery_alloc_stripe(conf, stripe_sect); /* * cannot get stripe from raid5_get_active_stripe * try replay some stripes @@ -1871,7 +1884,7 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, r5c_recovery_replay_stripes( cached_stripe_list, ctx); sh = r5c_recovery_alloc_stripe( - conf, stripe_sect, ctx->pos); + conf, stripe_sect); } if (!sh) { pr_debug("md/raid:%s: Increasing stripe cache size to %d to recovery data on journal.\n", @@ -1879,8 +1892,8 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, conf->min_nr_stripes * 2); raid5_set_cache_size(mddev, conf->min_nr_stripes * 2); - sh = r5c_recovery_alloc_stripe( - conf, stripe_sect, ctx->pos); + sh = r5c_recovery_alloc_stripe(conf, + stripe_sect); } if (!sh) { pr_err("md/raid:%s: Cannot get enough stripes due to memory pressure. Recovery failed.\n", @@ -1894,7 +1907,6 @@ r5c_recovery_analyze_meta_block(struct r5l_log *log, if (!test_bit(STRIPE_R5C_CACHING, &sh->state) && test_bit(R5_Wantwrite, &sh->dev[sh->pd_idx].flags)) { r5l_recovery_replay_one_stripe(conf, sh, ctx); - sh->log_start = ctx->pos; list_move_tail(&sh->lru, cached_stripe_list); } r5l_recovery_load_data(log, sh, ctx, payload, @@ -1933,8 +1945,6 @@ static void r5c_recovery_load_one_stripe(struct r5l_log *log, set_bit(R5_UPTODATE, &dev->flags); } } - list_add_tail(&sh->r5c, &log->stripe_in_journal_list); - atomic_inc(&log->stripe_in_journal_count); } /* @@ -2067,9 +2077,10 @@ static int r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log, struct r5l_recovery_ctx *ctx) { - struct stripe_head *sh, *next; + struct stripe_head *sh; struct mddev *mddev = log->rdev->mddev; struct page *page; + sector_t next_checkpoint = MaxSector; page = alloc_page(GFP_KERNEL); if (!page) { @@ -2078,7 +2089,9 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log, return -ENOMEM; } - list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) { + WARN_ON(list_empty(&ctx->cached_list)); + + list_for_each_entry(sh, &ctx->cached_list, lru) { struct r5l_meta_block *mb; int i; int offset; @@ -2123,14 +2136,42 @@ r5c_recovery_rewrite_data_only_stripes(struct r5l_log *log, sync_page_io(log->rdev, ctx->pos, PAGE_SIZE, page, REQ_OP_WRITE, REQ_FUA, false); sh->log_start = ctx->pos; + list_add_tail(&sh->r5c, &log->stripe_in_journal_list); + atomic_inc(&log->stripe_in_journal_count); ctx->pos = write_pos; ctx->seq += 1; + next_checkpoint = sh->log_start; + } + log->next_checkpoint = next_checkpoint; + __free_page(page); + return 0; +} + +static void r5c_recovery_flush_data_only_stripes(struct r5l_log *log, + struct r5l_recovery_ctx *ctx) +{ + struct mddev *mddev = log->rdev->mddev; + struct r5conf *conf = mddev->private; + struct stripe_head *sh, *next; + + if (ctx->data_only_stripes == 0) + return; + log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_BACK; + + list_for_each_entry_safe(sh, next, &ctx->cached_list, lru) { + r5c_make_stripe_write_out(sh); + set_bit(STRIPE_HANDLE, &sh->state); list_del_init(&sh->lru); raid5_release_stripe(sh); } - __free_page(page); - return 0; + + md_wakeup_thread(conf->mddev->thread); + /* reuse conf->wait_for_quiescent in recovery */ + wait_event(conf->wait_for_quiescent, + atomic_read(&conf->active_stripes) == 0); + + log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH; } static int r5l_recovery_log(struct r5l_log *log) @@ -2139,7 +2180,6 @@ static int r5l_recovery_log(struct r5l_log *log) struct r5l_recovery_ctx ctx; int ret; sector_t pos; - struct stripe_head *sh; ctx.pos = log->last_checkpoint; ctx.seq = log->last_cp_seq; @@ -2160,35 +2200,31 @@ static int r5l_recovery_log(struct r5l_log *log) pos = ctx.pos; ctx.seq += 10000; - if (ctx.data_only_stripes == 0) { - log->next_checkpoint = ctx.pos; - r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++); - ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS); - } else { - sh = list_last_entry(&ctx.cached_list, struct stripe_head, lru); - log->next_checkpoint = sh->log_start; - } if ((ctx.data_only_stripes == 0) && (ctx.data_parity_stripes == 0)) pr_debug("md/raid:%s: starting from clean shutdown\n", mdname(mddev)); - else { - pr_debug("md/raid:%s: recoverying %d data-only stripes and %d data-parity stripes\n", + else + pr_debug("md/raid:%s: recovering %d data-only stripes and %d data-parity stripes\n", mdname(mddev), ctx.data_only_stripes, ctx.data_parity_stripes); - if (ctx.data_only_stripes > 0) - if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) { - pr_err("md/raid:%s: failed to rewrite stripes to journal\n", - mdname(mddev)); - return -EIO; - } + if (ctx.data_only_stripes == 0) { + log->next_checkpoint = ctx.pos; + r5l_log_write_empty_meta_block(log, ctx.pos, ctx.seq++); + ctx.pos = r5l_ring_add(log, ctx.pos, BLOCK_SECTORS); + } else if (r5c_recovery_rewrite_data_only_stripes(log, &ctx)) { + pr_err("md/raid:%s: failed to rewrite stripes to journal\n", + mdname(mddev)); + return -EIO; } log->log_start = ctx.pos; log->seq = ctx.seq; log->last_checkpoint = pos; r5l_write_super(log, pos); + + r5c_recovery_flush_data_only_stripes(log, &ctx); return 0; } @@ -2250,6 +2286,10 @@ static ssize_t r5c_journal_mode_store(struct mddev *mddev, val > R5C_JOURNAL_MODE_WRITE_BACK) return -EINVAL; + if (raid5_calc_degraded(conf) > 0 && + val == R5C_JOURNAL_MODE_WRITE_BACK) + return -EINVAL; + mddev_suspend(mddev); conf->log->r5c_journal_mode = val; mddev_resume(mddev); @@ -2304,6 +2344,16 @@ int r5c_try_caching_write(struct r5conf *conf, set_bit(STRIPE_R5C_CACHING, &sh->state); } + /* + * When run in degraded mode, array is set to write-through mode. + * This check helps drain pending write safely in the transition to + * write-through mode. + */ + if (s->failed) { + r5c_make_stripe_write_out(sh); + return -EAGAIN; + } + for (i = disks; i--; ) { dev = &sh->dev[i]; /* if non-overwrite, use writing-out phase */ @@ -2354,6 +2404,8 @@ void r5c_release_extra_page(struct stripe_head *sh) struct page *p = sh->dev[i].orig_page; sh->dev[i].orig_page = sh->dev[i].page; + clear_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags); + if (!using_disk_info_extra_page) put_page(p); } @@ -2418,9 +2470,6 @@ void r5c_finish_stripe_write_out(struct r5conf *conf, if (do_wakeup) wake_up(&conf->wait_for_overlap); - if (conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_THROUGH) - return; - spin_lock_irq(&conf->log->stripe_in_journal_lock); list_del_init(&sh->r5c); spin_unlock_irq(&conf->log->stripe_in_journal_lock); @@ -2561,6 +2610,19 @@ ioerr: return ret; } +void r5c_update_on_rdev_error(struct mddev *mddev) +{ + struct r5conf *conf = mddev->private; + struct r5l_log *log = conf->log; + + if (!log) + return; + + if (raid5_calc_degraded(conf) > 0 && + conf->log->r5c_journal_mode == R5C_JOURNAL_MODE_WRITE_BACK) + schedule_work(&log->disable_writeback_work); +} + int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) { struct request_queue *q = bdev_get_queue(rdev->bdev); @@ -2633,20 +2695,23 @@ int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev) spin_lock_init(&log->no_space_stripes_lock); INIT_WORK(&log->deferred_io_work, r5l_submit_io_async); + INIT_WORK(&log->disable_writeback_work, r5c_disable_writeback_async); log->r5c_journal_mode = R5C_JOURNAL_MODE_WRITE_THROUGH; INIT_LIST_HEAD(&log->stripe_in_journal_list); spin_lock_init(&log->stripe_in_journal_lock); atomic_set(&log->stripe_in_journal_count, 0); + rcu_assign_pointer(conf->log, log); + if (r5l_load_log(log)) goto error; - rcu_assign_pointer(conf->log, log); set_bit(MD_HAS_JOURNAL, &conf->mddev->flags); return 0; error: + rcu_assign_pointer(conf->log, NULL); md_unregister_thread(&log->reclaim_thread); reclaim_thread: mempool_destroy(log->meta_pool); @@ -2663,6 +2728,7 @@ io_kc: void r5l_exit_log(struct r5l_log *log) { + flush_work(&log->disable_writeback_work); md_unregister_thread(&log->reclaim_thread); mempool_destroy(log->meta_pool); bioset_free(log->bs); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 06d7279bdd04..6214e699342c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -62,6 +62,8 @@ #include "raid0.h" #include "bitmap.h" +#define UNSUPPORTED_MDDEV_FLAGS (1L << MD_FAILFAST_SUPPORTED) + #define cpu_to_group(cpu) cpu_to_node(cpu) #define ANY_GROUP NUMA_NO_NODE @@ -554,7 +556,7 @@ static struct stripe_head *__find_stripe(struct r5conf *conf, sector_t sector, * of the two sections, and some non-in_sync devices may * be insync in the section most affected by failed devices. */ -static int calc_degraded(struct r5conf *conf) +int raid5_calc_degraded(struct r5conf *conf) { int degraded, degraded2; int i; @@ -617,7 +619,7 @@ static int has_failed(struct r5conf *conf) if (conf->mddev->reshape_position == MaxSector) return conf->mddev->degraded > conf->max_degraded; - degraded = calc_degraded(conf); + degraded = raid5_calc_degraded(conf); if (degraded > conf->max_degraded) return 1; return 0; @@ -1013,7 +1015,17 @@ again: if (test_bit(R5_SkipCopy, &sh->dev[i].flags)) WARN_ON(test_bit(R5_UPTODATE, &sh->dev[i].flags)); - sh->dev[i].vec.bv_page = sh->dev[i].page; + + if (!op_is_write(op) && + test_bit(R5_InJournal, &sh->dev[i].flags)) + /* + * issuing read for a page in journal, this + * must be preparing for prexor in rmw; read + * the data into orig_page + */ + sh->dev[i].vec.bv_page = sh->dev[i].orig_page; + else + sh->dev[i].vec.bv_page = sh->dev[i].page; bi->bi_vcnt = 1; bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_offset = 0; @@ -2378,6 +2390,13 @@ static void raid5_end_read_request(struct bio * bi) } else if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) clear_bit(R5_ReadNoMerge, &sh->dev[i].flags); + if (test_bit(R5_InJournal, &sh->dev[i].flags)) + /* + * end read for a page in journal, this + * must be preparing for prexor in rmw + */ + set_bit(R5_OrigPageUPTDODATE, &sh->dev[i].flags); + if (atomic_read(&rdev->read_errors)) atomic_set(&rdev->read_errors, 0); } else { @@ -2536,7 +2555,7 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev) spin_lock_irqsave(&conf->device_lock, flags); clear_bit(In_sync, &rdev->flags); - mddev->degraded = calc_degraded(conf); + mddev->degraded = raid5_calc_degraded(conf); spin_unlock_irqrestore(&conf->device_lock, flags); set_bit(MD_RECOVERY_INTR, &mddev->recovery); @@ -2550,6 +2569,7 @@ static void raid5_error(struct mddev *mddev, struct md_rdev *rdev) bdevname(rdev->bdev, b), mdname(mddev), conf->raid_disks - mddev->degraded); + r5c_update_on_rdev_error(mddev); } /* @@ -2878,6 +2898,30 @@ sector_t raid5_compute_blocknr(struct stripe_head *sh, int i, int previous) return r_sector; } +/* + * There are cases where we want handle_stripe_dirtying() and + * schedule_reconstruction() to delay towrite to some dev of a stripe. + * + * This function checks whether we want to delay the towrite. Specifically, + * we delay the towrite when: + * + * 1. degraded stripe has a non-overwrite to the missing dev, AND this + * stripe has data in journal (for other devices). + * + * In this case, when reading data for the non-overwrite dev, it is + * necessary to handle complex rmw of write back cache (prexor with + * orig_page, and xor with page). To keep read path simple, we would + * like to flush data in journal to RAID disks first, so complex rmw + * is handled in the write patch (handle_stripe_dirtying). + * + */ +static inline bool delay_towrite(struct r5dev *dev, + struct stripe_head_state *s) +{ + return !test_bit(R5_OVERWRITE, &dev->flags) && + !test_bit(R5_Insync, &dev->flags) && s->injournal; +} + static void schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, int rcw, int expand) @@ -2898,7 +2942,7 @@ schedule_reconstruction(struct stripe_head *sh, struct stripe_head_state *s, for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - if (dev->towrite) { + if (dev->towrite && !delay_towrite(dev, s)) { set_bit(R5_LOCKED, &dev->flags); set_bit(R5_Wantdrain, &dev->flags); if (!expand) @@ -3293,13 +3337,6 @@ static int want_replace(struct stripe_head *sh, int disk_idx) return rv; } -/* fetch_block - checks the given member device to see if its data needs - * to be read or computed to satisfy a request. - * - * Returns 1 when no more member devices need to be checked, otherwise returns - * 0 to tell the loop in handle_stripe_fill to continue - */ - static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, int disk_idx, int disks) { @@ -3390,6 +3427,12 @@ static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s, return 0; } +/* fetch_block - checks the given member device to see if its data needs + * to be read or computed to satisfy a request. + * + * Returns 1 when no more member devices need to be checked, otherwise returns + * 0 to tell the loop in handle_stripe_fill to continue + */ static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s, int disk_idx, int disks) { @@ -3476,10 +3519,26 @@ static void handle_stripe_fill(struct stripe_head *sh, * midst of changing due to a write */ if (!test_bit(STRIPE_COMPUTE_RUN, &sh->state) && !sh->check_state && - !sh->reconstruct_state) + !sh->reconstruct_state) { + + /* + * For degraded stripe with data in journal, do not handle + * read requests yet, instead, flush the stripe to raid + * disks first, this avoids handling complex rmw of write + * back cache (prexor with orig_page, and then xor with + * page) in the read path + */ + if (s->injournal && s->failed) { + if (test_bit(STRIPE_R5C_CACHING, &sh->state)) + r5c_make_stripe_write_out(sh); + goto out; + } + for (i = disks; i--; ) if (fetch_block(sh, s, i, disks)) break; + } +out: set_bit(STRIPE_HANDLE, &sh->state); } @@ -3592,6 +3651,21 @@ unhash: break_stripe_batch_list(head_sh, STRIPE_EXPAND_SYNC_FLAGS); } +/* + * For RMW in write back cache, we need extra page in prexor to store the + * old data. This page is stored in dev->orig_page. + * + * This function checks whether we have data for prexor. The exact logic + * is: + * R5_UPTODATE && (!R5_InJournal || R5_OrigPageUPTDODATE) + */ +static inline bool uptodate_for_rmw(struct r5dev *dev) +{ + return (test_bit(R5_UPTODATE, &dev->flags)) && + (!test_bit(R5_InJournal, &dev->flags) || + test_bit(R5_OrigPageUPTDODATE, &dev->flags)); +} + static int handle_stripe_dirtying(struct r5conf *conf, struct stripe_head *sh, struct stripe_head_state *s, @@ -3620,12 +3694,11 @@ static int handle_stripe_dirtying(struct r5conf *conf, } else for (i = disks; i--; ) { /* would I have to read this buffer for read_modify_write */ struct r5dev *dev = &sh->dev[i]; - if ((dev->towrite || i == sh->pd_idx || i == sh->qd_idx || + if (((dev->towrite && !delay_towrite(dev, s)) || + i == sh->pd_idx || i == sh->qd_idx || test_bit(R5_InJournal, &dev->flags)) && !test_bit(R5_LOCKED, &dev->flags) && - !((test_bit(R5_UPTODATE, &dev->flags) && - (!test_bit(R5_InJournal, &dev->flags) || - dev->page != dev->orig_page)) || + !(uptodate_for_rmw(dev) || test_bit(R5_Wantcompute, &dev->flags))) { if (test_bit(R5_Insync, &dev->flags)) rmw++; @@ -3637,7 +3710,6 @@ static int handle_stripe_dirtying(struct r5conf *conf, i != sh->pd_idx && i != sh->qd_idx && !test_bit(R5_LOCKED, &dev->flags) && !(test_bit(R5_UPTODATE, &dev->flags) || - test_bit(R5_InJournal, &dev->flags) || test_bit(R5_Wantcompute, &dev->flags))) { if (test_bit(R5_Insync, &dev->flags)) rcw++; @@ -3687,13 +3759,11 @@ static int handle_stripe_dirtying(struct r5conf *conf, for (i = disks; i--; ) { struct r5dev *dev = &sh->dev[i]; - if ((dev->towrite || + if (((dev->towrite && !delay_towrite(dev, s)) || i == sh->pd_idx || i == sh->qd_idx || test_bit(R5_InJournal, &dev->flags)) && !test_bit(R5_LOCKED, &dev->flags) && - !((test_bit(R5_UPTODATE, &dev->flags) && - (!test_bit(R5_InJournal, &dev->flags) || - dev->page != dev->orig_page)) || + !(uptodate_for_rmw(dev) || test_bit(R5_Wantcompute, &dev->flags)) && test_bit(R5_Insync, &dev->flags)) { if (test_bit(STRIPE_PREREAD_ACTIVE, @@ -3720,7 +3790,6 @@ static int handle_stripe_dirtying(struct r5conf *conf, i != sh->pd_idx && i != sh->qd_idx && !test_bit(R5_LOCKED, &dev->flags) && !(test_bit(R5_UPTODATE, &dev->flags) || - test_bit(R5_InJournal, &dev->flags) || test_bit(R5_Wantcompute, &dev->flags))) { rcw++; if (test_bit(R5_Insync, &dev->flags) && @@ -6262,10 +6331,10 @@ raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len) mddev_suspend(mddev); conf->skip_copy = new; if (new) - mddev->queue->backing_dev_info.capabilities |= + mddev->queue->backing_dev_info->capabilities |= BDI_CAP_STABLE_WRITES; else - mddev->queue->backing_dev_info.capabilities &= + mddev->queue->backing_dev_info->capabilities &= ~BDI_CAP_STABLE_WRITES; mddev_resume(mddev); } @@ -7023,7 +7092,7 @@ static int raid5_run(struct mddev *mddev) /* * 0 for a fully functional array, 1 or 2 for a degraded array. */ - mddev->degraded = calc_degraded(conf); + mddev->degraded = raid5_calc_degraded(conf); if (has_failed(conf)) { pr_crit("md/raid:%s: not enough operational devices (%d/%d failed)\n", @@ -7084,8 +7153,8 @@ static int raid5_run(struct mddev *mddev) int data_disks = conf->previous_raid_disks - conf->max_degraded; int stripe = data_disks * ((mddev->chunk_sectors << 9) / PAGE_SIZE); - if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe) - mddev->queue->backing_dev_info.ra_pages = 2 * stripe; + if (mddev->queue->backing_dev_info->ra_pages < 2 * stripe) + mddev->queue->backing_dev_info->ra_pages = 2 * stripe; chunk_size = mddev->chunk_sectors << 9; blk_queue_io_min(mddev->queue, chunk_size); @@ -7270,7 +7339,7 @@ static int raid5_spare_active(struct mddev *mddev) } } spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded = calc_degraded(conf); + mddev->degraded = raid5_calc_degraded(conf); spin_unlock_irqrestore(&conf->device_lock, flags); print_raid5_conf(conf); return count; @@ -7630,7 +7699,7 @@ static int raid5_start_reshape(struct mddev *mddev) * pre and post number of devices. */ spin_lock_irqsave(&conf->device_lock, flags); - mddev->degraded = calc_degraded(conf); + mddev->degraded = raid5_calc_degraded(conf); spin_unlock_irqrestore(&conf->device_lock, flags); } mddev->raid_disks = conf->raid_disks; @@ -7694,8 +7763,8 @@ static void end_reshape(struct r5conf *conf) int data_disks = conf->raid_disks - conf->max_degraded; int stripe = data_disks * ((conf->chunk_sectors << 9) / PAGE_SIZE); - if (conf->mddev->queue->backing_dev_info.ra_pages < 2 * stripe) - conf->mddev->queue->backing_dev_info.ra_pages = 2 * stripe; + if (conf->mddev->queue->backing_dev_info->ra_pages < 2 * stripe) + conf->mddev->queue->backing_dev_info->ra_pages = 2 * stripe; } } } @@ -7718,7 +7787,7 @@ static void raid5_finish_reshape(struct mddev *mddev) } else { int d; spin_lock_irq(&conf->device_lock); - mddev->degraded = calc_degraded(conf); + mddev->degraded = raid5_calc_degraded(conf); spin_unlock_irq(&conf->device_lock); for (d = conf->raid_disks ; d < conf->raid_disks - mddev->delta_disks; @@ -7829,8 +7898,9 @@ static void *raid5_takeover_raid1(struct mddev *mddev) mddev->new_chunk_sectors = chunksect; ret = setup_conf(mddev); - if (!IS_ERR_VALUE(ret)) - clear_bit(MD_FAILFAST_SUPPORTED, &mddev->flags); + if (!IS_ERR(ret)) + mddev_clear_unsupported_flags(mddev, + UNSUPPORTED_MDDEV_FLAGS); return ret; } diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index ed8e1362ab36..1440fa26e296 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -322,6 +322,11 @@ enum r5dev_flags { * data and parity being written are in the journal * device */ + R5_OrigPageUPTDODATE, /* with write back cache, we read old data into + * dev->orig_page for prexor. When this flag is + * set, orig_page contains latest data in the + * raid disk. + */ }; /* @@ -753,6 +758,7 @@ extern sector_t raid5_compute_sector(struct r5conf *conf, sector_t r_sector, extern struct stripe_head * raid5_get_active_stripe(struct r5conf *conf, sector_t sector, int previous, int noblock, int noquiesce); +extern int raid5_calc_degraded(struct r5conf *conf); extern int r5l_init_log(struct r5conf *conf, struct md_rdev *rdev); extern void r5l_exit_log(struct r5l_log *log); extern int r5l_write_stripe(struct r5l_log *log, struct stripe_head *head_sh); @@ -781,4 +787,5 @@ extern void r5c_flush_cache(struct r5conf *conf, int num); extern void r5c_check_stripe_cache_usage(struct r5conf *conf); extern void r5c_check_cached_full_stripe(struct r5conf *conf); extern struct md_sysfs_entry r5c_journal_mode; +extern void r5c_update_on_rdev_error(struct mddev *mddev); #endif diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 0ea4efb3de66..ccda41c2c9e4 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -30,8 +30,9 @@ #include "cec-priv.h" -static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx); -static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx); +static void cec_fill_msg_report_features(struct cec_adapter *adap, + struct cec_msg *msg, + unsigned int la_idx); /* * 400 ms is the time it takes for one 16 byte message to be @@ -288,10 +289,10 @@ static void cec_data_cancel(struct cec_data *data) /* Mark it as an error */ data->msg.tx_ts = ktime_get_ns(); - data->msg.tx_status = CEC_TX_STATUS_ERROR | - CEC_TX_STATUS_MAX_RETRIES; + data->msg.tx_status |= CEC_TX_STATUS_ERROR | + CEC_TX_STATUS_MAX_RETRIES; + data->msg.tx_error_cnt++; data->attempts = 0; - data->msg.tx_error_cnt = 1; /* Queue transmitted message for monitoring purposes */ cec_queue_msg_monitor(data->adap, &data->msg, 1); @@ -611,8 +612,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, } memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); if (msg->len == 1) { - if (cec_msg_initiator(msg) != 0xf || - cec_msg_destination(msg) == 0xf) { + if (cec_msg_destination(msg) == 0xf) { dprintk(1, "cec_transmit_msg: invalid poll message\n"); return -EINVAL; } @@ -637,7 +637,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, dprintk(1, "cec_transmit_msg: destination is the adapter itself\n"); return -EINVAL; } - if (cec_msg_initiator(msg) != 0xf && + if (msg->len > 1 && adap->is_configured && !cec_has_log_addr(adap, cec_msg_initiator(msg))) { dprintk(1, "cec_transmit_msg: initiator has unknown logical address %d\n", cec_msg_initiator(msg)); @@ -851,7 +851,7 @@ static const u8 cec_msg_size[256] = { [CEC_MSG_REQUEST_ARC_TERMINATION] = 2 | DIRECTED, [CEC_MSG_TERMINATE_ARC] = 2 | DIRECTED, [CEC_MSG_REQUEST_CURRENT_LATENCY] = 4 | BCAST, - [CEC_MSG_REPORT_CURRENT_LATENCY] = 7 | BCAST, + [CEC_MSG_REPORT_CURRENT_LATENCY] = 6 | BCAST, [CEC_MSG_CDC_MESSAGE] = 2 | BCAST, }; @@ -1071,7 +1071,7 @@ static int cec_config_log_addr(struct cec_adapter *adap, /* Send poll message */ msg.len = 1; - msg.msg[0] = 0xf0 | log_addr; + msg.msg[0] = (log_addr << 4) | log_addr; err = cec_transmit_msg_fh(adap, &msg, NULL, true); /* @@ -1205,7 +1205,7 @@ static int cec_config_thread_func(void *arg) las->log_addr[i] = CEC_LOG_ADDR_INVALID; if (last_la == CEC_LOG_ADDR_INVALID || last_la == CEC_LOG_ADDR_UNREGISTERED || - !(last_la & type2mask[type])) + !((1 << last_la) & type2mask[type])) last_la = la_list[0]; err = cec_config_log_addr(adap, i, last_la); @@ -1250,30 +1250,49 @@ configured: for (i = 1; i < las->num_log_addrs; i++) las->log_addr[i] = CEC_LOG_ADDR_INVALID; } + for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) + las->log_addr[i] = CEC_LOG_ADDR_INVALID; adap->is_configured = true; adap->is_configuring = false; cec_post_state_event(adap); - mutex_unlock(&adap->lock); + /* + * Now post the Report Features and Report Physical Address broadcast + * messages. Note that these are non-blocking transmits, meaning that + * they are just queued up and once adap->lock is unlocked the main + * thread will kick in and start transmitting these. + * + * If after this function is done (but before one or more of these + * messages are actually transmitted) the CEC adapter is unconfigured, + * then any remaining messages will be dropped by the main thread. + */ for (i = 0; i < las->num_log_addrs; i++) { + struct cec_msg msg = {}; + if (las->log_addr[i] == CEC_LOG_ADDR_INVALID || (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY)) continue; - /* - * Report Features must come first according - * to CEC 2.0 - */ - if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED) - cec_report_features(adap, i); - cec_report_phys_addr(adap, i); + msg.msg[0] = (las->log_addr[i] << 4) | 0x0f; + + /* Report Features must come first according to CEC 2.0 */ + if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED && + adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) { + cec_fill_msg_report_features(adap, &msg, i); + cec_transmit_msg_fh(adap, &msg, NULL, false); + } + + /* Report Physical Address */ + cec_msg_report_physical_addr(&msg, adap->phys_addr, + las->primary_device_type[i]); + dprintk(2, "config: la %d pa %x.%x.%x.%x\n", + las->log_addr[i], + cec_phys_addr_exp(adap->phys_addr)); + cec_transmit_msg_fh(adap, &msg, NULL, false); } - for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) - las->log_addr[i] = CEC_LOG_ADDR_INVALID; - mutex_lock(&adap->lock); adap->kthread_config = NULL; - mutex_unlock(&adap->lock); complete(&adap->config_completion); + mutex_unlock(&adap->lock); return 0; unconfigure: @@ -1526,52 +1545,32 @@ EXPORT_SYMBOL_GPL(cec_s_log_addrs); /* High-level core CEC message handling */ -/* Transmit the Report Features message */ -static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx) +/* Fill in the Report Features message */ +static void cec_fill_msg_report_features(struct cec_adapter *adap, + struct cec_msg *msg, + unsigned int la_idx) { - struct cec_msg msg = { }; const struct cec_log_addrs *las = &adap->log_addrs; const u8 *features = las->features[la_idx]; bool op_is_dev_features = false; unsigned int idx; - /* This is 2.0 and up only */ - if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0) - return 0; - /* Report Features */ - msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; - msg.len = 4; - msg.msg[1] = CEC_MSG_REPORT_FEATURES; - msg.msg[2] = adap->log_addrs.cec_version; - msg.msg[3] = las->all_device_types[la_idx]; + msg->msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; + msg->len = 4; + msg->msg[1] = CEC_MSG_REPORT_FEATURES; + msg->msg[2] = adap->log_addrs.cec_version; + msg->msg[3] = las->all_device_types[la_idx]; /* Write RC Profiles first, then Device Features */ for (idx = 0; idx < ARRAY_SIZE(las->features[0]); idx++) { - msg.msg[msg.len++] = features[idx]; + msg->msg[msg->len++] = features[idx]; if ((features[idx] & CEC_OP_FEAT_EXT) == 0) { if (op_is_dev_features) break; op_is_dev_features = true; } } - return cec_transmit_msg(adap, &msg, false); -} - -/* Transmit the Report Physical Address message */ -static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx) -{ - const struct cec_log_addrs *las = &adap->log_addrs; - struct cec_msg msg = { }; - - /* Report Physical Address */ - msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; - cec_msg_report_physical_addr(&msg, adap->phys_addr, - las->primary_device_type[la_idx]); - dprintk(2, "config: la %d pa %x.%x.%x.%x\n", - las->log_addr[la_idx], - cec_phys_addr_exp(adap->phys_addr)); - return cec_transmit_msg(adap, &msg, false); } /* Transmit the Feature Abort message */ @@ -1777,9 +1776,10 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, } case CEC_MSG_GIVE_FEATURES: - if (adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) - return cec_report_features(adap, la_idx); - return 0; + if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0) + return cec_feature_abort(adap, msg); + cec_fill_msg_report_features(adap, &tx_cec_msg, la_idx); + return cec_transmit_msg(adap, &tx_cec_msg, false); default: /* diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index bc5e8cfe7ca2..8f11d7e45993 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -719,6 +719,9 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, skb_copy_from_linear_data(h->priv->ule_skb, dest_addr, ETH_ALEN); skb_pull(h->priv->ule_skb, ETH_ALEN); + } else { + /* dest_addr buffer is only valid if h->priv->ule_dbit == 0 */ + eth_zero_addr(dest_addr); } /* Handle ULE Extension Headers. */ @@ -750,16 +753,8 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, if (!h->priv->ule_bridged) { skb_push(h->priv->ule_skb, ETH_HLEN); h->ethh = (struct ethhdr *)h->priv->ule_skb->data; - if (!h->priv->ule_dbit) { - /* - * dest_addr buffer is only valid if - * h->priv->ule_dbit == 0 - */ - memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN); - eth_zero_addr(h->ethh->h_source); - } else /* zeroize source and dest */ - memset(h->ethh, 0, ETH_ALEN * 2); - + memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN); + eth_zero_addr(h->ethh->h_source); h->ethh->h_proto = htons(h->priv->ule_sndu_type); } /* else: skb is in correct state; nothing to do. */ diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index b31fa6fae009..b979ea148251 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -655,6 +655,7 @@ config VIDEO_S5K6A3 config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select CRC32 ---help--- This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M camera sensor with an embedded SoC image signal processor. diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 59872b31f832..f4e92bdfe192 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2741,9 +2741,7 @@ static const struct v4l2_subdev_internal_ops smiapp_internal_ops = { * I2C Driver */ -#ifdef CONFIG_PM - -static int smiapp_suspend(struct device *dev) +static int __maybe_unused smiapp_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *subdev = i2c_get_clientdata(client); @@ -2768,7 +2766,7 @@ static int smiapp_suspend(struct device *dev) return 0; } -static int smiapp_resume(struct device *dev) +static int __maybe_unused smiapp_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *subdev = i2c_get_clientdata(client); @@ -2783,13 +2781,6 @@ static int smiapp_resume(struct device *dev) return rval; } -#else - -#define smiapp_suspend NULL -#define smiapp_resume NULL - -#endif /* CONFIG_PM */ - static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) { struct smiapp_hwconfig *hwcfg; @@ -2913,13 +2904,9 @@ static int smiapp_probe(struct i2c_client *client, if (IS_ERR(sensor->xshutdown)) return PTR_ERR(sensor->xshutdown); - pm_runtime_enable(&client->dev); - - rval = pm_runtime_get_sync(&client->dev); - if (rval < 0) { - rval = -ENODEV; - goto out_power_off; - } + rval = smiapp_power_on(&client->dev); + if (rval < 0) + return rval; rval = smiapp_identify_module(sensor); if (rval) { @@ -3100,6 +3087,9 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) goto out_media_entity_cleanup; + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); pm_runtime_set_autosuspend_delay(&client->dev, 1000); pm_runtime_use_autosuspend(&client->dev); pm_runtime_put_autosuspend(&client->dev); @@ -3113,8 +3103,7 @@ out_cleanup: smiapp_cleanup(sensor); out_power_off: - pm_runtime_put(&client->dev); - pm_runtime_disable(&client->dev); + smiapp_power_off(&client->dev); return rval; } @@ -3127,8 +3116,10 @@ static int smiapp_remove(struct i2c_client *client) v4l2_async_unregister_subdev(subdev); - pm_runtime_suspend(&client->dev); pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) + smiapp_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); for (i = 0; i < sensor->ssds_used; i++) { v4l2_device_unregister_subdev(&sensor->ssds[i].sd); diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 3a0fe8cc64e9..48646a7f3fb0 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -291,8 +291,12 @@ static void tvp5150_selmux(struct v4l2_subdev *sd) tvp5150_write(sd, TVP5150_OP_MODE_CTL, opmode); tvp5150_write(sd, TVP5150_VD_IN_SRC_SEL_1, input); - /* Svideo should enable YCrCb output and disable GPCL output - * For Composite and TV, it should be the reverse + /* + * Setup the FID/GLCO/VLK/HVLK and INTREQ/GPCL/VBLK output signals. For + * S-Video we output the vertical lock (VLK) signal on FID/GLCO/VLK/HVLK + * and set INTREQ/GPCL/VBLK to logic 0. For composite we output the + * field indicator (FID) signal on FID/GLCO/VLK/HVLK and set + * INTREQ/GPCL/VBLK to logic 1. */ val = tvp5150_read(sd, TVP5150_MISC_CTL); if (val < 0) { @@ -301,9 +305,9 @@ static void tvp5150_selmux(struct v4l2_subdev *sd) } if (decoder->input == TVP5150_SVIDEO) - val = (val & ~0x40) | 0x10; + val = (val & ~TVP5150_MISC_CTL_GPCL) | TVP5150_MISC_CTL_HVLK; else - val = (val & ~0x10) | 0x40; + val = (val & ~TVP5150_MISC_CTL_HVLK) | TVP5150_MISC_CTL_GPCL; tvp5150_write(sd, TVP5150_MISC_CTL, val); }; @@ -455,7 +459,12 @@ static const struct i2c_reg_value tvp5150_init_enable[] = { },{ /* Automatic offset and AGC enabled */ TVP5150_ANAL_CHL_CTL, 0x15 },{ /* Activate YCrCb output 0x9 or 0xd ? */ - TVP5150_MISC_CTL, 0x6f + TVP5150_MISC_CTL, TVP5150_MISC_CTL_GPCL | + TVP5150_MISC_CTL_INTREQ_OE | + TVP5150_MISC_CTL_YCBCR_OE | + TVP5150_MISC_CTL_SYNC_OE | + TVP5150_MISC_CTL_VBLANK | + TVP5150_MISC_CTL_CLOCK_OE, },{ /* Activates video std autodetection for all standards */ TVP5150_AUTOSW_MSK, 0x0 },{ /* Default format: 0x47. For 4:2:2: 0x40 */ @@ -861,8 +870,6 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, f = &format->format; - tvp5150_reset(sd, 0); - f->width = decoder->rect.width; f->height = decoder->rect.height / 2; @@ -1051,21 +1058,27 @@ static const struct media_entity_operations tvp5150_sd_media_ops = { static int tvp5150_s_stream(struct v4l2_subdev *sd, int enable) { struct tvp5150 *decoder = to_tvp5150(sd); - /* Output format: 8-bit ITU-R BT.656 with embedded syncs */ - int val = 0x09; - - /* Output format: 8-bit 4:2:2 YUV with discrete sync */ - if (decoder->mbus_type == V4L2_MBUS_PARALLEL) - val = 0x0d; + int val; - /* Initializes TVP5150 to its default values */ - /* # set PCLK (27MHz) */ - tvp5150_write(sd, TVP5150_CONF_SHARED_PIN, 0x00); + /* Enable or disable the video output signals. */ + val = tvp5150_read(sd, TVP5150_MISC_CTL); + if (val < 0) + return val; + + val &= ~(TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_SYNC_OE | + TVP5150_MISC_CTL_CLOCK_OE); + + if (enable) { + /* + * Enable the YCbCr and clock outputs. In discrete sync mode + * (non-BT.656) additionally enable the the sync outputs. + */ + val |= TVP5150_MISC_CTL_YCBCR_OE | TVP5150_MISC_CTL_CLOCK_OE; + if (decoder->mbus_type == V4L2_MBUS_PARALLEL) + val |= TVP5150_MISC_CTL_SYNC_OE; + } - if (enable) - tvp5150_write(sd, TVP5150_MISC_CTL, val); - else - tvp5150_write(sd, TVP5150_MISC_CTL, 0x00); + tvp5150_write(sd, TVP5150_MISC_CTL, val); return 0; } @@ -1524,7 +1537,6 @@ static int tvp5150_probe(struct i2c_client *c, res = core->hdl.error; goto err; } - v4l2_ctrl_handler_setup(&core->hdl); /* Default is no cropping */ core->rect.top = 0; @@ -1535,6 +1547,8 @@ static int tvp5150_probe(struct i2c_client *c, core->rect.left = 0; core->rect.width = TVP5150_H_MAX; + tvp5150_reset(sd, 0); /* Calls v4l2_ctrl_handler_setup() */ + res = v4l2_async_register_subdev(sd); if (res < 0) goto err; diff --git a/drivers/media/i2c/tvp5150_reg.h b/drivers/media/i2c/tvp5150_reg.h index 25a994944918..30a48c28d05a 100644 --- a/drivers/media/i2c/tvp5150_reg.h +++ b/drivers/media/i2c/tvp5150_reg.h @@ -9,6 +9,15 @@ #define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */ #define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */ #define TVP5150_MISC_CTL 0x03 /* Miscellaneous controls */ +#define TVP5150_MISC_CTL_VBLK_GPCL BIT(7) +#define TVP5150_MISC_CTL_GPCL BIT(6) +#define TVP5150_MISC_CTL_INTREQ_OE BIT(5) +#define TVP5150_MISC_CTL_HVLK BIT(4) +#define TVP5150_MISC_CTL_YCBCR_OE BIT(3) +#define TVP5150_MISC_CTL_SYNC_OE BIT(2) +#define TVP5150_MISC_CTL_VBLANK BIT(1) +#define TVP5150_MISC_CTL_CLOCK_OE BIT(0) + #define TVP5150_AUTOSW_MSK 0x04 /* Autoswitch mask: TVP5150A / TVP5150AM */ /* Reserved 05h */ diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index 979634000597..d5c911c09e2b 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -308,9 +308,7 @@ static void cobalt_pci_iounmap(struct cobalt *cobalt, struct pci_dev *pci_dev) static void cobalt_free_msi(struct cobalt *cobalt, struct pci_dev *pci_dev) { free_irq(pci_dev->irq, (void *)cobalt); - - if (cobalt->msi_enabled) - pci_disable_msi(pci_dev); + pci_free_irq_vectors(pci_dev); } static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, @@ -387,14 +385,12 @@ static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, from being generated. */ cobalt_set_interrupt(cobalt, false); - if (pci_enable_msi_range(pci_dev, 1, 1) < 1) { + if (pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_MSI) < 1) { cobalt_err("Could not enable MSI\n"); - cobalt->msi_enabled = false; ret = -EIO; goto err_release; } msi_config_show(cobalt, pci_dev); - cobalt->msi_enabled = true; /* Register IRQ */ if (request_irq(pci_dev->irq, cobalt_irq_handler, IRQF_SHARED, diff --git a/drivers/media/pci/cobalt/cobalt-driver.h b/drivers/media/pci/cobalt/cobalt-driver.h index ed00dc9d9399..00f773ec359a 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.h +++ b/drivers/media/pci/cobalt/cobalt-driver.h @@ -287,8 +287,6 @@ struct cobalt { u32 irq_none; u32 irq_full_fifo; - bool msi_enabled; - /* omnitek dma */ int dma_channels; int first_fifo_channel; diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 07fa08be9e99..d54ebe7e0215 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -97,14 +97,13 @@ struct pctv452e_state { u8 c; /* transaction counter, wraps around... */ u8 initialized; /* set to 1 if 0x15 has been sent */ u16 last_rc_key; - - unsigned char data[80]; }; static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, unsigned int write_len, unsigned int read_len) { struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 *buf; u8 id; unsigned int rlen; int ret; @@ -114,36 +113,39 @@ static int tt3650_ci_msg(struct dvb_usb_device *d, u8 cmd, u8 *data, return -EIO; } - mutex_lock(&state->ca_mutex); + buf = kmalloc(64, GFP_KERNEL); + if (!buf) + return -ENOMEM; + id = state->c++; - state->data[0] = SYNC_BYTE_OUT; - state->data[1] = id; - state->data[2] = cmd; - state->data[3] = write_len; + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = cmd; + buf[3] = write_len; - memcpy(state->data + 4, data, write_len); + memcpy(buf + 4, data, write_len); rlen = (read_len > 0) ? 64 : 0; - ret = dvb_usb_generic_rw(d, state->data, 4 + write_len, - state->data, rlen, /* delay_ms */ 0); + ret = dvb_usb_generic_rw(d, buf, 4 + write_len, + buf, rlen, /* delay_ms */ 0); if (0 != ret) goto failed; ret = -EIO; - if (SYNC_BYTE_IN != state->data[0] || id != state->data[1]) + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) goto failed; - memcpy(data, state->data + 4, read_len); + memcpy(data, buf + 4, read_len); - mutex_unlock(&state->ca_mutex); + kfree(buf); return 0; failed: err("CI error %d; %02X %02X %02X -> %*ph.", - ret, SYNC_BYTE_OUT, id, cmd, 3, state->data); + ret, SYNC_BYTE_OUT, id, cmd, 3, buf); - mutex_unlock(&state->ca_mutex); + kfree(buf); return ret; } @@ -410,53 +412,57 @@ static int pctv452e_i2c_msg(struct dvb_usb_device *d, u8 addr, u8 *rcv_buf, u8 rcv_len) { struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 *buf; u8 id; int ret; - mutex_lock(&state->ca_mutex); + buf = kmalloc(64, GFP_KERNEL); + if (!buf) + return -ENOMEM; + id = state->c++; ret = -EINVAL; if (snd_len > 64 - 7 || rcv_len > 64 - 7) goto failed; - state->data[0] = SYNC_BYTE_OUT; - state->data[1] = id; - state->data[2] = PCTV_CMD_I2C; - state->data[3] = snd_len + 3; - state->data[4] = addr << 1; - state->data[5] = snd_len; - state->data[6] = rcv_len; + buf[0] = SYNC_BYTE_OUT; + buf[1] = id; + buf[2] = PCTV_CMD_I2C; + buf[3] = snd_len + 3; + buf[4] = addr << 1; + buf[5] = snd_len; + buf[6] = rcv_len; - memcpy(state->data + 7, snd_buf, snd_len); + memcpy(buf + 7, snd_buf, snd_len); - ret = dvb_usb_generic_rw(d, state->data, 7 + snd_len, - state->data, /* rcv_len */ 64, + ret = dvb_usb_generic_rw(d, buf, 7 + snd_len, + buf, /* rcv_len */ 64, /* delay_ms */ 0); if (ret < 0) goto failed; /* TT USB protocol error. */ ret = -EIO; - if (SYNC_BYTE_IN != state->data[0] || id != state->data[1]) + if (SYNC_BYTE_IN != buf[0] || id != buf[1]) goto failed; /* I2C device didn't respond as expected. */ ret = -EREMOTEIO; - if (state->data[5] < snd_len || state->data[6] < rcv_len) + if (buf[5] < snd_len || buf[6] < rcv_len) goto failed; - memcpy(rcv_buf, state->data + 7, rcv_len); - mutex_unlock(&state->ca_mutex); + memcpy(rcv_buf, buf + 7, rcv_len); + kfree(buf); return rcv_len; failed: err("I2C error %d; %02X %02X %02X %02X %02X -> %*ph", ret, SYNC_BYTE_OUT, id, addr << 1, snd_len, rcv_len, - 7, state->data); + 7, buf); - mutex_unlock(&state->ca_mutex); + kfree(buf); return ret; } @@ -505,7 +511,7 @@ static u32 pctv452e_i2c_func(struct i2c_adapter *adapter) static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) { struct pctv452e_state *state = (struct pctv452e_state *)d->priv; - u8 *rx; + u8 *b0, *rx; int ret; info("%s: %d\n", __func__, i); @@ -516,11 +522,12 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) if (state->initialized) return 0; - rx = kmalloc(PCTV_ANSWER_LEN, GFP_KERNEL); - if (!rx) + b0 = kmalloc(5 + PCTV_ANSWER_LEN, GFP_KERNEL); + if (!b0) return -ENOMEM; - mutex_lock(&state->ca_mutex); + rx = b0 + 5; + /* hmm where shoud this should go? */ ret = usb_set_interface(d->udev, 0, ISOC_INTERFACE_ALTERNATIVE); if (ret != 0) @@ -528,66 +535,70 @@ static int pctv452e_power_ctrl(struct dvb_usb_device *d, int i) __func__, ret); /* this is a one-time initialization, dont know where to put */ - state->data[0] = 0xaa; - state->data[1] = state->c++; - state->data[2] = PCTV_CMD_RESET; - state->data[3] = 1; - state->data[4] = 0; + b0[0] = 0xaa; + b0[1] = state->c++; + b0[2] = PCTV_CMD_RESET; + b0[3] = 1; + b0[4] = 0; /* reset board */ - ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0); + ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0); if (ret) goto ret; - state->data[1] = state->c++; - state->data[4] = 1; + b0[1] = state->c++; + b0[4] = 1; /* reset board (again?) */ - ret = dvb_usb_generic_rw(d, state->data, 5, rx, PCTV_ANSWER_LEN, 0); + ret = dvb_usb_generic_rw(d, b0, 5, rx, PCTV_ANSWER_LEN, 0); if (ret) goto ret; state->initialized = 1; ret: - mutex_unlock(&state->ca_mutex); - kfree(rx); + kfree(b0); return ret; } static int pctv452e_rc_query(struct dvb_usb_device *d) { struct pctv452e_state *state = (struct pctv452e_state *)d->priv; + u8 *b, *rx; int ret, i; u8 id; - mutex_lock(&state->ca_mutex); + b = kmalloc(CMD_BUFFER_SIZE + PCTV_ANSWER_LEN, GFP_KERNEL); + if (!b) + return -ENOMEM; + + rx = b + CMD_BUFFER_SIZE; + id = state->c++; /* prepare command header */ - state->data[0] = SYNC_BYTE_OUT; - state->data[1] = id; - state->data[2] = PCTV_CMD_IR; - state->data[3] = 0; + b[0] = SYNC_BYTE_OUT; + b[1] = id; + b[2] = PCTV_CMD_IR; + b[3] = 0; /* send ir request */ - ret = dvb_usb_generic_rw(d, state->data, 4, - state->data, PCTV_ANSWER_LEN, 0); + ret = dvb_usb_generic_rw(d, b, 4, rx, PCTV_ANSWER_LEN, 0); if (ret != 0) goto ret; if (debug > 3) { - info("%s: read: %2d: %*ph: ", __func__, ret, 3, state->data); - for (i = 0; (i < state->data[3]) && ((i + 3) < PCTV_ANSWER_LEN); i++) - info(" %02x", state->data[i + 3]); + info("%s: read: %2d: %*ph: ", __func__, ret, 3, rx); + for (i = 0; (i < rx[3]) && ((i+3) < PCTV_ANSWER_LEN); i++) + info(" %02x", rx[i+3]); info("\n"); } - if ((state->data[3] == 9) && (state->data[12] & 0x01)) { + if ((rx[3] == 9) && (rx[12] & 0x01)) { /* got a "press" event */ - state->last_rc_key = RC_SCANCODE_RC5(state->data[7], state->data[6]); + state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]); if (debug > 2) info("%s: cmd=0x%02x sys=0x%02x\n", - __func__, state->data[6], state->data[7]); + __func__, rx[6], rx[7]); rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0); } else if (state->last_rc_key) { @@ -595,7 +606,7 @@ static int pctv452e_rc_query(struct dvb_usb_device *d) state->last_rc_key = 0; } ret: - mutex_unlock(&state->ca_mutex); + kfree(b); return ret; } diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index a4dcaec31d02..8c1f926567ec 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -218,22 +218,30 @@ static int smsusb_start_streaming(struct smsusb_device_t *dev) static int smsusb_sendrequest(void *context, void *buffer, size_t size) { struct smsusb_device_t *dev = (struct smsusb_device_t *) context; - struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer; - int dummy; + struct sms_msg_hdr *phdr; + int dummy, ret; if (dev->state != SMSUSB_ACTIVE) { pr_debug("Device not active yet\n"); return -ENOENT; } + phdr = kmalloc(size, GFP_KERNEL); + if (!phdr) + return -ENOMEM; + memcpy(phdr, buffer, size); + pr_debug("sending %s(%d) size: %d\n", smscore_translate_msg(phdr->msg_type), phdr->msg_type, phdr->msg_length); smsendian_handle_tx_message((struct sms_msg_data *) phdr); - smsendian_handle_message_header((struct sms_msg_hdr *)buffer); - return usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), - buffer, size, &dummy, 1000); + smsendian_handle_message_header((struct sms_msg_hdr *)phdr); + ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 2), + phdr, size, &dummy, 1000); + + kfree(phdr); + return ret; } static char *smsusb1_fw_lkup[] = { diff --git a/drivers/memstick/core/memstick.c b/drivers/memstick/core/memstick.c index a0547dbf9806..76382c858c35 100644 --- a/drivers/memstick/core/memstick.c +++ b/drivers/memstick/core/memstick.c @@ -330,7 +330,7 @@ static int h_memstick_read_dev_id(struct memstick_dev *card, struct ms_id_register id_reg; if (!(*mrq)) { - memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, NULL, + memstick_init_req(&card->current_mrq, MS_TPC_READ_REG, &id_reg, sizeof(struct ms_id_register)); *mrq = &card->current_mrq; return 0; diff --git a/drivers/memstick/core/ms_block.c b/drivers/memstick/core/ms_block.c index f3512404bc52..99e651c27fb7 100644 --- a/drivers/memstick/core/ms_block.c +++ b/drivers/memstick/core/ms_block.c @@ -2000,16 +2000,6 @@ static int msb_bd_getgeo(struct block_device *bdev, return 0; } -static int msb_prepare_req(struct request_queue *q, struct request *req) -{ - if (req->cmd_type != REQ_TYPE_FS) { - blk_dump_rq_flags(req, "MS unsupported request"); - return BLKPREP_KILL; - } - req->rq_flags |= RQF_DONTPREP; - return BLKPREP_OK; -} - static void msb_submit_req(struct request_queue *q) { struct memstick_dev *card = q->queuedata; @@ -2132,7 +2122,6 @@ static int msb_init_disk(struct memstick_dev *card) } msb->queue->queuedata = card; - blk_queue_prep_rq(msb->queue, msb_prepare_req); blk_queue_bounce_limit(msb->queue, limit); blk_queue_max_hw_sectors(msb->queue, MS_BLOCK_MAX_PAGES); diff --git a/drivers/memstick/core/mspro_block.c b/drivers/memstick/core/mspro_block.c index fa0746d182ff..c00d8a266878 100644 --- a/drivers/memstick/core/mspro_block.c +++ b/drivers/memstick/core/mspro_block.c @@ -827,18 +827,6 @@ static void mspro_block_start(struct memstick_dev *card) spin_unlock_irqrestore(&msb->q_lock, flags); } -static int mspro_block_prepare_req(struct request_queue *q, struct request *req) -{ - if (req->cmd_type != REQ_TYPE_FS) { - blk_dump_rq_flags(req, "MSPro unsupported request"); - return BLKPREP_KILL; - } - - req->rq_flags |= RQF_DONTPREP; - - return BLKPREP_OK; -} - static void mspro_block_submit_req(struct request_queue *q) { struct memstick_dev *card = q->queuedata; @@ -1228,7 +1216,6 @@ static int mspro_block_init_disk(struct memstick_dev *card) } msb->queue->queuedata = card; - blk_queue_prep_rq(msb->queue, mspro_block_prepare_req); blk_queue_bounce_limit(msb->queue, limit); blk_queue_max_hw_sectors(msb->queue, MSPRO_BLOCK_MAX_PAGES); diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 4ce333643943..f6308ad35b19 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2321,10 +2321,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, SmpPassthroughReply_t *smprep; smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply; - memcpy(req->sense, smprep, sizeof(*smprep)); - req->sense_len = sizeof(*smprep); - req->resid_len = 0; - rsp->resid_len -= smprep->ResponseDataLength; + memcpy(scsi_req(req)->sense, smprep, sizeof(*smprep)); + scsi_req(req)->sense_len = sizeof(*smprep); + scsi_req(req)->resid_len = 0; + scsi_req(rsp)->resid_len -= smprep->ResponseDataLength; } else { printk(MYIOC_s_ERR_FMT "%s: smp passthru reply failed to be returned\n", diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index 1ef7575547e6..be42957a78e1 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -56,6 +56,7 @@ * document number TBD : Wildcat Point-LP * document number TBD : 9 Series * document number TBD : Lewisburg + * document number TBD : Apollo Lake SoC */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -83,6 +84,17 @@ #define ACPIBASE_GCS_OFF 0x3410 #define ACPIBASE_GCS_END 0x3414 +#define SPIBASE_BYT 0x54 +#define SPIBASE_BYT_SZ 512 +#define SPIBASE_BYT_EN BIT(1) + +#define SPIBASE_LPT 0x3800 +#define SPIBASE_LPT_SZ 512 +#define BCR 0xdc +#define BCR_WPD BIT(0) + +#define SPIBASE_APL_SZ 4096 + #define GPIOBASE_ICH0 0x58 #define GPIOCTRL_ICH0 0x5C #define GPIOBASE_ICH6 0x48 @@ -133,6 +145,12 @@ static struct resource gpio_ich_res[] = { }, }; +static struct resource intel_spi_res[] = { + { + .flags = IORESOURCE_MEM, + } +}; + static struct mfd_cell lpc_ich_wdt_cell = { .name = "iTCO_wdt", .num_resources = ARRAY_SIZE(wdt_ich_res), @@ -147,6 +165,14 @@ static struct mfd_cell lpc_ich_gpio_cell = { .ignore_resource_conflicts = true, }; + +static struct mfd_cell lpc_ich_spi_cell = { + .name = "intel-spi", + .num_resources = ARRAY_SIZE(intel_spi_res), + .resources = intel_spi_res, + .ignore_resource_conflicts = true, +}; + /* chipset related info */ enum lpc_chipsets { LPC_ICH = 0, /* ICH */ @@ -216,6 +242,7 @@ enum lpc_chipsets { LPC_BRASWELL, /* Braswell SoC */ LPC_LEWISBURG, /* Lewisburg */ LPC_9S, /* 9 Series */ + LPC_APL, /* Apollo Lake SoC */ }; static struct lpc_ich_info lpc_chipset_info[] = { @@ -494,10 +521,12 @@ static struct lpc_ich_info lpc_chipset_info[] = { .name = "Lynx Point", .iTCO_version = 2, .gpio_version = ICH_V5_GPIO, + .spi_type = INTEL_SPI_LPT, }, [LPC_LPT_LP] = { .name = "Lynx Point_LP", .iTCO_version = 2, + .spi_type = INTEL_SPI_LPT, }, [LPC_WBG] = { .name = "Wellsburg", @@ -511,6 +540,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_BAYTRAIL] = { .name = "Bay Trail SoC", .iTCO_version = 3, + .spi_type = INTEL_SPI_BYT, }, [LPC_COLETO] = { .name = "Coleto Creek", @@ -519,10 +549,12 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_WPT_LP] = { .name = "Wildcat Point_LP", .iTCO_version = 2, + .spi_type = INTEL_SPI_LPT, }, [LPC_BRASWELL] = { .name = "Braswell SoC", .iTCO_version = 3, + .spi_type = INTEL_SPI_BYT, }, [LPC_LEWISBURG] = { .name = "Lewisburg", @@ -533,6 +565,10 @@ static struct lpc_ich_info lpc_chipset_info[] = { .iTCO_version = 2, .gpio_version = ICH_V5_GPIO, }, + [LPC_APL] = { + .name = "Apollo Lake SoC", + .spi_type = INTEL_SPI_BXT, + }, }; /* @@ -681,6 +717,7 @@ static const struct pci_device_id lpc_ich_ids[] = { { PCI_VDEVICE(INTEL, 0x3b14), LPC_3420}, { PCI_VDEVICE(INTEL, 0x3b16), LPC_3450}, { PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579}, + { PCI_VDEVICE(INTEL, 0x5ae8), LPC_APL}, { PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT}, { PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT}, @@ -1056,6 +1093,94 @@ wdt_done: return ret; } +static int lpc_ich_init_spi(struct pci_dev *dev) +{ + struct lpc_ich_priv *priv = pci_get_drvdata(dev); + struct resource *res = &intel_spi_res[0]; + struct intel_spi_boardinfo *info; + u32 spi_base, rcba, bcr; + + info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->type = lpc_chipset_info[priv->chipset].spi_type; + + switch (info->type) { + case INTEL_SPI_BYT: + pci_read_config_dword(dev, SPIBASE_BYT, &spi_base); + if (spi_base & SPIBASE_BYT_EN) { + res->start = spi_base & ~(SPIBASE_BYT_SZ - 1); + res->end = res->start + SPIBASE_BYT_SZ - 1; + } + break; + + case INTEL_SPI_LPT: + pci_read_config_dword(dev, RCBABASE, &rcba); + if (rcba & 1) { + spi_base = round_down(rcba, SPIBASE_LPT_SZ); + res->start = spi_base + SPIBASE_LPT; + res->end = res->start + SPIBASE_LPT_SZ - 1; + + /* + * Try to make the flash chip writeable now by + * setting BCR_WPD. It it fails we tell the driver + * that it can only read the chip. + */ + pci_read_config_dword(dev, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_write_config_dword(dev, BCR, bcr); + pci_read_config_dword(dev, BCR, &bcr); + } + info->writeable = !!(bcr & BCR_WPD); + } + break; + + case INTEL_SPI_BXT: { + unsigned int p2sb = PCI_DEVFN(13, 0); + unsigned int spi = PCI_DEVFN(13, 2); + struct pci_bus *bus = dev->bus; + + /* + * The P2SB is hidden by BIOS and we need to unhide it in + * order to read BAR of the SPI flash device. Once that is + * done we hide it again. + */ + pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0); + pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0, + &spi_base); + if (spi_base != ~0) { + res->start = spi_base & 0xfffffff0; + res->end = res->start + SPIBASE_APL_SZ - 1; + + pci_bus_read_config_dword(bus, spi, BCR, &bcr); + if (!(bcr & BCR_WPD)) { + bcr |= BCR_WPD; + pci_bus_write_config_dword(bus, spi, BCR, bcr); + pci_bus_read_config_dword(bus, spi, BCR, &bcr); + } + info->writeable = !!(bcr & BCR_WPD); + } + + pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); + break; + } + + default: + return -EINVAL; + } + + if (!res->start) + return -ENODEV; + + lpc_ich_spi_cell.platform_data = info; + lpc_ich_spi_cell.pdata_size = sizeof(*info); + + return mfd_add_devices(&dev->dev, PLATFORM_DEVID_NONE, + &lpc_ich_spi_cell, 1, NULL, 0, NULL); +} + static int lpc_ich_probe(struct pci_dev *dev, const struct pci_device_id *id) { @@ -1099,6 +1224,12 @@ static int lpc_ich_probe(struct pci_dev *dev, cell_added = true; } + if (lpc_chipset_info[priv->chipset].spi_type) { + ret = lpc_ich_init_spi(dev); + if (!ret) + cell_added = true; + } + /* * We only care if at least one or none of the cells registered * successfully. diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 7f1b282d7d96..cb290b8ca0c8 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -1396,7 +1396,7 @@ int genwqe_device_remove(struct genwqe_dev *cd) * application which will decrease this reference from * 1/unused to 0/illegal and not from 2/used 1/empty. */ - rc = atomic_read(&cd->cdev_genwqe.kobj.kref.refcount); + rc = kref_read(&cd->cdev_genwqe.kobj.kref); if (rc != 1) { dev_err(&pci_dev->dev, "[%s] err: cdev_genwqe...refcount=%d\n", __func__, rc); diff --git a/drivers/misc/lkdtm.h b/drivers/misc/lkdtm.h index cfa1039c62e7..67d27be60405 100644 --- a/drivers/misc/lkdtm.h +++ b/drivers/misc/lkdtm.h @@ -19,8 +19,12 @@ void lkdtm_SOFTLOCKUP(void); void lkdtm_HARDLOCKUP(void); void lkdtm_SPINLOCKUP(void); void lkdtm_HUNG_TASK(void); -void lkdtm_ATOMIC_UNDERFLOW(void); -void lkdtm_ATOMIC_OVERFLOW(void); +void lkdtm_REFCOUNT_SATURATE_INC(void); +void lkdtm_REFCOUNT_SATURATE_ADD(void); +void lkdtm_REFCOUNT_ZERO_DEC(void); +void lkdtm_REFCOUNT_ZERO_INC(void); +void lkdtm_REFCOUNT_ZERO_SUB(void); +void lkdtm_REFCOUNT_ZERO_ADD(void); void lkdtm_CORRUPT_LIST_ADD(void); void lkdtm_CORRUPT_LIST_DEL(void); diff --git a/drivers/misc/lkdtm_bugs.c b/drivers/misc/lkdtm_bugs.c index 91edd0b55e5c..cba0837aee2e 100644 --- a/drivers/misc/lkdtm_bugs.c +++ b/drivers/misc/lkdtm_bugs.c @@ -6,6 +6,7 @@ */ #include "lkdtm.h" #include <linux/list.h> +#include <linux/refcount.h> #include <linux/sched.h> struct lkdtm_list { @@ -129,28 +130,86 @@ void lkdtm_HUNG_TASK(void) schedule(); } -void lkdtm_ATOMIC_UNDERFLOW(void) +void lkdtm_REFCOUNT_SATURATE_INC(void) { - atomic_t under = ATOMIC_INIT(INT_MIN); + refcount_t over = REFCOUNT_INIT(UINT_MAX - 1); - pr_info("attempting good atomic increment\n"); - atomic_inc(&under); - atomic_dec(&under); + pr_info("attempting good refcount decrement\n"); + refcount_dec(&over); + refcount_inc(&over); - pr_info("attempting bad atomic underflow\n"); - atomic_dec(&under); + pr_info("attempting bad refcount inc overflow\n"); + refcount_inc(&over); + refcount_inc(&over); + if (refcount_read(&over) == UINT_MAX) + pr_err("Correctly stayed saturated, but no BUG?!\n"); + else + pr_err("Fail: refcount wrapped\n"); +} + +void lkdtm_REFCOUNT_SATURATE_ADD(void) +{ + refcount_t over = REFCOUNT_INIT(UINT_MAX - 1); + + pr_info("attempting good refcount decrement\n"); + refcount_dec(&over); + refcount_inc(&over); + + pr_info("attempting bad refcount add overflow\n"); + refcount_add(2, &over); + if (refcount_read(&over) == UINT_MAX) + pr_err("Correctly stayed saturated, but no BUG?!\n"); + else + pr_err("Fail: refcount wrapped\n"); +} + +void lkdtm_REFCOUNT_ZERO_DEC(void) +{ + refcount_t zero = REFCOUNT_INIT(1); + + pr_info("attempting bad refcount decrement to zero\n"); + refcount_dec(&zero); + if (refcount_read(&zero) == 0) + pr_err("Stayed at zero, but no BUG?!\n"); + else + pr_err("Fail: refcount went crazy\n"); } -void lkdtm_ATOMIC_OVERFLOW(void) +void lkdtm_REFCOUNT_ZERO_SUB(void) { - atomic_t over = ATOMIC_INIT(INT_MAX); + refcount_t zero = REFCOUNT_INIT(1); + + pr_info("attempting bad refcount subtract past zero\n"); + if (!refcount_sub_and_test(2, &zero)) + pr_info("wrap attempt was noticed\n"); + if (refcount_read(&zero) == 1) + pr_err("Correctly stayed above 0, but no BUG?!\n"); + else + pr_err("Fail: refcount wrapped\n"); +} - pr_info("attempting good atomic decrement\n"); - atomic_dec(&over); - atomic_inc(&over); +void lkdtm_REFCOUNT_ZERO_INC(void) +{ + refcount_t zero = REFCOUNT_INIT(0); - pr_info("attempting bad atomic overflow\n"); - atomic_inc(&over); + pr_info("attempting bad refcount increment from zero\n"); + refcount_inc(&zero); + if (refcount_read(&zero) == 0) + pr_err("Stayed at zero, but no BUG?!\n"); + else + pr_err("Fail: refcount went past zero\n"); +} + +void lkdtm_REFCOUNT_ZERO_ADD(void) +{ + refcount_t zero = REFCOUNT_INIT(0); + + pr_info("attempting bad refcount addition from zero\n"); + refcount_add(2, &zero); + if (refcount_read(&zero) == 0) + pr_err("Stayed at zero, but no BUG?!\n"); + else + pr_err("Fail: refcount went past zero\n"); } void lkdtm_CORRUPT_LIST_ADD(void) diff --git a/drivers/misc/lkdtm_core.c b/drivers/misc/lkdtm_core.c index 7eeb71a75549..16e4cf110930 100644 --- a/drivers/misc/lkdtm_core.c +++ b/drivers/misc/lkdtm_core.c @@ -220,8 +220,12 @@ struct crashtype crashtypes[] = { CRASHTYPE(WRITE_RO), CRASHTYPE(WRITE_RO_AFTER_INIT), CRASHTYPE(WRITE_KERN), - CRASHTYPE(ATOMIC_UNDERFLOW), - CRASHTYPE(ATOMIC_OVERFLOW), + CRASHTYPE(REFCOUNT_SATURATE_INC), + CRASHTYPE(REFCOUNT_SATURATE_ADD), + CRASHTYPE(REFCOUNT_ZERO_DEC), + CRASHTYPE(REFCOUNT_ZERO_INC), + CRASHTYPE(REFCOUNT_ZERO_SUB), + CRASHTYPE(REFCOUNT_ZERO_ADD), CRASHTYPE(USERCOPY_HEAP_SIZE_TO), CRASHTYPE(USERCOPY_HEAP_SIZE_FROM), CRASHTYPE(USERCOPY_HEAP_FLAG_TO), diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 18e05ca7584f..3600c9993a98 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -152,6 +152,9 @@ static void mei_mkhi_fix(struct mei_cl_device *cldev) { int ret; + if (!cldev->bus->hbm_f_os_supported) + return; + ret = mei_cldev_enable(cldev); if (ret) return; diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index 0037153c80a6..2d9c5dd06e42 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c @@ -450,7 +450,7 @@ bool mei_cldev_enabled(struct mei_cl_device *cldev) EXPORT_SYMBOL_GPL(mei_cldev_enabled); /** - * mei_cldev_enable_device - enable me client device + * mei_cldev_enable - enable me client device * create connection with me client * * @cldev: me client device diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 391936c1aa04..b0395601c6ae 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -1541,7 +1541,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, rets = first_chunk ? mei_cl_tx_flow_ctrl_creds(cl) : 1; if (rets < 0) - return rets; + goto err; if (rets == 0) { cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); @@ -1575,11 +1575,8 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cb->buf.size, cb->buf_idx); rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); - if (rets) { - cl->status = rets; - list_move_tail(&cb->list, &cmpl_list->list); - return rets; - } + if (rets) + goto err; cl->status = 0; cl->writing_state = MEI_WRITING; @@ -1587,14 +1584,21 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb, cb->completed = mei_hdr.msg_complete == 1; if (first_chunk) { - if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) - return -EIO; + if (mei_cl_tx_flow_ctrl_creds_reduce(cl)) { + rets = -EIO; + goto err; + } } if (mei_hdr.msg_complete) list_move_tail(&cb->list, &dev->write_waiting_list.list); return 0; + +err: + cl->status = rets; + list_move_tail(&cb->list, &cmpl_list->list); + return rets; } /** diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c index c6c051b52f55..a617aa5a3ad8 100644 --- a/drivers/misc/mei/debugfs.c +++ b/drivers/misc/mei/debugfs.c @@ -67,7 +67,7 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf, me_cl->props.max_number_of_connections, me_cl->props.max_msg_length, me_cl->props.single_recv_buf, - atomic_read(&me_cl->refcnt.refcount)); + kref_read(&me_cl->refcnt)); mei_me_cl_put(me_cl); } @@ -180,6 +180,8 @@ static ssize_t mei_dbgfs_read_devstate(struct file *fp, char __user *ubuf, dev->hbm_f_ev_supported); pos += scnprintf(buf + pos, bufsz - pos, "\tFA: %01d\n", dev->hbm_f_fa_supported); + pos += scnprintf(buf + pos, bufsz - pos, "\tOS: %01d\n", + dev->hbm_f_os_supported); } pos += scnprintf(buf + pos, bufsz - pos, "pg: %s, %s\n", diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index dd7f15a65eed..25b4a1ba522d 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c @@ -989,6 +989,10 @@ static void mei_hbm_config_features(struct mei_device *dev) /* Fixed Address Client Support */ if (dev->version.major_version >= HBM_MAJOR_VERSION_FA) dev->hbm_f_fa_supported = 1; + + /* OS ver message Support */ + if (dev->version.major_version >= HBM_MAJOR_VERSION_OS) + dev->hbm_f_os_supported = 1; } /** diff --git a/drivers/misc/mei/hw.h b/drivers/misc/mei/hw.h index 9daf3f9aed25..e1e4d47d4d7d 100644 --- a/drivers/misc/mei/hw.h +++ b/drivers/misc/mei/hw.h @@ -76,6 +76,12 @@ #define HBM_MINOR_VERSION_FA 0 #define HBM_MAJOR_VERSION_FA 2 +/* + * MEI version with OS ver message support + */ +#define HBM_MINOR_VERSION_OS 0 +#define HBM_MAJOR_VERSION_OS 2 + /* Host bus message command opcode */ #define MEI_HBM_CMD_OP_MSK 0x7f /* Host bus message command RESPONSE */ diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 699693cd8c59..8dadb98662a9 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h @@ -406,6 +406,7 @@ const char *mei_pg_state_str(enum mei_pg_state state); * @hbm_f_ev_supported : hbm feature event notification * @hbm_f_fa_supported : hbm feature fixed address client * @hbm_f_ie_supported : hbm feature immediate reply to enum request + * @hbm_f_os_supported : hbm feature support OS ver message * * @me_clients_rwsem: rw lock over me_clients list * @me_clients : list of FW clients @@ -487,6 +488,7 @@ struct mei_device { unsigned int hbm_f_ev_supported:1; unsigned int hbm_f_fa_supported:1; unsigned int hbm_f_ie_supported:1; + unsigned int hbm_f_os_supported:1; struct rw_semaphore me_clients_rwsem; struct list_head me_clients; diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c index b61b52f9da3d..0fccca075e29 100644 --- a/drivers/mmc/core/mmc.c +++ b/drivers/mmc/core/mmc.c @@ -1706,10 +1706,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, err = mmc_select_hs400(card); if (err) goto free_card; - } else if (mmc_card_hs(card)) { + } else { /* Select the desired bus width optionally */ err = mmc_select_bus_width(card); - if (err > 0) { + if (err > 0 && mmc_card_hs(card)) { err = mmc_select_hs_ddr(card); if (err) goto free_card; diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c index b11c3455b040..e6ea8503f40c 100644 --- a/drivers/mmc/core/mmc_ops.c +++ b/drivers/mmc/core/mmc_ops.c @@ -506,9 +506,6 @@ static int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms, } } while (busy); - if (host->ops->card_busy && send_status) - return mmc_switch_status(card); - return 0; } @@ -577,24 +574,26 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, if (!use_busy_signal) goto out; - /* Switch to new timing before poll and check switch status. */ - if (timing) - mmc_set_timing(host, timing); - /*If SPI or used HW busy detection above, then we don't need to poll. */ if (((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp) || - mmc_host_is_spi(host)) { - if (send_status) - err = mmc_switch_status(card); + mmc_host_is_spi(host)) goto out_tim; - } /* Let's try to poll to find out when the command is completed. */ err = mmc_poll_for_busy(card, timeout_ms, send_status, retry_crc_err); + if (err) + goto out; out_tim: - if (err && timing) - mmc_set_timing(host, old_timing); + /* Switch to new timing before check switch status. */ + if (timing) + mmc_set_timing(host, timing); + + if (send_status) { + err = mmc_switch_status(card); + if (err && timing) + mmc_set_timing(host, old_timing); + } out: mmc_retune_release(host); diff --git a/drivers/mmc/core/queue.c b/drivers/mmc/core/queue.c index a6496d8027bc..033f641eb8b7 100644 --- a/drivers/mmc/core/queue.c +++ b/drivers/mmc/core/queue.c @@ -30,15 +30,6 @@ static int mmc_prep_request(struct request_queue *q, struct request *req) { struct mmc_queue *mq = q->queuedata; - /* - * We only like normal block requests and discards. - */ - if (req->cmd_type != REQ_TYPE_FS && req_op(req) != REQ_OP_DISCARD && - req_op(req) != REQ_OP_SECURE_ERASE) { - blk_dump_rq_flags(req, "MMC bad request"); - return BLKPREP_KILL; - } - if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq))) return BLKPREP_KILL; diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index b44306b886cb..73db08558e4d 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -3354,10 +3354,11 @@ int dw_mci_runtime_resume(struct device *dev) if (!slot) continue; - if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) { + if (slot->mmc->pm_flags & MMC_PM_KEEP_POWER) dw_mci_set_ios(slot->mmc, &slot->mmc->ios); - dw_mci_setup_bus(slot, true); - } + + /* Force setup bus to guarantee available clock output */ + dw_mci_setup_bus(slot, true); } /* Now that slots are all setup, we can enable card detect */ diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index b352760c041e..09739352834c 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -578,13 +578,15 @@ static irqreturn_t meson_mmc_irq(int irq, void *dev_id) { struct meson_host *host = dev_id; struct mmc_request *mrq; - struct mmc_command *cmd = host->cmd; + struct mmc_command *cmd; u32 irq_en, status, raw_status; irqreturn_t ret = IRQ_HANDLED; if (WARN_ON(!host)) return IRQ_NONE; + cmd = host->cmd; + mrq = host->mrq; if (WARN_ON(!mrq)) @@ -670,10 +672,10 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) int ret = IRQ_HANDLED; if (WARN_ON(!mrq)) - ret = IRQ_NONE; + return IRQ_NONE; if (WARN_ON(!cmd)) - ret = IRQ_NONE; + return IRQ_NONE; data = cmd->data; if (data) { diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c index 01a804792f30..b5972440c1bf 100644 --- a/drivers/mmc/host/mmci.c +++ b/drivers/mmc/host/mmci.c @@ -1023,7 +1023,12 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, if (!host->busy_status && busy_resp && !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) && (readl(base + MMCISTATUS) & host->variant->busy_detect_flag)) { - /* Unmask the busy IRQ */ + + /* Clear the busy start IRQ */ + writel(host->variant->busy_detect_mask, + host->base + MMCICLEAR); + + /* Unmask the busy end IRQ */ writel(readl(base + MMCIMASK0) | host->variant->busy_detect_mask, base + MMCIMASK0); @@ -1038,10 +1043,14 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd, /* * At this point we are not busy with a command, we have - * not received a new busy request, mask the busy IRQ and - * fall through to process the IRQ. + * not received a new busy request, clear and mask the busy + * end IRQ and fall through to process the IRQ. */ if (host->busy_status) { + + writel(host->variant->busy_detect_mask, + host->base + MMCICLEAR); + writel(readl(base + MMCIMASK0) & ~host->variant->busy_detect_mask, base + MMCIMASK0); @@ -1283,12 +1292,21 @@ static irqreturn_t mmci_irq(int irq, void *dev_id) } /* - * We intentionally clear the MCI_ST_CARDBUSY IRQ here (if it's - * enabled) since the HW seems to be triggering the IRQ on both - * edges while monitoring DAT0 for busy completion. + * We intentionally clear the MCI_ST_CARDBUSY IRQ (if it's + * enabled) in mmci_cmd_irq() function where ST Micro busy + * detection variant is handled. Considering the HW seems to be + * triggering the IRQ on both edges while monitoring DAT0 for + * busy completion and that same status bit is used to monitor + * start and end of busy detection, special care must be taken + * to make sure that both start and end interrupts are always + * cleared one after the other. */ status &= readl(host->base + MMCIMASK0); - writel(status, host->base + MMCICLEAR); + if (host->variant->busy_detect) + writel(status & ~host->variant->busy_detect_mask, + host->base + MMCICLEAR); + else + writel(status, host->base + MMCICLEAR); dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status); diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c index 44ecebd1ea8c..c8b8ac66ff7e 100644 --- a/drivers/mmc/host/mxs-mmc.c +++ b/drivers/mmc/host/mxs-mmc.c @@ -309,6 +309,9 @@ static void mxs_mmc_ac(struct mxs_mmc_host *host) cmd0 = BF_SSP(cmd->opcode, CMD0_CMD); cmd1 = cmd->arg; + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmd0 |= BM_SSP_CMD0_APPEND_8CYC; + if (host->sdio_irq_en) { ctrl0 |= BM_SSP_CTRL0_SDIO_IRQ_CHECK; cmd0 |= BM_SSP_CMD0_CONT_CLKING_EN | BM_SSP_CMD0_SLOW_CLKING_EN; @@ -417,8 +420,7 @@ static void mxs_mmc_adtc(struct mxs_mmc_host *host) ssp->base + HW_SSP_BLOCK_SIZE); } - if ((cmd->opcode == MMC_STOP_TRANSMISSION) || - (cmd->opcode == SD_IO_RW_EXTENDED)) + if (cmd->opcode == SD_IO_RW_EXTENDED) cmd0 |= BM_SSP_CMD0_APPEND_8CYC; cmd1 = cmd->arg; diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c index 160f695cc09c..278a5a435ab7 100644 --- a/drivers/mmc/host/sdhci-acpi.c +++ b/drivers/mmc/host/sdhci-acpi.c @@ -395,7 +395,8 @@ static int sdhci_acpi_probe(struct platform_device *pdev) /* Power on the SDHCI controller and its children */ acpi_device_fix_up_power(device); list_for_each_entry(child, &device->children, node) - acpi_device_fix_up_power(child); + if (child->status.present && child->status.enabled) + acpi_device_fix_up_power(child); if (acpi_bus_get_status(device) || !device->status.present) return -ENODEV; diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 23909804ffb8..0def99590d16 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2733,7 +2733,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (intmask & SDHCI_INT_RETUNE) mmc_retune_needed(host->mmc); - if (intmask & SDHCI_INT_CARD_INT) { + if ((intmask & SDHCI_INT_CARD_INT) && + (host->ier & SDHCI_INT_CARD_INT)) { sdhci_enable_sdio_irq_nolock(host, false); host->thread_isr |= SDHCI_INT_CARD_INT; result = IRQ_WAKE_THREAD; diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 283ff7e17a0f..d10fa6c8f074 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -9,6 +9,7 @@ * */ +#include <linux/bcm47xx_nvram.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> @@ -83,6 +84,91 @@ out_default: return "rootfs"; } +static int bcm47xxpart_parse_trx(struct mtd_info *master, + struct mtd_partition *trx, + struct mtd_partition *parts, + size_t parts_len) +{ + struct trx_header header; + size_t bytes_read; + int curr_part = 0; + int i, err; + + if (parts_len < 3) { + pr_warn("No enough space to add TRX partitions!\n"); + return -ENOMEM; + } + + err = mtd_read(master, trx->offset, sizeof(header), &bytes_read, + (uint8_t *)&header); + if (err && !mtd_is_bitflip(err)) { + pr_err("mtd_read error while reading TRX header: %d\n", err); + return err; + } + + i = 0; + + /* We have LZMA loader if offset[2] points to sth */ + if (header.offset[2]) { + bcm47xxpart_add_part(&parts[curr_part++], "loader", + trx->offset + header.offset[i], 0); + i++; + } + + if (header.offset[i]) { + bcm47xxpart_add_part(&parts[curr_part++], "linux", + trx->offset + header.offset[i], 0); + i++; + } + + if (header.offset[i]) { + size_t offset = trx->offset + header.offset[i]; + const char *name = bcm47xxpart_trx_data_part_name(master, + offset); + + bcm47xxpart_add_part(&parts[curr_part++], name, offset, 0); + i++; + } + + /* + * Assume that every partition ends at the beginning of the one it is + * followed by. + */ + for (i = 0; i < curr_part; i++) { + u64 next_part_offset = (i < curr_part - 1) ? + parts[i + 1].offset : + trx->offset + trx->size; + + parts[i].size = next_part_offset - parts[i].offset; + } + + return curr_part; +} + +/** + * bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader + * + * Some devices may have more than one TRX partition. In such case one of them + * is the main one and another a failsafe one. Bootloader may fallback to the + * failsafe firmware if it detects corruption of the main image. + * + * This function provides info about currently used TRX partition. It's the one + * containing kernel started by the bootloader. + */ +static int bcm47xxpart_bootpartition(void) +{ + char buf[4]; + int bootpartition; + + /* Check CFE environment variable */ + if (bcm47xx_nvram_getenv("bootpartition", buf, sizeof(buf)) > 0) { + if (!kstrtoint(buf, 0, &bootpartition)) + return bootpartition; + } + + return 0; +} + static int bcm47xxpart_parse(struct mtd_info *master, const struct mtd_partition **pparts, struct mtd_part_parser_data *data) @@ -93,9 +179,8 @@ static int bcm47xxpart_parse(struct mtd_info *master, size_t bytes_read; uint32_t offset; uint32_t blocksize = master->erasesize; - struct trx_header *trx; - int trx_part = -1; - int last_trx_part = -1; + int trx_parts[2]; /* Array with indexes of TRX partitions */ + int trx_num = 0; /* Number of found TRX partitions */ int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, }; int err; @@ -182,54 +267,18 @@ static int bcm47xxpart_parse(struct mtd_info *master, /* TRX */ if (buf[0x000 / 4] == TRX_MAGIC) { - if (BCM47XXPART_MAX_PARTS - curr_part < 4) { - pr_warn("Not enough partitions left to register trx, scanning stopped!\n"); - break; - } - - trx = (struct trx_header *)buf; + struct trx_header *trx; - trx_part = curr_part; + if (trx_num >= ARRAY_SIZE(trx_parts)) + pr_warn("No enough space to store another TRX found at 0x%X\n", + offset); + else + trx_parts[trx_num++] = curr_part; bcm47xxpart_add_part(&parts[curr_part++], "firmware", offset, 0); - i = 0; - /* We have LZMA loader if offset[2] points to sth */ - if (trx->offset[2]) { - bcm47xxpart_add_part(&parts[curr_part++], - "loader", - offset + trx->offset[i], - 0); - i++; - } - - if (trx->offset[i]) { - bcm47xxpart_add_part(&parts[curr_part++], - "linux", - offset + trx->offset[i], - 0); - i++; - } - - /* - * Pure rootfs size is known and can be calculated as: - * trx->length - trx->offset[i]. We don't fill it as - * we want to have jffs2 (overlay) in the same mtd. - */ - if (trx->offset[i]) { - const char *name; - - name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]); - bcm47xxpart_add_part(&parts[curr_part++], - name, - offset + trx->offset[i], - 0); - i++; - } - - last_trx_part = curr_part - 1; - /* Jump to the end of TRX */ + trx = (struct trx_header *)buf; offset = roundup(offset + trx->length, blocksize); /* Next loop iteration will increase the offset */ offset -= blocksize; @@ -307,9 +356,23 @@ static int bcm47xxpart_parse(struct mtd_info *master, parts[i + 1].offset : master->size; parts[i].size = next_part_offset - parts[i].offset; - if (i == last_trx_part && trx_part >= 0) - parts[trx_part].size = next_part_offset - - parts[trx_part].offset; + } + + /* If there was TRX parse it now */ + for (i = 0; i < trx_num; i++) { + struct mtd_partition *trx = &parts[trx_parts[i]]; + + if (i == bcm47xxpart_bootpartition()) { + int num_parts; + + num_parts = bcm47xxpart_parse_trx(master, trx, + parts + curr_part, + BCM47XXPART_MAX_PARTS - curr_part); + if (num_parts > 0) + curr_part += num_parts; + } else { + trx->name = "failsafe"; + } } *pparts = parts; diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 514be04c0b6c..e2bd81817df4 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -105,15 +105,33 @@ static int bcm47xxsflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct bcm47xxsflash *b47s = mtd->priv; + size_t orig_len = len; /* Check address range */ if ((from + len) > mtd->size) return -EINVAL; - memcpy_fromio(buf, b47s->window + from, len); - *retlen = len; + /* Read as much as possible using fast MMIO window */ + if (from < BCM47XXSFLASH_WINDOW_SZ) { + size_t memcpy_len; - return len; + memcpy_len = min(len, (size_t)(BCM47XXSFLASH_WINDOW_SZ - from)); + memcpy_fromio(buf, b47s->window + from, memcpy_len); + from += memcpy_len; + len -= memcpy_len; + buf += memcpy_len; + } + + /* Use indirect access for content out of the window */ + for (; len; len--) { + b47s->cc_write(b47s, BCMA_CC_FLASHADDR, from++); + bcm47xxsflash_cmd(b47s, OPCODE_ST_READ4B); + *buf++ = b47s->cc_read(b47s, BCMA_CC_FLASHDATA); + } + + *retlen = orig_len; + + return orig_len; } static int bcm47xxsflash_write_st(struct mtd_info *mtd, u32 offset, size_t len, @@ -284,7 +302,6 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) b47s = devm_kzalloc(dev, sizeof(*b47s), GFP_KERNEL); if (!b47s) return -ENOMEM; - sflash->priv = b47s; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -334,6 +351,8 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) b47s->size = sflash->size; bcm47xxsflash_fill_mtd(b47s, &pdev->dev); + platform_set_drvdata(pdev, b47s); + err = mtd_device_parse_register(&b47s->mtd, probes, NULL, NULL, 0); if (err) { pr_err("Failed to register MTD device: %d\n", err); @@ -349,8 +368,7 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) static int bcm47xxsflash_bcma_remove(struct platform_device *pdev) { - struct bcma_sflash *sflash = dev_get_platdata(&pdev->dev); - struct bcm47xxsflash *b47s = sflash->priv; + struct bcm47xxsflash *b47s = platform_get_drvdata(pdev); mtd_device_unregister(&b47s->mtd); iounmap(b47s->window); diff --git a/drivers/mtd/devices/bcm47xxsflash.h b/drivers/mtd/devices/bcm47xxsflash.h index 1564b62b412e..b2d7b38f75fd 100644 --- a/drivers/mtd/devices/bcm47xxsflash.h +++ b/drivers/mtd/devices/bcm47xxsflash.h @@ -3,6 +3,8 @@ #include <linux/mtd/mtd.h> +#define BCM47XXSFLASH_WINDOW_SZ SZ_16M + /* Used for ST flashes only. */ #define OPCODE_ST_WREN 0x0006 /* Write Enable */ #define OPCODE_ST_WRDIS 0x0004 /* Write Disable */ @@ -16,6 +18,7 @@ #define OPCODE_ST_RES 0x03ab /* Read Electronic Signature */ #define OPCODE_ST_CSA 0x1000 /* Keep chip select asserted */ #define OPCODE_ST_SSE 0x0220 /* Sub-sector Erase */ +#define OPCODE_ST_READ4B 0x6313 /* Read Data Bytes in 4Byte addressing mode */ /* Used for Atmel flashes only. */ #define OPCODE_AT_READ 0x07e8 diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 9cf7fcd28034..c4df3b1bded0 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -172,7 +172,8 @@ static ssize_t m25p80_read(struct spi_nor *nor, loff_t from, size_t len, t[1].rx_buf = buf; t[1].rx_nbits = m25p80_rx_nbits(nor); - t[1].len = min(len, spi_max_transfer_size(spi)); + t[1].len = min3(len, spi_max_transfer_size(spi), + spi_max_message_size(spi) - t[0].len); spi_message_add_tail(&t[1], &m); ret = spi_sync(spi, &m); @@ -288,7 +289,6 @@ static const struct spi_device_id m25p_ids[] = { * should be kept for backward compatibility. */ {"at25df321a"}, {"at25df641"}, {"at26df081a"}, - {"mr25h256"}, {"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"}, {"mx25l25635e"},{"mx66l51235l"}, {"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"}, @@ -305,6 +305,11 @@ static const struct spi_device_id m25p_ids[] = { {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, + /* Everspin MRAMs (non-JEDEC) */ + { "mr25h256" }, /* 256 Kib, 40 MHz */ + { "mr25h10" }, /* 1 Mib, 40 MHz */ + { "mr25h40" }, /* 4 Mib, 40 MHz */ + { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h index f59a125295d0..8b81e15105dd 100644 --- a/drivers/mtd/devices/serial_flash_cmds.h +++ b/drivers/mtd/devices/serial_flash_cmds.h @@ -18,19 +18,12 @@ #define SPINOR_OP_RDVCR 0x85 /* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */ -#define SPINOR_OP_READ_1_2_2 0xbb /* DUAL I/O READ */ -#define SPINOR_OP_READ_1_4_4 0xeb /* QUAD I/O READ */ - #define SPINOR_OP_WRITE 0x02 /* PAGE PROGRAM */ #define SPINOR_OP_WRITE_1_1_2 0xa2 /* DUAL INPUT PROGRAM */ #define SPINOR_OP_WRITE_1_2_2 0xd2 /* DUAL INPUT EXT PROGRAM */ #define SPINOR_OP_WRITE_1_1_4 0x32 /* QUAD INPUT PROGRAM */ #define SPINOR_OP_WRITE_1_4_4 0x12 /* QUAD INPUT EXT PROGRAM */ -/* READ commands with 32-bit addressing */ -#define SPINOR_OP_READ4_1_2_2 0xbc -#define SPINOR_OP_READ4_1_4_4 0xec - /* Configuration flags */ #define FLASH_FLAG_SINGLE 0x000000ff #define FLASH_FLAG_READ_WRITE 0x00000001 diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c index 5454b4113589..804313a33f2b 100644 --- a/drivers/mtd/devices/st_spi_fsm.c +++ b/drivers/mtd/devices/st_spi_fsm.c @@ -507,13 +507,13 @@ static struct seq_rw_config n25q_read3_configs[] = { * - 'FAST' variants configured for 8 dummy cycles (see note above.) */ static struct seq_rw_config n25q_read4_configs[] = { - {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, - {0x00, 0, 0, 0, 0, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, + {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; /* @@ -553,13 +553,13 @@ static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq) * entering a state that is incompatible with the SPIBoot Controller. */ static struct seq_rw_config stfsm_s25fl_read4_configs[] = { - {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ4_1_4_4, 0, 4, 4, 0x00, 2, 4}, - {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ4_1_1_4, 0, 1, 4, 0x00, 0, 8}, - {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ4_1_2_2, 0, 2, 2, 0x00, 4, 0}, - {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ4_1_1_2, 0, 1, 2, 0x00, 0, 8}, - {FLASH_FLAG_READ_FAST, SPINOR_OP_READ4_FAST, 0, 1, 1, 0x00, 0, 8}, - {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ4, 0, 1, 1, 0x00, 0, 0}, - {0x00, 0, 0, 0, 0, 0x00, 0, 0}, + {FLASH_FLAG_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B, 0, 4, 4, 0x00, 2, 4}, + {FLASH_FLAG_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B, 0, 1, 4, 0x00, 0, 8}, + {FLASH_FLAG_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B, 0, 2, 2, 0x00, 4, 0}, + {FLASH_FLAG_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B, 0, 1, 2, 0x00, 0, 8}, + {FLASH_FLAG_READ_FAST, SPINOR_OP_READ_FAST_4B, 0, 1, 1, 0x00, 0, 8}, + {FLASH_FLAG_READ_WRITE, SPINOR_OP_READ_4B, 0, 1, 1, 0x00, 0, 0}, + {0x00, 0, 0, 0, 0, 0x00, 0, 0}, }; static struct seq_rw_config stfsm_s25fl_write4_configs[] = { diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 5bcc896a48c3..542fdf8e81fa 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -75,7 +75,7 @@ config MTD_PHYSMAP_OF taken from OF device tree. config MTD_PHYSMAP_OF_VERSATILE - bool "Support ARM Versatile physmap OF" + bool "ARM Versatile OF-based physical memory map handling" depends on MTD_PHYSMAP_OF depends on MFD_SYSCON default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW) @@ -84,6 +84,16 @@ config MTD_PHYSMAP_OF_VERSATILE platforms, basically to add a VPP (write protection) callback so the flash can be taken out of write protection. +config MTD_PHYSMAP_OF_GEMINI + bool "Cortina Gemini OF-based physical memory map handling" + depends on MTD_PHYSMAP_OF + depends on MFD_SYSCON + default ARCH_GEMINI + help + This provides some extra DT physmap parsing for the Gemini + platforms, some detection and setting up parallel mode on the + external interface. + config MTD_PMC_MSP_EVM tristate "CFI Flash device mapped on PMC-Sierra MSP" depends on PMC_MSP && MTD_CFI diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 644f7d36d35d..aef1846b4de2 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -17,10 +17,13 @@ obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o obj-$(CONFIG_MTD_PXA2XX) += pxa2xx-flash.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o -obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o ifdef CONFIG_MTD_PHYSMAP_OF_VERSATILE -obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of_versatile.o +physmap_of-objs += physmap_of_versatile.o +endif +ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI +physmap_of-objs += physmap_of_gemini.o endif +obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o obj-$(CONFIG_MTD_PISMO) += pismo.o obj-$(CONFIG_MTD_PMC_MSP_EVM) += pmcmsp-flash.o obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c index e17d02ae03f0..976d42f63aef 100644 --- a/drivers/mtd/maps/ichxrom.c +++ b/drivers/mtd/maps/ichxrom.c @@ -57,10 +57,12 @@ static void ichxrom_cleanup(struct ichxrom_window *window) { struct ichxrom_map_info *map, *scratch; u16 word; + int ret; /* Disable writes through the rom window */ - pci_read_config_word(window->pdev, BIOS_CNTL, &word); - pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1); + ret = pci_read_config_word(window->pdev, BIOS_CNTL, &word); + if (!ret) + pci_write_config_word(window->pdev, BIOS_CNTL, word & ~1); pci_dev_put(window->pdev); /* Free all of the mtd devices */ diff --git a/drivers/mtd/maps/lantiq-flash.c b/drivers/mtd/maps/lantiq-flash.c index c8febb326fa6..3e33ab66eb24 100644 --- a/drivers/mtd/maps/lantiq-flash.c +++ b/drivers/mtd/maps/lantiq-flash.c @@ -4,7 +4,7 @@ * by the Free Software Foundation. * * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE - * Copyright (C) 2010 John Crispin <blogic@openwrt.org> + * Copyright (C) 2010 John Crispin <john@phrozen.org> */ #include <linux/err.h> @@ -209,5 +209,5 @@ static struct platform_driver ltq_mtd_driver = { module_platform_driver(ltq_mtd_driver); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("John Crispin <blogic@openwrt.org>"); +MODULE_AUTHOR("John Crispin <john@phrozen.org>"); MODULE_DESCRIPTION("Lantiq SoC NOR"); diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c index 3fad35942895..14e8909c9955 100644 --- a/drivers/mtd/maps/physmap_of.c +++ b/drivers/mtd/maps/physmap_of.c @@ -24,6 +24,7 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/slab.h> +#include "physmap_of_gemini.h" #include "physmap_of_versatile.h" struct of_flash_list { @@ -241,11 +242,13 @@ static int of_flash_probe(struct platform_device *dev) info->list[i].map.size = res_size; info->list[i].map.bankwidth = be32_to_cpup(width); info->list[i].map.device_node = dp; + + err = of_flash_probe_gemini(dev, dp, &info->list[i].map); + if (err) + return err; err = of_flash_probe_versatile(dev, dp, &info->list[i].map); - if (err) { - dev_err(&dev->dev, "Can't probe Versatile VPP\n"); + if (err) return err; - } err = -ENOMEM; info->list[i].map.virt = ioremap(info->list[i].map.phys, diff --git a/drivers/mtd/maps/physmap_of_gemini.c b/drivers/mtd/maps/physmap_of_gemini.c new file mode 100644 index 000000000000..9d371cd728ea --- /dev/null +++ b/drivers/mtd/maps/physmap_of_gemini.c @@ -0,0 +1,117 @@ +/* + * Cortina Systems Gemini OF physmap add-on + * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org> + * + * This SoC has an elaborate flash control register, so we need to + * detect and set it up when booting on this platform. + */ +#include <linux/export.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/mtd/map.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/bitops.h> +#include "physmap_of_gemini.h" + +/* + * The Flash-relevant parts of the global status register + * These would also be relevant for a NAND driver. + */ +#define GLOBAL_STATUS 0x04 +#define FLASH_TYPE_MASK (0x3 << 24) +#define FLASH_TYPE_NAND_2K (0x3 << 24) +#define FLASH_TYPE_NAND_512 (0x2 << 24) +#define FLASH_TYPE_PARALLEL (0x1 << 24) +#define FLASH_TYPE_SERIAL (0x0 << 24) +/* if parallel */ +#define FLASH_WIDTH_16BIT (1 << 23) /* else 8 bit */ +/* if serial */ +#define FLASH_ATMEL (1 << 23) /* else STM */ + +#define FLASH_SIZE_MASK (0x3 << 21) +#define NAND_256M (0x3 << 21) /* and more */ +#define NAND_128M (0x2 << 21) +#define NAND_64M (0x1 << 21) +#define NAND_32M (0x0 << 21) +#define ATMEL_16M (0x3 << 21) /* and more */ +#define ATMEL_8M (0x2 << 21) +#define ATMEL_4M_2M (0x1 << 21) +#define ATMEL_1M (0x0 << 21) /* and less */ +#define STM_32M (1 << 22) /* and more */ +#define STM_16M (0 << 22) /* and less */ + +#define FLASH_PARALLEL_HIGH_PIN_CNT (1 << 20) /* else low pin cnt */ + +/* Miscellaneous Control Register */ +#define GLOBAL_MISC_CTRL 0x30 +#define FLASH_PADS_MASK 0x07 +#define NAND_PADS_DISABLE BIT(2) +#define PFLASH_PADS_DISABLE BIT(1) +#define SFLASH_PADS_DISABLE BIT(0) + +static const struct of_device_id syscon_match[] = { + { .compatible = "cortina,gemini-syscon" }, + { }, +}; + +int of_flash_probe_gemini(struct platform_device *pdev, + struct device_node *np, + struct map_info *map) +{ + static struct regmap *rmap; + struct device *dev = &pdev->dev; + u32 val; + int ret; + + /* Multiplatform guard */ + if (!of_device_is_compatible(np, "cortina,gemini-flash")) + return 0; + + rmap = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(rmap)) { + dev_err(dev, "no syscon\n"); + return PTR_ERR(rmap); + } + + ret = regmap_read(rmap, GLOBAL_STATUS, &val); + if (ret) { + dev_err(dev, "failed to read global status register\n"); + return -ENODEV; + } + dev_dbg(dev, "global status reg: %08x\n", val); + + /* + * It would be contradictory if a physmap flash was NOT parallel. + */ + if ((val & FLASH_TYPE_MASK) != FLASH_TYPE_PARALLEL) { + dev_err(dev, "flash is not parallel\n"); + return -ENODEV; + } + + /* + * Complain if DT data and hardware definition is different. + */ + if (val & FLASH_WIDTH_16BIT) { + if (map->bankwidth != 2) + dev_warn(dev, "flash hardware say flash is 16 bit wide but DT says it is %d bits wide\n", + map->bankwidth * 8); + } else { + if (map->bankwidth != 1) + dev_warn(dev, "flash hardware say flash is 8 bit wide but DT says it is %d bits wide\n", + map->bankwidth * 8); + } + + /* Activate parallel (NOR flash) mode */ + ret = regmap_update_bits(rmap, GLOBAL_MISC_CTRL, + FLASH_PADS_MASK, + SFLASH_PADS_DISABLE | NAND_PADS_DISABLE); + if (ret) { + dev_err(dev, "unable to set up physmap pads\n"); + return -ENODEV; + } + + dev_info(&pdev->dev, "initialized Gemini-specific physmap control\n"); + + return 0; +} diff --git a/drivers/mtd/maps/physmap_of_gemini.h b/drivers/mtd/maps/physmap_of_gemini.h new file mode 100644 index 000000000000..c675025288dd --- /dev/null +++ b/drivers/mtd/maps/physmap_of_gemini.h @@ -0,0 +1,16 @@ +#include <linux/of.h> +#include <linux/mtd/map.h> + +#ifdef CONFIG_MTD_PHYSMAP_OF_GEMINI +int of_flash_probe_gemini(struct platform_device *pdev, + struct device_node *np, + struct map_info *map); +#else +static inline +int of_flash_probe_gemini(struct platform_device *pdev, + struct device_node *np, + struct map_info *map) +{ + return 0; +} +#endif diff --git a/drivers/mtd/maps/physmap_of_versatile.c b/drivers/mtd/maps/physmap_of_versatile.c index 0f39b2a015f4..8c6ccded9be8 100644 --- a/drivers/mtd/maps/physmap_of_versatile.c +++ b/drivers/mtd/maps/physmap_of_versatile.c @@ -252,4 +252,3 @@ int of_flash_probe_versatile(struct platform_device *pdev, return 0; } -EXPORT_SYMBOL_GPL(of_flash_probe_versatile); diff --git a/drivers/mtd/maps/pmcmsp-flash.c b/drivers/mtd/maps/pmcmsp-flash.c index f9fa3fad728e..2051f28ddac6 100644 --- a/drivers/mtd/maps/pmcmsp-flash.c +++ b/drivers/mtd/maps/pmcmsp-flash.c @@ -139,15 +139,13 @@ static int __init init_msp_flash(void) } msp_maps[i].bankwidth = 1; - msp_maps[i].name = kmalloc(7, GFP_KERNEL); + msp_maps[i].name = kstrndup(flash_name, 7, GFP_KERNEL); if (!msp_maps[i].name) { iounmap(msp_maps[i].virt); kfree(msp_parts[i]); goto cleanup_loop; } - msp_maps[i].name = strncpy(msp_maps[i].name, flash_name, 7); - for (j = 0; j < pcnt; j++) { part_name[5] = '0' + i; part_name[7] = '0' + j; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index df8a5ef334c0..6b8d5cd7dbf6 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -84,9 +84,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, nsect = blk_rq_cur_bytes(req) >> tr->blkshift; buf = bio_data(req->bio); - if (req->cmd_type != REQ_TYPE_FS) - return -EIO; - if (req_op(req) == REQ_OP_FLUSH) return tr->flush(dev); @@ -94,16 +91,16 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, get_capacity(req->rq_disk)) return -EIO; - if (req_op(req) == REQ_OP_DISCARD) + switch (req_op(req)) { + case REQ_OP_DISCARD: return tr->discard(dev, block, nsect); - - if (rq_data_dir(req) == READ) { + case REQ_OP_READ: for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->readsect(dev, block, buf)) return -EIO; rq_flush_dcache_pages(req); return 0; - } else { + case REQ_OP_WRITE: if (!tr->writesect) return -EIO; @@ -112,6 +109,8 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (tr->writesect(dev, block, buf)) return -EIO; return 0; + default: + return -EIO; } } diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index ce5ccc573a9c..3568294d4854 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -451,7 +451,7 @@ static int mtdchar_readoob(struct file *file, struct mtd_info *mtd, * 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 + * to signal the caller that a bitflip has occurred and has * been corrected by the ECC algorithm. * * Note: currently the standard NAND function, nand_read_oob_std, diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 052772f7caef..66a9dedd1062 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1128,7 +1128,7 @@ EXPORT_SYMBOL_GPL(mtd_write_oob); * @oobecc: OOB region struct filled with the appropriate ECC position * information * - * This functions return ECC section information in the OOB area. I you want + * This function returns ECC section information in the OOB area. If you want * to get all the ECC bytes information, then you should call * mtd_ooblayout_ecc(mtd, section++, oobecc) until it returns -ERANGE. * @@ -1160,7 +1160,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc); * @oobfree: OOB region struct filled with the appropriate free position * information * - * This functions return free bytes position in the OOB area. I you want + * This function returns free bytes position in the OOB area. If you want * to get all the free bytes information, then you should call * mtd_ooblayout_free(mtd, section++, oobfree) until it returns -ERANGE. * @@ -1190,7 +1190,7 @@ EXPORT_SYMBOL_GPL(mtd_ooblayout_free); * @iter: iterator function. Should be either mtd_ooblayout_free or * mtd_ooblayout_ecc depending on the region type you're searching for * - * This functions returns the section id and oobregion information of a + * This function returns the section id and oobregion information of a * specific byte. For example, say you want to know where the 4th ECC byte is * stored, you'll use: * diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index fccdd49bb964..ea5e5307f667 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -349,6 +349,14 @@ static const struct mtd_ooblayout_ops part_ooblayout_ops = { .free = part_ooblayout_free, }; +static int part_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct mtd_part *part = mtd_to_part(mtd); + + return part->master->_max_bad_blocks(part->master, + ofs + part->offset, len); +} + static inline void free_partition(struct mtd_part *p) { kfree(p->mtd.name); @@ -424,6 +432,7 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? &master->dev : master->dev.parent; + slave->mtd.dev.of_node = part->of_node; slave->mtd._read = part_read; slave->mtd._write = part_write; @@ -475,6 +484,8 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd._block_isbad = part_block_isbad; if (master->_block_markbad) slave->mtd._block_markbad = part_block_markbad; + if (master->_max_bad_blocks) + slave->mtd._max_bad_blocks = part_max_bad_blocks; if (master->_get_device) slave->mtd._get_device = part_get_device; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 353a9ddf6b97..6d4d5672d1d8 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -426,6 +426,8 @@ config MTD_NAND_ORION config MTD_NAND_OXNAS tristate "NAND Flash support for Oxford Semiconductor SoC" + depends on ARCH_OXNAS || COMPILE_TEST + depends on HAS_IOMEM help This enables the NAND flash controller on Oxford Semiconductor SoCs. @@ -534,13 +536,14 @@ config MTD_NAND_JZ4780 config MTD_NAND_FSMC tristate "Support for NAND on ST Micros FSMC" + depends on OF depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 help Enables support for NAND Flash chips on the ST Microelectronics Flexible Static Memory Controller (FSMC) config MTD_NAND_XWAY - tristate "Support for NAND on Lantiq XWAY SoC" + bool "Support for NAND on Lantiq XWAY SoC" depends on LANTIQ && SOC_TYPE_XWAY help Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 0a177b1bfe3e..d1570f512f0b 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -258,9 +258,15 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) int bufnum = nctrl->page & priv->bufnum_mask; int sector = bufnum * chip->ecc.steps; int sector_end = sector + chip->ecc.steps - 1; + __be32 *eccstat_regs; + + if (ctrl->version >= FSL_IFC_VERSION_2_0_0) + eccstat_regs = ifc->ifc_nand.v2_nand_eccstat; + else + eccstat_regs = ifc->ifc_nand.v1_nand_eccstat; for (i = sector / 4; i <= sector_end / 4; i++) - eccstat[i] = ifc_in32(&ifc->ifc_nand.nand_eccstat[i]); + eccstat[i] = ifc_in32(&eccstat_regs[i]); for (i = sector; i <= sector_end; i++) { errors = check_read_ecc(mtd, ctrl, eccstat, i); diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 4924b43977ef..bda1e4667138 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -35,10 +35,133 @@ #include <linux/mtd/partitions.h> #include <linux/io.h> #include <linux/slab.h> -#include <linux/mtd/fsmc.h> #include <linux/amba/bus.h> #include <mtd/mtd-abi.h> +#define FSMC_NAND_BW8 1 +#define FSMC_NAND_BW16 2 + +#define FSMC_MAX_NOR_BANKS 4 +#define FSMC_MAX_NAND_BANKS 4 + +#define FSMC_FLASH_WIDTH8 1 +#define FSMC_FLASH_WIDTH16 2 + +/* fsmc controller registers for NOR flash */ +#define CTRL 0x0 + /* ctrl register definitions */ + #define BANK_ENABLE (1 << 0) + #define MUXED (1 << 1) + #define NOR_DEV (2 << 2) + #define WIDTH_8 (0 << 4) + #define WIDTH_16 (1 << 4) + #define RSTPWRDWN (1 << 6) + #define WPROT (1 << 7) + #define WRT_ENABLE (1 << 12) + #define WAIT_ENB (1 << 13) + +#define CTRL_TIM 0x4 + /* ctrl_tim register definitions */ + +#define FSMC_NOR_BANK_SZ 0x8 +#define FSMC_NOR_REG_SIZE 0x40 + +#define FSMC_NOR_REG(base, bank, reg) (base + \ + FSMC_NOR_BANK_SZ * (bank) + \ + reg) + +/* fsmc controller registers for NAND flash */ +#define PC 0x00 + /* pc register definitions */ + #define FSMC_RESET (1 << 0) + #define FSMC_WAITON (1 << 1) + #define FSMC_ENABLE (1 << 2) + #define FSMC_DEVTYPE_NAND (1 << 3) + #define FSMC_DEVWID_8 (0 << 4) + #define FSMC_DEVWID_16 (1 << 4) + #define FSMC_ECCEN (1 << 6) + #define FSMC_ECCPLEN_512 (0 << 7) + #define FSMC_ECCPLEN_256 (1 << 7) + #define FSMC_TCLR_1 (1) + #define FSMC_TCLR_SHIFT (9) + #define FSMC_TCLR_MASK (0xF) + #define FSMC_TAR_1 (1) + #define FSMC_TAR_SHIFT (13) + #define FSMC_TAR_MASK (0xF) +#define STS 0x04 + /* sts register definitions */ + #define FSMC_CODE_RDY (1 << 15) +#define COMM 0x08 + /* comm register definitions */ + #define FSMC_TSET_0 0 + #define FSMC_TSET_SHIFT 0 + #define FSMC_TSET_MASK 0xFF + #define FSMC_TWAIT_6 6 + #define FSMC_TWAIT_SHIFT 8 + #define FSMC_TWAIT_MASK 0xFF + #define FSMC_THOLD_4 4 + #define FSMC_THOLD_SHIFT 16 + #define FSMC_THOLD_MASK 0xFF + #define FSMC_THIZ_1 1 + #define FSMC_THIZ_SHIFT 24 + #define FSMC_THIZ_MASK 0xFF +#define ATTRIB 0x0C +#define IOATA 0x10 +#define ECC1 0x14 +#define ECC2 0x18 +#define ECC3 0x1C +#define FSMC_NAND_BANK_SZ 0x20 + +#define FSMC_NAND_REG(base, bank, reg) (base + FSMC_NOR_REG_SIZE + \ + (FSMC_NAND_BANK_SZ * (bank)) + \ + reg) + +#define FSMC_BUSY_WAIT_TIMEOUT (1 * HZ) + +struct fsmc_nand_timings { + uint8_t tclr; + uint8_t tar; + uint8_t thiz; + uint8_t thold; + uint8_t twait; + uint8_t tset; +}; + +enum access_mode { + USE_DMA_ACCESS = 1, + USE_WORD_ACCESS, +}; + +/** + * fsmc_nand_platform_data - platform specific NAND controller config + * @nand_timings: timing setup for the physical NAND interface + * @partitions: partition table for the platform, use a default fallback + * if this is NULL + * @nr_partitions: the number of partitions in the previous entry + * @options: different options for the driver + * @width: bus width + * @bank: default bank + * @select_bank: callback to select a certain bank, this is + * platform-specific. If the controller only supports one bank + * this may be set to NULL + */ +struct fsmc_nand_platform_data { + struct fsmc_nand_timings *nand_timings; + struct mtd_partition *partitions; + unsigned int nr_partitions; + unsigned int options; + unsigned int width; + unsigned int bank; + + enum access_mode mode; + + void (*select_bank)(uint32_t bank, uint32_t busw); + + /* priv structures for dma accesses */ + void *read_dma_priv; + void *write_dma_priv; +}; + static int fsmc_ecc1_ooblayout_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { @@ -714,7 +837,6 @@ static bool filter(struct dma_chan *chan, void *slave) return true; } -#ifdef CONFIG_OF static int fsmc_nand_probe_config_dt(struct platform_device *pdev, struct device_node *np) { @@ -757,13 +879,6 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, } return 0; } -#else -static int fsmc_nand_probe_config_dt(struct platform_device *pdev, - struct device_node *np) -{ - return -ENOSYS; -} -#endif /* * fsmc_nand_probe - Probe function @@ -782,19 +897,15 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) u32 pid; int i; - if (np) { - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - pdev->dev.platform_data = pdata; - ret = fsmc_nand_probe_config_dt(pdev, np); - if (ret) { - dev_err(&pdev->dev, "no platform data\n"); - return -ENODEV; - } - } + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; - if (!pdata) { - dev_err(&pdev->dev, "platform data is NULL\n"); - return -EINVAL; + pdev->dev.platform_data = pdata; + ret = fsmc_nand_probe_config_dt(pdev, np); + if (ret) { + dev_err(&pdev->dev, "no platform data\n"); + return -ENODEV; } /* Allocate memory for the device structure (and zero it) */ diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 5553a5d9efd1..846a66c1b133 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -775,7 +775,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) init_completion(&host->comp_controller); host->irq = platform_get_irq(pdev, 0); - if ((host->irq < 0) || (host->irq >= NR_IRQS)) { + if (host->irq < 0) { dev_err(&pdev->dev, "failed to get platform irq\n"); res = -EINVAL; goto err_exit3; diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 53bafe23ab39..a0669a33f8fe 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -797,22 +797,17 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) struct resource *rc; int res; - rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (rc == NULL) { - dev_err(&pdev->dev, "No memory resource found for device\n"); - return -EBUSY; - } - /* Allocate memory for the device structure (and zero it) */ host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) return -ENOMEM; - host->io_base_dma = rc->start; + rc = platform_get_resource(pdev, IORESOURCE_MEM, 0); host->io_base = devm_ioremap_resource(&pdev->dev, rc); if (IS_ERR(host->io_base)) return PTR_ERR(host->io_base); + host->io_base_dma = rc->start; if (pdev->dev.of_node) host->ncfg = lpc32xx_parse_dt(&pdev->dev); if (!host->ncfg) { diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c index 6c3eed3c2094..6c517c682939 100644 --- a/drivers/mtd/nand/mtk_nand.c +++ b/drivers/mtd/nand/mtk_nand.c @@ -1383,7 +1383,6 @@ static int mtk_nfc_probe(struct platform_device *pdev) nfc->regs = devm_ioremap_resource(dev, res); if (IS_ERR(nfc->regs)) { ret = PTR_ERR(nfc->regs); - dev_err(dev, "no nfi base\n"); goto release_ecc; } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ec1c28aaaf23..1492c12906f6 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3263,6 +3263,42 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) } /** + * nand_max_bad_blocks - [MTD Interface] Max number of bad blocks for an mtd + * @mtd: MTD device structure + * @ofs: offset relative to mtd start + * @len: length of mtd + */ +static int nand_max_bad_blocks(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + u32 part_start_block; + u32 part_end_block; + u32 part_start_die; + u32 part_end_die; + + /* + * max_bb_per_die and blocks_per_die used to determine + * the maximum bad block count. + */ + if (!chip->max_bb_per_die || !chip->blocks_per_die) + return -ENOTSUPP; + + /* Get the start and end of the partition in erase blocks. */ + part_start_block = mtd_div_by_eb(ofs, mtd); + part_end_block = mtd_div_by_eb(len, mtd) + part_start_block - 1; + + /* Get the start and end LUNs of the partition. */ + part_start_die = part_start_block / chip->blocks_per_die; + part_end_die = part_end_block / chip->blocks_per_die; + + /* + * Look up the bad blocks per unit and multiply by the number of units + * that the partition spans. + */ + return chip->max_bb_per_die * (part_end_die - part_start_die + 1); +} + +/** * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand * @mtd: MTD device structure * @chip: nand chip info structure @@ -3592,6 +3628,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count; chip->bits_per_cell = p->bits_per_cell; + chip->max_bb_per_die = le16_to_cpu(p->bb_per_lun); + chip->blocks_per_die = le32_to_cpu(p->blocks_per_lun); + if (onfi_feature(chip) & ONFI_FEATURE_16_BIT_BUS) *busw = NAND_BUSWIDTH_16; else @@ -4815,6 +4854,7 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->_block_isreserved = nand_block_isreserved; mtd->_block_isbad = nand_block_isbad; mtd->_block_markbad = nand_block_markbad; + mtd->_max_bad_blocks = nand_max_bad_blocks; mtd->writebufsize = mtd->writesize; /* diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index b3a332f37e14..4a2f75b0c200 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -185,6 +185,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_SANDISK, "SanDisk"}, {NAND_MFR_INTEL, "Intel"}, {NAND_MFR_ATO, "ATO"}, + {NAND_MFR_WINBOND, "Winbond"}, {0x0, "Unknown"} }; diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index e40482a65de6..0eeeb8b889ea 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -321,6 +321,10 @@ static int sunxi_nfc_wait_events(struct sunxi_nfc *nfc, u32 events, ret = wait_for_completion_timeout(&nfc->complete, msecs_to_jiffies(timeout_ms)); + if (!ret) + ret = -ETIMEDOUT; + else + ret = 0; writel(0, nfc->regs + NFC_REG_INT); } else { @@ -518,6 +522,8 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) u32 tmp; while (len > offs) { + bool poll = false; + cnt = min(len - offs, NFC_SRAM_SIZE); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); @@ -528,7 +534,11 @@ static void sunxi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) tmp = NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD; writel(tmp, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + /* Arbitrary limit for polling mode */ + if (cnt < 64) + poll = true; + + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0); if (ret) break; @@ -551,6 +561,8 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, u32 tmp; while (len > offs) { + bool poll = false; + cnt = min(len - offs, NFC_SRAM_SIZE); ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); @@ -563,7 +575,11 @@ static void sunxi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, NFC_ACCESS_DIR; writel(tmp, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + /* Arbitrary limit for polling mode */ + if (cnt < 64) + poll = true; + + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, poll, 0); if (ret) break; @@ -588,10 +604,6 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller); int ret; - ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); - if (ret) - return; - if (dat == NAND_CMD_NONE && (ctrl & NAND_NCE) && !(ctrl & (NAND_CLE | NAND_ALE))) { u32 cmd = 0; @@ -621,6 +633,10 @@ static void sunxi_nfc_cmd_ctrl(struct mtd_info *mtd, int dat, writel(sunxi_nand->addr[1], nfc->regs + NFC_REG_ADDR_HIGH); + ret = sunxi_nfc_wait_cmd_fifo_empty(nfc); + if (ret) + return; + writel(cmd, nfc->regs + NFC_REG_CMD); sunxi_nand->addr[0] = 0; sunxi_nand->addr[1] = 0; @@ -957,7 +973,7 @@ static int sunxi_nfc_hw_ecc_read_chunk(struct mtd_info *mtd, writel(NFC_DATA_TRANS | NFC_DATA_SWAP_METHOD | NFC_ECC_OP, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); sunxi_nfc_randomizer_disable(mtd); if (ret) return ret; @@ -1069,7 +1085,7 @@ static int sunxi_nfc_hw_ecc_read_chunks_dma(struct mtd_info *mtd, uint8_t *buf, writel(NFC_PAGE_OP | NFC_DATA_SWAP_METHOD | NFC_DATA_TRANS, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); if (ret) dmaengine_terminate_all(nfc->dmac); @@ -1189,7 +1205,7 @@ static int sunxi_nfc_hw_ecc_write_chunk(struct mtd_info *mtd, NFC_ACCESS_DIR | NFC_ECC_OP, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); sunxi_nfc_randomizer_disable(mtd); if (ret) return ret; @@ -1428,7 +1444,7 @@ static int sunxi_nfc_hw_ecc_write_page_dma(struct mtd_info *mtd, NFC_DATA_TRANS | NFC_ACCESS_DIR, nfc->regs + NFC_REG_CMD); - ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, true, 0); + ret = sunxi_nfc_wait_events(nfc, NFC_CMD_INT_FLAG, false, 0); if (ret) dmaengine_terminate_all(nfc->dmac); diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 28c7f474be77..4a5e948c62df 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -632,11 +632,13 @@ static int tango_nand_probe(struct platform_device *pdev) if (IS_ERR(nfc->pbus_base)) return PTR_ERR(nfc->pbus_base); + writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE); + clk = clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); - nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox"); + nfc->chan = dma_request_chan(&pdev->dev, "rxtx"); if (IS_ERR(nfc->chan)) return PTR_ERR(nfc->chan); diff --git a/drivers/mtd/nand/xway_nand.c b/drivers/mtd/nand/xway_nand.c index 1f2948c0c458..ddee4005248c 100644 --- a/drivers/mtd/nand/xway_nand.c +++ b/drivers/mtd/nand/xway_nand.c @@ -3,7 +3,7 @@ * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * - * Copyright © 2012 John Crispin <blogic@openwrt.org> + * Copyright © 2012 John Crispin <john@phrozen.org> * Copyright © 2016 Hauke Mehrtens <hauke@hauke-m.de> */ @@ -232,7 +232,6 @@ static const struct of_device_id xway_nand_match[] = { { .compatible = "lantiq,nand-xway" }, {}, }; -MODULE_DEVICE_TABLE(of, xway_nand_match); static struct platform_driver xway_nand_driver = { .probe = xway_nand_probe, @@ -243,6 +242,4 @@ static struct platform_driver xway_nand_driver = { }, }; -module_platform_driver(xway_nand_driver); - -MODULE_LICENSE("GPL"); +builtin_platform_driver(xway_nand_driver); diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c index ede407d6e106..464470122493 100644 --- a/drivers/mtd/ofpart.c +++ b/drivers/mtd/ofpart.c @@ -108,6 +108,7 @@ static int parse_ofpart_partitions(struct mtd_info *master, parts[i].offset = of_read_number(reg, a_cells); parts[i].size = of_read_number(reg + a_cells, s_cells); + parts[i].of_node = pp; partname = of_get_property(pp, "label", &len); if (!partname) diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig index 4a682ee0f632..7252087ef407 100644 --- a/drivers/mtd/spi-nor/Kconfig +++ b/drivers/mtd/spi-nor/Kconfig @@ -29,6 +29,16 @@ config MTD_SPI_NOR_USE_4K_SECTORS Please note that some tools/drivers/filesystems may not work with 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). +config SPI_ASPEED_SMC + tristate "Aspeed flash controllers in SPI mode" + depends on ARCH_ASPEED || COMPILE_TEST + depends on HAS_IOMEM && OF + help + This enables support for the Firmware Memory controller (FMC) + in the Aspeed AST2500/AST2400 SoCs when attached to SPI NOR chips, + and support for the SPI flash memory controller (SPI) for + the host firmware. The implementation only supports SPI NOR. + config SPI_ATMEL_QUADSPI tristate "Atmel Quad SPI Controller" depends on ARCH_AT91 || (ARM && COMPILE_TEST) @@ -40,7 +50,7 @@ config SPI_ATMEL_QUADSPI config SPI_CADENCE_QUADSPI tristate "Cadence Quad SPI controller" - depends on OF && ARM + depends on OF && (ARM || COMPILE_TEST) help Enable support for the Cadence Quad SPI Flash controller. @@ -76,4 +86,24 @@ config SPI_NXP_SPIFI Flash. Enable this option if you have a device with a SPIFI controller and want to access the Flash as a mtd device. +config SPI_INTEL_SPI + tristate + +config SPI_INTEL_SPI_PLATFORM + tristate "Intel PCH/PCU SPI flash platform driver" if EXPERT + depends on X86 + select SPI_INTEL_SPI + help + This enables platform support for the Intel PCH/PCU SPI + controller in master mode. This controller is present in modern + Intel hardware and is used to hold BIOS and other persistent + settings. Using this driver it is possible to upgrade BIOS + directly from Linux. + + Say N here unless you know what you are doing. Overwriting the + SPI flash may render the system unbootable. + + To compile this driver as a module, choose M here: the module + will be called intel-spi-platform. + endif # MTD_SPI_NOR diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile index 121695e83542..72238a793198 100644 --- a/drivers/mtd/spi-nor/Makefile +++ b/drivers/mtd/spi-nor/Makefile @@ -1,7 +1,10 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o +obj-$(CONFIG_SPI_ASPEED_SMC) += aspeed-smc.o obj-$(CONFIG_SPI_ATMEL_QUADSPI) += atmel-quadspi.o obj-$(CONFIG_SPI_CADENCE_QUADSPI) += cadence-quadspi.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o obj-$(CONFIG_SPI_HISI_SFC) += hisi-sfc.o obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o +obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o +obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c new file mode 100644 index 000000000000..56051d30f000 --- /dev/null +++ b/drivers/mtd/spi-nor/aspeed-smc.c @@ -0,0 +1,754 @@ +/* + * ASPEED Static Memory Controller driver + * + * Copyright (c) 2015-2016, IBM Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/bug.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/spi-nor.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/sysfs.h> + +#define DEVICE_NAME "aspeed-smc" + +/* + * The driver only support SPI flash + */ +enum aspeed_smc_flash_type { + smc_type_nor = 0, + smc_type_nand = 1, + smc_type_spi = 2, +}; + +struct aspeed_smc_chip; + +struct aspeed_smc_info { + u32 maxsize; /* maximum size of chip window */ + u8 nce; /* number of chip enables */ + bool hastype; /* flash type field exists in config reg */ + u8 we0; /* shift for write enable bit for CE0 */ + u8 ctl0; /* offset in regs of ctl for CE0 */ + + void (*set_4b)(struct aspeed_smc_chip *chip); +}; + +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip); +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip); + +static const struct aspeed_smc_info fmc_2400_info = { + .maxsize = 64 * 1024 * 1024, + .nce = 5, + .hastype = true, + .we0 = 16, + .ctl0 = 0x10, + .set_4b = aspeed_smc_chip_set_4b, +}; + +static const struct aspeed_smc_info spi_2400_info = { + .maxsize = 64 * 1024 * 1024, + .nce = 1, + .hastype = false, + .we0 = 0, + .ctl0 = 0x04, + .set_4b = aspeed_smc_chip_set_4b_spi_2400, +}; + +static const struct aspeed_smc_info fmc_2500_info = { + .maxsize = 256 * 1024 * 1024, + .nce = 3, + .hastype = true, + .we0 = 16, + .ctl0 = 0x10, + .set_4b = aspeed_smc_chip_set_4b, +}; + +static const struct aspeed_smc_info spi_2500_info = { + .maxsize = 128 * 1024 * 1024, + .nce = 2, + .hastype = false, + .we0 = 16, + .ctl0 = 0x10, + .set_4b = aspeed_smc_chip_set_4b, +}; + +enum aspeed_smc_ctl_reg_value { + smc_base, /* base value without mode for other commands */ + smc_read, /* command reg for (maybe fast) reads */ + smc_write, /* command reg for writes */ + smc_max, +}; + +struct aspeed_smc_controller; + +struct aspeed_smc_chip { + int cs; + struct aspeed_smc_controller *controller; + void __iomem *ctl; /* control register */ + void __iomem *ahb_base; /* base of chip window */ + u32 ctl_val[smc_max]; /* control settings */ + enum aspeed_smc_flash_type type; /* what type of flash */ + struct spi_nor nor; +}; + +struct aspeed_smc_controller { + struct device *dev; + + struct mutex mutex; /* controller access mutex */ + const struct aspeed_smc_info *info; /* type info of controller */ + void __iomem *regs; /* controller registers */ + void __iomem *ahb_base; /* per-chip windows resource */ + + struct aspeed_smc_chip *chips[0]; /* pointers to attached chips */ +}; + +/* + * SPI Flash Configuration Register (AST2500 SPI) + * or + * Type setting Register (AST2500 FMC). + * CE0 and CE1 can only be of type SPI. CE2 can be of type NOR but the + * driver does not support it. + */ +#define CONFIG_REG 0x0 +#define CONFIG_DISABLE_LEGACY BIT(31) /* 1 */ + +#define CONFIG_CE2_WRITE BIT(18) +#define CONFIG_CE1_WRITE BIT(17) +#define CONFIG_CE0_WRITE BIT(16) + +#define CONFIG_CE2_TYPE BIT(4) /* AST2500 FMC only */ +#define CONFIG_CE1_TYPE BIT(2) /* AST2500 FMC only */ +#define CONFIG_CE0_TYPE BIT(0) /* AST2500 FMC only */ + +/* + * CE Control Register + */ +#define CE_CONTROL_REG 0x4 + +/* + * CEx Control Register + */ +#define CONTROL_AAF_MODE BIT(31) +#define CONTROL_IO_MODE_MASK GENMASK(30, 28) +#define CONTROL_IO_DUAL_DATA BIT(29) +#define CONTROL_IO_DUAL_ADDR_DATA (BIT(29) | BIT(28)) +#define CONTROL_IO_QUAD_DATA BIT(30) +#define CONTROL_IO_QUAD_ADDR_DATA (BIT(30) | BIT(28)) +#define CONTROL_CE_INACTIVE_SHIFT 24 +#define CONTROL_CE_INACTIVE_MASK GENMASK(27, \ + CONTROL_CE_INACTIVE_SHIFT) +/* 0 = 16T ... 15 = 1T T=HCLK */ +#define CONTROL_COMMAND_SHIFT 16 +#define CONTROL_DUMMY_COMMAND_OUT BIT(15) +#define CONTROL_IO_DUMMY_HI BIT(14) +#define CONTROL_IO_DUMMY_HI_SHIFT 14 +#define CONTROL_CLK_DIV4 BIT(13) /* others */ +#define CONTROL_IO_ADDRESS_4B BIT(13) /* AST2400 SPI */ +#define CONTROL_RW_MERGE BIT(12) +#define CONTROL_IO_DUMMY_LO_SHIFT 6 +#define CONTROL_IO_DUMMY_LO GENMASK(7, \ + CONTROL_IO_DUMMY_LO_SHIFT) +#define CONTROL_IO_DUMMY_MASK (CONTROL_IO_DUMMY_HI | \ + CONTROL_IO_DUMMY_LO) +#define CONTROL_IO_DUMMY_SET(dummy) \ + (((((dummy) >> 2) & 0x1) << CONTROL_IO_DUMMY_HI_SHIFT) | \ + (((dummy) & 0x3) << CONTROL_IO_DUMMY_LO_SHIFT)) + +#define CONTROL_CLOCK_FREQ_SEL_SHIFT 8 +#define CONTROL_CLOCK_FREQ_SEL_MASK GENMASK(11, \ + CONTROL_CLOCK_FREQ_SEL_SHIFT) +#define CONTROL_LSB_FIRST BIT(5) +#define CONTROL_CLOCK_MODE_3 BIT(4) +#define CONTROL_IN_DUAL_DATA BIT(3) +#define CONTROL_CE_STOP_ACTIVE_CONTROL BIT(2) +#define CONTROL_COMMAND_MODE_MASK GENMASK(1, 0) +#define CONTROL_COMMAND_MODE_NORMAL 0 +#define CONTROL_COMMAND_MODE_FREAD 1 +#define CONTROL_COMMAND_MODE_WRITE 2 +#define CONTROL_COMMAND_MODE_USER 3 + +#define CONTROL_KEEP_MASK \ + (CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \ + CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK | \ + CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3) + +/* + * The Segment Register uses a 8MB unit to encode the start address + * and the end address of the mapping window of a flash SPI slave : + * + * | byte 1 | byte 2 | byte 3 | byte 4 | + * +--------+--------+--------+--------+ + * | end | start | 0 | 0 | + */ +#define SEGMENT_ADDR_REG0 0x30 +#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23) +#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23) + +/* + * In user mode all data bytes read or written to the chip decode address + * range are transferred to or from the SPI bus. The range is treated as a + * fifo of arbitratry 1, 2, or 4 byte width but each write has to be aligned + * to its size. The address within the multiple 8kB range is ignored when + * sending bytes to the SPI bus. + * + * On the arm architecture, as of Linux version 4.3, memcpy_fromio and + * memcpy_toio on little endian targets use the optimized memcpy routines + * that were designed for well behavied memory storage. These routines + * have a stutter if the source and destination are not both word aligned, + * once with a duplicate access to the source after aligning to the + * destination to a word boundary, and again with a duplicate access to + * the source when the final byte count is not word aligned. + * + * When writing or reading the fifo this stutter discards data or sends + * too much data to the fifo and can not be used by this driver. + * + * While the low level io string routines that implement the insl family do + * the desired accesses and memory increments, the cross architecture io + * macros make them essentially impossible to use on a memory mapped address + * instead of a a token from the call to iomap of an io port. + * + * These fifo routines use readl and friends to a constant io port and update + * the memory buffer pointer and count via explicit code. The final updates + * to len are optimistically suppressed. + */ +static int aspeed_smc_read_from_ahb(void *buf, void __iomem *src, size_t len) +{ + size_t offset = 0; + + if (IS_ALIGNED((uintptr_t)src, sizeof(uintptr_t)) && + IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) { + ioread32_rep(src, buf, len >> 2); + offset = len & ~0x3; + len -= offset; + } + ioread8_rep(src, (u8 *)buf + offset, len); + return 0; +} + +static int aspeed_smc_write_to_ahb(void __iomem *dst, const void *buf, + size_t len) +{ + size_t offset = 0; + + if (IS_ALIGNED((uintptr_t)dst, sizeof(uintptr_t)) && + IS_ALIGNED((uintptr_t)buf, sizeof(uintptr_t))) { + iowrite32_rep(dst, buf, len >> 2); + offset = len & ~0x3; + len -= offset; + } + iowrite8_rep(dst, (const u8 *)buf + offset, len); + return 0; +} + +static inline u32 aspeed_smc_chip_write_bit(struct aspeed_smc_chip *chip) +{ + return BIT(chip->controller->info->we0 + chip->cs); +} + +static void aspeed_smc_chip_check_config(struct aspeed_smc_chip *chip) +{ + struct aspeed_smc_controller *controller = chip->controller; + u32 reg; + + reg = readl(controller->regs + CONFIG_REG); + + if (reg & aspeed_smc_chip_write_bit(chip)) + return; + + dev_dbg(controller->dev, "config write is not set ! @%p: 0x%08x\n", + controller->regs + CONFIG_REG, reg); + reg |= aspeed_smc_chip_write_bit(chip); + writel(reg, controller->regs + CONFIG_REG); +} + +static void aspeed_smc_start_user(struct spi_nor *nor) +{ + struct aspeed_smc_chip *chip = nor->priv; + u32 ctl = chip->ctl_val[smc_base]; + + /* + * When the chip is controlled in user mode, we need write + * access to send the opcodes to it. So check the config. + */ + aspeed_smc_chip_check_config(chip); + + ctl |= CONTROL_COMMAND_MODE_USER | + CONTROL_CE_STOP_ACTIVE_CONTROL; + writel(ctl, chip->ctl); + + ctl &= ~CONTROL_CE_STOP_ACTIVE_CONTROL; + writel(ctl, chip->ctl); +} + +static void aspeed_smc_stop_user(struct spi_nor *nor) +{ + struct aspeed_smc_chip *chip = nor->priv; + + u32 ctl = chip->ctl_val[smc_read]; + u32 ctl2 = ctl | CONTROL_COMMAND_MODE_USER | + CONTROL_CE_STOP_ACTIVE_CONTROL; + + writel(ctl2, chip->ctl); /* stop user CE control */ + writel(ctl, chip->ctl); /* default to fread or read mode */ +} + +static int aspeed_smc_prep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct aspeed_smc_chip *chip = nor->priv; + + mutex_lock(&chip->controller->mutex); + return 0; +} + +static void aspeed_smc_unprep(struct spi_nor *nor, enum spi_nor_ops ops) +{ + struct aspeed_smc_chip *chip = nor->priv; + + mutex_unlock(&chip->controller->mutex); +} + +static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +{ + struct aspeed_smc_chip *chip = nor->priv; + + aspeed_smc_start_user(nor); + aspeed_smc_write_to_ahb(chip->ahb_base, &opcode, 1); + aspeed_smc_read_from_ahb(buf, chip->ahb_base, len); + aspeed_smc_stop_user(nor); + return 0; +} + +static int aspeed_smc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, + int len) +{ + struct aspeed_smc_chip *chip = nor->priv; + + aspeed_smc_start_user(nor); + aspeed_smc_write_to_ahb(chip->ahb_base, &opcode, 1); + aspeed_smc_write_to_ahb(chip->ahb_base, buf, len); + aspeed_smc_stop_user(nor); + return 0; +} + +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr) +{ + struct aspeed_smc_chip *chip = nor->priv; + __be32 temp; + u32 cmdaddr; + + switch (nor->addr_width) { + default: + WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n", + nor->addr_width); + /* FALLTHROUGH */ + case 3: + cmdaddr = addr & 0xFFFFFF; + cmdaddr |= cmd << 24; + + temp = cpu_to_be32(cmdaddr); + aspeed_smc_write_to_ahb(chip->ahb_base, &temp, 4); + break; + case 4: + temp = cpu_to_be32(addr); + aspeed_smc_write_to_ahb(chip->ahb_base, &cmd, 1); + aspeed_smc_write_to_ahb(chip->ahb_base, &temp, 4); + break; + } +} + +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from, + size_t len, u_char *read_buf) +{ + struct aspeed_smc_chip *chip = nor->priv; + int i; + u8 dummy = 0xFF; + + aspeed_smc_start_user(nor); + aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from); + for (i = 0; i < chip->nor.read_dummy / 8; i++) + aspeed_smc_write_to_ahb(chip->ahb_base, &dummy, sizeof(dummy)); + + aspeed_smc_read_from_ahb(read_buf, chip->ahb_base, len); + aspeed_smc_stop_user(nor); + return len; +} + +static ssize_t aspeed_smc_write_user(struct spi_nor *nor, loff_t to, + size_t len, const u_char *write_buf) +{ + struct aspeed_smc_chip *chip = nor->priv; + + aspeed_smc_start_user(nor); + aspeed_smc_send_cmd_addr(nor, nor->program_opcode, to); + aspeed_smc_write_to_ahb(chip->ahb_base, write_buf, len); + aspeed_smc_stop_user(nor); + return len; +} + +static int aspeed_smc_unregister(struct aspeed_smc_controller *controller) +{ + struct aspeed_smc_chip *chip; + int n; + + for (n = 0; n < controller->info->nce; n++) { + chip = controller->chips[n]; + if (chip) + mtd_device_unregister(&chip->nor.mtd); + } + + return 0; +} + +static int aspeed_smc_remove(struct platform_device *dev) +{ + return aspeed_smc_unregister(platform_get_drvdata(dev)); +} + +static const struct of_device_id aspeed_smc_matches[] = { + { .compatible = "aspeed,ast2400-fmc", .data = &fmc_2400_info }, + { .compatible = "aspeed,ast2400-spi", .data = &spi_2400_info }, + { .compatible = "aspeed,ast2500-fmc", .data = &fmc_2500_info }, + { .compatible = "aspeed,ast2500-spi", .data = &spi_2500_info }, + { } +}; +MODULE_DEVICE_TABLE(of, aspeed_smc_matches); + +/* + * Each chip has a mapping window defined by a segment address + * register defining a start and an end address on the AHB bus. These + * addresses can be configured to fit the chip size and offer a + * contiguous memory region across chips. For the moment, we only + * check that each chip segment is valid. + */ +static void __iomem *aspeed_smc_chip_base(struct aspeed_smc_chip *chip, + struct resource *res) +{ + struct aspeed_smc_controller *controller = chip->controller; + u32 offset = 0; + u32 reg; + + if (controller->info->nce > 1) { + reg = readl(controller->regs + SEGMENT_ADDR_REG0 + + chip->cs * 4); + + if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg)) + return NULL; + + offset = SEGMENT_ADDR_START(reg) - res->start; + } + + return controller->ahb_base + offset; +} + +static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip) +{ + struct aspeed_smc_controller *controller = chip->controller; + u32 reg; + + reg = readl(controller->regs + CONFIG_REG); + + reg |= aspeed_smc_chip_write_bit(chip); + writel(reg, controller->regs + CONFIG_REG); +} + +static void aspeed_smc_chip_set_type(struct aspeed_smc_chip *chip, int type) +{ + struct aspeed_smc_controller *controller = chip->controller; + u32 reg; + + chip->type = type; + + reg = readl(controller->regs + CONFIG_REG); + reg &= ~(3 << (chip->cs * 2)); + reg |= chip->type << (chip->cs * 2); + writel(reg, controller->regs + CONFIG_REG); +} + +/* + * The AST2500 FMC flash controller should be strapped by hardware, or + * autodetected, but the AST2500 SPI flash needs to be set. + */ +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip) +{ + struct aspeed_smc_controller *controller = chip->controller; + u32 reg; + + if (chip->controller->info == &spi_2500_info) { + reg = readl(controller->regs + CE_CONTROL_REG); + reg |= 1 << chip->cs; + writel(reg, controller->regs + CE_CONTROL_REG); + } +} + +/* + * The AST2400 SPI flash controller does not have a CE Control + * register. It uses the CE0 control register to set 4Byte mode at the + * controller level. + */ +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip) +{ + chip->ctl_val[smc_base] |= CONTROL_IO_ADDRESS_4B; + chip->ctl_val[smc_read] |= CONTROL_IO_ADDRESS_4B; +} + +static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip, + struct resource *res) +{ + struct aspeed_smc_controller *controller = chip->controller; + const struct aspeed_smc_info *info = controller->info; + u32 reg, base_reg; + + /* + * Always turn on the write enable bit to allow opcodes to be + * sent in user mode. + */ + aspeed_smc_chip_enable_write(chip); + + /* The driver only supports SPI type flash */ + if (info->hastype) + aspeed_smc_chip_set_type(chip, smc_type_spi); + + /* + * Configure chip base address in memory + */ + chip->ahb_base = aspeed_smc_chip_base(chip, res); + if (!chip->ahb_base) { + dev_warn(chip->nor.dev, "CE segment window closed.\n"); + return -EINVAL; + } + + /* + * Get value of the inherited control register. U-Boot usually + * does some timing calibration on the FMC chip, so it's good + * to keep them. In the future, we should handle calibration + * from Linux. + */ + reg = readl(chip->ctl); + dev_dbg(controller->dev, "control register: %08x\n", reg); + + base_reg = reg & CONTROL_KEEP_MASK; + if (base_reg != reg) { + dev_dbg(controller->dev, + "control register changed to: %08x\n", + base_reg); + } + chip->ctl_val[smc_base] = base_reg; + + /* + * Retain the prior value of the control register as the + * default if it was normal access mode. Otherwise start with + * the sanitized base value set to read mode. + */ + if ((reg & CONTROL_COMMAND_MODE_MASK) == + CONTROL_COMMAND_MODE_NORMAL) + chip->ctl_val[smc_read] = reg; + else + chip->ctl_val[smc_read] = chip->ctl_val[smc_base] | + CONTROL_COMMAND_MODE_NORMAL; + + dev_dbg(controller->dev, "default control register: %08x\n", + chip->ctl_val[smc_read]); + return 0; +} + +static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip) +{ + struct aspeed_smc_controller *controller = chip->controller; + const struct aspeed_smc_info *info = controller->info; + u32 cmd; + + if (chip->nor.addr_width == 4 && info->set_4b) + info->set_4b(chip); + + /* + * base mode has not been optimized yet. use it for writes. + */ + chip->ctl_val[smc_write] = chip->ctl_val[smc_base] | + chip->nor.program_opcode << CONTROL_COMMAND_SHIFT | + CONTROL_COMMAND_MODE_WRITE; + + dev_dbg(controller->dev, "write control register: %08x\n", + chip->ctl_val[smc_write]); + + /* + * TODO: Adjust clocks if fast read is supported and interpret + * SPI-NOR flags to adjust controller settings. + */ + switch (chip->nor.flash_read) { + case SPI_NOR_NORMAL: + cmd = CONTROL_COMMAND_MODE_NORMAL; + break; + case SPI_NOR_FAST: + cmd = CONTROL_COMMAND_MODE_FREAD; + break; + default: + dev_err(chip->nor.dev, "unsupported SPI read mode\n"); + return -EINVAL; + } + + chip->ctl_val[smc_read] |= cmd | + CONTROL_IO_DUMMY_SET(chip->nor.read_dummy / 8); + + dev_dbg(controller->dev, "base control register: %08x\n", + chip->ctl_val[smc_read]); + return 0; +} + +static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller, + struct device_node *np, struct resource *r) +{ + const struct aspeed_smc_info *info = controller->info; + struct device *dev = controller->dev; + struct device_node *child; + unsigned int cs; + int ret = -ENODEV; + + for_each_available_child_of_node(np, child) { + struct aspeed_smc_chip *chip; + struct spi_nor *nor; + struct mtd_info *mtd; + + /* This driver does not support NAND or NOR flash devices. */ + if (!of_device_is_compatible(child, "jedec,spi-nor")) + continue; + + ret = of_property_read_u32(child, "reg", &cs); + if (ret) { + dev_err(dev, "Couldn't not read chip select.\n"); + break; + } + + if (cs >= info->nce) { + dev_err(dev, "Chip select %d out of range.\n", + cs); + ret = -ERANGE; + break; + } + + if (controller->chips[cs]) { + dev_err(dev, "Chip select %d already in use by %s\n", + cs, dev_name(controller->chips[cs]->nor.dev)); + ret = -EBUSY; + break; + } + + chip = devm_kzalloc(controller->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) { + ret = -ENOMEM; + break; + } + + chip->controller = controller; + chip->ctl = controller->regs + info->ctl0 + cs * 4; + chip->cs = cs; + + nor = &chip->nor; + mtd = &nor->mtd; + + nor->dev = dev; + nor->priv = chip; + spi_nor_set_flash_node(nor, child); + nor->read = aspeed_smc_read_user; + nor->write = aspeed_smc_write_user; + nor->read_reg = aspeed_smc_read_reg; + nor->write_reg = aspeed_smc_write_reg; + nor->prepare = aspeed_smc_prep; + nor->unprepare = aspeed_smc_unprep; + + ret = aspeed_smc_chip_setup_init(chip, r); + if (ret) + break; + + /* + * TODO: Add support for SPI_NOR_QUAD and SPI_NOR_DUAL + * attach when board support is present as determined + * by of property. + */ + ret = spi_nor_scan(nor, NULL, SPI_NOR_NORMAL); + if (ret) + break; + + ret = aspeed_smc_chip_setup_finish(chip); + if (ret) + break; + + ret = mtd_device_register(mtd, NULL, 0); + if (ret) + break; + + controller->chips[cs] = chip; + } + + if (ret) + aspeed_smc_unregister(controller); + + return ret; +} + +static int aspeed_smc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct aspeed_smc_controller *controller; + const struct of_device_id *match; + const struct aspeed_smc_info *info; + struct resource *res; + int ret; + + match = of_match_device(aspeed_smc_matches, &pdev->dev); + if (!match || !match->data) + return -ENODEV; + info = match->data; + + controller = devm_kzalloc(&pdev->dev, sizeof(*controller) + + info->nce * sizeof(controller->chips[0]), GFP_KERNEL); + if (!controller) + return -ENOMEM; + controller->info = info; + controller->dev = dev; + + mutex_init(&controller->mutex); + platform_set_drvdata(pdev, controller); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + controller->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(controller->regs)) + return PTR_ERR(controller->regs); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + controller->ahb_base = devm_ioremap_resource(dev, res); + if (IS_ERR(controller->ahb_base)) + return PTR_ERR(controller->ahb_base); + + ret = aspeed_smc_setup_flash(controller, np, res); + if (ret) + dev_err(dev, "Aspeed SMC probe failed %d\n", ret); + + return ret; +} + +static struct platform_driver aspeed_smc_driver = { + .probe = aspeed_smc_probe, + .remove = aspeed_smc_remove, + .driver = { + .name = DEVICE_NAME, + .of_match_table = aspeed_smc_matches, + } +}; + +module_platform_driver(aspeed_smc_driver); + +MODULE_DESCRIPTION("ASPEED Static Memory Controller Driver"); +MODULE_AUTHOR("Cedric Le Goater <clg@kaod.org>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index d489fbd07c12..9f8102de1b16 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -526,7 +526,8 @@ static int cqspi_indirect_read_execute(struct spi_nor *nor, bytes_to_read *= cqspi->fifo_width; bytes_to_read = bytes_to_read > remaining ? remaining : bytes_to_read; - readsl(ahb_base, rxbuf, DIV_ROUND_UP(bytes_to_read, 4)); + ioread32_rep(ahb_base, rxbuf, + DIV_ROUND_UP(bytes_to_read, 4)); rxbuf += bytes_to_read; remaining -= bytes_to_read; bytes_to_read = cqspi_get_rd_sram_level(cqspi); @@ -610,7 +611,8 @@ static int cqspi_indirect_write_execute(struct spi_nor *nor, while (remaining > 0) { write_bytes = remaining > page_size ? page_size : remaining; - writesl(cqspi->ahb_base, txbuf, DIV_ROUND_UP(write_bytes, 4)); + iowrite32_rep(cqspi->ahb_base, txbuf, + DIV_ROUND_UP(write_bytes, 4)); ret = wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies @@ -891,7 +893,7 @@ static ssize_t cqspi_write(struct spi_nor *nor, loff_t to, if (ret) return ret; - return (ret < 0) ? ret : len; + return len; } static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, @@ -911,7 +913,7 @@ static ssize_t cqspi_read(struct spi_nor *nor, loff_t from, if (ret) return ret; - return (ret < 0) ? ret : len; + return len; } static int cqspi_erase(struct spi_nor *nor, loff_t offs) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index b4d8953fb30a..1476135e0d50 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -193,7 +193,7 @@ #define QUADSPI_LUT_NUM 64 /* SEQID -- we can have 16 seqids at most. */ -#define SEQID_QUAD_READ 0 +#define SEQID_READ 0 #define SEQID_WREN 1 #define SEQID_WRDI 2 #define SEQID_RDSR 3 @@ -373,32 +373,26 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) void __iomem *base = q->iobase; int rxfifo = q->devtype_data->rxfifo; u32 lut_base; - u8 cmd, addrlen, dummy; int i; + struct spi_nor *nor = &q->nor[0]; + u8 addrlen = (nor->addr_width == 3) ? ADDR24BIT : ADDR32BIT; + u8 read_op = nor->read_opcode; + u8 read_dm = nor->read_dummy; + fsl_qspi_unlock_lut(q); /* Clear all the LUT table */ for (i = 0; i < QUADSPI_LUT_NUM; i++) qspi_writel(q, 0, base + QUADSPI_LUT_BASE + i * 4); - /* Quad Read */ - lut_base = SEQID_QUAD_READ * 4; - - if (q->nor_size <= SZ_16M) { - cmd = SPINOR_OP_READ_1_1_4; - addrlen = ADDR24BIT; - dummy = 8; - } else { - /* use the 4-byte address */ - cmd = SPINOR_OP_READ_1_1_4; - addrlen = ADDR32BIT; - dummy = 8; - } + /* Read */ + lut_base = SEQID_READ * 4; - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + qspi_writel(q, LUT0(CMD, PAD1, read_op) | LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); - qspi_writel(q, LUT0(DUMMY, PAD1, dummy) | LUT1(FSL_READ, PAD4, rxfifo), + qspi_writel(q, LUT0(DUMMY, PAD1, read_dm) | + LUT1(FSL_READ, PAD4, rxfifo), base + QUADSPI_LUT(lut_base + 1)); /* Write enable */ @@ -409,16 +403,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Page Program */ lut_base = SEQID_PP * 4; - if (q->nor_size <= SZ_16M) { - cmd = SPINOR_OP_PP; - addrlen = ADDR24BIT; - } else { - /* use the 4-byte address */ - cmd = SPINOR_OP_PP; - addrlen = ADDR32BIT; - } - - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + qspi_writel(q, LUT0(CMD, PAD1, nor->program_opcode) | + LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); qspi_writel(q, LUT0(FSL_WRITE, PAD1, 0), base + QUADSPI_LUT(lut_base + 1)); @@ -432,10 +418,8 @@ static void fsl_qspi_init_lut(struct fsl_qspi *q) /* Erase a sector */ lut_base = SEQID_SE * 4; - cmd = q->nor[0].erase_opcode; - addrlen = q->nor_size <= SZ_16M ? ADDR24BIT : ADDR32BIT; - - qspi_writel(q, LUT0(CMD, PAD1, cmd) | LUT1(ADDR, PAD1, addrlen), + qspi_writel(q, LUT0(CMD, PAD1, nor->erase_opcode) | + LUT1(ADDR, PAD1, addrlen), base + QUADSPI_LUT(lut_base)); /* Erase the whole chip */ @@ -484,7 +468,7 @@ static int fsl_qspi_get_seqid(struct fsl_qspi *q, u8 cmd) { switch (cmd) { case SPINOR_OP_READ_1_1_4: - return SEQID_QUAD_READ; + return SEQID_READ; case SPINOR_OP_WREN: return SEQID_WREN; case SPINOR_OP_WRDI: diff --git a/drivers/mtd/spi-nor/intel-spi-platform.c b/drivers/mtd/spi-nor/intel-spi-platform.c new file mode 100644 index 000000000000..5c943df9398f --- /dev/null +++ b/drivers/mtd/spi-nor/intel-spi-platform.c @@ -0,0 +1,57 @@ +/* + * Intel PCH/PCU SPI flash platform driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "intel-spi.h" + +static int intel_spi_platform_probe(struct platform_device *pdev) +{ + struct intel_spi_boardinfo *info; + struct intel_spi *ispi; + struct resource *mem; + + info = dev_get_platdata(&pdev->dev); + if (!info) + return -EINVAL; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ispi = intel_spi_probe(&pdev->dev, mem, info); + if (IS_ERR(ispi)) + return PTR_ERR(ispi); + + platform_set_drvdata(pdev, ispi); + return 0; +} + +static int intel_spi_platform_remove(struct platform_device *pdev) +{ + struct intel_spi *ispi = platform_get_drvdata(pdev); + + return intel_spi_remove(ispi); +} + +static struct platform_driver intel_spi_platform_driver = { + .probe = intel_spi_platform_probe, + .remove = intel_spi_platform_remove, + .driver = { + .name = "intel-spi", + }, +}; + +module_platform_driver(intel_spi_platform_driver); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash platform driver"); +MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:intel-spi"); diff --git a/drivers/mtd/spi-nor/intel-spi.c b/drivers/mtd/spi-nor/intel-spi.c new file mode 100644 index 000000000000..a10f6027b386 --- /dev/null +++ b/drivers/mtd/spi-nor/intel-spi.c @@ -0,0 +1,777 @@ +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/sizes.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/spi-nor.h> +#include <linux/platform_data/intel-spi.h> + +#include "intel-spi.h" + +/* Offsets are from @ispi->base */ +#define BFPREG 0x00 + +#define HSFSTS_CTL 0x04 +#define HSFSTS_CTL_FSMIE BIT(31) +#define HSFSTS_CTL_FDBC_SHIFT 24 +#define HSFSTS_CTL_FDBC_MASK (0x3f << HSFSTS_CTL_FDBC_SHIFT) + +#define HSFSTS_CTL_FCYCLE_SHIFT 17 +#define HSFSTS_CTL_FCYCLE_MASK (0x0f << HSFSTS_CTL_FCYCLE_SHIFT) +/* HW sequencer opcodes */ +#define HSFSTS_CTL_FCYCLE_READ (0x00 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRITE (0x02 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE (0x03 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_ERASE_64K (0x04 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDID (0x06 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_WRSR (0x07 << HSFSTS_CTL_FCYCLE_SHIFT) +#define HSFSTS_CTL_FCYCLE_RDSR (0x08 << HSFSTS_CTL_FCYCLE_SHIFT) + +#define HSFSTS_CTL_FGO BIT(16) +#define HSFSTS_CTL_FLOCKDN BIT(15) +#define HSFSTS_CTL_FDV BIT(14) +#define HSFSTS_CTL_SCIP BIT(5) +#define HSFSTS_CTL_AEL BIT(2) +#define HSFSTS_CTL_FCERR BIT(1) +#define HSFSTS_CTL_FDONE BIT(0) + +#define FADDR 0x08 +#define DLOCK 0x0c +#define FDATA(n) (0x10 + ((n) * 4)) + +#define FRACC 0x50 + +#define FREG(n) (0x54 + ((n) * 4)) +#define FREG_BASE_MASK 0x3fff +#define FREG_LIMIT_SHIFT 16 +#define FREG_LIMIT_MASK (0x03fff << FREG_LIMIT_SHIFT) + +/* Offset is from @ispi->pregs */ +#define PR(n) ((n) * 4) +#define PR_WPE BIT(31) +#define PR_LIMIT_SHIFT 16 +#define PR_LIMIT_MASK (0x3fff << PR_LIMIT_SHIFT) +#define PR_RPE BIT(15) +#define PR_BASE_MASK 0x3fff +/* Last PR is GPR0 */ +#define PR_NUM (5 + 1) + +/* Offsets are from @ispi->sregs */ +#define SSFSTS_CTL 0x00 +#define SSFSTS_CTL_FSMIE BIT(23) +#define SSFSTS_CTL_DS BIT(22) +#define SSFSTS_CTL_DBC_SHIFT 16 +#define SSFSTS_CTL_SPOP BIT(11) +#define SSFSTS_CTL_ACS BIT(10) +#define SSFSTS_CTL_SCGO BIT(9) +#define SSFSTS_CTL_COP_SHIFT 12 +#define SSFSTS_CTL_FRS BIT(7) +#define SSFSTS_CTL_DOFRS BIT(6) +#define SSFSTS_CTL_AEL BIT(4) +#define SSFSTS_CTL_FCERR BIT(3) +#define SSFSTS_CTL_FDONE BIT(2) +#define SSFSTS_CTL_SCIP BIT(0) + +#define PREOP_OPTYPE 0x04 +#define OPMENU0 0x08 +#define OPMENU1 0x0c + +/* CPU specifics */ +#define BYT_PR 0x74 +#define BYT_SSFSTS_CTL 0x90 +#define BYT_BCR 0xfc +#define BYT_BCR_WPD BIT(0) +#define BYT_FREG_NUM 5 + +#define LPT_PR 0x74 +#define LPT_SSFSTS_CTL 0x90 +#define LPT_FREG_NUM 5 + +#define BXT_PR 0x84 +#define BXT_SSFSTS_CTL 0xa0 +#define BXT_FREG_NUM 12 + +#define INTEL_SPI_TIMEOUT 5000 /* ms */ +#define INTEL_SPI_FIFO_SZ 64 + +/** + * struct intel_spi - Driver private data + * @dev: Device pointer + * @info: Pointer to board specific info + * @nor: SPI NOR layer structure + * @base: Beginning of MMIO space + * @pregs: Start of protection registers + * @sregs: Start of software sequencer registers + * @nregions: Maximum number of regions + * @writeable: Is the chip writeable + * @swseq: Use SW sequencer in register reads/writes + * @erase_64k: 64k erase supported + * @opcodes: Opcodes which are supported. This are programmed by BIOS + * before it locks down the controller. + * @preopcodes: Preopcodes which are supported. + */ +struct intel_spi { + struct device *dev; + const struct intel_spi_boardinfo *info; + struct spi_nor nor; + void __iomem *base; + void __iomem *pregs; + void __iomem *sregs; + size_t nregions; + bool writeable; + bool swseq; + bool erase_64k; + u8 opcodes[8]; + u8 preopcodes[2]; +}; + +static bool writeable; +module_param(writeable, bool, 0); +MODULE_PARM_DESC(writeable, "Enable write access to SPI flash chip (default=0)"); + +static void intel_spi_dump_regs(struct intel_spi *ispi) +{ + u32 value; + int i; + + dev_dbg(ispi->dev, "BFPREG=0x%08x\n", readl(ispi->base + BFPREG)); + + value = readl(ispi->base + HSFSTS_CTL); + dev_dbg(ispi->dev, "HSFSTS_CTL=0x%08x\n", value); + if (value & HSFSTS_CTL_FLOCKDN) + dev_dbg(ispi->dev, "-> Locked\n"); + + dev_dbg(ispi->dev, "FADDR=0x%08x\n", readl(ispi->base + FADDR)); + dev_dbg(ispi->dev, "DLOCK=0x%08x\n", readl(ispi->base + DLOCK)); + + for (i = 0; i < 16; i++) + dev_dbg(ispi->dev, "FDATA(%d)=0x%08x\n", + i, readl(ispi->base + FDATA(i))); + + dev_dbg(ispi->dev, "FRACC=0x%08x\n", readl(ispi->base + FRACC)); + + for (i = 0; i < ispi->nregions; i++) + dev_dbg(ispi->dev, "FREG(%d)=0x%08x\n", i, + readl(ispi->base + FREG(i))); + for (i = 0; i < PR_NUM; i++) + dev_dbg(ispi->dev, "PR(%d)=0x%08x\n", i, + readl(ispi->pregs + PR(i))); + + value = readl(ispi->sregs + SSFSTS_CTL); + dev_dbg(ispi->dev, "SSFSTS_CTL=0x%08x\n", value); + dev_dbg(ispi->dev, "PREOP_OPTYPE=0x%08x\n", + readl(ispi->sregs + PREOP_OPTYPE)); + dev_dbg(ispi->dev, "OPMENU0=0x%08x\n", readl(ispi->sregs + OPMENU0)); + dev_dbg(ispi->dev, "OPMENU1=0x%08x\n", readl(ispi->sregs + OPMENU1)); + + if (ispi->info->type == INTEL_SPI_BYT) + dev_dbg(ispi->dev, "BCR=0x%08x\n", readl(ispi->base + BYT_BCR)); + + dev_dbg(ispi->dev, "Protected regions:\n"); + for (i = 0; i < PR_NUM; i++) { + u32 base, limit; + + value = readl(ispi->pregs + PR(i)); + if (!(value & (PR_WPE | PR_RPE))) + continue; + + limit = (value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + base = value & PR_BASE_MASK; + + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x [%c%c]\n", + i, base << 12, (limit << 12) | 0xfff, + value & PR_WPE ? 'W' : '.', + value & PR_RPE ? 'R' : '.'); + } + + dev_dbg(ispi->dev, "Flash regions:\n"); + for (i = 0; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || (i > 0 && limit == 0)) + dev_dbg(ispi->dev, " %02d disabled\n", i); + else + dev_dbg(ispi->dev, " %02d base: 0x%08x limit: 0x%08x\n", + i, base << 12, (limit << 12) | 0xfff); + } + + dev_dbg(ispi->dev, "Using %cW sequencer for register access\n", + ispi->swseq ? 'S' : 'H'); +} + +/* Reads max INTEL_SPI_FIFO_SZ bytes from the device fifo */ +static int intel_spi_read_block(struct intel_spi *ispi, void *buf, size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_fromio(buf, ispi->base + FDATA(i), bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +/* Writes max INTEL_SPI_FIFO_SZ bytes to the device fifo */ +static int intel_spi_write_block(struct intel_spi *ispi, const void *buf, + size_t size) +{ + size_t bytes; + int i = 0; + + if (size > INTEL_SPI_FIFO_SZ) + return -EINVAL; + + while (size > 0) { + bytes = min_t(size_t, size, 4); + memcpy_toio(ispi->base + FDATA(i), buf, bytes); + size -= bytes; + buf += bytes; + i++; + } + + return 0; +} + +static int intel_spi_wait_hw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->base + HSFSTS_CTL, val, + !(val & HSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static int intel_spi_wait_sw_busy(struct intel_spi *ispi) +{ + u32 val; + + return readl_poll_timeout(ispi->sregs + SSFSTS_CTL, val, + !(val & SSFSTS_CTL_SCIP), 0, + INTEL_SPI_TIMEOUT * 1000); +} + +static int intel_spi_init(struct intel_spi *ispi) +{ + u32 opmenu0, opmenu1, val; + int i; + + switch (ispi->info->type) { + case INTEL_SPI_BYT: + ispi->sregs = ispi->base + BYT_SSFSTS_CTL; + ispi->pregs = ispi->base + BYT_PR; + ispi->nregions = BYT_FREG_NUM; + + if (writeable) { + /* Disable write protection */ + val = readl(ispi->base + BYT_BCR); + if (!(val & BYT_BCR_WPD)) { + val |= BYT_BCR_WPD; + writel(val, ispi->base + BYT_BCR); + val = readl(ispi->base + BYT_BCR); + } + + ispi->writeable = !!(val & BYT_BCR_WPD); + } + + break; + + case INTEL_SPI_LPT: + ispi->sregs = ispi->base + LPT_SSFSTS_CTL; + ispi->pregs = ispi->base + LPT_PR; + ispi->nregions = LPT_FREG_NUM; + break; + + case INTEL_SPI_BXT: + ispi->sregs = ispi->base + BXT_SSFSTS_CTL; + ispi->pregs = ispi->base + BXT_PR; + ispi->nregions = BXT_FREG_NUM; + ispi->erase_64k = true; + break; + + default: + return -EINVAL; + } + + /* Disable #SMI generation */ + val = readl(ispi->base + HSFSTS_CTL); + val &= ~HSFSTS_CTL_FSMIE; + writel(val, ispi->base + HSFSTS_CTL); + + /* + * BIOS programs allowed opcodes and then locks down the register. + * So read back what opcodes it decided to support. That's the set + * we are going to support as well. + */ + opmenu0 = readl(ispi->sregs + OPMENU0); + opmenu1 = readl(ispi->sregs + OPMENU1); + + /* + * Some controllers can only do basic operations using hardware + * sequencer. All other operations are supposed to be carried out + * using software sequencer. If we find that BIOS has programmed + * opcodes for the software sequencer we use that over the hardware + * sequencer. + */ + if (opmenu0 && opmenu1) { + for (i = 0; i < ARRAY_SIZE(ispi->opcodes) / 2; i++) { + ispi->opcodes[i] = opmenu0 >> i * 8; + ispi->opcodes[i + 4] = opmenu1 >> i * 8; + } + + val = readl(ispi->sregs + PREOP_OPTYPE); + ispi->preopcodes[0] = val; + ispi->preopcodes[1] = val >> 8; + + /* Disable #SMI generation from SW sequencer */ + val = readl(ispi->sregs + SSFSTS_CTL); + val &= ~SSFSTS_CTL_FSMIE; + writel(val, ispi->sregs + SSFSTS_CTL); + + ispi->swseq = true; + } + + intel_spi_dump_regs(ispi); + + return 0; +} + +static int intel_spi_opcode_index(struct intel_spi *ispi, u8 opcode) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ispi->opcodes); i++) + if (ispi->opcodes[i] == opcode) + return i; + return -EINVAL; +} + +static int intel_spi_hw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf, + int len) +{ + u32 val, status; + int ret; + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FCYCLE_MASK | HSFSTS_CTL_FDBC_MASK); + + switch (opcode) { + case SPINOR_OP_RDID: + val |= HSFSTS_CTL_FCYCLE_RDID; + break; + case SPINOR_OP_WRSR: + val |= HSFSTS_CTL_FCYCLE_WRSR; + break; + case SPINOR_OP_RDSR: + val |= HSFSTS_CTL_FCYCLE_RDSR; + break; + default: + return -EINVAL; + } + + val |= (len - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + else if (status & HSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_sw_cycle(struct intel_spi *ispi, u8 opcode, u8 *buf, + int len) +{ + u32 val, status; + int ret; + + ret = intel_spi_opcode_index(ispi, opcode); + if (ret < 0) + return ret; + + val = (len << SSFSTS_CTL_DBC_SHIFT) | SSFSTS_CTL_DS; + val |= ret << SSFSTS_CTL_COP_SHIFT; + val |= SSFSTS_CTL_FCERR | SSFSTS_CTL_FDONE; + val |= SSFSTS_CTL_SCGO; + writel(val, ispi->sregs + SSFSTS_CTL); + + ret = intel_spi_wait_sw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + SSFSTS_CTL); + if (status & SSFSTS_CTL_FCERR) + return -EIO; + else if (status & SSFSTS_CTL_AEL) + return -EACCES; + + return 0; +} + +static int intel_spi_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +{ + struct intel_spi *ispi = nor->priv; + int ret; + + /* Address of the first chip */ + writel(0, ispi->base + FADDR); + + if (ispi->swseq) + ret = intel_spi_sw_cycle(ispi, opcode, buf, len); + else + ret = intel_spi_hw_cycle(ispi, opcode, buf, len); + + if (ret) + return ret; + + return intel_spi_read_block(ispi, buf, len); +} + +static int intel_spi_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len) +{ + struct intel_spi *ispi = nor->priv; + int ret; + + /* + * This is handled with atomic operation and preop code in Intel + * controller so skip it here now. + */ + if (opcode == SPINOR_OP_WREN) + return 0; + + writel(0, ispi->base + FADDR); + + /* Write the value beforehand */ + ret = intel_spi_write_block(ispi, buf, len); + if (ret) + return ret; + + if (ispi->swseq) + return intel_spi_sw_cycle(ispi, opcode, buf, len); + return intel_spi_hw_cycle(ispi, opcode, buf, len); +} + +static ssize_t intel_spi_read(struct spi_nor *nor, loff_t from, size_t len, + u_char *read_buf) +{ + struct intel_spi *ispi = nor->priv; + size_t block_size, retlen = 0; + u32 val, status; + ssize_t ret; + + switch (nor->read_opcode) { + case SPINOR_OP_READ: + case SPINOR_OP_READ_FAST: + break; + default: + return -EINVAL; + } + + while (len > 0) { + block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + + writel(from, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_READ; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "read error: %llx: %#x\n", from, + status); + return ret; + } + + ret = intel_spi_read_block(ispi, read_buf, block_size); + if (ret) + return ret; + + len -= block_size; + from += block_size; + retlen += block_size; + read_buf += block_size; + } + + return retlen; +} + +static ssize_t intel_spi_write(struct spi_nor *nor, loff_t to, size_t len, + const u_char *write_buf) +{ + struct intel_spi *ispi = nor->priv; + size_t block_size, retlen = 0; + u32 val, status; + ssize_t ret; + + while (len > 0) { + block_size = min_t(size_t, len, INTEL_SPI_FIFO_SZ); + + writel(to, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= (block_size - 1) << HSFSTS_CTL_FDBC_SHIFT; + val |= HSFSTS_CTL_FCYCLE_WRITE; + + /* Write enable */ + if (ispi->preopcodes[1] == SPINOR_OP_WREN) + val |= SSFSTS_CTL_SPOP; + val |= SSFSTS_CTL_ACS; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_write_block(ispi, write_buf, block_size); + if (ret) { + dev_err(ispi->dev, "failed to write block\n"); + return ret; + } + + /* Start the write now */ + val = readl(ispi->base + HSFSTS_CTL); + writel(val | HSFSTS_CTL_FGO, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) { + dev_err(ispi->dev, "timeout\n"); + return ret; + } + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + ret = -EIO; + else if (status & HSFSTS_CTL_AEL) + ret = -EACCES; + + if (ret < 0) { + dev_err(ispi->dev, "write error: %llx: %#x\n", to, + status); + return ret; + } + + len -= block_size; + to += block_size; + retlen += block_size; + write_buf += block_size; + } + + return retlen; +} + +static int intel_spi_erase(struct spi_nor *nor, loff_t offs) +{ + size_t erase_size, len = nor->mtd.erasesize; + struct intel_spi *ispi = nor->priv; + u32 val, status, cmd; + int ret; + + /* If the hardware can do 64k erase use that when possible */ + if (len >= SZ_64K && ispi->erase_64k) { + cmd = HSFSTS_CTL_FCYCLE_ERASE_64K; + erase_size = SZ_64K; + } else { + cmd = HSFSTS_CTL_FCYCLE_ERASE; + erase_size = SZ_4K; + } + + while (len > 0) { + writel(offs, ispi->base + FADDR); + + val = readl(ispi->base + HSFSTS_CTL); + val &= ~(HSFSTS_CTL_FDBC_MASK | HSFSTS_CTL_FCYCLE_MASK); + val |= HSFSTS_CTL_AEL | HSFSTS_CTL_FCERR | HSFSTS_CTL_FDONE; + val |= cmd; + val |= HSFSTS_CTL_FGO; + writel(val, ispi->base + HSFSTS_CTL); + + ret = intel_spi_wait_hw_busy(ispi); + if (ret) + return ret; + + status = readl(ispi->base + HSFSTS_CTL); + if (status & HSFSTS_CTL_FCERR) + return -EIO; + else if (status & HSFSTS_CTL_AEL) + return -EACCES; + + offs += erase_size; + len -= erase_size; + } + + return 0; +} + +static bool intel_spi_is_protected(const struct intel_spi *ispi, + unsigned int base, unsigned int limit) +{ + int i; + + for (i = 0; i < PR_NUM; i++) { + u32 pr_base, pr_limit, pr_value; + + pr_value = readl(ispi->pregs + PR(i)); + if (!(pr_value & (PR_WPE | PR_RPE))) + continue; + + pr_limit = (pr_value & PR_LIMIT_MASK) >> PR_LIMIT_SHIFT; + pr_base = pr_value & PR_BASE_MASK; + + if (pr_base >= base && pr_limit <= limit) + return true; + } + + return false; +} + +/* + * There will be a single partition holding all enabled flash regions. We + * call this "BIOS". + */ +static void intel_spi_fill_partition(struct intel_spi *ispi, + struct mtd_partition *part) +{ + u64 end; + int i; + + memset(part, 0, sizeof(*part)); + + /* Start from the mandatory descriptor region */ + part->size = 4096; + part->name = "BIOS"; + + /* + * Now try to find where this partition ends based on the flash + * region registers. + */ + for (i = 1; i < ispi->nregions; i++) { + u32 region, base, limit; + + region = readl(ispi->base + FREG(i)); + base = region & FREG_BASE_MASK; + limit = (region & FREG_LIMIT_MASK) >> FREG_LIMIT_SHIFT; + + if (base >= limit || limit == 0) + continue; + + /* + * If any of the regions have protection bits set, make the + * whole partition read-only to be on the safe side. + */ + if (intel_spi_is_protected(ispi, base, limit)) + ispi->writeable = 0; + + end = (limit << 12) + 4096; + if (end > part->size) + part->size = end; + } +} + +struct intel_spi *intel_spi_probe(struct device *dev, + struct resource *mem, const struct intel_spi_boardinfo *info) +{ + struct mtd_partition part; + struct intel_spi *ispi; + int ret; + + if (!info || !mem) + return ERR_PTR(-EINVAL); + + ispi = devm_kzalloc(dev, sizeof(*ispi), GFP_KERNEL); + if (!ispi) + return ERR_PTR(-ENOMEM); + + ispi->base = devm_ioremap_resource(dev, mem); + if (IS_ERR(ispi->base)) + return ispi->base; + + ispi->dev = dev; + ispi->info = info; + ispi->writeable = info->writeable; + + ret = intel_spi_init(ispi); + if (ret) + return ERR_PTR(ret); + + ispi->nor.dev = ispi->dev; + ispi->nor.priv = ispi; + ispi->nor.read_reg = intel_spi_read_reg; + ispi->nor.write_reg = intel_spi_write_reg; + ispi->nor.read = intel_spi_read; + ispi->nor.write = intel_spi_write; + ispi->nor.erase = intel_spi_erase; + + ret = spi_nor_scan(&ispi->nor, NULL, SPI_NOR_NORMAL); + if (ret) { + dev_info(dev, "failed to locate the chip\n"); + return ERR_PTR(ret); + } + + intel_spi_fill_partition(ispi, &part); + + /* Prevent writes if not explicitly enabled */ + if (!ispi->writeable || !writeable) + ispi->nor.mtd.flags &= ~MTD_WRITEABLE; + + ret = mtd_device_parse_register(&ispi->nor.mtd, NULL, NULL, &part, 1); + if (ret) + return ERR_PTR(ret); + + return ispi; +} +EXPORT_SYMBOL_GPL(intel_spi_probe); + +int intel_spi_remove(struct intel_spi *ispi) +{ + return mtd_device_unregister(&ispi->nor.mtd); +} +EXPORT_SYMBOL_GPL(intel_spi_remove); + +MODULE_DESCRIPTION("Intel PCH/PCU SPI flash core driver"); +MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mtd/spi-nor/intel-spi.h b/drivers/mtd/spi-nor/intel-spi.h new file mode 100644 index 000000000000..5ab7dc250050 --- /dev/null +++ b/drivers/mtd/spi-nor/intel-spi.h @@ -0,0 +1,24 @@ +/* + * Intel PCH/PCU SPI flash driver. + * + * Copyright (C) 2016, Intel Corporation + * Author: Mika Westerberg <mika.westerberg@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef INTEL_SPI_H +#define INTEL_SPI_H + +#include <linux/platform_data/intel-spi.h> + +struct intel_spi; +struct resource; + +struct intel_spi *intel_spi_probe(struct device *dev, + struct resource *mem, const struct intel_spi_boardinfo *info); +int intel_spi_remove(struct intel_spi *ispi); + +#endif /* INTEL_SPI_H */ diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index da7cd69d4857..1ae872bfc3ba 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -75,6 +75,16 @@ struct flash_info { * bit. Must be used with * SPI_NOR_HAS_LOCK. */ +#define SPI_S3AN BIT(10) /* + * Xilinx Spartan 3AN In-System Flash + * (MFR cannot be used for probing + * because it has the same value as + * ATMEL flashes) + */ +#define SPI_NOR_4B_OPCODES BIT(11) /* + * Use dedicated 4byte address op codes + * to support memory size above 128Mib. + */ }; #define JEDEC_MFR(info) ((info)->id[0]) @@ -122,7 +132,7 @@ static int read_fsr(struct spi_nor *nor) /* * Read configuration register, returning its value in the * location. Return the configuration register value. - * Returns negative if error occured. + * Returns negative if error occurred. */ static int read_cr(struct spi_nor *nor) { @@ -188,6 +198,78 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) return mtd->priv; } + +static u8 spi_nor_convert_opcode(u8 opcode, const u8 table[][2], size_t size) +{ + size_t i; + + for (i = 0; i < size; i++) + if (table[i][0] == opcode) + return table[i][1]; + + /* No conversion found, keep input op code. */ + return opcode; +} + +static inline u8 spi_nor_convert_3to4_read(u8 opcode) +{ + static const u8 spi_nor_3to4_read[][2] = { + { SPINOR_OP_READ, SPINOR_OP_READ_4B }, + { SPINOR_OP_READ_FAST, SPINOR_OP_READ_FAST_4B }, + { SPINOR_OP_READ_1_1_2, SPINOR_OP_READ_1_1_2_4B }, + { SPINOR_OP_READ_1_2_2, SPINOR_OP_READ_1_2_2_4B }, + { SPINOR_OP_READ_1_1_4, SPINOR_OP_READ_1_1_4_4B }, + { SPINOR_OP_READ_1_4_4, SPINOR_OP_READ_1_4_4_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_read, + ARRAY_SIZE(spi_nor_3to4_read)); +} + +static inline u8 spi_nor_convert_3to4_program(u8 opcode) +{ + static const u8 spi_nor_3to4_program[][2] = { + { SPINOR_OP_PP, SPINOR_OP_PP_4B }, + { SPINOR_OP_PP_1_1_4, SPINOR_OP_PP_1_1_4_4B }, + { SPINOR_OP_PP_1_4_4, SPINOR_OP_PP_1_4_4_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_program, + ARRAY_SIZE(spi_nor_3to4_program)); +} + +static inline u8 spi_nor_convert_3to4_erase(u8 opcode) +{ + static const u8 spi_nor_3to4_erase[][2] = { + { SPINOR_OP_BE_4K, SPINOR_OP_BE_4K_4B }, + { SPINOR_OP_BE_32K, SPINOR_OP_BE_32K_4B }, + { SPINOR_OP_SE, SPINOR_OP_SE_4B }, + }; + + return spi_nor_convert_opcode(opcode, spi_nor_3to4_erase, + ARRAY_SIZE(spi_nor_3to4_erase)); +} + +static void spi_nor_set_4byte_opcodes(struct spi_nor *nor, + const struct flash_info *info) +{ + /* Do some manufacturer fixups first */ + switch (JEDEC_MFR(info)) { + case SNOR_MFR_SPANSION: + /* No small sector erase for 4-byte command set */ + nor->erase_opcode = SPINOR_OP_SE; + nor->mtd.erasesize = info->sector_size; + break; + + default: + break; + } + + nor->read_opcode = spi_nor_convert_3to4_read(nor->read_opcode); + nor->program_opcode = spi_nor_convert_3to4_program(nor->program_opcode); + nor->erase_opcode = spi_nor_convert_3to4_erase(nor->erase_opcode); +} + /* Enable/disable 4-byte addressing mode. */ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) @@ -217,6 +299,21 @@ static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, return nor->write_reg(nor, SPINOR_OP_BRWR, nor->cmd_buf, 1); } } + +static int s3an_sr_ready(struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); + return ret; + } + + return !!(val & XSR_RDY); +} + static inline int spi_nor_sr_ready(struct spi_nor *nor) { int sr = read_sr(nor); @@ -238,7 +335,11 @@ static inline int spi_nor_fsr_ready(struct spi_nor *nor) static int spi_nor_ready(struct spi_nor *nor) { int sr, fsr; - sr = spi_nor_sr_ready(nor); + + if (nor->flags & SNOR_F_READY_XSR_RDY) + sr = s3an_sr_ready(nor); + else + sr = spi_nor_sr_ready(nor); if (sr < 0) return sr; fsr = nor->flags & SNOR_F_USE_FSR ? spi_nor_fsr_ready(nor) : 1; @@ -320,6 +421,27 @@ static void spi_nor_unlock_and_unprep(struct spi_nor *nor, enum spi_nor_ops ops) } /* + * This code converts an address to the Default Address Mode, that has non + * power of two page sizes. We must support this mode because it is the default + * mode supported by Xilinx tools, it can access the whole flash area and + * changing over to the Power-of-two mode is irreversible and corrupts the + * original data. + * Addr can safely be unsigned int, the biggest S3AN device is smaller than + * 4 MiB. + */ +static loff_t spi_nor_s3an_addr_convert(struct spi_nor *nor, unsigned int addr) +{ + unsigned int offset; + unsigned int page; + + offset = addr % nor->page_size; + page = addr / nor->page_size; + page <<= (nor->page_size > 512) ? 10 : 9; + + return page | offset; +} + +/* * Initiate the erasure of a single sector */ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) @@ -327,6 +449,9 @@ static int spi_nor_erase_sector(struct spi_nor *nor, u32 addr) u8 buf[SPI_NOR_MAX_ADDR_WIDTH]; int i; + if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) + addr = spi_nor_s3an_addr_convert(nor, addr); + if (nor->erase) return nor->erase(nor, addr); @@ -368,7 +493,7 @@ static int spi_nor_erase(struct mtd_info *mtd, struct erase_info *instr) return ret; /* whole-chip erase? */ - if (len == mtd->size) { + if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) { unsigned long timeout; write_enable(nor); @@ -782,6 +907,19 @@ static int spi_nor_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) .addr_width = (_addr_width), \ .flags = (_flags), +#define S3AN_INFO(_jedec_id, _n_sectors, _page_size) \ + .id = { \ + ((_jedec_id) >> 16) & 0xff, \ + ((_jedec_id) >> 8) & 0xff, \ + (_jedec_id) & 0xff \ + }, \ + .id_len = 3, \ + .sector_size = (8*_page_size), \ + .n_sectors = (_n_sectors), \ + .page_size = _page_size, \ + .addr_width = 3, \ + .flags = SPI_NOR_NO_FR | SPI_S3AN, + /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which * have been converging on command sets which including JEDEC ID. @@ -821,7 +959,7 @@ static const struct flash_info spi_nor_ids[] = { { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) }, /* ESMT */ - { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, + { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_HAS_LOCK) }, /* Everspin */ { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, @@ -833,6 +971,11 @@ static const struct flash_info spi_nor_ids[] = { /* GigaDevice */ { + "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32, + SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | + SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) + }, + { "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) @@ -1014,6 +1157,13 @@ static const struct flash_info spi_nor_ids[] = { { "cat25c09", CAT25_INFO( 128, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "cat25c17", CAT25_INFO( 256, 8, 32, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "cat25128", CAT25_INFO(2048, 8, 64, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + + /* Xilinx S3AN Internal Flash */ + { "3S50AN", S3AN_INFO(0x1f2200, 64, 264) }, + { "3S200AN", S3AN_INFO(0x1f2400, 256, 264) }, + { "3S400AN", S3AN_INFO(0x1f2400, 256, 264) }, + { "3S700AN", S3AN_INFO(0x1f2500, 512, 264) }, + { "3S1400AN", S3AN_INFO(0x1f2600, 512, 528) }, { }, }; @@ -1054,7 +1204,12 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len, return ret; while (len) { - ret = nor->read(nor, from, len, buf); + loff_t addr = from; + + if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) + addr = spi_nor_s3an_addr_convert(nor, addr); + + ret = nor->read(nor, addr, len, buf); if (ret == 0) { /* We shouldn't see 0-length reads */ ret = -EIO; @@ -1175,17 +1330,32 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len, for (i = 0; i < len; ) { ssize_t written; + loff_t addr = to + i; + + /* + * If page_size is a power of two, the offset can be quickly + * calculated with an AND operation. On the other cases we + * need to do a modulus operation (more expensive). + * Power of two numbers have only one bit set and we can use + * the instruction hweight32 to detect if we need to do a + * modulus (do_div()) or not. + */ + if (hweight32(nor->page_size) == 1) { + page_offset = addr & (nor->page_size - 1); + } else { + uint64_t aux = addr; - page_offset = (to + i) & (nor->page_size - 1); - WARN_ONCE(page_offset, - "Writing at offset %zu into a NOR page. Writing partial pages may decrease reliability and increase wear of NOR flash.", - page_offset); + page_offset = do_div(aux, nor->page_size); + } /* the size of data remaining on the first page */ page_remain = min_t(size_t, nor->page_size - page_offset, len - i); + if (nor->flags & SNOR_F_S3AN_ADDR_DEFAULT) + addr = spi_nor_s3an_addr_convert(nor, addr); + write_enable(nor); - ret = nor->write(nor, to + i, page_remain, buf + i); + ret = nor->write(nor, addr, page_remain, buf + i); if (ret < 0) goto write_err; written = ret; @@ -1216,6 +1386,9 @@ static int macronix_quad_enable(struct spi_nor *nor) val = read_sr(nor); if (val < 0) return val; + if (val & SR_QUAD_EN_MX) + return 0; + write_enable(nor); write_sr(nor, val | SR_QUAD_EN_MX); @@ -1236,7 +1409,7 @@ static int macronix_quad_enable(struct spi_nor *nor) * Write status Register and configuration register with 2 bytes * The first byte will be written to the status register, while the * second byte will be written to the configuration register. - * Return negative if error occured. + * Return negative if error occurred. */ static int write_sr_cr(struct spi_nor *nor, u16 val) { @@ -1312,6 +1485,47 @@ static int spi_nor_check(struct spi_nor *nor) return 0; } +static int s3an_nor_scan(const struct flash_info *info, struct spi_nor *nor) +{ + int ret; + u8 val; + + ret = nor->read_reg(nor, SPINOR_OP_XRDSR, &val, 1); + if (ret < 0) { + dev_err(nor->dev, "error %d reading XRDSR\n", (int) ret); + return ret; + } + + nor->erase_opcode = SPINOR_OP_XSE; + nor->program_opcode = SPINOR_OP_XPP; + nor->read_opcode = SPINOR_OP_READ; + nor->flags |= SNOR_F_NO_OP_CHIP_ERASE; + + /* + * This flashes have a page size of 264 or 528 bytes (known as + * Default addressing mode). It can be changed to a more standard + * Power of two mode where the page size is 256/512. This comes + * with a price: there is 3% less of space, the data is corrupted + * and the page size cannot be changed back to default addressing + * mode. + * + * The current addressing mode can be read from the XRDSR register + * and should not be changed, because is a destructive operation. + */ + if (val & XSR_PAGESIZE) { + /* Flash in Power of 2 mode */ + nor->page_size = (nor->page_size == 264) ? 256 : 512; + nor->mtd.writebufsize = nor->page_size; + nor->mtd.size = 8 * nor->page_size * info->n_sectors; + nor->mtd.erasesize = 8 * nor->page_size; + } else { + /* Flash in Default addressing mode */ + nor->flags |= SNOR_F_S3AN_ADDR_DEFAULT; + } + + return 0; +} + int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { const struct flash_info *info = NULL; @@ -1360,6 +1574,14 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) mutex_init(&nor->lock); /* + * Make sure the XSR_RDY flag is set before calling + * spi_nor_wait_till_ready(). Xilinx S3AN share MFR + * with Atmel spi-nor + */ + if (info->flags & SPI_S3AN) + nor->flags |= SNOR_F_READY_XSR_RDY; + + /* * Atmel, SST, Intel/Numonyx, and others serial NOR tend to power up * with the software protection bits set */ @@ -1483,27 +1705,10 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) else if (mtd->size > 0x1000000) { /* enable 4-byte addressing if the device exceeds 16MiB */ nor->addr_width = 4; - if (JEDEC_MFR(info) == SNOR_MFR_SPANSION) { - /* Dedicated 4-byte command set */ - switch (nor->flash_read) { - case SPI_NOR_QUAD: - nor->read_opcode = SPINOR_OP_READ4_1_1_4; - break; - case SPI_NOR_DUAL: - nor->read_opcode = SPINOR_OP_READ4_1_1_2; - break; - case SPI_NOR_FAST: - nor->read_opcode = SPINOR_OP_READ4_FAST; - break; - case SPI_NOR_NORMAL: - nor->read_opcode = SPINOR_OP_READ4; - break; - } - nor->program_opcode = SPINOR_OP_PP_4B; - /* No small sector erase for 4-byte command set */ - nor->erase_opcode = SPINOR_OP_SE_4B; - mtd->erasesize = info->sector_size; - } else + if (JEDEC_MFR(info) == SNOR_MFR_SPANSION || + info->flags & SPI_NOR_4B_OPCODES) + spi_nor_set_4byte_opcodes(nor, info); + else set_4byte(nor, info, 1); } else { nor->addr_width = 3; @@ -1517,6 +1722,12 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) nor->read_dummy = spi_nor_read_dummy_cycles(nor); + if (info->flags & SPI_S3AN) { + ret = s3an_nor_scan(info, nor); + if (ret) + return ret; + } + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c index d1e6931c132f..c80869e60909 100644 --- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -323,16 +323,15 @@ static int ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx, struct ubiblock *dev = hctx->queue->queuedata; struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req); - if (req->cmd_type != REQ_TYPE_FS) + switch (req_op(req)) { + case REQ_OP_READ: + ubi_sgl_init(&pdu->usgl); + queue_work(dev->wq, &pdu->work); + return BLK_MQ_RQ_QUEUE_OK; + default: return BLK_MQ_RQ_QUEUE_ERROR; + } - if (rq_data_dir(req) != READ) - return BLK_MQ_RQ_QUEUE_ERROR; /* Write not implemented */ - - ubi_sgl_init(&pdu->usgl); - queue_work(dev->wq, &pdu->work); - - return BLK_MQ_RQ_QUEUE_OK; } static int ubiblock_init_request(void *data, struct request *req, diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index b8c293373ecc..a306de4318d7 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -190,7 +190,7 @@ static netdev_tx_t ipddp_xmit(struct sk_buff *skb, struct net_device *dev) */ static int ipddp_create(struct ipddp_route *new_rt) { - struct ipddp_route *rt = kmalloc(sizeof(*rt), GFP_KERNEL); + struct ipddp_route *rt = kzalloc(sizeof(*rt), GFP_KERNEL); if (rt == NULL) return -ENOMEM; diff --git a/drivers/net/can/c_can/c_can_pci.c b/drivers/net/can/c_can/c_can_pci.c index 7be393c96b1a..cf7c18947189 100644 --- a/drivers/net/can/c_can/c_can_pci.c +++ b/drivers/net/can/c_can/c_can_pci.c @@ -161,6 +161,7 @@ static int c_can_pci_probe(struct pci_dev *pdev, dev->irq = pdev->irq; priv->base = addr; + priv->device = &pdev->dev; if (!c_can_pci_data->freq) { dev_err(&pdev->dev, "no clock frequency defined\n"); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 680d1ff07a55..6749b1829469 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -948,7 +948,12 @@ static int ti_hecc_probe(struct platform_device *pdev) netif_napi_add(ndev, &priv->napi, ti_hecc_rx_poll, HECC_DEF_NAPI_WEIGHT); - clk_enable(priv->clk); + err = clk_prepare_enable(priv->clk); + if (err) { + dev_err(&pdev->dev, "clk_prepare_enable() failed\n"); + goto probe_exit_clk; + } + err = register_candev(ndev); if (err) { dev_err(&pdev->dev, "register_candev() failed\n"); @@ -981,7 +986,7 @@ static int ti_hecc_remove(struct platform_device *pdev) struct ti_hecc_priv *priv = netdev_priv(ndev); unregister_candev(ndev); - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); clk_put(priv->clk); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); iounmap(priv->base); @@ -1006,7 +1011,7 @@ static int ti_hecc_suspend(struct platform_device *pdev, pm_message_t state) hecc_set_bit(priv, HECC_CANMC, HECC_CANMC_PDR); priv->can.state = CAN_STATE_SLEEPING; - clk_disable(priv->clk); + clk_disable_unprepare(priv->clk); return 0; } @@ -1015,8 +1020,11 @@ static int ti_hecc_resume(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); struct ti_hecc_priv *priv = netdev_priv(dev); + int err; - clk_enable(priv->clk); + err = clk_prepare_enable(priv->clk); + if (err) + return err; hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_PDR); priv->can.state = CAN_STATE_ERROR_ACTIVE; diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 9ec33b51a0ed..2ce7ae97ac91 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -393,7 +393,7 @@ static int bcm_sf2_sw_mdio_read(struct mii_bus *bus, int addr, int regnum) if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) return bcm_sf2_sw_indir_rw(priv, 1, addr, regnum, 0); else - return mdiobus_read(priv->master_mii_bus, addr, regnum); + return mdiobus_read_nested(priv->master_mii_bus, addr, regnum); } static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, @@ -407,7 +407,7 @@ static int bcm_sf2_sw_mdio_write(struct mii_bus *bus, int addr, int regnum, if (addr == BRCM_PSEUDO_PHY_ADDR && priv->indir_phy_mask & BIT(addr)) bcm_sf2_sw_indir_rw(priv, 0, addr, regnum, val); else - mdiobus_write(priv->master_mii_bus, addr, regnum, val); + mdiobus_write_nested(priv->master_mii_bus, addr, regnum, val); return 0; } @@ -982,6 +982,7 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; struct device_node *dn = pdev->dev.of_node; struct b53_platform_data *pdata; + struct dsa_switch_ops *ops; struct bcm_sf2_priv *priv; struct b53_device *dev; struct dsa_switch *ds; @@ -995,6 +996,10 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + ops = devm_kzalloc(&pdev->dev, sizeof(*ops), GFP_KERNEL); + if (!ops) + return -ENOMEM; + dev = b53_switch_alloc(&pdev->dev, &bcm_sf2_io_ops, priv); if (!dev) return -ENOMEM; @@ -1014,6 +1019,8 @@ static int bcm_sf2_sw_probe(struct platform_device *pdev) ds = dev->ds; /* Override the parts that are non-standard wrt. normal b53 devices */ + memcpy(ops, ds->ops, sizeof(*ops)); + ds->ops = ops; ds->ops->get_tag_protocol = bcm_sf2_sw_get_tag_protocol; ds->ops->setup = bcm_sf2_sw_setup; ds->ops->get_phy_flags = bcm_sf2_sw_get_phy_flags; diff --git a/drivers/net/ethernet/adaptec/starfire.c b/drivers/net/ethernet/adaptec/starfire.c index c12d2618eebf..3872ab96b80a 100644 --- a/drivers/net/ethernet/adaptec/starfire.c +++ b/drivers/net/ethernet/adaptec/starfire.c @@ -1152,6 +1152,12 @@ static void init_ring(struct net_device *dev) if (skb == NULL) break; np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(np->pci_dev, + np->rx_info[i].mapping)) { + dev_kfree_skb(skb); + np->rx_info[i].skb = NULL; + break; + } /* Grrr, we cannot offset to correctly align the IP header. */ np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid); } @@ -1182,8 +1188,9 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); unsigned int entry; + unsigned int prev_tx; u32 status; - int i; + int i, j; /* * be cautious here, wrapping the queue has weird semantics @@ -1201,6 +1208,7 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) } #endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */ + prev_tx = np->cur_tx; entry = np->cur_tx % TX_RING_SIZE; for (i = 0; i < skb_num_frags(skb); i++) { int wrap_ring = 0; @@ -1234,6 +1242,11 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) skb_frag_size(this_frag), PCI_DMA_TODEVICE); } + if (pci_dma_mapping_error(np->pci_dev, + np->tx_info[entry].mapping)) { + dev->stats.tx_dropped++; + goto err_out; + } np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping); np->tx_ring[entry].status = cpu_to_le32(status); @@ -1268,8 +1281,30 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); return NETDEV_TX_OK; -} +err_out: + entry = prev_tx % TX_RING_SIZE; + np->tx_info[entry].skb = NULL; + if (i > 0) { + pci_unmap_single(np->pci_dev, + np->tx_info[entry].mapping, + skb_first_frag_len(skb), + PCI_DMA_TODEVICE); + np->tx_info[entry].mapping = 0; + entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE; + for (j = 1; j < i; j++) { + pci_unmap_single(np->pci_dev, + np->tx_info[entry].mapping, + skb_frag_size( + &skb_shinfo(skb)->frags[j-1]), + PCI_DMA_TODEVICE); + entry++; + } + } + dev_kfree_skb_any(skb); + np->cur_tx = prev_tx; + return NETDEV_TX_OK; +} /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ @@ -1569,6 +1604,12 @@ static void refill_rx_ring(struct net_device *dev) break; /* Better luck next round. */ np->rx_info[entry].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(np->pci_dev, + np->rx_info[entry].mapping)) { + dev_kfree_skb(skb); + np->rx_info[entry].skb = NULL; + break; + } np->rx_ring[entry].rxaddr = cpu_to_dma(np->rx_info[entry].mapping | RxDescValid); } diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h index 5b7ba25e0065..8a280e7d66bd 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h @@ -891,6 +891,8 @@ #define PCS_V1_WINDOW_SELECT 0x03fc #define PCS_V2_WINDOW_DEF 0x9060 #define PCS_V2_WINDOW_SELECT 0x9064 +#define PCS_V2_RV_WINDOW_DEF 0x1060 +#define PCS_V2_RV_WINDOW_SELECT 0x1064 /* PCS register entry bit positions and sizes */ #define PCS_V2_WINDOW_DEF_OFFSET_INDEX 6 diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c index aaf0350076a9..a7d16db5c4b2 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c @@ -1151,7 +1151,7 @@ static int xgbe_read_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad, offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); spin_lock_irqsave(&pdata->xpcs_lock, flags); - XPCS32_IOWRITE(pdata, PCS_V2_WINDOW_SELECT, index); + XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index); mmd_data = XPCS16_IOREAD(pdata, offset); spin_unlock_irqrestore(&pdata->xpcs_lock, flags); @@ -1183,7 +1183,7 @@ static void xgbe_write_mmd_regs_v2(struct xgbe_prv_data *pdata, int prtad, offset = pdata->xpcs_window + (mmd_address & pdata->xpcs_window_mask); spin_lock_irqsave(&pdata->xpcs_lock, flags); - XPCS32_IOWRITE(pdata, PCS_V2_WINDOW_SELECT, index); + XPCS32_IOWRITE(pdata, pdata->xpcs_window_sel_reg, index); XPCS16_IOWRITE(pdata, offset, mmd_data); spin_unlock_irqrestore(&pdata->xpcs_lock, flags); } @@ -3407,8 +3407,10 @@ static int xgbe_init(struct xgbe_prv_data *pdata) /* Flush Tx queues */ ret = xgbe_flush_tx_queues(pdata); - if (ret) + if (ret) { + netdev_err(pdata->netdev, "error flushing TX queues\n"); return ret; + } /* * Initialize DMA related features diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c index 155190db682d..1c87cc204075 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c @@ -539,6 +539,7 @@ static irqreturn_t xgbe_isr(int irq, void *data) } } +isr_done: /* If there is not a separate AN irq, handle it here */ if (pdata->dev_irq == pdata->an_irq) pdata->phy_if.an_isr(irq, pdata); @@ -551,7 +552,6 @@ static irqreturn_t xgbe_isr(int irq, void *data) if (pdata->vdata->i2c_support && (pdata->dev_irq == pdata->i2c_irq)) pdata->i2c_if.i2c_isr(irq, pdata); -isr_done: return IRQ_HANDLED; } @@ -1070,7 +1070,9 @@ static int xgbe_start(struct xgbe_prv_data *pdata) DBGPR("-->xgbe_start\n"); - hw_if->init(pdata); + ret = hw_if->init(pdata); + if (ret) + return ret; xgbe_napi_enable(pdata, 1); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c index e76b7f65b805..c2730f15bd8b 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c @@ -265,6 +265,7 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct xgbe_prv_data *pdata; struct device *dev = &pdev->dev; void __iomem * const *iomap_table; + struct pci_dev *rdev; unsigned int ma_lo, ma_hi; unsigned int reg; int bar_mask; @@ -326,8 +327,20 @@ static int xgbe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (netif_msg_probe(pdata)) dev_dbg(dev, "xpcs_regs = %p\n", pdata->xpcs_regs); + /* Set the PCS indirect addressing definition registers */ + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (rdev && + (rdev->vendor == PCI_VENDOR_ID_AMD) && (rdev->device == 0x15d0)) { + pdata->xpcs_window_def_reg = PCS_V2_RV_WINDOW_DEF; + pdata->xpcs_window_sel_reg = PCS_V2_RV_WINDOW_SELECT; + } else { + pdata->xpcs_window_def_reg = PCS_V2_WINDOW_DEF; + pdata->xpcs_window_sel_reg = PCS_V2_WINDOW_SELECT; + } + pci_dev_put(rdev); + /* Configure the PCS indirect addressing support */ - reg = XPCS32_IOREAD(pdata, PCS_V2_WINDOW_DEF); + reg = XPCS32_IOREAD(pdata, pdata->xpcs_window_def_reg); pdata->xpcs_window = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, OFFSET); pdata->xpcs_window <<= 6; pdata->xpcs_window_size = XPCS_GET_BITS(reg, PCS_V2_WINDOW_DEF, SIZE); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h index f52a9bd05bac..00108815b55e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe.h +++ b/drivers/net/ethernet/amd/xgbe/xgbe.h @@ -955,6 +955,8 @@ struct xgbe_prv_data { /* XPCS indirect addressing lock */ spinlock_t xpcs_lock; + unsigned int xpcs_window_def_reg; + unsigned int xpcs_window_sel_reg; unsigned int xpcs_window; unsigned int xpcs_window_size; unsigned int xpcs_window_mask; diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c8f525574d68..7dcc907a449d 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -685,8 +685,6 @@ static int alx_alloc_rings(struct alx_priv *alx) return -ENOMEM; } - alx_reinit_rings(alx); - return 0; } @@ -703,7 +701,7 @@ static void alx_free_rings(struct alx_priv *alx) if (alx->qnapi[0] && alx->qnapi[0]->rxq) kfree(alx->qnapi[0]->rxq->bufs); - if (!alx->descmem.virt) + if (alx->descmem.virt) dma_free_coherent(&alx->hw.pdev->dev, alx->descmem.size, alx->descmem.virt, @@ -984,6 +982,7 @@ static int alx_realloc_resources(struct alx_priv *alx) alx_free_rings(alx); alx_free_napis(alx); alx_disable_advanced_intr(alx); + alx_init_intr(alx, false); err = alx_alloc_napis(alx); if (err) @@ -1241,6 +1240,12 @@ static int __alx_open(struct alx_priv *alx, bool resume) if (err) goto out_free_rings; + /* must be called after alx_request_irq because the chip stops working + * if we copy the dma addresses in alx_init_ring_ptrs twice when + * requesting msi-x interrupts failed + */ + alx_reinit_rings(alx); + netif_set_real_num_tx_queues(alx->dev, alx->num_txq); netif_set_real_num_rx_queues(alx->dev, alx->num_rxq); diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.c b/drivers/net/ethernet/broadcom/bcm63xx_enet.c index 3b14d5144228..c483618b57bd 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.c +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.c @@ -913,6 +913,8 @@ static int bcm_enet_open(struct net_device *dev) priv->old_link = 0; priv->old_duplex = -1; priv->old_pause = -1; + } else { + phydev = NULL; } /* mask all interrupts and request them */ @@ -1083,7 +1085,7 @@ static int bcm_enet_open(struct net_device *dev) enet_dmac_writel(priv, priv->dma_chan_int_mask, ENETDMAC_IRMASK, priv->tx_chan); - if (priv->has_phy) + if (phydev) phy_start(phydev); else bcm_enet_adjust_link(dev); @@ -1126,7 +1128,7 @@ out_freeirq: free_irq(dev->irq, dev); out_phy_disconnect: - if (priv->has_phy) + if (phydev) phy_disconnect(phydev); return ret; diff --git a/drivers/net/ethernet/broadcom/bcmsysport.c b/drivers/net/ethernet/broadcom/bcmsysport.c index 25d1eb4933d0..744ed6ddaf37 100644 --- a/drivers/net/ethernet/broadcom/bcmsysport.c +++ b/drivers/net/ethernet/broadcom/bcmsysport.c @@ -710,11 +710,8 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, unsigned int c_index, last_c_index, last_tx_cn, num_tx_cbs; unsigned int pkts_compl = 0, bytes_compl = 0; struct bcm_sysport_cb *cb; - struct netdev_queue *txq; u32 hw_ind; - txq = netdev_get_tx_queue(ndev, ring->index); - /* Compute how many descriptors have been processed since last call */ hw_ind = tdma_readl(priv, TDMA_DESC_RING_PROD_CONS_INDEX(ring->index)); c_index = (hw_ind >> RING_CONS_INDEX_SHIFT) & RING_CONS_INDEX_MASK; @@ -745,9 +742,6 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, ring->c_index = c_index; - if (netif_tx_queue_stopped(txq) && pkts_compl) - netif_tx_wake_queue(txq); - netif_dbg(priv, tx_done, ndev, "ring=%d c_index=%d pkts_compl=%d, bytes_compl=%d\n", ring->index, ring->c_index, pkts_compl, bytes_compl); @@ -759,16 +753,33 @@ static unsigned int __bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, static unsigned int bcm_sysport_tx_reclaim(struct bcm_sysport_priv *priv, struct bcm_sysport_tx_ring *ring) { + struct netdev_queue *txq; unsigned int released; unsigned long flags; + txq = netdev_get_tx_queue(priv->netdev, ring->index); + spin_lock_irqsave(&ring->lock, flags); released = __bcm_sysport_tx_reclaim(priv, ring); + if (released) + netif_tx_wake_queue(txq); + spin_unlock_irqrestore(&ring->lock, flags); return released; } +/* Locked version of the per-ring TX reclaim, but does not wake the queue */ +static void bcm_sysport_tx_clean(struct bcm_sysport_priv *priv, + struct bcm_sysport_tx_ring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + __bcm_sysport_tx_reclaim(priv, ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + static int bcm_sysport_tx_poll(struct napi_struct *napi, int budget) { struct bcm_sysport_tx_ring *ring = @@ -1012,15 +1023,6 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, goto out; } - /* Insert TSB and checksum infos */ - if (priv->tsb_en) { - skb = bcm_sysport_insert_tsb(skb, dev); - if (!skb) { - ret = NETDEV_TX_OK; - goto out; - } - } - /* The Ethernet switch we are interfaced with needs packets to be at * least 64 bytes (including FCS) otherwise they will be discarded when * they enter the switch port logic. When Broadcom tags are enabled, we @@ -1028,13 +1030,21 @@ static netdev_tx_t bcm_sysport_xmit(struct sk_buff *skb, * (including FCS and tag) because the length verification is done after * the Broadcom tag is stripped off the ingress packet. */ - if (skb_padto(skb, ETH_ZLEN + ENET_BRCM_TAG_LEN)) { + if (skb_put_padto(skb, ETH_ZLEN + ENET_BRCM_TAG_LEN)) { ret = NETDEV_TX_OK; goto out; } - skb_len = skb->len < ETH_ZLEN + ENET_BRCM_TAG_LEN ? - ETH_ZLEN + ENET_BRCM_TAG_LEN : skb->len; + /* Insert TSB and checksum infos */ + if (priv->tsb_en) { + skb = bcm_sysport_insert_tsb(skb, dev); + if (!skb) { + ret = NETDEV_TX_OK; + goto out; + } + } + + skb_len = skb->len; mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE); if (dma_mapping_error(kdev, mapping)) { @@ -1253,7 +1263,7 @@ static void bcm_sysport_fini_tx_ring(struct bcm_sysport_priv *priv, napi_disable(&ring->napi); netif_napi_del(&ring->napi); - bcm_sysport_tx_reclaim(priv, ring); + bcm_sysport_tx_clean(priv, ring); kfree(ring->cbs); ring->cbs = NULL; diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 9608cb49a11c..4fcc6a84a087 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -1099,7 +1099,7 @@ static struct sk_buff *bnxt_gro_func_5730x(struct bnxt_tpa_info *tpa_info, { #ifdef CONFIG_INET struct tcphdr *th; - int len, nw_off, tcp_opt_len; + int len, nw_off, tcp_opt_len = 0; if (tcp_ts) tcp_opt_len = 12; @@ -5314,17 +5314,12 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state) if ((link_info->support_auto_speeds | diff) != link_info->support_auto_speeds) { /* An advertised speed is no longer supported, so we need to - * update the advertisement settings. See bnxt_reset() for - * comments about the rtnl_lock() sequence below. + * update the advertisement settings. Caller holds RTNL + * so we can modify link settings. */ - clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); - rtnl_lock(); link_info->advertising = link_info->support_auto_speeds; - if (test_bit(BNXT_STATE_OPEN, &bp->state) && - (link_info->autoneg & BNXT_AUTONEG_SPEED)) + if (link_info->autoneg & BNXT_AUTONEG_SPEED) bnxt_hwrm_set_link_setting(bp, true, false); - set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); - rtnl_unlock(); } return 0; } @@ -6200,29 +6195,37 @@ bnxt_restart_timer: mod_timer(&bp->timer, jiffies + bp->current_interval); } -/* Only called from bnxt_sp_task() */ -static void bnxt_reset(struct bnxt *bp, bool silent) +static void bnxt_rtnl_lock_sp(struct bnxt *bp) { - /* bnxt_reset_task() calls bnxt_close_nic() which waits - * for BNXT_STATE_IN_SP_TASK to clear. - * If there is a parallel dev_close(), bnxt_close() may be holding + /* We are called from bnxt_sp_task which has BNXT_STATE_IN_SP_TASK + * set. If the device is being closed, bnxt_close() may be holding * rtnl() and waiting for BNXT_STATE_IN_SP_TASK to clear. So we * must clear BNXT_STATE_IN_SP_TASK before holding rtnl(). */ clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); rtnl_lock(); - if (test_bit(BNXT_STATE_OPEN, &bp->state)) - bnxt_reset_task(bp, silent); +} + +static void bnxt_rtnl_unlock_sp(struct bnxt *bp) +{ set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); rtnl_unlock(); } +/* Only called from bnxt_sp_task() */ +static void bnxt_reset(struct bnxt *bp, bool silent) +{ + bnxt_rtnl_lock_sp(bp); + if (test_bit(BNXT_STATE_OPEN, &bp->state)) + bnxt_reset_task(bp, silent); + bnxt_rtnl_unlock_sp(bp); +} + static void bnxt_cfg_ntp_filters(struct bnxt *); static void bnxt_sp_task(struct work_struct *work) { struct bnxt *bp = container_of(work, struct bnxt, sp_task); - int rc; set_bit(BNXT_STATE_IN_SP_TASK, &bp->state); smp_mb__after_atomic(); @@ -6236,16 +6239,6 @@ static void bnxt_sp_task(struct work_struct *work) if (test_and_clear_bit(BNXT_RX_NTP_FLTR_SP_EVENT, &bp->sp_event)) bnxt_cfg_ntp_filters(bp); - if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) { - if (test_and_clear_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, - &bp->sp_event)) - bnxt_hwrm_phy_qcaps(bp); - - rc = bnxt_update_link(bp, true); - if (rc) - netdev_err(bp->dev, "SP task can't update link (rc: %x)\n", - rc); - } if (test_and_clear_bit(BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT, &bp->sp_event)) bnxt_hwrm_exec_fwd_req(bp); if (test_and_clear_bit(BNXT_VXLAN_ADD_PORT_SP_EVENT, &bp->sp_event)) { @@ -6266,18 +6259,39 @@ static void bnxt_sp_task(struct work_struct *work) bnxt_hwrm_tunnel_dst_port_free( bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_GENEVE); } + if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) + bnxt_hwrm_port_qstats(bp); + + /* These functions below will clear BNXT_STATE_IN_SP_TASK. They + * must be the last functions to be called before exiting. + */ + if (test_and_clear_bit(BNXT_LINK_CHNG_SP_EVENT, &bp->sp_event)) { + int rc = 0; + + if (test_and_clear_bit(BNXT_LINK_SPEED_CHNG_SP_EVENT, + &bp->sp_event)) + bnxt_hwrm_phy_qcaps(bp); + + bnxt_rtnl_lock_sp(bp); + if (test_bit(BNXT_STATE_OPEN, &bp->state)) + rc = bnxt_update_link(bp, true); + bnxt_rtnl_unlock_sp(bp); + if (rc) + netdev_err(bp->dev, "SP task can't update link (rc: %x)\n", + rc); + } + if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) { + bnxt_rtnl_lock_sp(bp); + if (test_bit(BNXT_STATE_OPEN, &bp->state)) + bnxt_get_port_module_status(bp); + bnxt_rtnl_unlock_sp(bp); + } if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) bnxt_reset(bp, false); if (test_and_clear_bit(BNXT_RESET_TASK_SILENT_SP_EVENT, &bp->sp_event)) bnxt_reset(bp, true); - if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event)) - bnxt_get_port_module_status(bp); - - if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event)) - bnxt_hwrm_port_qstats(bp); - smp_mb__before_atomic(); clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state); } diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 185e9e047aa9..ae42de4fdddf 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -8720,11 +8720,14 @@ static void tg3_free_consistent(struct tg3 *tp) tg3_mem_rx_release(tp); tg3_mem_tx_release(tp); + /* Protect tg3_get_stats64() from reading freed tp->hw_stats. */ + tg3_full_lock(tp, 0); if (tp->hw_stats) { dma_free_coherent(&tp->pdev->dev, sizeof(struct tg3_hw_stats), tp->hw_stats, tp->stats_mapping); tp->hw_stats = NULL; } + tg3_full_unlock(tp); } /* diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index c0fb80acc2da..baba2db9d9c2 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -43,13 +43,13 @@ #define DEFAULT_RX_RING_SIZE 512 /* must be power of 2 */ #define MIN_RX_RING_SIZE 64 #define MAX_RX_RING_SIZE 8192 -#define RX_RING_BYTES(bp) (sizeof(struct macb_dma_desc) \ +#define RX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ * (bp)->rx_ring_size) #define DEFAULT_TX_RING_SIZE 512 /* must be power of 2 */ #define MIN_TX_RING_SIZE 64 #define MAX_TX_RING_SIZE 4096 -#define TX_RING_BYTES(bp) (sizeof(struct macb_dma_desc) \ +#define TX_RING_BYTES(bp) (macb_dma_desc_get_size(bp) \ * (bp)->tx_ring_size) /* level of occupied TX descriptors under which we wake up TX process */ @@ -78,6 +78,37 @@ */ #define MACB_HALT_TIMEOUT 1230 +/* DMA buffer descriptor might be different size + * depends on hardware configuration. + */ +static unsigned int macb_dma_desc_get_size(struct macb *bp) +{ +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + return sizeof(struct macb_dma_desc) + sizeof(struct macb_dma_desc_64); +#endif + return sizeof(struct macb_dma_desc); +} + +static unsigned int macb_adj_dma_desc_idx(struct macb *bp, unsigned int idx) +{ +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + /* Dma buffer descriptor is 4 words length (instead of 2 words) + * for 64b GEM. + */ + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + idx <<= 1; +#endif + return idx; +} + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT +static struct macb_dma_desc_64 *macb_64b_desc(struct macb *bp, struct macb_dma_desc *desc) +{ + return (struct macb_dma_desc_64 *)((void *)desc + sizeof(struct macb_dma_desc)); +} +#endif + /* Ring buffer accessors */ static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index) { @@ -87,7 +118,9 @@ static unsigned int macb_tx_ring_wrap(struct macb *bp, unsigned int index) static struct macb_dma_desc *macb_tx_desc(struct macb_queue *queue, unsigned int index) { - return &queue->tx_ring[macb_tx_ring_wrap(queue->bp, index)]; + index = macb_tx_ring_wrap(queue->bp, index); + index = macb_adj_dma_desc_idx(queue->bp, index); + return &queue->tx_ring[index]; } static struct macb_tx_skb *macb_tx_skb(struct macb_queue *queue, @@ -101,7 +134,7 @@ static dma_addr_t macb_tx_dma(struct macb_queue *queue, unsigned int index) dma_addr_t offset; offset = macb_tx_ring_wrap(queue->bp, index) * - sizeof(struct macb_dma_desc); + macb_dma_desc_get_size(queue->bp); return queue->tx_ring_dma + offset; } @@ -113,7 +146,9 @@ static unsigned int macb_rx_ring_wrap(struct macb *bp, unsigned int index) static struct macb_dma_desc *macb_rx_desc(struct macb *bp, unsigned int index) { - return &bp->rx_ring[macb_rx_ring_wrap(bp, index)]; + index = macb_rx_ring_wrap(bp, index); + index = macb_adj_dma_desc_idx(bp, index); + return &bp->rx_ring[index]; } static void *macb_rx_buffer(struct macb *bp, unsigned int index) @@ -560,12 +595,32 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb) } } -static inline void macb_set_addr(struct macb_dma_desc *desc, dma_addr_t addr) +static void macb_set_addr(struct macb *bp, struct macb_dma_desc *desc, dma_addr_t addr) { - desc->addr = (u32)addr; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - desc->addrh = (u32)(addr >> 32); + struct macb_dma_desc_64 *desc_64; + + if (bp->hw_dma_cap == HW_DMA_CAP_64B) { + desc_64 = macb_64b_desc(bp, desc); + desc_64->addrh = upper_32_bits(addr); + } #endif + desc->addr = lower_32_bits(addr); +} + +static dma_addr_t macb_get_addr(struct macb *bp, struct macb_dma_desc *desc) +{ + dma_addr_t addr = 0; +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + struct macb_dma_desc_64 *desc_64; + + if (bp->hw_dma_cap == HW_DMA_CAP_64B) { + desc_64 = macb_64b_desc(bp, desc); + addr = ((u64)(desc_64->addrh) << 32); + } +#endif + addr |= MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); + return addr; } static void macb_tx_error_task(struct work_struct *work) @@ -649,16 +704,17 @@ static void macb_tx_error_task(struct work_struct *work) /* Set end of TX queue */ desc = macb_tx_desc(queue, 0); - macb_set_addr(desc, 0); + macb_set_addr(bp, desc, 0); desc->ctrl = MACB_BIT(TX_USED); /* Make descriptor updates visible to hardware */ wmb(); /* Reinitialize the TX desc queue */ - queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma)); + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32)); + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif /* Make TX ring reflect state of hardware */ queue->tx_head = 0; @@ -750,6 +806,7 @@ static void gem_rx_refill(struct macb *bp) unsigned int entry; struct sk_buff *skb; dma_addr_t paddr; + struct macb_dma_desc *desc; while (CIRC_SPACE(bp->rx_prepared_head, bp->rx_tail, bp->rx_ring_size) > 0) { @@ -759,6 +816,7 @@ static void gem_rx_refill(struct macb *bp) rmb(); bp->rx_prepared_head++; + desc = macb_rx_desc(bp, entry); if (!bp->rx_skbuff[entry]) { /* allocate sk_buff for this free entry in ring */ @@ -782,14 +840,14 @@ static void gem_rx_refill(struct macb *bp) if (entry == bp->rx_ring_size - 1) paddr |= MACB_BIT(RX_WRAP); - macb_set_addr(&(bp->rx_ring[entry]), paddr); - bp->rx_ring[entry].ctrl = 0; + macb_set_addr(bp, desc, paddr); + desc->ctrl = 0; /* properly align Ethernet header */ skb_reserve(skb, NET_IP_ALIGN); } else { - bp->rx_ring[entry].addr &= ~MACB_BIT(RX_USED); - bp->rx_ring[entry].ctrl = 0; + desc->addr &= ~MACB_BIT(RX_USED); + desc->ctrl = 0; } } @@ -835,16 +893,13 @@ static int gem_rx(struct macb *bp, int budget) bool rxused; entry = macb_rx_ring_wrap(bp, bp->rx_tail); - desc = &bp->rx_ring[entry]; + desc = macb_rx_desc(bp, entry); /* Make hw descriptor updates visible to CPU */ rmb(); rxused = (desc->addr & MACB_BIT(RX_USED)) ? true : false; - addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - addr |= ((u64)(desc->addrh) << 32); -#endif + addr = macb_get_addr(bp, desc); ctrl = desc->ctrl; if (!rxused) @@ -987,15 +1042,17 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, static inline void macb_init_rx_ring(struct macb *bp) { dma_addr_t addr; + struct macb_dma_desc *desc = NULL; int i; addr = bp->rx_buffers_dma; for (i = 0; i < bp->rx_ring_size; i++) { - bp->rx_ring[i].addr = addr; - bp->rx_ring[i].ctrl = 0; + desc = macb_rx_desc(bp, i); + macb_set_addr(bp, desc, addr); + desc->ctrl = 0; addr += bp->rx_buffer_size; } - bp->rx_ring[bp->rx_ring_size - 1].addr |= MACB_BIT(RX_WRAP); + desc->addr |= MACB_BIT(RX_WRAP); bp->rx_tail = 0; } @@ -1008,15 +1065,14 @@ static int macb_rx(struct macb *bp, int budget) for (tail = bp->rx_tail; budget > 0; tail++) { struct macb_dma_desc *desc = macb_rx_desc(bp, tail); - u32 addr, ctrl; + u32 ctrl; /* Make hw descriptor updates visible to CPU */ rmb(); - addr = desc->addr; ctrl = desc->ctrl; - if (!(addr & MACB_BIT(RX_USED))) + if (!(desc->addr & MACB_BIT(RX_USED))) break; if (ctrl & MACB_BIT(RX_SOF)) { @@ -1336,7 +1392,7 @@ static unsigned int macb_tx_map(struct macb *bp, i = tx_head; entry = macb_tx_ring_wrap(bp, i); ctrl = MACB_BIT(TX_USED); - desc = &queue->tx_ring[entry]; + desc = macb_tx_desc(queue, entry); desc->ctrl = ctrl; if (lso_ctrl) { @@ -1358,7 +1414,7 @@ static unsigned int macb_tx_map(struct macb *bp, i--; entry = macb_tx_ring_wrap(bp, i); tx_skb = &queue->tx_skb[entry]; - desc = &queue->tx_ring[entry]; + desc = macb_tx_desc(queue, entry); ctrl = (u32)tx_skb->size; if (eof) { @@ -1379,7 +1435,7 @@ static unsigned int macb_tx_map(struct macb *bp, ctrl |= MACB_BF(MSS_MFS, mss_mfs); /* Set TX buffer descriptor */ - macb_set_addr(desc, tx_skb->mapping); + macb_set_addr(bp, desc, tx_skb->mapping); /* desc->addr must be visible to hardware before clearing * 'TX_USED' bit in desc->ctrl. */ @@ -1586,11 +1642,9 @@ static void gem_free_rx_buffers(struct macb *bp) if (!skb) continue; - desc = &bp->rx_ring[i]; - addr = MACB_BF(RX_WADDR, MACB_BFEXT(RX_WADDR, desc->addr)); -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - addr |= ((u64)(desc->addrh) << 32); -#endif + desc = macb_rx_desc(bp, i); + addr = macb_get_addr(bp, desc); + dma_unmap_single(&bp->pdev->dev, addr, bp->rx_buffer_size, DMA_FROM_DEVICE); dev_kfree_skb_any(skb); @@ -1711,15 +1765,17 @@ out_err: static void gem_init_rings(struct macb *bp) { struct macb_queue *queue; + struct macb_dma_desc *desc = NULL; unsigned int q; int i; for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { for (i = 0; i < bp->tx_ring_size; i++) { - queue->tx_ring[i].addr = 0; - queue->tx_ring[i].ctrl = MACB_BIT(TX_USED); + desc = macb_tx_desc(queue, i); + macb_set_addr(bp, desc, 0); + desc->ctrl = MACB_BIT(TX_USED); } - queue->tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP); + desc->ctrl |= MACB_BIT(TX_WRAP); queue->tx_head = 0; queue->tx_tail = 0; } @@ -1733,16 +1789,18 @@ static void gem_init_rings(struct macb *bp) static void macb_init_rings(struct macb *bp) { int i; + struct macb_dma_desc *desc = NULL; macb_init_rx_ring(bp); for (i = 0; i < bp->tx_ring_size; i++) { - bp->queues[0].tx_ring[i].addr = 0; - bp->queues[0].tx_ring[i].ctrl = MACB_BIT(TX_USED); + desc = macb_tx_desc(&bp->queues[0], i); + macb_set_addr(bp, desc, 0); + desc->ctrl = MACB_BIT(TX_USED); } bp->queues[0].tx_head = 0; bp->queues[0].tx_tail = 0; - bp->queues[0].tx_ring[bp->tx_ring_size - 1].ctrl |= MACB_BIT(TX_WRAP); + desc->ctrl |= MACB_BIT(TX_WRAP); } static void macb_reset_hw(struct macb *bp) @@ -1863,7 +1921,8 @@ static void macb_configure_dma(struct macb *bp) dmacfg &= ~GEM_BIT(TXCOEN); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - dmacfg |= GEM_BIT(ADDR64); + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + dmacfg |= GEM_BIT(ADDR64); #endif netdev_dbg(bp->dev, "Cadence configure DMA with 0x%08x\n", dmacfg); @@ -1910,14 +1969,16 @@ static void macb_init_hw(struct macb *bp) macb_configure_dma(bp); /* Initialize TX and RX buffers */ - macb_writel(bp, RBQP, (u32)(bp->rx_ring_dma)); + macb_writel(bp, RBQP, lower_32_bits(bp->rx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - macb_writel(bp, RBQPH, (u32)(bp->rx_ring_dma >> 32)); + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + macb_writel(bp, RBQPH, upper_32_bits(bp->rx_ring_dma)); #endif for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { - queue_writel(queue, TBQP, (u32)(queue->tx_ring_dma)); + queue_writel(queue, TBQP, lower_32_bits(queue->tx_ring_dma)); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - queue_writel(queue, TBQPH, (u32)(queue->tx_ring_dma >> 32)); + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + queue_writel(queue, TBQPH, upper_32_bits(queue->tx_ring_dma)); #endif /* Enable interrupts */ @@ -2627,7 +2688,8 @@ static int macb_init(struct platform_device *pdev) queue->IMR = GEM_IMR(hw_q - 1); queue->TBQP = GEM_TBQP(hw_q - 1); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - queue->TBQPH = GEM_TBQPH(hw_q -1); + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + queue->TBQPH = GEM_TBQPH(hw_q - 1); #endif } else { /* queue0 uses legacy registers */ @@ -2637,7 +2699,8 @@ static int macb_init(struct platform_device *pdev) queue->IMR = MACB_IMR; queue->TBQP = MACB_TBQP; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - queue->TBQPH = MACB_TBQPH; + if (bp->hw_dma_cap == HW_DMA_CAP_64B) + queue->TBQPH = MACB_TBQPH; #endif } @@ -2730,13 +2793,14 @@ static int macb_init(struct platform_device *pdev) static int at91ether_start(struct net_device *dev) { struct macb *lp = netdev_priv(dev); + struct macb_dma_desc *desc; dma_addr_t addr; u32 ctl; int i; lp->rx_ring = dma_alloc_coherent(&lp->pdev->dev, (AT91ETHER_MAX_RX_DESCR * - sizeof(struct macb_dma_desc)), + macb_dma_desc_get_size(lp)), &lp->rx_ring_dma, GFP_KERNEL); if (!lp->rx_ring) return -ENOMEM; @@ -2748,7 +2812,7 @@ static int at91ether_start(struct net_device *dev) if (!lp->rx_buffers) { dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * - sizeof(struct macb_dma_desc), + macb_dma_desc_get_size(lp), lp->rx_ring, lp->rx_ring_dma); lp->rx_ring = NULL; return -ENOMEM; @@ -2756,13 +2820,14 @@ static int at91ether_start(struct net_device *dev) addr = lp->rx_buffers_dma; for (i = 0; i < AT91ETHER_MAX_RX_DESCR; i++) { - lp->rx_ring[i].addr = addr; - lp->rx_ring[i].ctrl = 0; + desc = macb_rx_desc(lp, i); + macb_set_addr(lp, desc, addr); + desc->ctrl = 0; addr += AT91ETHER_MAX_RBUFF_SZ; } /* Set the Wrap bit on the last descriptor */ - lp->rx_ring[AT91ETHER_MAX_RX_DESCR - 1].addr |= MACB_BIT(RX_WRAP); + desc->addr |= MACB_BIT(RX_WRAP); /* Reset buffer index */ lp->rx_tail = 0; @@ -2834,7 +2899,7 @@ static int at91ether_close(struct net_device *dev) dma_free_coherent(&lp->pdev->dev, AT91ETHER_MAX_RX_DESCR * - sizeof(struct macb_dma_desc), + macb_dma_desc_get_size(lp), lp->rx_ring, lp->rx_ring_dma); lp->rx_ring = NULL; @@ -2885,13 +2950,15 @@ static int at91ether_start_xmit(struct sk_buff *skb, struct net_device *dev) static void at91ether_rx(struct net_device *dev) { struct macb *lp = netdev_priv(dev); + struct macb_dma_desc *desc; unsigned char *p_recv; struct sk_buff *skb; unsigned int pktlen; - while (lp->rx_ring[lp->rx_tail].addr & MACB_BIT(RX_USED)) { + desc = macb_rx_desc(lp, lp->rx_tail); + while (desc->addr & MACB_BIT(RX_USED)) { p_recv = lp->rx_buffers + lp->rx_tail * AT91ETHER_MAX_RBUFF_SZ; - pktlen = MACB_BF(RX_FRMLEN, lp->rx_ring[lp->rx_tail].ctrl); + pktlen = MACB_BF(RX_FRMLEN, desc->ctrl); skb = netdev_alloc_skb(dev, pktlen + 2); if (skb) { skb_reserve(skb, 2); @@ -2905,17 +2972,19 @@ static void at91ether_rx(struct net_device *dev) lp->stats.rx_dropped++; } - if (lp->rx_ring[lp->rx_tail].ctrl & MACB_BIT(RX_MHASH_MATCH)) + if (desc->ctrl & MACB_BIT(RX_MHASH_MATCH)) lp->stats.multicast++; /* reset ownership bit */ - lp->rx_ring[lp->rx_tail].addr &= ~MACB_BIT(RX_USED); + desc->addr &= ~MACB_BIT(RX_USED); /* wrap after last buffer */ if (lp->rx_tail == AT91ETHER_MAX_RX_DESCR - 1) lp->rx_tail = 0; else lp->rx_tail++; + + desc = macb_rx_desc(lp, lp->rx_tail); } } @@ -3211,8 +3280,11 @@ static int macb_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, bp->wol & MACB_WOL_HAS_MAGIC_PACKET); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - if (GEM_BFEXT(DBWDEF, gem_readl(bp, DCFG1)) > GEM_DBW32) + if (GEM_BFEXT(DAW64, gem_readl(bp, DCFG6))) { dma_set_mask(&pdev->dev, DMA_BIT_MASK(44)); + bp->hw_dma_cap = HW_DMA_CAP_64B; + } else + bp->hw_dma_cap = HW_DMA_CAP_32B; #endif spin_lock_init(&bp->lock); diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d67adad67be1..fc8550a5d47f 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -385,6 +385,8 @@ /* Bitfields in DCFG6. */ #define GEM_PBUF_LSO_OFFSET 27 #define GEM_PBUF_LSO_SIZE 1 +#define GEM_DAW64_OFFSET 23 +#define GEM_DAW64_SIZE 1 /* Constants for CLK */ #define MACB_CLK_DIV8 0 @@ -487,12 +489,20 @@ struct macb_dma_desc { u32 addr; u32 ctrl; +}; + #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - u32 addrh; - u32 resvd; -#endif +enum macb_hw_dma_cap { + HW_DMA_CAP_32B, + HW_DMA_CAP_64B, }; +struct macb_dma_desc_64 { + u32 addrh; + u32 resvd; +}; +#endif + /* DMA descriptor bitfields */ #define MACB_RX_USED_OFFSET 0 #define MACB_RX_USED_SIZE 1 @@ -874,6 +884,10 @@ struct macb { unsigned int jumbo_max_len; u32 wol; + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + enum macb_hw_dma_cap hw_dma_cap; +#endif }; static inline bool macb_is_gem(struct macb *bp) diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c index 92be2cd8f817..9906fda76087 100644 --- a/drivers/net/ethernet/cadence/macb_pci.c +++ b/drivers/net/ethernet/cadence/macb_pci.c @@ -1,5 +1,5 @@ /** - * macb_pci.c - Cadence GEM PCI wrapper. + * Cadence GEM PCI wrapper. * * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com * @@ -45,32 +45,27 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct macb_platform_data plat_data; struct resource res[2]; - /* sanity check */ - if (!id) - return -EINVAL; - /* enable pci device */ - err = pci_enable_device(pdev); + err = pcim_enable_device(pdev); if (err < 0) { - dev_err(&pdev->dev, "Enabling PCI device has failed: 0x%04X", - err); - return -EACCES; + dev_err(&pdev->dev, "Enabling PCI device has failed: %d", err); + return err; } pci_set_master(pdev); /* set up resources */ memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); - res[0].start = pdev->resource[0].start; - res[0].end = pdev->resource[0].end; + res[0].start = pci_resource_start(pdev, 0); + res[0].end = pci_resource_end(pdev, 0); res[0].name = PCI_DRIVER_NAME; res[0].flags = IORESOURCE_MEM; - res[1].start = pdev->irq; + res[1].start = pci_irq_vector(pdev, 0); res[1].name = PCI_DRIVER_NAME; res[1].flags = IORESOURCE_IRQ; - dev_info(&pdev->dev, "EMAC physical base addr = 0x%p\n", - (void *)(uintptr_t)pci_resource_start(pdev, 0)); + dev_info(&pdev->dev, "EMAC physical base addr: %pa\n", + &res[0].start); /* set up macb platform data */ memset(&plat_data, 0, sizeof(plat_data)); @@ -100,7 +95,7 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id) plat_info.num_res = ARRAY_SIZE(res); plat_info.data = &plat_data; plat_info.size_data = sizeof(plat_data); - plat_info.dma_mask = DMA_BIT_MASK(32); + plat_info.dma_mask = pdev->dma_mask; /* register platform device */ plat_dev = platform_device_register_full(&plat_info); @@ -120,7 +115,6 @@ err_hclk_register: clk_unregister(plat_data.pclk); err_pclk_register: - pci_disable_device(pdev); return err; } @@ -130,7 +124,6 @@ static void macb_remove(struct pci_dev *pdev) struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev); platform_device_unregister(plat_dev); - pci_disable_device(pdev); clk_unregister(plat_data->pclk); clk_unregister(plat_data->hclk); } diff --git a/drivers/net/ethernet/cavium/Kconfig b/drivers/net/ethernet/cavium/Kconfig index bbc8bd16cb97..dcbce6cac63e 100644 --- a/drivers/net/ethernet/cavium/Kconfig +++ b/drivers/net/ethernet/cavium/Kconfig @@ -77,7 +77,7 @@ config OCTEON_MGMT_ETHERNET config LIQUIDIO_VF tristate "Cavium LiquidIO VF support" depends on 64BIT && PCI_MSI - select PTP_1588_CLOCK + imply PTP_1588_CLOCK ---help--- This driver supports Cavium LiquidIO Intelligent Server Adapter based on CN23XX chips. diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 9211c750e064..1e4695270da6 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -31,6 +31,7 @@ struct lmac { u8 lmac_type; u8 lane_to_sds; bool use_training; + bool autoneg; bool link_up; int lmacid; /* ID within BGX */ int lmacid_bd; /* ID on board */ @@ -47,8 +48,9 @@ struct lmac { struct bgx { u8 bgx_id; struct lmac lmac[MAX_LMAC_PER_BGX]; - int lmac_count; + u8 lmac_count; u8 max_lmac; + u8 acpi_lmac_idx; void __iomem *reg_base; struct pci_dev *pdev; bool is_dlm; @@ -460,7 +462,17 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) /* power down, reset autoneg, autoneg enable */ cfg = bgx_reg_read(bgx, lmacid, BGX_GMP_PCS_MRX_CTL); cfg &= ~PCS_MRX_CTL_PWR_DN; - cfg |= (PCS_MRX_CTL_RST_AN | PCS_MRX_CTL_AN_EN); + cfg |= PCS_MRX_CTL_RST_AN; + if (lmac->phydev) { + cfg |= PCS_MRX_CTL_AN_EN; + } else { + /* In scenarios where PHY driver is not present or it's a + * non-standard PHY, FW sets AN_EN to inform Linux driver + * to do auto-neg and link polling or not. + */ + if (cfg & PCS_MRX_CTL_AN_EN) + lmac->autoneg = true; + } bgx_reg_write(bgx, lmacid, BGX_GMP_PCS_MRX_CTL, cfg); if (lmac->lmac_type == BGX_MODE_QSGMII) { @@ -471,7 +483,7 @@ static int bgx_lmac_sgmii_init(struct bgx *bgx, struct lmac *lmac) return 0; } - if (lmac->lmac_type == BGX_MODE_SGMII) { + if ((lmac->lmac_type == BGX_MODE_SGMII) && lmac->phydev) { if (bgx_poll_reg(bgx, lmacid, BGX_GMP_PCS_MRX_STATUS, PCS_MRX_STATUS_AN_CPT, false)) { dev_err(&bgx->pdev->dev, "BGX AN_CPT not completed\n"); @@ -677,12 +689,71 @@ static int bgx_xaui_check_link(struct lmac *lmac) return -1; } +static void bgx_poll_for_sgmii_link(struct lmac *lmac) +{ + u64 pcs_link, an_result; + u8 speed; + + pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid, + BGX_GMP_PCS_MRX_STATUS); + + /*Link state bit is sticky, read it again*/ + if (!(pcs_link & PCS_MRX_STATUS_LINK)) + pcs_link = bgx_reg_read(lmac->bgx, lmac->lmacid, + BGX_GMP_PCS_MRX_STATUS); + + if (bgx_poll_reg(lmac->bgx, lmac->lmacid, BGX_GMP_PCS_MRX_STATUS, + PCS_MRX_STATUS_AN_CPT, false)) { + lmac->link_up = false; + lmac->last_speed = SPEED_UNKNOWN; + lmac->last_duplex = DUPLEX_UNKNOWN; + goto next_poll; + } + + lmac->link_up = ((pcs_link & PCS_MRX_STATUS_LINK) != 0) ? true : false; + an_result = bgx_reg_read(lmac->bgx, lmac->lmacid, + BGX_GMP_PCS_ANX_AN_RESULTS); + + speed = (an_result >> 3) & 0x3; + lmac->last_duplex = (an_result >> 1) & 0x1; + switch (speed) { + case 0: + lmac->last_speed = 10; + break; + case 1: + lmac->last_speed = 100; + break; + case 2: + lmac->last_speed = 1000; + break; + default: + lmac->link_up = false; + lmac->last_speed = SPEED_UNKNOWN; + lmac->last_duplex = DUPLEX_UNKNOWN; + break; + } + +next_poll: + + if (lmac->last_link != lmac->link_up) { + if (lmac->link_up) + bgx_sgmii_change_link_state(lmac); + lmac->last_link = lmac->link_up; + } + + queue_delayed_work(lmac->check_link, &lmac->dwork, HZ * 3); +} + static void bgx_poll_for_link(struct work_struct *work) { struct lmac *lmac; u64 spu_link, smu_link; lmac = container_of(work, struct lmac, dwork.work); + if (lmac->is_sgmii) { + bgx_poll_for_sgmii_link(lmac); + return; + } /* Receive link is latching low. Force it high and verify it */ bgx_reg_modify(lmac->bgx, lmac->lmacid, @@ -774,9 +845,21 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) (lmac->lmac_type != BGX_MODE_XLAUI) && (lmac->lmac_type != BGX_MODE_40G_KR) && (lmac->lmac_type != BGX_MODE_10G_KR)) { - if (!lmac->phydev) - return -ENODEV; - + if (!lmac->phydev) { + if (lmac->autoneg) { + bgx_reg_write(bgx, lmacid, + BGX_GMP_PCS_LINKX_TIMER, + PCS_LINKX_TIMER_COUNT); + goto poll; + } else { + /* Default to below link speed and duplex */ + lmac->link_up = true; + lmac->last_speed = 1000; + lmac->last_duplex = 1; + bgx_sgmii_change_link_state(lmac); + return 0; + } + } lmac->phydev->dev_flags = 0; if (phy_connect_direct(&lmac->netdev, lmac->phydev, @@ -785,15 +868,17 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid) return -ENODEV; phy_start_aneg(lmac->phydev); - } else { - lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND | - WQ_MEM_RECLAIM, 1); - if (!lmac->check_link) - return -ENOMEM; - INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link); - queue_delayed_work(lmac->check_link, &lmac->dwork, 0); + return 0; } +poll: + lmac->check_link = alloc_workqueue("check_link", WQ_UNBOUND | + WQ_MEM_RECLAIM, 1); + if (!lmac->check_link) + return -ENOMEM; + INIT_DELAYED_WORK(&lmac->dwork, bgx_poll_for_link); + queue_delayed_work(lmac->check_link, &lmac->dwork, 0); + return 0; } @@ -1143,13 +1228,13 @@ static acpi_status bgx_acpi_register_phy(acpi_handle handle, if (acpi_bus_get_device(handle, &adev)) goto out; - acpi_get_mac_address(dev, adev, bgx->lmac[bgx->lmac_count].mac); + acpi_get_mac_address(dev, adev, bgx->lmac[bgx->acpi_lmac_idx].mac); - SET_NETDEV_DEV(&bgx->lmac[bgx->lmac_count].netdev, dev); + SET_NETDEV_DEV(&bgx->lmac[bgx->acpi_lmac_idx].netdev, dev); - bgx->lmac[bgx->lmac_count].lmacid = bgx->lmac_count; + bgx->lmac[bgx->acpi_lmac_idx].lmacid = bgx->acpi_lmac_idx; + bgx->acpi_lmac_idx++; /* move to next LMAC */ out: - bgx->lmac_count++; return AE_OK; } diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index c18ebfeb2039..a60f189429bb 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -153,10 +153,15 @@ #define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14) #define PCS_MRX_CTL_RESET BIT_ULL(15) #define BGX_GMP_PCS_MRX_STATUS 0x30008 +#define PCS_MRX_STATUS_LINK BIT_ULL(2) #define PCS_MRX_STATUS_AN_CPT BIT_ULL(5) +#define BGX_GMP_PCS_ANX_ADV 0x30010 #define BGX_GMP_PCS_ANX_AN_RESULTS 0x30020 +#define BGX_GMP_PCS_LINKX_TIMER 0x30040 +#define PCS_LINKX_TIMER_COUNT 0x1E84 #define BGX_GMP_PCS_SGM_AN_ADV 0x30068 #define BGX_GMP_PCS_MISCX_CTL 0x30078 +#define PCS_MISC_CTL_MODE BIT_ULL(8) #define PCS_MISC_CTL_DISP_EN BIT_ULL(13) #define PCS_MISC_CTL_GMX_ENO BIT_ULL(11) #define PCS_MISC_CTL_SAMP_PT_MASK 0x7Full diff --git a/drivers/net/ethernet/cavium/thunder/thunder_xcv.c b/drivers/net/ethernet/cavium/thunder/thunder_xcv.c index 67befedef709..578c7f8f11bf 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_xcv.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_xcv.c @@ -116,8 +116,7 @@ void xcv_setup_link(bool link_up, int link_speed) int speed = 2; if (!xcv) { - dev_err(&xcv->pdev->dev, - "XCV init not done, probe may have failed\n"); + pr_err("XCV init not done, probe may have failed\n"); return; } diff --git a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c index 0f0de5b63622..d04a6c163445 100644 --- a/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c +++ b/drivers/net/ethernet/chelsio/libcxgb/libcxgb_cm.c @@ -133,17 +133,15 @@ cxgb_find_route6(struct cxgb4_lld_info *lldi, if (ipv6_addr_type(&fl6.daddr) & IPV6_ADDR_LINKLOCAL) fl6.flowi6_oif = sin6_scope_id; dst = ip6_route_output(&init_net, NULL, &fl6); - if (!dst) - goto out; - if (!cxgb_our_interface(lldi, get_real_dev, - ip6_dst_idev(dst)->dev) && - !(ip6_dst_idev(dst)->dev->flags & IFF_LOOPBACK)) { + if (dst->error || + (!cxgb_our_interface(lldi, get_real_dev, + ip6_dst_idev(dst)->dev) && + !(ip6_dst_idev(dst)->dev->flags & IFF_LOOPBACK))) { dst_release(dst); - dst = NULL; + return NULL; } } -out: return dst; } EXPORT_SYMBOL(cxgb_find_route6); diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 0e74529a4209..30e855004c57 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1118,7 +1118,7 @@ int be_cmd_pmac_add(struct be_adapter *adapter, u8 *mac_addr, err: mutex_unlock(&adapter->mcc_lock); - if (status == MCC_STATUS_UNAUTHORIZED_REQUEST) + if (base_status(status) == MCC_STATUS_UNAUTHORIZED_REQUEST) status = -EPERM; return status; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 7e1633bf5a22..cd49a54c538d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -275,8 +275,7 @@ static int be_dev_mac_add(struct be_adapter *adapter, u8 *mac) /* Check if mac has already been added as part of uc-list */ for (i = 0; i < adapter->uc_macs; i++) { - if (ether_addr_equal((u8 *)&adapter->uc_list[i * ETH_ALEN], - mac)) { + if (ether_addr_equal(adapter->uc_list[i].mac, mac)) { /* mac already added, skip addition */ adapter->pmac_id[0] = adapter->pmac_id[i + 1]; return 0; @@ -319,6 +318,13 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) if (ether_addr_equal(addr->sa_data, adapter->dev_mac)) return 0; + /* BE3 VFs without FILTMGMT privilege are not allowed to set its MAC + * address + */ + if (BEx_chip(adapter) && be_virtfn(adapter) && + !check_privilege(adapter, BE_PRIV_FILTMGMT)) + return -EPERM; + /* if device is not running, copy MAC to netdev->dev_addr */ if (!netif_running(netdev)) goto done; @@ -356,8 +362,10 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) status = -EPERM; goto err; } -done: + + /* Remember currently programmed MAC */ ether_addr_copy(adapter->dev_mac, addr->sa_data); +done: ether_addr_copy(netdev->dev_addr, addr->sa_data); dev_info(dev, "MAC address changed to %pM\n", addr->sa_data); return 0; @@ -1655,14 +1663,12 @@ static void be_clear_mc_list(struct be_adapter *adapter) static int be_uc_mac_add(struct be_adapter *adapter, int uc_idx) { - if (ether_addr_equal((u8 *)&adapter->uc_list[uc_idx * ETH_ALEN], - adapter->dev_mac)) { + if (ether_addr_equal(adapter->uc_list[uc_idx].mac, adapter->dev_mac)) { adapter->pmac_id[uc_idx + 1] = adapter->pmac_id[0]; return 0; } - return be_cmd_pmac_add(adapter, - (u8 *)&adapter->uc_list[uc_idx * ETH_ALEN], + return be_cmd_pmac_add(adapter, adapter->uc_list[uc_idx].mac, adapter->if_handle, &adapter->pmac_id[uc_idx + 1], 0); } @@ -1698,9 +1704,8 @@ static void be_set_uc_list(struct be_adapter *adapter) } if (adapter->update_uc_list) { - i = 1; /* First slot is claimed by the Primary MAC */ - /* cache the uc-list in adapter array */ + i = 0; netdev_for_each_uc_addr(ha, netdev) { ether_addr_copy(adapter->uc_list[i].mac, ha->addr); i++; @@ -3613,7 +3618,13 @@ static void be_rx_qs_destroy(struct be_adapter *adapter) static void be_disable_if_filters(struct be_adapter *adapter) { - be_dev_mac_del(adapter, adapter->pmac_id[0]); + /* Don't delete MAC on BE3 VFs without FILTMGMT privilege */ + if (!BEx_chip(adapter) || !be_virtfn(adapter) || + check_privilege(adapter, BE_PRIV_FILTMGMT)) { + be_dev_mac_del(adapter, adapter->pmac_id[0]); + eth_zero_addr(adapter->dev_mac); + } + be_clear_uc_list(adapter); be_clear_mc_list(adapter); @@ -3766,11 +3777,27 @@ static int be_enable_if_filters(struct be_adapter *adapter) if (status) return status; - /* For BE3 VFs, the PF programs the initial MAC address */ - if (!(BEx_chip(adapter) && be_virtfn(adapter))) { + /* Normally this condition usually true as the ->dev_mac is zeroed. + * But on BE3 VFs the initial MAC is pre-programmed by PF and + * subsequent be_dev_mac_add() can fail (after fresh boot) + */ + if (!ether_addr_equal(adapter->dev_mac, adapter->netdev->dev_addr)) { + int old_pmac_id = -1; + + /* Remember old programmed MAC if any - can happen on BE3 VF */ + if (!is_zero_ether_addr(adapter->dev_mac)) + old_pmac_id = adapter->pmac_id[0]; + status = be_dev_mac_add(adapter, adapter->netdev->dev_addr); if (status) return status; + + /* Delete the old programmed MAC as we successfully programmed + * a new MAC + */ + if (old_pmac_id >= 0 && old_pmac_id != adapter->pmac_id[0]) + be_dev_mac_del(adapter, old_pmac_id); + ether_addr_copy(adapter->dev_mac, adapter->netdev->dev_addr); } @@ -4544,6 +4571,10 @@ static int be_mac_setup(struct be_adapter *adapter) memcpy(adapter->netdev->dev_addr, mac, ETH_ALEN); memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN); + + /* Initial MAC for BE3 VFs is already programmed by PF */ + if (BEx_chip(adapter) && be_virtfn(adapter)) + memcpy(adapter->dev_mac, mac, ETH_ALEN); } return 0; @@ -5155,7 +5186,9 @@ static netdev_features_t be_features_check(struct sk_buff *skb, skb->inner_protocol_type != ENCAP_TYPE_ETHER || skb->inner_protocol != htons(ETH_P_TEB) || skb_inner_mac_header(skb) - skb_transport_header(skb) != - sizeof(struct udphdr) + sizeof(struct vxlanhdr)) + sizeof(struct udphdr) + sizeof(struct vxlanhdr) || + !adapter->vxlan_port || + udp_hdr(skb)->dest != adapter->vxlan_port) return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); return features; diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 624ba9058dc4..726b5693ae8a 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -733,6 +733,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv) priv->cgr_data.cgr.cb = dpaa_eth_cgscn; /* Enable Congestion State Change Notifications and CS taildrop */ + memset(&initcgr, 0, sizeof(initcgr)); initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES); initcgr.cgr.cscn_en = QM_CGR_EN; @@ -1667,7 +1668,7 @@ static struct sk_buff *sg_fd_to_skb(const struct dpaa_priv *priv, free_buffers: /* compensate sw bpool counter changes */ - for (i--; i > 0; i--) { + for (i--; i >= 0; i--) { dpaa_bp = dpaa_bpid2pool(sgt[i].bpid); if (dpaa_bp) { count_ptr = this_cpu_ptr(dpaa_bp->percpu_count); @@ -2291,7 +2292,8 @@ static int dpaa_open(struct net_device *net_dev) net_dev->phydev = mac_dev->init_phy(net_dev, priv->mac_dev); if (!net_dev->phydev) { netif_err(priv, ifup, net_dev, "init_phy() failed\n"); - return -ENODEV; + err = -ENODEV; + goto phy_init_failed; } for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) { @@ -2314,6 +2316,7 @@ mac_start_failed: for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) fman_port_disable(mac_dev->port[i]); +phy_init_failed: dpaa_eth_napi_disable(priv); return err; @@ -2420,6 +2423,7 @@ static int dpaa_ingress_cgr_init(struct dpaa_priv *priv) } /* Enable CS TD, but disable Congestion State Change Notifications. */ + memset(&initcgr, 0, sizeof(initcgr)); initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CS_THRES); initcgr.cgr.cscn_en = QM_CGR_EN; cs_th = DPAA_INGRESS_CS_THRESHOLD; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 38160c2bebcb..8be7034b2e7b 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -2910,6 +2910,7 @@ static void set_multicast_list(struct net_device *ndev) struct netdev_hw_addr *ha; unsigned int i, bit, data, crc, tmp; unsigned char hash; + unsigned int hash_high = 0, hash_low = 0; if (ndev->flags & IFF_PROMISC) { tmp = readl(fep->hwp + FEC_R_CNTRL); @@ -2932,11 +2933,7 @@ static void set_multicast_list(struct net_device *ndev) return; } - /* Clear filter and add the addresses in hash register - */ - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - + /* Add the addresses in hash register */ netdev_for_each_mc_addr(ha, ndev) { /* calculate crc32 value of mac address */ crc = 0xffffffff; @@ -2954,16 +2951,14 @@ static void set_multicast_list(struct net_device *ndev) */ hash = (crc >> (32 - FEC_HASH_BITS)) & 0x3f; - if (hash > 31) { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - tmp |= 1 << (hash - 32); - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); - } else { - tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); - tmp |= 1 << hash; - writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); - } + if (hash > 31) + hash_high |= 1 << (hash - 32); + else + hash_low |= 1 << hash; } + + writel(hash_high, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); + writel(hash_low, fep->hwp + FEC_GRP_HASH_TABLE_LOW); } /* Set a MAC change in hardware. */ diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index a6e7afa878be..957bfc220978 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2010,8 +2010,8 @@ static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) if (!rxb->page) continue; - dma_unmap_single(rx_queue->dev, rxb->dma, - PAGE_SIZE, DMA_FROM_DEVICE); + dma_unmap_page(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); __free_page(rxb->page); rxb->page = NULL; @@ -2948,7 +2948,7 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, } /* try reuse page */ - if (unlikely(page_count(page) != 1)) + if (unlikely(page_count(page) != 1 || page_is_pfmemalloc(page))) return false; /* change offset to the other half */ diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h index 87226685f742..8fa18fc17cd2 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h +++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h @@ -1014,9 +1014,7 @@ static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value) { - u8 __iomem *reg_addr = ACCESS_ONCE(base); - - writel(value, reg_addr + reg); + writel(value, base + reg); } #define dsaf_write_dev(a, reg, value) \ @@ -1024,9 +1022,7 @@ static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value) static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg) { - u8 __iomem *reg_addr = ACCESS_ONCE(base); - - return readl(reg_addr + reg); + return readl(base + reg); } static inline void dsaf_write_syscon(struct regmap *base, u32 reg, u32 value) diff --git a/drivers/net/ethernet/hisilicon/hns/hns_enet.c b/drivers/net/ethernet/hisilicon/hns/hns_enet.c index 672b64606321..8aed72860e7c 100644 --- a/drivers/net/ethernet/hisilicon/hns/hns_enet.c +++ b/drivers/net/ethernet/hisilicon/hns/hns_enet.c @@ -305,8 +305,8 @@ int hns_nic_net_xmit_hw(struct net_device *ndev, struct hns_nic_ring_data *ring_data) { struct hns_nic_priv *priv = netdev_priv(ndev); - struct device *dev = priv->dev; struct hnae_ring *ring = ring_data->ring; + struct device *dev = ring_to_dev(ring); struct netdev_queue *dev_queue; struct skb_frag_struct *frag; int buf_num; diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index a831f947ca8c..309f5c66083c 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1601,8 +1601,11 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) netdev->netdev_ops = &ibmveth_netdev_ops; netdev->ethtool_ops = &netdev_ethtool_ops; SET_NETDEV_DEV(netdev, &dev->dev); - netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->hw_features = NETIF_F_SG; + if (vio_get_attribute(dev, "ibm,illan-options", NULL) != NULL) { + netdev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_RXCSUM; + } netdev->features |= netdev->hw_features; diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index c12596676bbb..a07b8d79174c 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -189,9 +189,10 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter, } ltb->map_id = adapter->map_id; adapter->map_id++; + + init_completion(&adapter->fw_done); send_request_map(adapter, ltb->addr, ltb->size, ltb->map_id); - init_completion(&adapter->fw_done); wait_for_completion(&adapter->fw_done); return 0; } @@ -505,7 +506,7 @@ rx_pool_alloc_failed: adapter->rx_pool = NULL; rx_pool_arr_alloc_failed: for (i = 0; i < adapter->req_rx_queues; i++) - napi_enable(&adapter->napi[i]); + napi_disable(&adapter->napi[i]); alloc_napi_failed: return -ENOMEM; } @@ -1121,10 +1122,10 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev, crq.request_statistics.ioba = cpu_to_be32(adapter->stats_token); crq.request_statistics.len = cpu_to_be32(sizeof(struct ibmvnic_statistics)); - ibmvnic_send_crq(adapter, &crq); /* Wait for data to be written */ init_completion(&adapter->stats_done); + ibmvnic_send_crq(adapter, &crq); wait_for_completion(&adapter->stats_done); for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++) @@ -1496,7 +1497,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry) adapter->req_rx_queues = adapter->opt_rx_comp_queues; adapter->req_rx_add_queues = adapter->max_rx_add_queues; - adapter->req_mtu = adapter->max_mtu; + adapter->req_mtu = adapter->netdev->mtu + ETH_HLEN; } total_queues = adapter->req_tx_queues + adapter->req_rx_queues; @@ -2185,12 +2186,12 @@ static void handle_error_info_rsp(union ibmvnic_crq *crq, if (!found) { dev_err(dev, "Couldn't find error id %x\n", - crq->request_error_rsp.error_id); + be32_to_cpu(crq->request_error_rsp.error_id)); return; } dev_err(dev, "Detailed info for error id %x:", - crq->request_error_rsp.error_id); + be32_to_cpu(crq->request_error_rsp.error_id)); for (i = 0; i < error_buff->len; i++) { pr_cont("%02x", (int)error_buff->buff[i]); @@ -2269,8 +2270,8 @@ static void handle_error_indication(union ibmvnic_crq *crq, dev_err(dev, "Firmware reports %serror id %x, cause %d\n", crq->error_indication. flags & IBMVNIC_FATAL_ERROR ? "FATAL " : "", - crq->error_indication.error_id, - crq->error_indication.error_cause); + be32_to_cpu(crq->error_indication.error_id), + be16_to_cpu(crq->error_indication.error_cause)); error_buff = kmalloc(sizeof(*error_buff), GFP_ATOMIC); if (!error_buff) @@ -2388,10 +2389,10 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq, case PARTIALSUCCESS: dev_info(dev, "req=%lld, rsp=%ld in %s queue, retrying.\n", *req_value, - (long int)be32_to_cpu(crq->request_capability_rsp. + (long int)be64_to_cpu(crq->request_capability_rsp. number), name); release_sub_crqs_no_irqs(adapter); - *req_value = be32_to_cpu(crq->request_capability_rsp.number); + *req_value = be64_to_cpu(crq->request_capability_rsp.number); init_sub_crqs(adapter, 1); return; default: @@ -2626,12 +2627,12 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq, break; case MIN_MTU: adapter->min_mtu = be64_to_cpu(crq->query_capability.number); - netdev->min_mtu = adapter->min_mtu; + netdev->min_mtu = adapter->min_mtu - ETH_HLEN; netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu); break; case MAX_MTU: adapter->max_mtu = be64_to_cpu(crq->query_capability.number); - netdev->max_mtu = adapter->max_mtu; + netdev->max_mtu = adapter->max_mtu - ETH_HLEN; netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu); break; case MAX_MULTICAST_FILTERS: @@ -2799,9 +2800,9 @@ static ssize_t trace_read(struct file *file, char __user *user_buf, size_t len, crq.collect_fw_trace.correlator = adapter->ras_comps[num].correlator; crq.collect_fw_trace.ioba = cpu_to_be32(trace_tok); crq.collect_fw_trace.len = adapter->ras_comps[num].trace_buff_size; - ibmvnic_send_crq(adapter, &crq); init_completion(&adapter->fw_done); + ibmvnic_send_crq(adapter, &crq); wait_for_completion(&adapter->fw_done); if (*ppos + len > be32_to_cpu(adapter->ras_comps[num].trace_buff_size)) @@ -3581,9 +3582,9 @@ static int ibmvnic_dump_show(struct seq_file *seq, void *v) memset(&crq, 0, sizeof(crq)); crq.request_dump_size.first = IBMVNIC_CRQ_CMD; crq.request_dump_size.cmd = REQUEST_DUMP_SIZE; - ibmvnic_send_crq(adapter, &crq); init_completion(&adapter->fw_done); + ibmvnic_send_crq(adapter, &crq); wait_for_completion(&adapter->fw_done); seq_write(seq, adapter->dump_data, adapter->dump_data_size); @@ -3629,8 +3630,8 @@ static void handle_crq_init_rsp(struct work_struct *work) } } - send_version_xchg(adapter); reinit_completion(&adapter->init_done); + send_version_xchg(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Passive init timeout\n"); goto task_failed; @@ -3640,9 +3641,9 @@ static void handle_crq_init_rsp(struct work_struct *work) if (adapter->renegotiate) { adapter->renegotiate = false; release_sub_crqs_no_irqs(adapter); - send_cap_queries(adapter); reinit_completion(&adapter->init_done); + send_cap_queries(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) { dev_err(dev, "Passive init timeout\n"); @@ -3656,9 +3657,7 @@ static void handle_crq_init_rsp(struct work_struct *work) goto task_failed; netdev->real_num_tx_queues = adapter->req_tx_queues; - netdev->mtu = adapter->req_mtu; - netdev->min_mtu = adapter->min_mtu; - netdev->max_mtu = adapter->max_mtu; + netdev->mtu = adapter->req_mtu - ETH_HLEN; if (adapter->failover) { adapter->failover = false; @@ -3772,9 +3771,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) adapter->debugfs_dump = ent; } } - ibmvnic_send_crq_init(adapter); init_completion(&adapter->init_done); + ibmvnic_send_crq_init(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) return 0; @@ -3782,9 +3781,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) if (adapter->renegotiate) { adapter->renegotiate = false; release_sub_crqs_no_irqs(adapter); - send_cap_queries(adapter); reinit_completion(&adapter->init_done); + send_cap_queries(adapter); if (!wait_for_completion_timeout(&adapter->init_done, timeout)) return 0; @@ -3798,7 +3797,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) } netdev->real_num_tx_queues = adapter->req_tx_queues; - netdev->mtu = adapter->req_mtu; + netdev->mtu = adapter->req_mtu - ETH_HLEN; rc = register_netdev(netdev); if (rc) { diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index a761001308dc..1515abaa5ac9 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3962,8 +3962,8 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring) PAGE_SIZE, DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - __page_frag_drain(buffer_info->page, 0, - buffer_info->pagecnt_bias); + __page_frag_cache_drain(buffer_info->page, + buffer_info->pagecnt_bias); buffer_info->page = NULL; } @@ -6991,7 +6991,7 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE, DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - __page_frag_drain(page, 0, rx_buffer->pagecnt_bias); + __page_frag_cache_drain(page, rx_buffer->pagecnt_bias); } /* clear contents of rx_buffer */ diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 3dd87889e67e..1c29c86f8709 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2517,7 +2517,7 @@ static int mtk_remove(struct platform_device *pdev) } const struct of_device_id of_mtk_match[] = { - { .compatible = "mediatek,mt7623-eth" }, + { .compatible = "mediatek,mt2701-eth" }, {}, }; MODULE_DEVICE_TABLE(of, of_mtk_match); diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c index c7e939945259..53daa6ca5d83 100644 --- a/drivers/net/ethernet/mellanox/mlx4/catas.c +++ b/drivers/net/ethernet/mellanox/mlx4/catas.c @@ -158,7 +158,7 @@ static int mlx4_reset_slave(struct mlx4_dev *dev) return -ETIMEDOUT; } -static int mlx4_comm_internal_err(u32 slave_read) +int mlx4_comm_internal_err(u32 slave_read) { return (u32)COMM_CHAN_EVENT_INTERNAL_ERR == (slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/cq.c b/drivers/net/ethernet/mellanox/mlx4/cq.c index a849da92f857..6b8635378f1f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/cq.c @@ -101,13 +101,19 @@ void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn) { struct mlx4_cq *cq; + rcu_read_lock(); cq = radix_tree_lookup(&mlx4_priv(dev)->cq_table.tree, cqn & (dev->caps.num_cqs - 1)); + rcu_read_unlock(); + if (!cq) { mlx4_dbg(dev, "Completion event for bogus CQ %08x\n", cqn); return; } + /* Acessing the CQ outside of rcu_read_lock is safe, because + * the CQ is freed only after interrupt handling is completed. + */ ++cq->arm_sn; cq->comp(cq); @@ -118,23 +124,19 @@ void mlx4_cq_event(struct mlx4_dev *dev, u32 cqn, int event_type) struct mlx4_cq_table *cq_table = &mlx4_priv(dev)->cq_table; struct mlx4_cq *cq; - spin_lock(&cq_table->lock); - + rcu_read_lock(); cq = radix_tree_lookup(&cq_table->tree, cqn & (dev->caps.num_cqs - 1)); - if (cq) - atomic_inc(&cq->refcount); - - spin_unlock(&cq_table->lock); + rcu_read_unlock(); if (!cq) { - mlx4_warn(dev, "Async event for bogus CQ %08x\n", cqn); + mlx4_dbg(dev, "Async event for bogus CQ %08x\n", cqn); return; } + /* Acessing the CQ outside of rcu_read_lock is safe, because + * the CQ is freed only after interrupt handling is completed. + */ cq->event(cq, event_type); - - if (atomic_dec_and_test(&cq->refcount)) - complete(&cq->free); } static int mlx4_SW2HW_CQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox, @@ -301,9 +303,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, if (err) return err; - spin_lock_irq(&cq_table->lock); + spin_lock(&cq_table->lock); err = radix_tree_insert(&cq_table->tree, cq->cqn, cq); - spin_unlock_irq(&cq_table->lock); + spin_unlock(&cq_table->lock); if (err) goto err_icm; @@ -349,9 +351,9 @@ int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, return 0; err_radix: - spin_lock_irq(&cq_table->lock); + spin_lock(&cq_table->lock); radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); + spin_unlock(&cq_table->lock); err_icm: mlx4_cq_free_icm(dev, cq->cqn); @@ -370,15 +372,15 @@ void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq) if (err) mlx4_warn(dev, "HW2SW_CQ failed (%d) for CQN %06x\n", err, cq->cqn); + spin_lock(&cq_table->lock); + radix_tree_delete(&cq_table->tree, cq->cqn); + spin_unlock(&cq_table->lock); + synchronize_irq(priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq); if (priv->eq_table.eq[MLX4_CQ_TO_EQ_VECTOR(cq->vector)].irq != priv->eq_table.eq[MLX4_EQ_ASYNC].irq) synchronize_irq(priv->eq_table.eq[MLX4_EQ_ASYNC].irq); - spin_lock_irq(&cq_table->lock); - radix_tree_delete(&cq_table->tree, cq->cqn); - spin_unlock_irq(&cq_table->lock); - if (atomic_dec_and_test(&cq->refcount)) complete(&cq->free); wait_for_completion(&cq->free); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c index 015198c14fa8..504461a464c5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c @@ -245,13 +245,9 @@ static u32 freq_to_shift(u16 freq) { u32 freq_khz = freq * 1000; u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC; - u64 tmp_rounded = - roundup_pow_of_two(max_val_cycles) > max_val_cycles ? - roundup_pow_of_two(max_val_cycles) - 1 : UINT_MAX; - u64 max_val_cycles_rounded = is_power_of_2(max_val_cycles + 1) ? - max_val_cycles : tmp_rounded; + u64 max_val_cycles_rounded = 1ULL << fls64(max_val_cycles - 1); /* calculate max possible multiplier in order to fit in 64bit */ - u64 max_mul = div_u64(0xffffffffffffffffULL, max_val_cycles_rounded); + u64 max_mul = div64_u64(ULLONG_MAX, max_val_cycles_rounded); /* This comes from the reverse of clocksource_khz2mult */ return ilog2(div_u64(max_mul * freq_khz, 1000000)); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index d9c9f86a30df..9aa422691954 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1099,7 +1099,7 @@ static int mlx4_en_set_ringparam(struct net_device *dev, memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); new_prof.tx_ring_size = tx_size; new_prof.rx_ring_size = rx_size; - err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); if (err) goto out; @@ -1732,8 +1732,6 @@ static void mlx4_en_get_channels(struct net_device *dev, { struct mlx4_en_priv *priv = netdev_priv(dev); - memset(channel, 0, sizeof(*channel)); - channel->max_rx = MAX_RX_RINGS; channel->max_tx = MLX4_EN_MAX_TX_RING_P_UP; @@ -1752,10 +1750,7 @@ static int mlx4_en_set_channels(struct net_device *dev, int xdp_count; int err = 0; - if (channel->other_count || channel->combined_count || - channel->tx_count > MLX4_EN_MAX_TX_RING_P_UP || - channel->rx_count > MAX_RX_RINGS || - !channel->tx_count || !channel->rx_count) + if (!channel->tx_count || !channel->rx_count) return -EINVAL; tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); @@ -1779,7 +1774,7 @@ static int mlx4_en_set_channels(struct net_device *dev, new_prof.tx_ring_num[TX_XDP] = xdp_count; new_prof.rx_ring_num = channel->rx_count; - err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); if (err) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index edbe200ac2fa..3b4961a8e8e4 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1748,8 +1748,11 @@ int mlx4_en_start_port(struct net_device *dev) /* Process all completions if exist to prevent * the queues freezing if they are full */ - for (i = 0; i < priv->rx_ring_num; i++) + for (i = 0; i < priv->rx_ring_num; i++) { + local_bh_disable(); napi_schedule(&priv->rx_cq[i]->napi); + local_bh_enable(); + } netif_tx_start_all_queues(dev); netif_device_attach(dev); @@ -2039,6 +2042,8 @@ static void mlx4_en_free_resources(struct mlx4_en_priv *priv) if (priv->tx_cq[t] && priv->tx_cq[t][i]) mlx4_en_destroy_cq(priv, &priv->tx_cq[t][i]); } + kfree(priv->tx_ring[t]); + kfree(priv->tx_cq[t]); } for (i = 0; i < priv->rx_ring_num; i++) { @@ -2181,9 +2186,11 @@ static void mlx4_en_update_priv(struct mlx4_en_priv *dst, int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, struct mlx4_en_priv *tmp, - struct mlx4_en_port_profile *prof) + struct mlx4_en_port_profile *prof, + bool carry_xdp_prog) { - int t; + struct bpf_prog *xdp_prog; + int i, t; mlx4_en_copy_priv(tmp, priv, prof); @@ -2197,6 +2204,23 @@ int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, } return -ENOMEM; } + + /* All rx_rings has the same xdp_prog. Pick the first one. */ + xdp_prog = rcu_dereference_protected( + priv->rx_ring[0]->xdp_prog, + lockdep_is_held(&priv->mdev->state_lock)); + + if (xdp_prog && carry_xdp_prog) { + xdp_prog = bpf_prog_add(xdp_prog, tmp->rx_ring_num); + if (IS_ERR(xdp_prog)) { + mlx4_en_free_resources(tmp); + return PTR_ERR(xdp_prog); + } + for (i = 0; i < tmp->rx_ring_num; i++) + rcu_assign_pointer(tmp->rx_ring[i]->xdp_prog, + xdp_prog); + } + return 0; } @@ -2211,7 +2235,6 @@ void mlx4_en_destroy_netdev(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_dev *mdev = priv->mdev; - int t; en_dbg(DRV, priv, "Destroying netdev on port:%d\n", priv->port); @@ -2245,11 +2268,6 @@ void mlx4_en_destroy_netdev(struct net_device *dev) mlx4_en_free_resources(priv); mutex_unlock(&mdev->state_lock); - for (t = 0; t < MLX4_EN_NUM_TX_TYPES; t++) { - kfree(priv->tx_ring[t]); - kfree(priv->tx_cq[t]); - } - free_netdev(dev); } @@ -2277,7 +2295,7 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) if (priv->tx_ring_num[TX_XDP] && !mlx4_en_check_xdp_mtu(dev, new_mtu)) - return -ENOTSUPP; + return -EOPNOTSUPP; dev->mtu = new_mtu; @@ -2752,7 +2770,7 @@ static int mlx4_xdp_set(struct net_device *dev, struct bpf_prog *prog) en_warn(priv, "Reducing the number of TX rings, to not exceed the max total rings number.\n"); } - err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, false); if (err) { if (prog) bpf_prog_sub(prog, priv->rx_ring_num - 1); @@ -3496,7 +3514,7 @@ int mlx4_en_reset_config(struct net_device *dev, memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile)); memcpy(&new_prof.hwtstamp_config, &ts_config, sizeof(ts_config)); - err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof); + err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof, true); if (err) goto out; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 3c37e216bbf3..cc003fdf0ed9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -445,8 +445,14 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) ring->cqn = priv->rx_cq[ring_ind]->mcq.cqn; ring->stride = stride; - if (ring->stride <= TXBB_SIZE) + if (ring->stride <= TXBB_SIZE) { + /* Stamp first unused send wqe */ + __be32 *ptr = (__be32 *)ring->buf; + __be32 stamp = cpu_to_be32(1 << STAMP_SHIFT); + *ptr = stamp; + /* Move pointer to start of rx section */ ring->buf += TXBB_SIZE; + } ring->log_stride = ffs(ring->stride) - 1; ring->buf_size = ring->size * ring->stride; @@ -508,8 +514,11 @@ void mlx4_en_recover_from_oom(struct mlx4_en_priv *priv) return; for (ring = 0; ring < priv->rx_ring_num; ring++) { - if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) + if (mlx4_en_is_ring_empty(priv->rx_ring[ring])) { + local_bh_disable(); napi_reschedule(&priv->rx_cq[ring]->napi); + local_bh_enable(); + } } } diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c index cd3638e6fe25..0509996957d9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/eq.c +++ b/drivers/net/ethernet/mellanox/mlx4/eq.c @@ -554,8 +554,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) break; case MLX4_EVENT_TYPE_SRQ_LIMIT: - mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT\n", - __func__); + mlx4_dbg(dev, "%s: MLX4_EVENT_TYPE_SRQ_LIMIT. srq_no=0x%x, eq 0x%x\n", + __func__, be32_to_cpu(eqe->event.srq.srqn), + eq->eqn); case MLX4_EVENT_TYPE_SRQ_CATAS_ERROR: if (mlx4_is_master(dev)) { /* forward only to slave owning the SRQ */ @@ -570,15 +571,19 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq) eq->eqn, eq->cons_index, ret); break; } - mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", - __func__, slave, - be32_to_cpu(eqe->event.srq.srqn), - eqe->type, eqe->subtype); + if (eqe->type == + MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) + mlx4_warn(dev, "%s: slave:%d, srq_no:0x%x, event: %02x(%02x)\n", + __func__, slave, + be32_to_cpu(eqe->event.srq.srqn), + eqe->type, eqe->subtype); if (!ret && slave != dev->caps.function) { - mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n", - __func__, eqe->type, - eqe->subtype, slave); + if (eqe->type == + MLX4_EVENT_TYPE_SRQ_CATAS_ERROR) + mlx4_warn(dev, "%s: sending event %02x(%02x) to slave:%d\n", + __func__, eqe->type, + eqe->subtype, slave); mlx4_slave_event(dev, slave, eqe); break; } diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c index 2a9dd460a95f..e1f9e7cebf8f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/icm.c +++ b/drivers/net/ethernet/mellanox/mlx4/icm.c @@ -118,8 +118,13 @@ static int mlx4_alloc_icm_coherent(struct device *dev, struct scatterlist *mem, if (!buf) return -ENOMEM; + if (offset_in_page(buf)) { + dma_free_coherent(dev, PAGE_SIZE << order, + buf, sg_dma_address(mem)); + return -ENOMEM; + } + sg_set_buf(mem, buf, PAGE_SIZE << order); - BUG_ON(mem->offset); sg_dma_len(mem) = PAGE_SIZE << order; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 0e8b7c44931f..8258d08acd8c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -222,6 +222,18 @@ void mlx4_unregister_device(struct mlx4_dev *dev) return; mlx4_stop_catas_poll(dev); + if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION && + mlx4_is_slave(dev)) { + /* In mlx4_remove_one on a VF */ + u32 slave_read = + swab32(readl(&mlx4_priv(dev)->mfunc.comm->slave_read)); + + if (mlx4_comm_internal_err(slave_read)) { + mlx4_dbg(dev, "%s: comm channel is down, entering error state.\n", + __func__); + mlx4_enter_error_state(dev->persist); + } + } mutex_lock(&intf_mutex); list_for_each_entry(intf, &intf_list, list) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 5e7840a7a33b..bffa6f345f2f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -42,6 +42,7 @@ #include <linux/io-mapping.h> #include <linux/delay.h> #include <linux/kmod.h> +#include <linux/etherdevice.h> #include <net/devlink.h> #include <linux/mlx4/device.h> @@ -782,6 +783,23 @@ int mlx4_is_slave_active(struct mlx4_dev *dev, int slave) } EXPORT_SYMBOL(mlx4_is_slave_active); +void mlx4_handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl, + struct _rule_hw *eth_header) +{ + if (is_multicast_ether_addr(eth_header->eth.dst_mac) || + is_broadcast_ether_addr(eth_header->eth.dst_mac)) { + struct mlx4_net_trans_rule_hw_eth *eth = + (struct mlx4_net_trans_rule_hw_eth *)eth_header; + struct _rule_hw *next_rule = (struct _rule_hw *)(eth + 1); + bool last_rule = next_rule->size == 0 && next_rule->id == 0 && + next_rule->rsvd == 0; + + if (last_rule) + ctrl->prio = cpu_to_be16(MLX4_DOMAIN_NIC); + } +} +EXPORT_SYMBOL(mlx4_handle_eth_header_mcast_prio); + static void slave_adjust_steering_mode(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap, struct mlx4_init_hca_param *hca_param) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 88ee7d8a5923..086920b615af 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -1220,6 +1220,7 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type); void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type); void mlx4_enter_error_state(struct mlx4_dev_persistent *persist); +int mlx4_comm_internal_err(u32 slave_read); int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port, enum mlx4_port_type *type); diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index ba1c6cd0cc79..cec59bc264c9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -679,7 +679,8 @@ void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev, int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv, struct mlx4_en_priv *tmp, - struct mlx4_en_port_profile *prof); + struct mlx4_en_port_profile *prof, + bool carry_xdp_prog); void mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv, struct mlx4_en_priv *tmp); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index c548beaaf910..1822382212ee 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -2980,6 +2980,9 @@ int mlx4_RST2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, put_res(dev, slave, srqn, RES_SRQ); qp->srq = srq; } + + /* Save param3 for dynamic changes from VST back to VGT */ + qp->param3 = qpc->param3; put_res(dev, slave, rcqn, RES_CQ); put_res(dev, slave, mtt_base, RES_MTT); res_end_move(dev, slave, RES_QP, qpn); @@ -3772,7 +3775,6 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, int qpn = vhcr->in_modifier & 0x7fffff; struct res_qp *qp; u8 orig_sched_queue; - __be32 orig_param3 = qpc->param3; u8 orig_vlan_control = qpc->pri_path.vlan_control; u8 orig_fvl_rx = qpc->pri_path.fvl_rx; u8 orig_pri_path_fl = qpc->pri_path.fl; @@ -3814,7 +3816,6 @@ out: */ if (!err) { qp->sched_queue = orig_sched_queue; - qp->param3 = orig_param3; qp->vlan_control = orig_vlan_control; qp->fvl_rx = orig_fvl_rx; qp->pri_path_fl = orig_pri_path_fl; @@ -4164,22 +4165,6 @@ static int validate_eth_header_mac(int slave, struct _rule_hw *eth_header, return 0; } -static void handle_eth_header_mcast_prio(struct mlx4_net_trans_rule_hw_ctrl *ctrl, - struct _rule_hw *eth_header) -{ - if (is_multicast_ether_addr(eth_header->eth.dst_mac) || - is_broadcast_ether_addr(eth_header->eth.dst_mac)) { - struct mlx4_net_trans_rule_hw_eth *eth = - (struct mlx4_net_trans_rule_hw_eth *)eth_header; - struct _rule_hw *next_rule = (struct _rule_hw *)(eth + 1); - bool last_rule = next_rule->size == 0 && next_rule->id == 0 && - next_rule->rsvd == 0; - - if (last_rule) - ctrl->prio = cpu_to_be16(MLX4_DOMAIN_NIC); - } -} - /* * In case of missing eth header, append eth header with a MAC address * assigned to the VF. @@ -4363,10 +4348,7 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, header_id = map_hw_to_sw_id(be16_to_cpu(rule_header->id)); if (header_id == MLX4_NET_TRANS_RULE_ID_ETH) - handle_eth_header_mcast_prio(ctrl, rule_header); - - if (slave == dev->caps.function) - goto execute; + mlx4_handle_eth_header_mcast_prio(ctrl, rule_header); switch (header_id) { case MLX4_NET_TRANS_RULE_ID_ETH: @@ -4394,7 +4376,6 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave, goto err_put_qp; } -execute: err = mlx4_cmd_imm(dev, inbox->dma, &vhcr->out_param, vhcr->in_modifier, 0, MLX4_QP_FLOW_STEERING_ATTACH, MLX4_CMD_TIME_CLASS_A, @@ -4473,6 +4454,7 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, struct res_qp *rqp; struct res_fs_rule *rrule; u64 mirr_reg_id; + int qpn; if (dev->caps.steering_mode != MLX4_STEERING_MODE_DEVICE_MANAGED) @@ -4489,10 +4471,11 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, } mirr_reg_id = rrule->mirr_rule_id; kfree(rrule->mirr_mbox); + qpn = rrule->qpn; /* Release the rule form busy state before removal */ put_res(dev, slave, vhcr->in_param, RES_FS_RULE); - err = get_res(dev, slave, rrule->qpn, RES_QP, &rqp); + err = get_res(dev, slave, qpn, RES_QP, &rqp); if (err) return err; @@ -4517,7 +4500,7 @@ int mlx4_QP_FLOW_STEERING_DETACH_wrapper(struct mlx4_dev *dev, int slave, if (!err) atomic_dec(&rqp->ref_count); out: - put_res(dev, slave, rrule->qpn, RES_QP); + put_res(dev, slave, qpn, RES_QP); return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c index 3797cc7c1288..caa837e5e2b9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/cmd.c @@ -1728,7 +1728,7 @@ int mlx5_cmd_init(struct mlx5_core_dev *dev) if (cmd->cmdif_rev > CMD_IF_REV) { dev_err(&dev->pdev->dev, "driver does not support command interface version. driver %d, firmware %d\n", CMD_IF_REV, cmd->cmdif_rev); - err = -ENOTSUPP; + err = -EOPNOTSUPP; goto err_free_page; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 951dbd58594d..d5ecb8f53fd4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -791,7 +791,8 @@ void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv); int mlx5e_modify_rqs_vsd(struct mlx5e_priv *priv, bool vsd); int mlx5e_redirect_rqt(struct mlx5e_priv *priv, u32 rqtn, int sz, int ix); -void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv); +void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc, + enum mlx5e_traffic_types tt); int mlx5e_open_locked(struct net_device *netdev); int mlx5e_close_locked(struct net_device *netdev); @@ -863,12 +864,12 @@ static inline void mlx5e_arfs_destroy_tables(struct mlx5e_priv *priv) {} static inline int mlx5e_arfs_enable(struct mlx5e_priv *priv) { - return -ENOTSUPP; + return -EOPNOTSUPP; } static inline int mlx5e_arfs_disable(struct mlx5e_priv *priv) { - return -ENOTSUPP; + return -EOPNOTSUPP; } #else int mlx5e_arfs_create_tables(struct mlx5e_priv *priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c index 7f6c225666c1..0523ed47f597 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c @@ -89,7 +89,7 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev, int i; if (!MLX5_CAP_GEN(priv->mdev, ets)) - return -ENOTSUPP; + return -EOPNOTSUPP; ets->ets_cap = mlx5_max_tc(priv->mdev) + 1; for (i = 0; i < ets->ets_cap; i++) { @@ -236,7 +236,7 @@ static int mlx5e_dcbnl_ieee_setets(struct net_device *netdev, int err; if (!MLX5_CAP_GEN(priv->mdev, ets)) - return -ENOTSUPP; + return -EOPNOTSUPP; err = mlx5e_dbcnl_validate_ets(netdev, ets); if (err) @@ -402,7 +402,7 @@ static u8 mlx5e_dcbnl_setall(struct net_device *netdev) struct mlx5_core_dev *mdev = priv->mdev; struct ieee_ets ets; struct ieee_pfc pfc; - int err = -ENOTSUPP; + int err = -EOPNOTSUPP; int i; if (!MLX5_CAP_GEN(mdev, ets)) @@ -511,6 +511,11 @@ static void mlx5e_dcbnl_getpgtccfgtx(struct net_device *netdev, struct mlx5e_priv *priv = netdev_priv(netdev); struct mlx5_core_dev *mdev = priv->mdev; + if (!MLX5_CAP_GEN(priv->mdev, ets)) { + netdev_err(netdev, "%s, ets is not supported\n", __func__); + return; + } + if (priority >= CEE_DCBX_MAX_PRIO) { netdev_err(netdev, "%s, priority is out of range\n", __func__); @@ -723,6 +728,9 @@ static void mlx5e_ets_init(struct mlx5e_priv *priv) int i; struct ieee_ets ets; + if (!MLX5_CAP_GEN(priv->mdev, ets)) + return; + memset(&ets, 0, sizeof(ets)); ets.ets_cap = mlx5_max_tc(priv->mdev) + 1; for (i = 0; i < ets.ets_cap; i++) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 352462af8d51..bb67863aa361 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -171,7 +171,6 @@ static int mlx5e_get_sset_count(struct net_device *dev, int sset) return NUM_SW_COUNTERS + MLX5E_NUM_Q_CNTRS(priv) + NUM_VPORT_COUNTERS + NUM_PPORT_COUNTERS + - NUM_PCIE_COUNTERS + MLX5E_NUM_RQ_STATS(priv) + MLX5E_NUM_SQ_STATS(priv) + MLX5E_NUM_PFC_COUNTERS(priv) + @@ -219,14 +218,6 @@ static void mlx5e_fill_stats_strings(struct mlx5e_priv *priv, uint8_t *data) strcpy(data + (idx++) * ETH_GSTRING_LEN, pport_2819_stats_desc[i].format); - for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++) - strcpy(data + (idx++) * ETH_GSTRING_LEN, - pcie_perf_stats_desc[i].format); - - for (i = 0; i < NUM_PCIE_TAS_COUNTERS; i++) - strcpy(data + (idx++) * ETH_GSTRING_LEN, - pcie_tas_stats_desc[i].format); - for (prio = 0; prio < NUM_PPORT_PRIO; prio++) { for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++) sprintf(data + (idx++) * ETH_GSTRING_LEN, @@ -339,14 +330,6 @@ static void mlx5e_get_ethtool_stats(struct net_device *dev, data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.RFC_2819_counters, pport_2819_stats_desc, i); - for (i = 0; i < NUM_PCIE_PERF_COUNTERS; i++) - data[idx++] = MLX5E_READ_CTR32_BE(&priv->stats.pcie.pcie_perf_counters, - pcie_perf_stats_desc, i); - - for (i = 0; i < NUM_PCIE_TAS_COUNTERS; i++) - data[idx++] = MLX5E_READ_CTR32_BE(&priv->stats.pcie.pcie_tas_counters, - pcie_tas_stats_desc, i); - for (prio = 0; prio < NUM_PPORT_PRIO; prio++) { for (i = 0; i < NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS; i++) data[idx++] = MLX5E_READ_CTR64_BE(&priv->stats.pport.per_prio_counters[prio], @@ -560,7 +543,6 @@ static int mlx5e_set_channels(struct net_device *dev, struct ethtool_channels *ch) { struct mlx5e_priv *priv = netdev_priv(dev); - int ncv = mlx5e_get_max_num_channels(priv->mdev); unsigned int count = ch->combined_count; bool arfs_enabled; bool was_opened; @@ -571,16 +553,6 @@ static int mlx5e_set_channels(struct net_device *dev, __func__); return -EINVAL; } - if (ch->rx_count || ch->tx_count) { - netdev_info(dev, "%s: separate rx/tx count not supported\n", - __func__); - return -EINVAL; - } - if (count > ncv) { - netdev_info(dev, "%s: count (%d) > max (%d)\n", - __func__, count, ncv); - return -EINVAL; - } if (priv->params.num_channels == count) return 0; @@ -623,7 +595,7 @@ static int mlx5e_get_coalesce(struct net_device *netdev, struct mlx5e_priv *priv = netdev_priv(netdev); if (!MLX5_CAP_GEN(priv->mdev, cq_moderation)) - return -ENOTSUPP; + return -EOPNOTSUPP; coal->rx_coalesce_usecs = priv->params.rx_cq_moderation.usec; coal->rx_max_coalesced_frames = priv->params.rx_cq_moderation.pkts; @@ -648,7 +620,7 @@ static int mlx5e_set_coalesce(struct net_device *netdev, int i; if (!MLX5_CAP_GEN(mdev, cq_moderation)) - return -ENOTSUPP; + return -EOPNOTSUPP; mutex_lock(&priv->state_lock); @@ -1008,15 +980,18 @@ static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, static void mlx5e_modify_tirs_hash(struct mlx5e_priv *priv, void *in, int inlen) { - struct mlx5_core_dev *mdev = priv->mdev; void *tirc = MLX5_ADDR_OF(modify_tir_in, in, ctx); - int i; + struct mlx5_core_dev *mdev = priv->mdev; + int ctxlen = MLX5_ST_SZ_BYTES(tirc); + int tt; MLX5_SET(modify_tir_in, in, bitmask.hash, 1); - mlx5e_build_tir_ctx_hash(tirc, priv); - for (i = 0; i < MLX5E_NUM_INDIR_TIRS; i++) - mlx5_core_modify_tir(mdev, priv->indir_tir[i].tirn, in, inlen); + for (tt = 0; tt < MLX5E_NUM_INDIR_TIRS; tt++) { + memset(tirc, 0, ctxlen); + mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt); + mlx5_core_modify_tir(mdev, priv->indir_tir[tt].tirn, in, inlen); + } } static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, @@ -1024,6 +999,7 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, { struct mlx5e_priv *priv = netdev_priv(dev); int inlen = MLX5_ST_SZ_BYTES(modify_tir_in); + bool hash_changed = false; void *in; if ((hfunc != ETH_RSS_HASH_NO_CHANGE) && @@ -1045,14 +1021,21 @@ static int mlx5e_set_rxfh(struct net_device *dev, const u32 *indir, mlx5e_redirect_rqt(priv, rqtn, MLX5E_INDIR_RQT_SIZE, 0); } - if (key) + if (hfunc != ETH_RSS_HASH_NO_CHANGE && + hfunc != priv->params.rss_hfunc) { + priv->params.rss_hfunc = hfunc; + hash_changed = true; + } + + if (key) { memcpy(priv->params.toeplitz_hash_key, key, sizeof(priv->params.toeplitz_hash_key)); + hash_changed = hash_changed || + priv->params.rss_hfunc == ETH_RSS_HASH_TOP; + } - if (hfunc != ETH_RSS_HASH_NO_CHANGE) - priv->params.rss_hfunc = hfunc; - - mlx5e_modify_tirs_hash(priv, in, inlen); + if (hash_changed) + mlx5e_modify_tirs_hash(priv, in, inlen); mutex_unlock(&priv->state_lock); @@ -1324,7 +1307,7 @@ static int mlx5e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) u32 mlx5_wol_mode; if (!wol_supported) - return -ENOTSUPP; + return -EOPNOTSUPP; if (wol->wolopts & ~wol_supported) return -EINVAL; @@ -1454,7 +1437,7 @@ static int set_pflag_rx_cqe_based_moder(struct net_device *netdev, bool enable) if (rx_cq_period_mode == MLX5_CQ_PERIOD_MODE_START_FROM_CQE && !MLX5_CAP_GEN(mdev, cq_period_start_from_cqe)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (!rx_mode_changed) return 0; @@ -1480,7 +1463,7 @@ static int set_pflag_rx_cqe_compress(struct net_device *netdev, bool reset; if (!MLX5_CAP_GEN(mdev, cqe_compression)) - return -ENOTSUPP; + return -EOPNOTSUPP; if (enable && priv->tstamp.hwtstamp_config.rx_filter != HWTSTAMP_FILTER_NONE) { netdev_err(netdev, "Can't enable cqe compression while timestamping is enabled.\n"); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c index 1fe80de5d68f..a0e5a69402b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs.c @@ -1089,7 +1089,7 @@ int mlx5e_create_flow_steering(struct mlx5e_priv *priv) MLX5_FLOW_NAMESPACE_KERNEL); if (!priv->fs.ns) - return -EINVAL; + return -EOPNOTSUPP; err = mlx5e_arfs_create_tables(priv); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index 3691451c728c..f33f72d0237c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -92,7 +92,7 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv, ns = mlx5_get_flow_namespace(priv->mdev, MLX5_FLOW_NAMESPACE_ETHTOOL); if (!ns) - return ERR_PTR(-ENOTSUPP); + return ERR_PTR(-EOPNOTSUPP); table_size = min_t(u32, BIT(MLX5_CAP_FLOWTABLE(priv->mdev, flow_table_properties_nic_receive.log_max_ft_size)), @@ -247,6 +247,7 @@ static int set_flow_attrs(u32 *match_c, u32 *match_v, } if (fs->flow_type & FLOW_MAC_EXT && !is_zero_ether_addr(fs->m_ext.h_dest)) { + mask_spec(fs->m_ext.h_dest, fs->h_ext.h_dest, ETH_ALEN); ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, dmac_47_16), fs->m_ext.h_dest); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index cbfa38fc72c0..f14ca3385fdd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -291,36 +291,12 @@ static void mlx5e_update_q_counter(struct mlx5e_priv *priv) &qcnt->rx_out_of_buffer); } -static void mlx5e_update_pcie_counters(struct mlx5e_priv *priv) -{ - struct mlx5e_pcie_stats *pcie_stats = &priv->stats.pcie; - struct mlx5_core_dev *mdev = priv->mdev; - int sz = MLX5_ST_SZ_BYTES(mpcnt_reg); - void *out; - u32 *in; - - in = mlx5_vzalloc(sz); - if (!in) - return; - - out = pcie_stats->pcie_perf_counters; - MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_PERFORMANCE_COUNTERS_GROUP); - mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0); - - out = pcie_stats->pcie_tas_counters; - MLX5_SET(mpcnt_reg, in, grp, MLX5_PCIE_TIMERS_AND_STATES_COUNTERS_GROUP); - mlx5_core_access_reg(mdev, in, sz, out, sz, MLX5_REG_MPCNT, 0, 0); - - kvfree(in); -} - void mlx5e_update_stats(struct mlx5e_priv *priv) { mlx5e_update_q_counter(priv); mlx5e_update_vport_counters(priv); mlx5e_update_pport_counters(priv); mlx5e_update_sw_counters(priv); - mlx5e_update_pcie_counters(priv); } void mlx5e_update_stats_work(struct work_struct *work) @@ -2046,8 +2022,23 @@ static void mlx5e_build_tir_ctx_lro(void *tirc, struct mlx5e_priv *priv) MLX5_SET(tirc, tirc, lro_timeout_period_usecs, priv->params.lro_timeout); } -void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv) +void mlx5e_build_indir_tir_ctx_hash(struct mlx5e_priv *priv, void *tirc, + enum mlx5e_traffic_types tt) { + void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); + +#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP) + +#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_L4_SPORT |\ + MLX5_HASH_FIELD_SEL_L4_DPORT) + +#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_IPSEC_SPI) + MLX5_SET(tirc, tirc, rx_hash_fn, mlx5e_rx_hash_fn(priv->params.rss_hfunc)); if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { @@ -2059,6 +2050,88 @@ void mlx5e_build_tir_ctx_hash(void *tirc, struct mlx5e_priv *priv) MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); memcpy(rss_key, priv->params.toeplitz_hash_key, len); } + + switch (tt) { + case MLX5E_TT_IPV4_TCP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_TCP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_L4PORTS); + break; + + case MLX5E_TT_IPV6_TCP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_TCP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_L4PORTS); + break; + + case MLX5E_TT_IPV4_UDP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_UDP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_L4PORTS); + break; + + case MLX5E_TT_IPV6_UDP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, + MLX5_L4_PROT_TYPE_UDP); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_L4PORTS); + break; + + case MLX5E_TT_IPV4_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV4_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV4: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP); + break; + + case MLX5E_TT_IPV6: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP); + break; + default: + WARN_ONCE(true, "%s: bad traffic type!\n", __func__); + } } static int mlx5e_modify_tirs_lro(struct mlx5e_priv *priv) @@ -2428,110 +2501,13 @@ void mlx5e_cleanup_nic_tx(struct mlx5e_priv *priv) static void mlx5e_build_indir_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, enum mlx5e_traffic_types tt) { - void *hfso = MLX5_ADDR_OF(tirc, tirc, rx_hash_field_selector_outer); - MLX5_SET(tirc, tirc, transport_domain, priv->mdev->mlx5e_res.td.tdn); -#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP) - -#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP |\ - MLX5_HASH_FIELD_SEL_L4_SPORT |\ - MLX5_HASH_FIELD_SEL_L4_DPORT) - -#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP |\ - MLX5_HASH_FIELD_SEL_IPSEC_SPI) - mlx5e_build_tir_ctx_lro(tirc, priv); MLX5_SET(tirc, tirc, disp_type, MLX5_TIRC_DISP_TYPE_INDIRECT); MLX5_SET(tirc, tirc, indirect_table, priv->indir_rqt.rqtn); - mlx5e_build_tir_ctx_hash(tirc, priv); - - switch (tt) { - case MLX5E_TT_IPV4_TCP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV4); - MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, - MLX5_L4_PROT_TYPE_TCP); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_L4PORTS); - break; - - case MLX5E_TT_IPV6_TCP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV6); - MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, - MLX5_L4_PROT_TYPE_TCP); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_L4PORTS); - break; - - case MLX5E_TT_IPV4_UDP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV4); - MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, - MLX5_L4_PROT_TYPE_UDP); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_L4PORTS); - break; - - case MLX5E_TT_IPV6_UDP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV6); - MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, - MLX5_L4_PROT_TYPE_UDP); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_L4PORTS); - break; - - case MLX5E_TT_IPV4_IPSEC_AH: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV4); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_IPSEC_SPI); - break; - - case MLX5E_TT_IPV6_IPSEC_AH: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV6); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_IPSEC_SPI); - break; - - case MLX5E_TT_IPV4_IPSEC_ESP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV4); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_IPSEC_SPI); - break; - - case MLX5E_TT_IPV6_IPSEC_ESP: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV6); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP_IPSEC_SPI); - break; - - case MLX5E_TT_IPV4: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV4); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP); - break; - - case MLX5E_TT_IPV6: - MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, - MLX5_L3_PROT_TYPE_IPV6); - MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_IP); - break; - default: - WARN_ONCE(true, - "mlx5e_build_indir_tir_ctx: bad traffic type!\n"); - } + mlx5e_build_indir_tir_ctx_hash(priv, tirc, tt); } static void mlx5e_build_direct_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, @@ -3355,7 +3331,7 @@ static const struct net_device_ops mlx5e_netdev_ops_sriov = { static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) { if (MLX5_CAP_GEN(mdev, port_type) != MLX5_CAP_PORT_TYPE_ETH) - return -ENOTSUPP; + return -EOPNOTSUPP; if (!MLX5_CAP_GEN(mdev, eth_net_offloads) || !MLX5_CAP_GEN(mdev, nic_flow_table) || !MLX5_CAP_ETH(mdev, csum_cap) || @@ -3367,7 +3343,7 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) < 3) { mlx5_core_warn(mdev, "Not creating net device, some required device capabilities are missing\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable)) mlx5_core_warn(mdev, "Self loop back prevention is not supported\n"); @@ -3699,14 +3675,8 @@ static void mlx5e_nic_init(struct mlx5_core_dev *mdev, static void mlx5e_nic_cleanup(struct mlx5e_priv *priv) { - struct mlx5_core_dev *mdev = priv->mdev; - struct mlx5_eswitch *esw = mdev->priv.eswitch; - mlx5e_vxlan_cleanup(priv); - if (MLX5_CAP_GEN(mdev, vport_group_manager)) - mlx5_eswitch_unregister_vport_rep(esw, 0); - if (priv->xdp_prog) bpf_prog_put(priv->xdp_prog); } @@ -3805,14 +3775,7 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) mlx5_lag_add(mdev, netdev); - if (mlx5e_vxlan_allowed(mdev)) { - rtnl_lock(); - udp_tunnel_get_rx_info(netdev); - rtnl_unlock(); - } - mlx5e_enable_async_events(priv); - queue_work(priv->wq, &priv->set_rx_mode_work); if (MLX5_CAP_GEN(mdev, vport_group_manager)) { mlx5_query_nic_vport_mac_address(mdev, 0, rep.hw_id); @@ -3822,13 +3785,30 @@ static void mlx5e_nic_enable(struct mlx5e_priv *priv) rep.netdev = netdev; mlx5_eswitch_register_vport_rep(esw, 0, &rep); } + + if (netdev->reg_state != NETREG_REGISTERED) + return; + + /* Device already registered: sync netdev system state */ + if (mlx5e_vxlan_allowed(mdev)) { + rtnl_lock(); + udp_tunnel_get_rx_info(netdev); + rtnl_unlock(); + } + + queue_work(priv->wq, &priv->set_rx_mode_work); } static void mlx5e_nic_disable(struct mlx5e_priv *priv) { + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5_eswitch *esw = mdev->priv.eswitch; + queue_work(priv->wq, &priv->set_rx_mode_work); + if (MLX5_CAP_GEN(mdev, vport_group_manager)) + mlx5_eswitch_unregister_vport_rep(esw, 0); mlx5e_disable_async_events(priv); - mlx5_lag_remove(priv->mdev); + mlx5_lag_remove(mdev); } static const struct mlx5e_profile mlx5e_nic_profile = { @@ -3966,10 +3946,6 @@ void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev) const struct mlx5e_profile *profile = priv->profile; set_bit(MLX5E_STATE_DESTROYING, &priv->state); - if (profile->disable) - profile->disable(priv); - - flush_workqueue(priv->wq); rtnl_lock(); if (netif_running(netdev)) @@ -3977,6 +3953,10 @@ void mlx5e_detach_netdev(struct mlx5_core_dev *mdev, struct net_device *netdev) netif_device_detach(netdev); rtnl_unlock(); + if (profile->disable) + profile->disable(priv); + flush_workqueue(priv->wq); + mlx5e_destroy_q_counter(priv); profile->cleanup_rx(priv); mlx5e_close_drop_rq(priv); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c index 0e2fb3ed1790..06d5e6fecb0a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c @@ -193,6 +193,9 @@ static inline bool mlx5e_rx_cache_put(struct mlx5e_rq *rq, return false; } + if (unlikely(page_is_pfmemalloc(dma_info->page))) + return false; + cache->page_cache[cache->tail] = *dma_info; cache->tail = tail_next; return true; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c b/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c index 1fffe48a93cc..cbfac06b7ffd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_rx_am.c @@ -109,7 +109,6 @@ static bool mlx5e_am_on_top(struct mlx5e_rx_am *am) switch (am->tune_state) { case MLX5E_AM_PARKING_ON_TOP: case MLX5E_AM_PARKING_TIRED: - WARN_ONCE(true, "mlx5e_am_on_top: PARKING\n"); return true; case MLX5E_AM_GOING_RIGHT: return (am->steps_left > 1) && (am->steps_right == 1); @@ -123,7 +122,6 @@ static void mlx5e_am_turn(struct mlx5e_rx_am *am) switch (am->tune_state) { case MLX5E_AM_PARKING_ON_TOP: case MLX5E_AM_PARKING_TIRED: - WARN_ONCE(true, "mlx5e_am_turn: PARKING\n"); break; case MLX5E_AM_GOING_RIGHT: am->tune_state = MLX5E_AM_GOING_LEFT; @@ -144,7 +142,6 @@ static int mlx5e_am_step(struct mlx5e_rx_am *am) switch (am->tune_state) { case MLX5E_AM_PARKING_ON_TOP: case MLX5E_AM_PARKING_TIRED: - WARN_ONCE(true, "mlx5e_am_step: PARKING\n"); break; case MLX5E_AM_GOING_RIGHT: if (am->profile_ix == (MLX5E_PARAMS_AM_NUM_PROFILES - 1)) @@ -282,10 +279,8 @@ static void mlx5e_am_calc_stats(struct mlx5e_rx_am_sample *start, u32 delta_us = ktime_us_delta(end->time, start->time); unsigned int npkts = end->pkt_ctr - start->pkt_ctr; - if (!delta_us) { - WARN_ONCE(true, "mlx5e_am_calc_stats: delta_us=0\n"); + if (!delta_us) return; - } curr_stats->ppms = (npkts * USEC_PER_MSEC) / delta_us; curr_stats->epms = (MLX5E_AM_NEVENTS * USEC_PER_MSEC) / delta_us; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h index f202f872f57f..ba5db1dd23a9 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_stats.h @@ -39,7 +39,7 @@ #define MLX5E_READ_CTR32_CPU(ptr, dsc, i) \ (*(u32 *)((char *)ptr + dsc[i].offset)) #define MLX5E_READ_CTR32_BE(ptr, dsc, i) \ - be32_to_cpu(*(__be32 *)((char *)ptr + dsc[i].offset)) + be64_to_cpu(*(__be32 *)((char *)ptr + dsc[i].offset)) #define MLX5E_DECLARE_STAT(type, fld) #fld, offsetof(type, fld) #define MLX5E_DECLARE_RX_STAT(type, fld) "rx%d_"#fld, offsetof(type, fld) @@ -276,32 +276,6 @@ static const struct counter_desc pport_per_prio_pfc_stats_desc[] = { { "rx_%s_pause_transition", PPORT_PER_PRIO_OFF(rx_pause_transition) }, }; -#define PCIE_PERF_OFF(c) \ - MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_perf_cntrs_grp_data_layout.c) -#define PCIE_PERF_GET(pcie_stats, c) \ - MLX5_GET(mpcnt_reg, pcie_stats->pcie_perf_counters, \ - counter_set.pcie_perf_cntrs_grp_data_layout.c) -#define PCIE_TAS_OFF(c) \ - MLX5_BYTE_OFF(mpcnt_reg, counter_set.pcie_tas_cntrs_grp_data_layout.c) -#define PCIE_TAS_GET(pcie_stats, c) \ - MLX5_GET(mpcnt_reg, pcie_stats->pcie_tas_counters, \ - counter_set.pcie_tas_cntrs_grp_data_layout.c) - -struct mlx5e_pcie_stats { - __be64 pcie_perf_counters[MLX5_ST_SZ_QW(mpcnt_reg)]; - __be64 pcie_tas_counters[MLX5_ST_SZ_QW(mpcnt_reg)]; -}; - -static const struct counter_desc pcie_perf_stats_desc[] = { - { "rx_pci_signal_integrity", PCIE_PERF_OFF(rx_errors) }, - { "tx_pci_signal_integrity", PCIE_PERF_OFF(tx_errors) }, -}; - -static const struct counter_desc pcie_tas_stats_desc[] = { - { "tx_pci_transport_nonfatal_msg", PCIE_TAS_OFF(non_fatal_err_msg_sent) }, - { "tx_pci_transport_fatal_msg", PCIE_TAS_OFF(fatal_err_msg_sent) }, -}; - struct mlx5e_rq_stats { u64 packets; u64 bytes; @@ -386,8 +360,6 @@ static const struct counter_desc sq_stats_desc[] = { #define NUM_PPORT_802_3_COUNTERS ARRAY_SIZE(pport_802_3_stats_desc) #define NUM_PPORT_2863_COUNTERS ARRAY_SIZE(pport_2863_stats_desc) #define NUM_PPORT_2819_COUNTERS ARRAY_SIZE(pport_2819_stats_desc) -#define NUM_PCIE_PERF_COUNTERS ARRAY_SIZE(pcie_perf_stats_desc) -#define NUM_PCIE_TAS_COUNTERS ARRAY_SIZE(pcie_tas_stats_desc) #define NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS \ ARRAY_SIZE(pport_per_prio_traffic_stats_desc) #define NUM_PPORT_PER_PRIO_PFC_COUNTERS \ @@ -397,7 +369,6 @@ static const struct counter_desc sq_stats_desc[] = { NUM_PPORT_2819_COUNTERS + \ NUM_PPORT_PER_PRIO_TRAFFIC_COUNTERS * \ NUM_PPORT_PRIO) -#define NUM_PCIE_COUNTERS (NUM_PCIE_PERF_COUNTERS + NUM_PCIE_TAS_COUNTERS) #define NUM_RQ_STATS ARRAY_SIZE(rq_stats_desc) #define NUM_SQ_STATS ARRAY_SIZE(sq_stats_desc) @@ -406,7 +377,6 @@ struct mlx5e_stats { struct mlx5e_qcounter_stats qcnt; struct mlx5e_vport_stats vport; struct mlx5e_pport_stats pport; - struct mlx5e_pcie_stats pcie; struct rtnl_link_stats64 vf_vport; }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index f8829b517156..2ebbe80d8126 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -161,15 +161,21 @@ static void mlx5e_detach_encap(struct mlx5e_priv *priv, } } +/* we get here also when setting rule to the FW failed, etc. It means that the + * flow rule itself might not exist, but some offloading related to the actions + * should be cleaned. + */ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, struct mlx5e_tc_flow *flow) { struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_fc *counter = NULL; - counter = mlx5_flow_rule_counter(flow->rule); - - mlx5_del_flow_rules(flow->rule); + if (!IS_ERR(flow->rule)) { + counter = mlx5_flow_rule_counter(flow->rule); + mlx5_del_flow_rules(flow->rule); + mlx5_fc_destroy(priv->mdev, counter); + } if (esw && esw->mode == SRIOV_OFFLOADS) { mlx5_eswitch_del_vlan_action(esw, flow->attr); @@ -177,8 +183,6 @@ static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, mlx5e_detach_encap(priv, flow); } - mlx5_fc_destroy(priv->mdev, counter); - if (!mlx5e_tc_num_filters(priv) && (priv->fs.tc.t)) { mlx5_destroy_flow_table(priv->fs.tc.t); priv->fs.tc.t = NULL; @@ -225,6 +229,11 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, void *headers_v = MLX5_ADDR_OF(fte_match_param, spec->match_value, outer_headers); + struct flow_dissector_key_control *enc_control = + skb_flow_dissector_target(f->dissector, + FLOW_DISSECTOR_KEY_ENC_CONTROL, + f->key); + if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) { struct flow_dissector_key_ports *key = skb_flow_dissector_target(f->dissector, @@ -237,28 +246,34 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, /* Full udp dst port must be given */ if (memchr_inv(&mask->dst, 0xff, sizeof(mask->dst))) - return -EOPNOTSUPP; - - /* udp src port isn't supported */ - if (memchr_inv(&mask->src, 0, sizeof(mask->src))) - return -EOPNOTSUPP; + goto vxlan_match_offload_err; if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->dst)) && MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) parse_vxlan_attr(spec, f); - else + else { + netdev_warn(priv->netdev, + "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->dst)); return -EOPNOTSUPP; + } MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport, ntohs(mask->dst)); MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, ntohs(key->dst)); + MLX5_SET(fte_match_set_lyr_2_4, headers_c, + udp_sport, ntohs(mask->src)); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, + udp_sport, ntohs(key->src)); } else { /* udp dst port must be given */ - return -EOPNOTSUPP; +vxlan_match_offload_err: + netdev_warn(priv->netdev, + "IP tunnel decap offload supported only for vxlan, must set UDP dport\n"); + return -EOPNOTSUPP; } - if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) { + if (enc_control->addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) { struct flow_dissector_key_ipv4_addrs *key = skb_flow_dissector_target(f->dissector, FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS, @@ -280,10 +295,10 @@ static int parse_tunnel_attr(struct mlx5e_priv *priv, MLX5_SET(fte_match_set_lyr_2_4, headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4, ntohl(key->dst)); - } - MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); - MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); + MLX5_SET_TO_ONES(fte_match_set_lyr_2_4, headers_c, ethertype); + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); + } /* Enforce DMAC when offloading incoming tunneled flows. * Flow counters require a match on the DMAC. @@ -346,6 +361,9 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, if (parse_tunnel_attr(priv, spec, f)) return -EOPNOTSUPP; break; + case FLOW_DISSECTOR_KEY_IPV6_ADDRS: + netdev_warn(priv->netdev, + "IPv6 tunnel decap offload isn't supported\n"); default: return -EOPNOTSUPP; } @@ -375,6 +393,10 @@ static int __parse_cls_flower(struct mlx5e_priv *priv, MLX5_SET(fte_match_set_lyr_2_4, headers_c, frag, 1); MLX5_SET(fte_match_set_lyr_2_4, headers_v, frag, key->flags & FLOW_DIS_IS_FRAGMENT); + + /* the HW doesn't need L3 inline to match on frag=no */ + if (key->flags & FLOW_DIS_IS_FRAGMENT) + *min_inline = MLX5_INLINE_MODE_IP; } } @@ -641,26 +663,26 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, __be32 *saddr, int *out_ttl) { + struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct rtable *rt; struct neighbour *n = NULL; int ttl; #if IS_ENABLED(CONFIG_INET) + int ret; + rt = ip_route_output_key(dev_net(mirred_dev), fl4); - if (IS_ERR(rt)) { - pr_warn("%s: no route to %pI4\n", __func__, &fl4->daddr); - return -EOPNOTSUPP; - } + ret = PTR_ERR_OR_ZERO(rt); + if (ret) + return ret; #else return -EOPNOTSUPP; #endif - - if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) { - pr_warn("%s: Can't offload the flow, netdevices aren't on the same HW e-switch\n", - __func__); - ip_rt_put(rt); - return -EOPNOTSUPP; - } + /* if the egress device isn't on the same HW e-switch, we use the uplink */ + if (!switchdev_port_same_parent_id(priv->netdev, rt->dst.dev)) + *out_dev = mlx5_eswitch_get_uplink_netdev(esw); + else + *out_dev = rt->dst.dev; ttl = ip4_dst_hoplimit(&rt->dst); n = dst_neigh_lookup(&rt->dst, &fl4->daddr); @@ -671,7 +693,6 @@ static int mlx5e_route_lookup_ipv4(struct mlx5e_priv *priv, *out_n = n; *saddr = fl4->saddr; *out_ttl = ttl; - *out_dev = rt->dst.dev; return 0; } @@ -718,8 +739,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, struct net_device **out_dev) { int max_encap_size = MLX5_CAP_ESW(priv->mdev, max_encap_header_size); + struct neighbour *n = NULL; struct flowi4 fl4 = {}; - struct neighbour *n; char *encap_header; int encap_size; __be32 saddr; @@ -750,7 +771,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, e->out_dev = *out_dev; if (!(n->nud_state & NUD_VALID)) { - err = -ENOTSUPP; + pr_warn("%s: can't offload, neighbour to %pI4 invalid\n", __func__, &fl4.daddr); + err = -EOPNOTSUPP; goto out; } @@ -772,6 +794,8 @@ static int mlx5e_create_encap_header_ipv4(struct mlx5e_priv *priv, err = mlx5_encap_alloc(priv->mdev, e->tunnel_type, encap_size, encap_header, &e->encap_id); out: + if (err && n) + neigh_release(n); kfree(encap_header); return err; } @@ -792,9 +816,17 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, int tunnel_type; int err; - /* udp dst port must be given */ + /* udp dst port must be set */ if (!memchr_inv(&key->tp_dst, 0, sizeof(key->tp_dst))) + goto vxlan_encap_offload_err; + + /* setting udp src port isn't supported */ + if (memchr_inv(&key->tp_src, 0, sizeof(key->tp_src))) { +vxlan_encap_offload_err: + netdev_warn(priv->netdev, + "must set udp dst port and not set udp src port\n"); return -EOPNOTSUPP; + } if (mlx5e_vxlan_lookup_port(priv, be16_to_cpu(key->tp_dst)) && MLX5_CAP_ESW(priv->mdev, vxlan_encap_decap)) { @@ -802,6 +834,8 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, info.tun_id = tunnel_id_to_key32(key->tun_id); tunnel_type = MLX5_HEADER_TYPE_VXLAN; } else { + netdev_warn(priv->netdev, + "%d isn't an offloaded vxlan udp dport\n", be16_to_cpu(key->tp_dst)); return -EOPNOTSUPP; } @@ -809,6 +843,9 @@ static int mlx5e_attach_encap(struct mlx5e_priv *priv, case AF_INET: info.daddr = key->u.ipv4.dst; break; + case AF_INET6: + netdev_warn(priv->netdev, + "IPv6 tunnel encap offload isn't supported\n"); default: return -EOPNOTSUPP; } @@ -986,7 +1023,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, if (IS_ERR(flow->rule)) { err = PTR_ERR(flow->rule); - goto err_free; + goto err_del_rule; } err = rhashtable_insert_fast(&tc->ht, &flow->node, @@ -997,7 +1034,7 @@ int mlx5e_configure_flower(struct mlx5e_priv *priv, __be16 protocol, goto out; err_del_rule: - mlx5_del_flow_rules(flow->rule); + mlx5e_tc_del_flow(priv, flow); err_free: kfree(flow); @@ -1050,10 +1087,14 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv, mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse); + preempt_disable(); + tcf_exts_to_list(f->exts, &actions); list_for_each_entry(a, &actions, list) tcf_action_stats_update(a, bytes, packets, lastuse); + preempt_enable(); + return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index d6807c3cc461..d0c8bf014453 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -133,7 +133,7 @@ static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u32 vport, if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) || !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist)) - return -ENOTSUPP; + return -EOPNOTSUPP; esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n", vport, vlan, qos, set_flags); @@ -353,7 +353,7 @@ static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw, int nvports) root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); if (!root_ns) { esw_warn(dev, "Failed to get FDB flow namespace\n"); - return -ENOMEM; + return -EOPNOTSUPP; } flow_group_in = mlx5_vzalloc(inlen); @@ -962,7 +962,7 @@ static int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw, root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS); if (!root_ns) { esw_warn(dev, "Failed to get E-Switch egress flow namespace\n"); - return -EIO; + return -EOPNOTSUPP; } flow_group_in = mlx5_vzalloc(inlen); @@ -1079,7 +1079,7 @@ static int esw_vport_enable_ingress_acl(struct mlx5_eswitch *esw, root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS); if (!root_ns) { esw_warn(dev, "Failed to get E-Switch ingress flow namespace\n"); - return -EIO; + return -EOPNOTSUPP; } flow_group_in = mlx5_vzalloc(inlen); @@ -1630,7 +1630,7 @@ int mlx5_eswitch_enable_sriov(struct mlx5_eswitch *esw, int nvfs, int mode) if (!MLX5_CAP_GEN(esw->dev, eswitch_flow_table) || !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) { esw_warn(esw->dev, "E-Switch FDB is not supported, aborting ...\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support)) @@ -1860,7 +1860,7 @@ int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw, if (!ESW_ALLOWED(esw)) return -EPERM; - if (!LEGAL_VPORT(esw, vport)) + if (!LEGAL_VPORT(esw, vport) || is_multicast_ether_addr(mac)) return -EINVAL; mutex_lock(&esw->state_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 466e161010f7..595f7c7383b3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -166,7 +166,7 @@ static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr, return 0; out_notsupp: - return -ENOTSUPP; + return -EOPNOTSUPP; } int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw, @@ -424,6 +424,7 @@ static int esw_create_offloads_fdb_table(struct mlx5_eswitch *esw, int nvports) root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB); if (!root_ns) { esw_warn(dev, "Failed to get FDB flow namespace\n"); + err = -EOPNOTSUPP; goto ns_err; } @@ -535,7 +536,7 @@ static int esw_create_offloads_table(struct mlx5_eswitch *esw) ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS); if (!ns) { esw_warn(esw->dev, "Failed to get offloads flow namespace\n"); - return -ENOMEM; + return -EOPNOTSUPP; } ft_offloads = mlx5_create_flow_table(ns, 0, dev->priv.sriov.num_vfs + 2, 0, 0); @@ -655,7 +656,7 @@ static int esw_offloads_start(struct mlx5_eswitch *esw) esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err); err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY); if (err1) - esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err); + esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1); } if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) { if (mlx5_eswitch_inline_mode_get(esw, @@ -674,9 +675,14 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports) int vport; int err; + /* disable PF RoCE so missed packets don't go through RoCE steering */ + mlx5_dev_list_lock(); + mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB); + mlx5_dev_list_unlock(); + err = esw_create_offloads_fdb_table(esw, nvports); if (err) - return err; + goto create_fdb_err; err = esw_create_offloads_table(esw); if (err) @@ -695,6 +701,7 @@ int esw_offloads_init(struct mlx5_eswitch *esw, int nvports) if (err) goto err_reps; } + return 0; err_reps: @@ -711,6 +718,13 @@ create_fg_err: create_ft_err: esw_destroy_offloads_fdb_table(esw); + +create_fdb_err: + /* enable back PF RoCE */ + mlx5_dev_list_lock(); + mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB); + mlx5_dev_list_unlock(); + return err; } @@ -727,6 +741,11 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw) esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err); } + /* enable back PF RoCE */ + mlx5_dev_list_lock(); + mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB); + mlx5_dev_list_unlock(); + return err; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c index c4478ecd8056..b53fc85a2375 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c @@ -322,7 +322,7 @@ int mlx5_cmd_update_fte(struct mlx5_core_dev *dev, flow_table_properties_nic_receive. flow_modify_en); if (!atomic_mod_cap) - return -ENOTSUPP; + return -EOPNOTSUPP; opmod = 1; return mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, group_id, fte); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c index a263d8904a4c..6346a8f5883b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_core.c @@ -1263,6 +1263,7 @@ static struct mlx5_flow_handle *add_rule_fg(struct mlx5_flow_group *fg, nested_lock_ref_node(&fte->node, FS_MUTEX_CHILD); handle = add_rule_fte(fte, fg, dest, dest_num, false); if (IS_ERR(handle)) { + unlock_ref_node(&fte->node); kfree(fte); goto unlock_fg; } @@ -1821,7 +1822,7 @@ static int create_anchor_flow_table(struct mlx5_flow_steering *steering) struct mlx5_flow_table *ft; ns = mlx5_get_flow_namespace(steering->dev, MLX5_FLOW_NAMESPACE_ANCHOR); - if (!ns) + if (WARN_ON(!ns)) return -EINVAL; ft = mlx5_create_flow_table(ns, ANCHOR_PRIO, ANCHOR_SIZE, ANCHOR_LEVEL, 0); if (IS_ERR(ft)) { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index 54e5a786f191..3c315eb8d270 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -503,6 +503,13 @@ static int handle_hca_cap(struct mlx5_core_dev *dev) MLX5_SET(cmd_hca_cap, set_hca_cap, pkey_table_size, to_fw_pkey_sz(dev, 128)); + /* Check log_max_qp from HCA caps to set in current profile */ + if (MLX5_CAP_GEN_MAX(dev, log_max_qp) < profile[prof_sel].log_max_qp) { + mlx5_core_warn(dev, "log_max_qp value in current profile is %d, changing it to HCA capability limit (%d)\n", + profile[prof_sel].log_max_qp, + MLX5_CAP_GEN_MAX(dev, log_max_qp)); + profile[prof_sel].log_max_qp = MLX5_CAP_GEN_MAX(dev, log_max_qp); + } if (prof->mask & MLX5_PROF_MASK_QP_SIZE) MLX5_SET(cmd_hca_cap, set_hca_cap, log_max_qp, prof->log_max_qp); @@ -575,7 +582,6 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) struct mlx5_priv *priv = &mdev->priv; struct msix_entry *msix = priv->msix_arr; int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; - int numa_node = priv->numa_node; int err; if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { @@ -583,7 +589,7 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) return -ENOMEM; } - cpumask_set_cpu(cpumask_local_spread(i, numa_node), + cpumask_set_cpu(cpumask_local_spread(i, priv->numa_node), priv->irq_info[i].mask); err = irq_set_affinity_hint(irq, priv->irq_info[i].mask); @@ -801,7 +807,7 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev) return 0; } - return -ENOTSUPP; + return -EOPNOTSUPP; } @@ -1189,6 +1195,9 @@ static int mlx5_unload_one(struct mlx5_core_dev *dev, struct mlx5_priv *priv, { int err = 0; + if (cleanup) + mlx5_drain_health_wq(dev); + mutex_lock(&dev->intf_state_mutex); if (test_bit(MLX5_INTERFACE_STATE_DOWN, &dev->intf_state)) { dev_warn(&dev->pdev->dev, "%s: interface is down, NOP\n", @@ -1351,7 +1360,7 @@ static pci_ers_result_t mlx5_pci_err_detected(struct pci_dev *pdev, mlx5_enter_error_state(dev); mlx5_unload_one(dev, priv, false); - /* In case of kernel call save the pci state and drain health wq */ + /* In case of kernel call save the pci state and drain the health wq */ if (state) { pci_save_state(pdev); mlx5_drain_health_wq(dev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/port.c b/drivers/net/ethernet/mellanox/mlx5/core/port.c index d2ec9d232a70..fd12e0a377a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/port.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/port.c @@ -620,7 +620,7 @@ static int mlx5_set_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *in, u32 out[MLX5_ST_SZ_DW(qtct_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) - return -ENOTSUPP; + return -EOPNOTSUPP; return mlx5_core_access_reg(mdev, in, inlen, out, sizeof(out), MLX5_REG_QETCR, 0, 1); @@ -632,7 +632,7 @@ static int mlx5_query_port_qetcr_reg(struct mlx5_core_dev *mdev, u32 *out, u32 in[MLX5_ST_SZ_DW(qtct_reg)]; if (!MLX5_CAP_GEN(mdev, ets)) - return -ENOTSUPP; + return -EOPNOTSUPP; memset(in, 0, sizeof(in)); return mlx5_core_access_reg(mdev, in, sizeof(in), out, outlen, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/vport.c b/drivers/net/ethernet/mellanox/mlx5/core/vport.c index 269e4401c342..7129c30a2ab4 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/vport.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/vport.c @@ -532,7 +532,7 @@ int mlx5_modify_nic_vport_node_guid(struct mlx5_core_dev *mdev, if (!MLX5_CAP_GEN(mdev, vport_group_manager)) return -EACCES; if (!MLX5_CAP_ESW(mdev, nic_vport_node_guid_modify)) - return -ENOTSUPP; + return -EOPNOTSUPP; in = mlx5_vzalloc(inlen); if (!in) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h index d147ddd97997..0af3338bfcb4 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h +++ b/drivers/net/ethernet/mellanox/mlxsw/pci_hw.h @@ -209,21 +209,21 @@ MLXSW_ITEM32(pci, eqe, owner, 0x0C, 0, 1); /* pci_eqe_cmd_token * Command completion event - token */ -MLXSW_ITEM32(pci, eqe, cmd_token, 0x08, 16, 16); +MLXSW_ITEM32(pci, eqe, cmd_token, 0x00, 16, 16); /* pci_eqe_cmd_status * Command completion event - status */ -MLXSW_ITEM32(pci, eqe, cmd_status, 0x08, 0, 8); +MLXSW_ITEM32(pci, eqe, cmd_status, 0x00, 0, 8); /* pci_eqe_cmd_out_param_h * Command completion event - output parameter - higher part */ -MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x0C, 0, 32); +MLXSW_ITEM32(pci, eqe, cmd_out_param_h, 0x04, 0, 32); /* pci_eqe_cmd_out_param_l * Command completion event - output parameter - lower part */ -MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x10, 0, 32); +MLXSW_ITEM32(pci, eqe, cmd_out_param_l, 0x08, 0, 32); #endif diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index d768c7b6c6d6..003093abb170 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -684,6 +684,7 @@ static netdev_tx_t mlxsw_sp_port_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb_orig); return NETDEV_TX_OK; } + dev_consume_skb_any(skb_orig); } if (eth_skb_pad(skb)) { diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 01d0efa9c5c7..9e494a446b7e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1172,7 +1172,8 @@ static int mlxsw_sp_nexthop_mac_update(struct mlxsw_sp *mlxsw_sp, u32 adj_index, static int mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_nexthop_group *nh_grp) + struct mlxsw_sp_nexthop_group *nh_grp, + bool reallocate) { u32 adj_index = nh_grp->adj_index; /* base */ struct mlxsw_sp_nexthop *nh; @@ -1187,7 +1188,7 @@ mlxsw_sp_nexthop_group_mac_update(struct mlxsw_sp *mlxsw_sp, continue; } - if (nh->update) { + if (nh->update || reallocate) { err = mlxsw_sp_nexthop_mac_update(mlxsw_sp, adj_index, nh); if (err) @@ -1248,7 +1249,8 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp, /* Nothing was added or removed, so no need to reallocate. Just * update MAC on existing adjacency indexes. */ - err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp); + err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp, + false); if (err) { dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n"); goto set_trap; @@ -1276,7 +1278,7 @@ mlxsw_sp_nexthop_group_refresh(struct mlxsw_sp *mlxsw_sp, nh_grp->adj_index_valid = 1; nh_grp->adj_index = adj_index; nh_grp->ecmp_size = ecmp_size; - err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp); + err = mlxsw_sp_nexthop_group_mac_update(mlxsw_sp, nh_grp, true); if (err) { dev_warn(mlxsw_sp->bus_info->dev, "Failed to update neigh MAC in adjacency table.\n"); goto set_trap; diff --git a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c index 150ccf5192a9..2e88115e8735 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/switchx2.c +++ b/drivers/net/ethernet/mellanox/mlxsw/switchx2.c @@ -345,6 +345,7 @@ static netdev_tx_t mlxsw_sx_port_xmit(struct sk_buff *skb, dev_kfree_skb_any(skb_orig); return NETDEV_TX_OK; } + dev_consume_skb_any(skb_orig); } mlxsw_sx_txhdr_construct(skb, &tx_info); /* TX header is consumed by HW on the way so we shouldn't count its diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 8e5cb7605b0f..873ce2cd76ba 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -297,7 +297,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_del(&p_pkt->list_entry); b_last_packet = list_empty(&p_tx->active_descq); list_add_tail(&p_pkt->list_entry, &p_tx->free_descq); - if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -309,7 +309,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used; tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->gsi_enable) + if (p_ll2_conn->conn.gsi_enable) qed_ll2b_release_tx_gsi_packet(p_hwfn, p_ll2_conn-> my_id, @@ -378,7 +378,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) spin_unlock_irqrestore(&p_tx->lock, flags); tx_frag = p_pkt->bds_set[0].tx_frag; - if (p_ll2_conn->gsi_enable) + if (p_ll2_conn->conn.gsi_enable) qed_ll2b_complete_tx_gsi_packet(p_hwfn, p_ll2_conn->my_id, p_pkt->cookie, @@ -550,7 +550,7 @@ static void qed_ll2_rxq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle) list_move_tail(&p_pkt->list_entry, &p_rx->free_descq); - if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) { + if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) { struct qed_ooo_buffer *p_buffer; p_buffer = (struct qed_ooo_buffer *)p_pkt->cookie; @@ -738,7 +738,7 @@ qed_ooo_submit_tx_buffers(struct qed_hwfn *p_hwfn, rc = qed_ll2_prepare_tx_packet(p_hwfn, p_ll2_conn->my_id, 1, p_buffer->vlan, bd_flags, l4_hdr_offset_w, - p_ll2_conn->tx_dest, 0, + p_ll2_conn->conn.tx_dest, 0, first_frag, p_buffer->packet_length, p_buffer, true); @@ -858,7 +858,7 @@ qed_ll2_acquire_connection_ooo(struct qed_hwfn *p_hwfn, u16 buf_idx; int rc = 0; - if (p_ll2_info->conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_info->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) return rc; if (!rx_num_ooo_buffers) @@ -901,7 +901,7 @@ static void qed_ll2_establish_connection_ooo(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { - if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -913,7 +913,7 @@ static void qed_ll2_release_connection_ooo(struct qed_hwfn *p_hwfn, { struct qed_ooo_buffer *p_buffer; - if (p_ll2_conn->conn_type != QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->conn.conn_type != QED_LL2_TYPE_ISCSI_OOO) return; qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); @@ -945,23 +945,19 @@ static int qed_ll2_start_ooo(struct qed_dev *cdev, { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); u8 *handle = &hwfn->pf_params.iscsi_pf_params.ll2_ooo_queue_id; - struct qed_ll2_info *ll2_info; + struct qed_ll2_conn ll2_info; int rc; - ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL); - if (!ll2_info) - return -ENOMEM; - ll2_info->conn_type = QED_LL2_TYPE_ISCSI_OOO; - ll2_info->mtu = params->mtu; - ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets; - ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping; - ll2_info->tx_tc = OOO_LB_TC; - ll2_info->tx_dest = CORE_TX_DEST_LB; - - rc = qed_ll2_acquire_connection(hwfn, ll2_info, + ll2_info.conn_type = QED_LL2_TYPE_ISCSI_OOO; + ll2_info.mtu = params->mtu; + ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets; + ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping; + ll2_info.tx_tc = OOO_LB_TC; + ll2_info.tx_dest = CORE_TX_DEST_LB; + + rc = qed_ll2_acquire_connection(hwfn, &ll2_info, QED_LL2_RX_SIZE, QED_LL2_TX_SIZE, handle); - kfree(ll2_info); if (rc) { DP_INFO(cdev, "Failed to acquire LL2 OOO connection\n"); goto out; @@ -1006,7 +1002,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn, u8 action_on_error) { - enum qed_ll2_conn_type conn_type = p_ll2_conn->conn_type; + enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type; struct qed_ll2_rx_queue *p_rx = &p_ll2_conn->rx_queue; struct core_rx_start_ramrod_data *p_ramrod = NULL; struct qed_spq_entry *p_ent = NULL; @@ -1032,7 +1028,7 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->sb_index = p_rx->rx_sb_index; p_ramrod->complete_event_flg = 1; - p_ramrod->mtu = cpu_to_le16(p_ll2_conn->mtu); + p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu); DMA_REGPAIR_LE(p_ramrod->bd_base, p_rx->rxq_chain.p_phys_addr); cqe_pbl_size = (u16)qed_chain_get_page_cnt(&p_rx->rcq_chain); @@ -1040,8 +1036,8 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, DMA_REGPAIR_LE(p_ramrod->cqe_pbl_addr, qed_chain_get_pbl_phys(&p_rx->rcq_chain)); - p_ramrod->drop_ttl0_flg = p_ll2_conn->rx_drop_ttl0_flg; - p_ramrod->inner_vlan_removal_en = p_ll2_conn->rx_vlan_removal_en; + p_ramrod->drop_ttl0_flg = p_ll2_conn->conn.rx_drop_ttl0_flg; + p_ramrod->inner_vlan_removal_en = p_ll2_conn->conn.rx_vlan_removal_en; p_ramrod->queue_id = p_ll2_conn->queue_id; p_ramrod->main_func_queue = (conn_type == QED_LL2_TYPE_ISCSI_OOO) ? 0 : 1; @@ -1056,14 +1052,14 @@ static int qed_sp_ll2_rx_queue_start(struct qed_hwfn *p_hwfn, } p_ramrod->action_on_error.error_type = action_on_error; - p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable; + p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable; return qed_spq_post(p_hwfn, p_ent, NULL); } static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, struct qed_ll2_info *p_ll2_conn) { - enum qed_ll2_conn_type conn_type = p_ll2_conn->conn_type; + enum qed_ll2_conn_type conn_type = p_ll2_conn->conn.conn_type; struct qed_ll2_tx_queue *p_tx = &p_ll2_conn->tx_queue; struct core_tx_start_ramrod_data *p_ramrod = NULL; struct qed_spq_entry *p_ent = NULL; @@ -1075,7 +1071,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) return 0; - if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) p_ll2_conn->tx_stats_en = 0; else p_ll2_conn->tx_stats_en = 1; @@ -1096,7 +1092,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->sb_id = cpu_to_le16(qed_int_get_sp_sb_id(p_hwfn)); p_ramrod->sb_index = p_tx->tx_sb_index; - p_ramrod->mtu = cpu_to_le16(p_ll2_conn->mtu); + p_ramrod->mtu = cpu_to_le16(p_ll2_conn->conn.mtu); p_ramrod->stats_en = p_ll2_conn->tx_stats_en; p_ramrod->stats_id = p_ll2_conn->tx_stats_id; @@ -1106,7 +1102,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, p_ramrod->pbl_size = cpu_to_le16(pbl_size); memset(&pq_params, 0, sizeof(pq_params)); - pq_params.core.tc = p_ll2_conn->tx_tc; + pq_params.core.tc = p_ll2_conn->conn.tx_tc; pq_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_CORE, &pq_params); p_ramrod->qm_pq_id = cpu_to_le16(pq_id); @@ -1123,7 +1119,7 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn, DP_NOTICE(p_hwfn, "Unknown connection type: %d\n", conn_type); } - p_ramrod->gsi_offload_flag = p_ll2_conn->gsi_enable; + p_ramrod->gsi_offload_flag = p_ll2_conn->conn.gsi_enable; return qed_spq_post(p_hwfn, p_ent, NULL); } @@ -1224,7 +1220,7 @@ qed_ll2_acquire_connection_rx(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_LL2, "Allocated LL2 Rxq [Type %08x] with 0x%08x buffers\n", - p_ll2_info->conn_type, rx_num_desc); + p_ll2_info->conn.conn_type, rx_num_desc); out: return rc; @@ -1262,7 +1258,7 @@ static int qed_ll2_acquire_connection_tx(struct qed_hwfn *p_hwfn, DP_VERBOSE(p_hwfn, QED_MSG_LL2, "Allocated LL2 Txq [Type %08x] with 0x%08x buffers\n", - p_ll2_info->conn_type, tx_num_desc); + p_ll2_info->conn.conn_type, tx_num_desc); out: if (rc) @@ -1273,7 +1269,7 @@ out: } int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_params, + struct qed_ll2_conn *p_params, u16 rx_num_desc, u16 tx_num_desc, u8 *p_connection_handle) @@ -1302,15 +1298,7 @@ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, if (!p_ll2_info) return -EBUSY; - p_ll2_info->conn_type = p_params->conn_type; - p_ll2_info->mtu = p_params->mtu; - p_ll2_info->rx_drop_ttl0_flg = p_params->rx_drop_ttl0_flg; - p_ll2_info->rx_vlan_removal_en = p_params->rx_vlan_removal_en; - p_ll2_info->tx_tc = p_params->tx_tc; - p_ll2_info->tx_dest = p_params->tx_dest; - p_ll2_info->ai_err_packet_too_big = p_params->ai_err_packet_too_big; - p_ll2_info->ai_err_no_buf = p_params->ai_err_no_buf; - p_ll2_info->gsi_enable = p_params->gsi_enable; + p_ll2_info->conn = *p_params; rc = qed_ll2_acquire_connection_rx(p_hwfn, p_ll2_info, rx_num_desc); if (rc) @@ -1371,9 +1359,9 @@ static int qed_ll2_establish_connection_rx(struct qed_hwfn *p_hwfn, SET_FIELD(action_on_error, CORE_RX_ACTION_ON_ERROR_PACKET_TOO_BIG, - p_ll2_conn->ai_err_packet_too_big); + p_ll2_conn->conn.ai_err_packet_too_big); SET_FIELD(action_on_error, - CORE_RX_ACTION_ON_ERROR_NO_BUFF, p_ll2_conn->ai_err_no_buf); + CORE_RX_ACTION_ON_ERROR_NO_BUFF, p_ll2_conn->conn.ai_err_no_buf); return qed_sp_ll2_rx_queue_start(p_hwfn, p_ll2_conn, action_on_error); } @@ -1600,7 +1588,7 @@ static void qed_ll2_prepare_tx_packet_set_bd(struct qed_hwfn *p_hwfn, "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Tx Producer at [0x%04x] - set with a %04x bytes %02x BDs buffer at %08x:%08x\n", p_ll2->queue_id, p_ll2->cid, - p_ll2->conn_type, + p_ll2->conn.conn_type, prod_idx, first_frag_len, num_of_bds, @@ -1676,7 +1664,7 @@ static void qed_ll2_tx_packet_notify(struct qed_hwfn *p_hwfn, (NETIF_MSG_TX_QUEUED | QED_MSG_LL2), "LL2 [q 0x%02x cid 0x%08x type 0x%08x] Doorbelled [producer 0x%04x]\n", p_ll2_conn->queue_id, - p_ll2_conn->cid, p_ll2_conn->conn_type, db_msg.spq_prod); + p_ll2_conn->cid, p_ll2_conn->conn.conn_type, db_msg.spq_prod); } int qed_ll2_prepare_tx_packet(struct qed_hwfn *p_hwfn, @@ -1817,7 +1805,7 @@ int qed_ll2_terminate_connection(struct qed_hwfn *p_hwfn, u8 connection_handle) qed_ll2_rxq_flush(p_hwfn, connection_handle); } - if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO) + if (p_ll2_conn->conn.conn_type == QED_LL2_TYPE_ISCSI_OOO) qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info); return rc; @@ -1993,7 +1981,7 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev, static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) { - struct qed_ll2_info ll2_info; + struct qed_ll2_conn ll2_info; struct qed_ll2_buffer *buffer, *tmp_buffer; enum qed_ll2_conn_type conn_type; struct qed_ptt *p_ptt; @@ -2041,6 +2029,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) /* Prepare the temporary ll2 information */ memset(&ll2_info, 0, sizeof(ll2_info)); + ll2_info.conn_type = conn_type; ll2_info.mtu = params->mtu; ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets; @@ -2120,7 +2109,6 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params) } ether_addr_copy(cdev->ll2_mac_address, params->ll2_mac_address); - return 0; release_terminate_all: diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h index 6625a3ae5a33..31417928b635 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h @@ -112,15 +112,8 @@ struct qed_ll2_tx_queue { bool b_completing_packet; }; -struct qed_ll2_info { - /* Lock protecting the state of LL2 */ - struct mutex mutex; +struct qed_ll2_conn { enum qed_ll2_conn_type conn_type; - u32 cid; - u8 my_id; - u8 queue_id; - u8 tx_stats_id; - bool b_active; u16 mtu; u8 rx_drop_ttl0_flg; u8 rx_vlan_removal_en; @@ -128,10 +121,21 @@ struct qed_ll2_info { enum core_tx_dest tx_dest; enum core_error_handle ai_err_packet_too_big; enum core_error_handle ai_err_no_buf; + u8 gsi_enable; +}; + +struct qed_ll2_info { + /* Lock protecting the state of LL2 */ + struct mutex mutex; + struct qed_ll2_conn conn; + u32 cid; + u8 my_id; + u8 queue_id; + u8 tx_stats_id; + bool b_active; u8 tx_stats_en; struct qed_ll2_rx_queue rx_queue; struct qed_ll2_tx_queue tx_queue; - u8 gsi_enable; }; /** @@ -149,7 +153,7 @@ struct qed_ll2_info { * @return 0 on success, failure otherwise */ int qed_ll2_acquire_connection(struct qed_hwfn *p_hwfn, - struct qed_ll2_info *p_params, + struct qed_ll2_conn *p_params, u16 rx_num_desc, u16 tx_num_desc, u8 *p_connection_handle); diff --git a/drivers/net/ethernet/qlogic/qed/qed_roce.c b/drivers/net/ethernet/qlogic/qed/qed_roce.c index 2a16547c8966..2dbdb3298991 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_roce.c +++ b/drivers/net/ethernet/qlogic/qed/qed_roce.c @@ -2632,7 +2632,7 @@ static int qed_roce_ll2_start(struct qed_dev *cdev, { struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev); struct qed_roce_ll2_info *roce_ll2; - struct qed_ll2_info ll2_params; + struct qed_ll2_conn ll2_params; int rc; if (!params) { diff --git a/drivers/net/ethernet/qualcomm/emac/emac-phy.c b/drivers/net/ethernet/qualcomm/emac/emac-phy.c index 99a14df28b96..2851b4c56570 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac-phy.c +++ b/drivers/net/ethernet/qualcomm/emac/emac-phy.c @@ -201,6 +201,13 @@ int emac_phy_config(struct platform_device *pdev, struct emac_adapter *adpt) else adpt->phydev = mdiobus_get_phy(mii_bus, phy_addr); + /* of_phy_find_device() claims a reference to the phydev, + * so we do that here manually as well. When the driver + * later unloads, it can unilaterally drop the reference + * without worrying about ACPI vs DT. + */ + if (adpt->phydev) + get_device(&adpt->phydev->mdio.dev); } else { struct device_node *phy_np; diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index 422289c232bc..f46d300bd585 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -719,8 +719,7 @@ static int emac_probe(struct platform_device *pdev) err_undo_napi: netif_napi_del(&adpt->rx_q.napi); err_undo_mdiobus: - if (!has_acpi_companion(&pdev->dev)) - put_device(&adpt->phydev->mdio.dev); + put_device(&adpt->phydev->mdio.dev); mdiobus_unregister(adpt->mii_bus); err_undo_clocks: emac_clks_teardown(adpt); @@ -740,8 +739,7 @@ static int emac_remove(struct platform_device *pdev) emac_clks_teardown(adpt); - if (!has_acpi_companion(&pdev->dev)) - put_device(&adpt->phydev->mdio.dev); + put_device(&adpt->phydev->mdio.dev); mdiobus_unregister(adpt->mii_bus); free_netdev(netdev); diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 44389c90056a..8f1623bf2134 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -696,7 +696,7 @@ enum rtl_tx_desc_bit_1 { enum rtl_rx_desc_bit { /* Rx private */ PID1 = (1 << 18), /* Protocol ID bit 1/2 */ - PID0 = (1 << 17), /* Protocol ID bit 2/2 */ + PID0 = (1 << 17), /* Protocol ID bit 0/2 */ #define RxProtoUDP (PID1) #define RxProtoTCP (PID0) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 92d7692c840d..301f48755093 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -179,6 +179,49 @@ static struct mdiobb_ops bb_ops = { .get_mdio_data = ravb_get_mdio_data, }; +/* Free TX skb function for AVB-IP */ +static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) +{ + struct ravb_private *priv = netdev_priv(ndev); + struct net_device_stats *stats = &priv->stats[q]; + struct ravb_tx_desc *desc; + int free_num = 0; + int entry; + u32 size; + + for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { + bool txed; + + entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] * + NUM_TX_DESC); + desc = &priv->tx_ring[q][entry]; + txed = desc->die_dt == DT_FEMPTY; + if (free_txed_only && !txed) + break; + /* Descriptor type must be checked before all other reads */ + dma_rmb(); + size = le16_to_cpu(desc->ds_tagl) & TX_DS; + /* Free the original skb. */ + if (priv->tx_skb[q][entry / NUM_TX_DESC]) { + dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), + size, DMA_TO_DEVICE); + /* Last packet descriptor? */ + if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) { + entry /= NUM_TX_DESC; + dev_kfree_skb_any(priv->tx_skb[q][entry]); + priv->tx_skb[q][entry] = NULL; + if (txed) + stats->tx_packets++; + } + free_num++; + } + if (txed) + stats->tx_bytes += size; + desc->die_dt = DT_EEMPTY; + } + return free_num; +} + /* Free skb's and DMA buffers for Ethernet AVB */ static void ravb_ring_free(struct net_device *ndev, int q) { @@ -194,19 +237,21 @@ static void ravb_ring_free(struct net_device *ndev, int q) kfree(priv->rx_skb[q]); priv->rx_skb[q] = NULL; - /* Free TX skb ringbuffer */ - if (priv->tx_skb[q]) { - for (i = 0; i < priv->num_tx_ring[q]; i++) - dev_kfree_skb(priv->tx_skb[q][i]); - } - kfree(priv->tx_skb[q]); - priv->tx_skb[q] = NULL; - /* Free aligned TX buffers */ kfree(priv->tx_align[q]); priv->tx_align[q] = NULL; if (priv->rx_ring[q]) { + for (i = 0; i < priv->num_rx_ring[q]; i++) { + struct ravb_ex_rx_desc *desc = &priv->rx_ring[q][i]; + + if (!dma_mapping_error(ndev->dev.parent, + le32_to_cpu(desc->dptr))) + dma_unmap_single(ndev->dev.parent, + le32_to_cpu(desc->dptr), + PKT_BUF_SZ, + DMA_FROM_DEVICE); + } ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); dma_free_coherent(ndev->dev.parent, ring_size, priv->rx_ring[q], @@ -215,12 +260,20 @@ static void ravb_ring_free(struct net_device *ndev, int q) } if (priv->tx_ring[q]) { + ravb_tx_free(ndev, q, false); + ring_size = sizeof(struct ravb_tx_desc) * (priv->num_tx_ring[q] * NUM_TX_DESC + 1); dma_free_coherent(ndev->dev.parent, ring_size, priv->tx_ring[q], priv->tx_desc_dma[q]); priv->tx_ring[q] = NULL; } + + /* Free TX skb ringbuffer. + * SKBs are freed by ravb_tx_free() call above. + */ + kfree(priv->tx_skb[q]); + priv->tx_skb[q] = NULL; } /* Format skb and descriptor buffer for Ethernet AVB */ @@ -431,44 +484,6 @@ static int ravb_dmac_init(struct net_device *ndev) return 0; } -/* Free TX skb function for AVB-IP */ -static int ravb_tx_free(struct net_device *ndev, int q) -{ - struct ravb_private *priv = netdev_priv(ndev); - struct net_device_stats *stats = &priv->stats[q]; - struct ravb_tx_desc *desc; - int free_num = 0; - int entry; - u32 size; - - for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { - entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] * - NUM_TX_DESC); - desc = &priv->tx_ring[q][entry]; - if (desc->die_dt != DT_FEMPTY) - break; - /* Descriptor type must be checked before all other reads */ - dma_rmb(); - size = le16_to_cpu(desc->ds_tagl) & TX_DS; - /* Free the original skb. */ - if (priv->tx_skb[q][entry / NUM_TX_DESC]) { - dma_unmap_single(ndev->dev.parent, le32_to_cpu(desc->dptr), - size, DMA_TO_DEVICE); - /* Last packet descriptor? */ - if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) { - entry /= NUM_TX_DESC; - dev_kfree_skb_any(priv->tx_skb[q][entry]); - priv->tx_skb[q][entry] = NULL; - stats->tx_packets++; - } - free_num++; - } - stats->tx_bytes += size; - desc->die_dt = DT_EEMPTY; - } - return free_num; -} - static void ravb_get_tx_tstamp(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); @@ -902,7 +917,7 @@ static int ravb_poll(struct napi_struct *napi, int budget) spin_lock_irqsave(&priv->lock, flags); /* Clear TX interrupt */ ravb_write(ndev, ~mask, TIS); - ravb_tx_free(ndev, q); + ravb_tx_free(ndev, q, true); netif_wake_subqueue(ndev, q); mmiowb(); spin_unlock_irqrestore(&priv->lock, flags); @@ -926,14 +941,10 @@ static int ravb_poll(struct napi_struct *napi, int budget) /* Receive error message handling */ priv->rx_over_errors = priv->stats[RAVB_BE].rx_over_errors; priv->rx_over_errors += priv->stats[RAVB_NC].rx_over_errors; - if (priv->rx_over_errors != ndev->stats.rx_over_errors) { + if (priv->rx_over_errors != ndev->stats.rx_over_errors) ndev->stats.rx_over_errors = priv->rx_over_errors; - netif_err(priv, rx_err, ndev, "Receive Descriptor Empty\n"); - } - if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors) { + if (priv->rx_fifo_errors != ndev->stats.rx_fifo_errors) ndev->stats.rx_fifo_errors = priv->rx_fifo_errors; - netif_err(priv, rx_err, ndev, "Receive FIFO Overflow\n"); - } out: return budget - quota; } @@ -1508,6 +1519,19 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + entry / NUM_TX_DESC * DPTR_ALIGN; len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; + /* Zero length DMA descriptors are problematic as they seem to + * terminate DMA transfers. Avoid them by simply using a length of + * DPTR_ALIGN (4) when skb data is aligned to DPTR_ALIGN. + * + * As skb is guaranteed to have at least ETH_ZLEN (60) bytes of + * data by the call to skb_put_padto() above this is safe with + * respect to both the length of the first DMA descriptor (len) + * overflowing the available data and the length of the second DMA + * descriptor (skb->len - len) being negative. + */ + if (len == 0) + len = DPTR_ALIGN; + memcpy(buffer, skb->data, len); dma_addr = dma_map_single(ndev->dev.parent, buffer, len, DMA_TO_DEVICE); if (dma_mapping_error(ndev->dev.parent, dma_addr)) @@ -1558,7 +1582,8 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) priv->cur_tx[q] += NUM_TX_DESC; if (priv->cur_tx[q] - priv->dirty_tx[q] > - (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q)) + (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && + !ravb_tx_free(ndev, q, true)) netif_stop_subqueue(ndev, q); exit: diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index f341c1bc7001..f729a6b43958 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -574,6 +574,7 @@ static struct sh_eth_cpu_data r8a7740_data = { .rpadir_value = 2 << 16, .no_trimd = 1, .no_ade = 1, + .hw_crc = 1, .tsu = 1, .select_mii = 1, .shift_rd0 = 1, @@ -802,7 +803,7 @@ static struct sh_eth_cpu_data sh7734_data = { .ecsr_value = ECSR_ICD | ECSR_MPD, .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, - .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff, .tx_check = EESR_TC1 | EESR_FTC, .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | @@ -819,6 +820,7 @@ static struct sh_eth_cpu_data sh7734_data = { .tsu = 1, .hw_crc = 1, .select_mii = 1, + .shift_rd0 = 1, }; /* SH7763 */ @@ -831,7 +833,7 @@ static struct sh_eth_cpu_data sh7763_data = { .ecsr_value = ECSR_ICD | ECSR_MPD, .ecsipr_value = ECSIPR_LCHNGIP | ECSIPR_ICDIP | ECSIPR_MPDIP, - .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003fffff, + .eesipr_value = DMAC_M_RFRMER | DMAC_M_ECI | 0x003f07ff, .tx_check = EESR_TC1 | EESR_FTC, .eesr_err_check = EESR_TWB1 | EESR_TWB | EESR_TABT | EESR_RABT | @@ -1656,7 +1658,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev) else goto out; - if (!likely(mdp->irq_enabled)) { + if (unlikely(!mdp->irq_enabled)) { sh_eth_write(ndev, 0, EESIPR); goto out; } diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index de2947ccc5ad..5eb0e684fd76 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -1323,7 +1323,8 @@ static int efx_ef10_init_nic(struct efx_nic *efx) } /* don't fail init if RSS setup doesn't work */ - efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table); + rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table); + efx->rss_active = (rc == 0); return 0; } diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 87bdc56b4e3a..18ebaea44e82 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -975,6 +975,8 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev, case ETHTOOL_GRXFH: { info->data = 0; + if (!efx->rss_active) /* No RSS */ + return 0; switch (info->flow_type) { case UDP_V4_FLOW: if (efx->rx_hash_udp_4tuple) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 1a635ced62d0..1c62c1a00fca 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -860,6 +860,7 @@ struct vfdi_status; * @rx_hash_key: Toeplitz hash key for RSS * @rx_indir_table: Indirection table for RSS * @rx_scatter: Scatter mode enabled for receives + * @rss_active: RSS enabled on hardware * @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled * @int_error_count: Number of internal errors seen recently * @int_error_expire: Time at which error count will be expired @@ -998,6 +999,7 @@ struct efx_nic { u8 rx_hash_key[40]; u32 rx_indir_table[128]; bool rx_scatter; + bool rss_active; bool rx_hash_udp_4tuple; unsigned int_error_count; diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index a3901bc96586..4e54e5dc9fcb 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -403,6 +403,7 @@ static int siena_init_nic(struct efx_nic *efx) efx_writeo(efx, &temp, FR_AZ_RX_CFG); siena_rx_push_rss_config(efx, false, efx->rx_indir_table); + efx->rss_active = true; /* Enable event logging */ rc = efx_mcdi_log_ctrl(efx, true, false, 0); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c index c35597586121..3dc7d279f805 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-oxnas.c @@ -60,8 +60,9 @@ struct oxnas_dwmac { struct regmap *regmap; }; -static int oxnas_dwmac_init(struct oxnas_dwmac *dwmac) +static int oxnas_dwmac_init(struct platform_device *pdev, void *priv) { + struct oxnas_dwmac *dwmac = priv; unsigned int value; int ret; @@ -105,20 +106,20 @@ static int oxnas_dwmac_init(struct oxnas_dwmac *dwmac) return 0; } +static void oxnas_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct oxnas_dwmac *dwmac = priv; + + clk_disable_unprepare(dwmac->clk); +} + static int oxnas_dwmac_probe(struct platform_device *pdev) { struct plat_stmmacenet_data *plat_dat; struct stmmac_resources stmmac_res; - struct device_node *sysctrl; struct oxnas_dwmac *dwmac; int ret; - sysctrl = of_parse_phandle(pdev->dev.of_node, "oxsemi,sys-ctrl", 0); - if (!sysctrl) { - dev_err(&pdev->dev, "failed to get sys-ctrl node\n"); - return -EINVAL; - } - ret = stmmac_get_platform_resources(pdev, &stmmac_res); if (ret) return ret; @@ -128,72 +129,48 @@ static int oxnas_dwmac_probe(struct platform_device *pdev) return PTR_ERR(plat_dat); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) - return -ENOMEM; + if (!dwmac) { + ret = -ENOMEM; + goto err_remove_config_dt; + } dwmac->dev = &pdev->dev; plat_dat->bsp_priv = dwmac; + plat_dat->init = oxnas_dwmac_init; + plat_dat->exit = oxnas_dwmac_exit; - dwmac->regmap = syscon_node_to_regmap(sysctrl); + dwmac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "oxsemi,sys-ctrl"); if (IS_ERR(dwmac->regmap)) { dev_err(&pdev->dev, "failed to have sysctrl regmap\n"); - return PTR_ERR(dwmac->regmap); + ret = PTR_ERR(dwmac->regmap); + goto err_remove_config_dt; } dwmac->clk = devm_clk_get(&pdev->dev, "gmac"); - if (IS_ERR(dwmac->clk)) - return PTR_ERR(dwmac->clk); + if (IS_ERR(dwmac->clk)) { + ret = PTR_ERR(dwmac->clk); + goto err_remove_config_dt; + } - ret = oxnas_dwmac_init(dwmac); + ret = oxnas_dwmac_init(pdev, plat_dat->bsp_priv); if (ret) - return ret; + goto err_remove_config_dt; ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); if (ret) - clk_disable_unprepare(dwmac->clk); + goto err_dwmac_exit; - return ret; -} -static int oxnas_dwmac_remove(struct platform_device *pdev) -{ - struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(&pdev->dev); - int ret = stmmac_dvr_remove(&pdev->dev); - - clk_disable_unprepare(dwmac->clk); - - return ret; -} - -#ifdef CONFIG_PM_SLEEP -static int oxnas_dwmac_suspend(struct device *dev) -{ - struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(dev); - int ret; - - ret = stmmac_suspend(dev); - clk_disable_unprepare(dwmac->clk); - - return ret; -} - -static int oxnas_dwmac_resume(struct device *dev) -{ - struct oxnas_dwmac *dwmac = get_stmmac_bsp_priv(dev); - int ret; - - ret = oxnas_dwmac_init(dwmac); - if (ret) - return ret; + return 0; - ret = stmmac_resume(dev); +err_dwmac_exit: + oxnas_dwmac_exit(pdev, plat_dat->bsp_priv); +err_remove_config_dt: + stmmac_remove_config_dt(pdev, plat_dat); return ret; } -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(oxnas_dwmac_pm_ops, - oxnas_dwmac_suspend, oxnas_dwmac_resume); static const struct of_device_id oxnas_dwmac_match[] = { { .compatible = "oxsemi,ox820-dwmac" }, @@ -203,10 +180,10 @@ MODULE_DEVICE_TABLE(of, oxnas_dwmac_match); static struct platform_driver oxnas_dwmac_driver = { .probe = oxnas_dwmac_probe, - .remove = oxnas_dwmac_remove, + .remove = stmmac_pltfr_remove, .driver = { .name = "oxnas-dwmac", - .pm = &oxnas_dwmac_pm_ops, + .pm = &stmmac_pltfr_pm_ops, .of_match_table = oxnas_dwmac_match, }, }; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index be3c91c7f211..5484fd726d5a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -305,8 +305,12 @@ static int dwmac1000_irq_status(struct mac_device_info *hw, { void __iomem *ioaddr = hw->pcsr; u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); + u32 intr_mask = readl(ioaddr + GMAC_INT_MASK); int ret = 0; + /* Discard masked bits */ + intr_status &= ~intr_mask; + /* Not used events (e.g. MMC interrupts) are not handled. */ if ((intr_status & GMAC_INT_STATUS_MMCTIS)) x->mmc_tx_irq_n++; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index bb40382e205d..e3f6389e1b01 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3319,8 +3319,16 @@ int stmmac_dvr_probe(struct device *device, ndev->max_mtu = JUMBO_LEN; else ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); - if (priv->plat->maxmtu < ndev->max_mtu) + /* Will not overwrite ndev->max_mtu if plat->maxmtu > ndev->max_mtu + * as well as plat->maxmtu < ndev->min_mtu which is a invalid range. + */ + if ((priv->plat->maxmtu < ndev->max_mtu) && + (priv->plat->maxmtu >= ndev->min_mtu)) ndev->max_mtu = priv->plat->maxmtu; + else if (priv->plat->maxmtu < ndev->min_mtu) + dev_warn(priv->device, + "%s: warning: maxmtu having invalid value (%d)\n", + __func__, priv->plat->maxmtu); if (flow_ctrl) priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ @@ -3332,20 +3340,14 @@ int stmmac_dvr_probe(struct device *device, */ if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) { priv->use_riwt = 1; - netdev_info(priv->dev, "Enable RX Mitigation via HW Watchdog Timer\n"); + dev_info(priv->device, + "Enable RX Mitigation via HW Watchdog Timer\n"); } netif_napi_add(ndev, &priv->napi, stmmac_poll, 64); spin_lock_init(&priv->lock); - ret = register_netdev(ndev); - if (ret) { - netdev_err(priv->dev, "%s: ERROR %i registering the device\n", - __func__, ret); - goto error_netdev_register; - } - /* If a specific clk_csr value is passed from the platform * this means that the CSR Clock Range selection cannot be * changed at run-time and it is fixed. Viceversa the driver'll try to @@ -3365,18 +3367,28 @@ int stmmac_dvr_probe(struct device *device, /* MDIO bus Registration */ ret = stmmac_mdio_register(ndev); if (ret < 0) { - netdev_err(priv->dev, - "%s: MDIO bus (id: %d) registration failed", - __func__, priv->plat->bus_id); + dev_err(priv->device, + "%s: MDIO bus (id: %d) registration failed", + __func__, priv->plat->bus_id); goto error_mdio_register; } } - return 0; + ret = register_netdev(ndev); + if (ret) { + dev_err(priv->device, "%s: ERROR %i registering the device\n", + __func__, ret); + goto error_netdev_register; + } + + return ret; -error_mdio_register: - unregister_netdev(ndev); error_netdev_register: + if (priv->hw->pcs != STMMAC_PCS_RGMII && + priv->hw->pcs != STMMAC_PCS_TBI && + priv->hw->pcs != STMMAC_PCS_RTBI) + stmmac_mdio_unregister(ndev); +error_mdio_register: netif_napi_del(&priv->napi); error_hw_init: clk_disable_unprepare(priv->pclk); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c index a2831773431a..3da4737620cb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c @@ -89,6 +89,9 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat) /* Set default value for unicast filter entries */ plat->unicast_filter_entries = 1; + + /* Set the maxmtu to a default of JUMBO_LEN */ + plat->maxmtu = JUMBO_LEN; } static int quark_default_data(struct plat_stmmacenet_data *plat, @@ -126,6 +129,9 @@ static int quark_default_data(struct plat_stmmacenet_data *plat, /* Set default value for unicast filter entries */ plat->unicast_filter_entries = 1; + /* Set the maxmtu to a default of JUMBO_LEN */ + plat->maxmtu = JUMBO_LEN; + return 0; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 082cd48db6a7..36942f5a6a53 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -351,6 +351,7 @@ void stmmac_remove_config_dt(struct platform_device *pdev, if (of_phy_is_fixed_link(np)) of_phy_deregister_fixed_link(np); of_node_put(plat->phy_node); + of_node_put(plat->mdio_node); } #else struct plat_stmmacenet_data * diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index 77c88fcf2b86..9b8a30bf939b 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -1210,7 +1210,7 @@ int cpmac_init(void) goto fail_alloc; } -#warning FIXME: unhardcode gpio&reset bits + /* FIXME: unhardcode gpio&reset bits */ ar7_gpio_disable(26); ar7_gpio_disable(27); ar7_device_reset(AR7_RESET_BIT_CPMAC_LO); diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index b203143647e6..65088224c207 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -3160,7 +3160,7 @@ static int cpsw_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev = platform_get_drvdata(pdev); - struct cpsw_common *cpsw = netdev_priv(ndev); + struct cpsw_common *cpsw = ndev_to_cpsw(ndev); /* Select default pin state */ pinctrl_pm_select_default_state(dev); diff --git a/drivers/net/ethernet/xilinx/xilinx_emaclite.c b/drivers/net/ethernet/xilinx/xilinx_emaclite.c index 93dc10b10c09..aa02a03a6d8d 100644 --- a/drivers/net/ethernet/xilinx/xilinx_emaclite.c +++ b/drivers/net/ethernet/xilinx/xilinx_emaclite.c @@ -100,6 +100,14 @@ /* BUFFER_ALIGN(adr) calculates the number of bytes to the next alignment. */ #define BUFFER_ALIGN(adr) ((ALIGNMENT - ((u32) adr)) % ALIGNMENT) +#ifdef __BIG_ENDIAN +#define xemaclite_readl ioread32be +#define xemaclite_writel iowrite32be +#else +#define xemaclite_readl ioread32 +#define xemaclite_writel iowrite32 +#endif + /** * struct net_local - Our private per device data * @ndev: instance of the network device @@ -156,15 +164,15 @@ static void xemaclite_enable_interrupts(struct net_local *drvdata) u32 reg_data; /* Enable the Tx interrupts for the first Buffer */ - reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET); - __raw_writel(reg_data | XEL_TSR_XMIT_IE_MASK, - drvdata->base_addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(drvdata->base_addr + XEL_TSR_OFFSET); + xemaclite_writel(reg_data | XEL_TSR_XMIT_IE_MASK, + drvdata->base_addr + XEL_TSR_OFFSET); /* Enable the Rx interrupts for the first buffer */ - __raw_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET); + xemaclite_writel(XEL_RSR_RECV_IE_MASK, drvdata->base_addr + XEL_RSR_OFFSET); /* Enable the Global Interrupt Enable */ - __raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET); + xemaclite_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET); } /** @@ -179,17 +187,17 @@ static void xemaclite_disable_interrupts(struct net_local *drvdata) u32 reg_data; /* Disable the Global Interrupt Enable */ - __raw_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET); + xemaclite_writel(XEL_GIER_GIE_MASK, drvdata->base_addr + XEL_GIER_OFFSET); /* Disable the Tx interrupts for the first buffer */ - reg_data = __raw_readl(drvdata->base_addr + XEL_TSR_OFFSET); - __raw_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK), - drvdata->base_addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(drvdata->base_addr + XEL_TSR_OFFSET); + xemaclite_writel(reg_data & (~XEL_TSR_XMIT_IE_MASK), + drvdata->base_addr + XEL_TSR_OFFSET); /* Disable the Rx interrupts for the first buffer */ - reg_data = __raw_readl(drvdata->base_addr + XEL_RSR_OFFSET); - __raw_writel(reg_data & (~XEL_RSR_RECV_IE_MASK), - drvdata->base_addr + XEL_RSR_OFFSET); + reg_data = xemaclite_readl(drvdata->base_addr + XEL_RSR_OFFSET); + xemaclite_writel(reg_data & (~XEL_RSR_RECV_IE_MASK), + drvdata->base_addr + XEL_RSR_OFFSET); } /** @@ -321,7 +329,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, byte_count = ETH_FRAME_LEN; /* Check if the expected buffer is available */ - reg_data = __raw_readl(addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK)) == 0) { @@ -334,7 +342,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, addr = (void __iomem __force *)((u32 __force)addr ^ XEL_BUFFER_OFFSET); - reg_data = __raw_readl(addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); if ((reg_data & (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK)) != 0) @@ -345,16 +353,16 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, /* Write the frame to the buffer */ xemaclite_aligned_write(data, (u32 __force *) addr, byte_count); - __raw_writel((byte_count & XEL_TPLR_LENGTH_MASK), - addr + XEL_TPLR_OFFSET); + xemaclite_writel((byte_count & XEL_TPLR_LENGTH_MASK), + addr + XEL_TPLR_OFFSET); /* Update the Tx Status Register to indicate that there is a * frame to send. Set the XEL_TSR_XMIT_ACTIVE_MASK flag which * is used by the interrupt handler to check whether a frame * has been transmitted */ - reg_data = __raw_readl(addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); reg_data |= (XEL_TSR_XMIT_BUSY_MASK | XEL_TSR_XMIT_ACTIVE_MASK); - __raw_writel(reg_data, addr + XEL_TSR_OFFSET); + xemaclite_writel(reg_data, addr + XEL_TSR_OFFSET); return 0; } @@ -369,7 +377,7 @@ static int xemaclite_send_data(struct net_local *drvdata, u8 *data, * * Return: Total number of bytes received */ -static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) +static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data, int maxlen) { void __iomem *addr; u16 length, proto_type; @@ -379,7 +387,7 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) addr = (drvdata->base_addr + drvdata->next_rx_buf_to_use); /* Verify which buffer has valid data */ - reg_data = __raw_readl(addr + XEL_RSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET); if ((reg_data & XEL_RSR_RECV_DONE_MASK) == XEL_RSR_RECV_DONE_MASK) { if (drvdata->rx_ping_pong != 0) @@ -396,27 +404,28 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) return 0; /* No data was available */ /* Verify that buffer has valid data */ - reg_data = __raw_readl(addr + XEL_RSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET); if ((reg_data & XEL_RSR_RECV_DONE_MASK) != XEL_RSR_RECV_DONE_MASK) return 0; /* No data was available */ } /* Get the protocol type of the ethernet frame that arrived */ - proto_type = ((ntohl(__raw_readl(addr + XEL_HEADER_OFFSET + + proto_type = ((ntohl(xemaclite_readl(addr + XEL_HEADER_OFFSET + XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) & XEL_RPLR_LENGTH_MASK); /* Check if received ethernet frame is a raw ethernet frame * or an IP packet or an ARP packet */ - if (proto_type > (ETH_FRAME_LEN + ETH_FCS_LEN)) { + if (proto_type > ETH_DATA_LEN) { if (proto_type == ETH_P_IP) { - length = ((ntohl(__raw_readl(addr + + length = ((ntohl(xemaclite_readl(addr + XEL_HEADER_IP_LENGTH_OFFSET + XEL_RXBUFF_OFFSET)) >> XEL_HEADER_SHIFT) & XEL_RPLR_LENGTH_MASK); + length = min_t(u16, length, ETH_DATA_LEN); length += ETH_HLEN + ETH_FCS_LEN; } else if (proto_type == ETH_P_ARP) @@ -429,14 +438,17 @@ static u16 xemaclite_recv_data(struct net_local *drvdata, u8 *data) /* Use the length in the frame, plus the header and trailer */ length = proto_type + ETH_HLEN + ETH_FCS_LEN; + if (WARN_ON(length > maxlen)) + length = maxlen; + /* Read from the EmacLite device */ xemaclite_aligned_read((u32 __force *) (addr + XEL_RXBUFF_OFFSET), data, length); /* Acknowledge the frame */ - reg_data = __raw_readl(addr + XEL_RSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_RSR_OFFSET); reg_data &= ~XEL_RSR_RECV_DONE_MASK; - __raw_writel(reg_data, addr + XEL_RSR_OFFSET); + xemaclite_writel(reg_data, addr + XEL_RSR_OFFSET); return length; } @@ -463,14 +475,14 @@ static void xemaclite_update_address(struct net_local *drvdata, xemaclite_aligned_write(address_ptr, (u32 __force *) addr, ETH_ALEN); - __raw_writel(ETH_ALEN, addr + XEL_TPLR_OFFSET); + xemaclite_writel(ETH_ALEN, addr + XEL_TPLR_OFFSET); /* Update the MAC address in the EmacLite */ - reg_data = __raw_readl(addr + XEL_TSR_OFFSET); - __raw_writel(reg_data | XEL_TSR_PROG_MAC_ADDR, addr + XEL_TSR_OFFSET); + reg_data = xemaclite_readl(addr + XEL_TSR_OFFSET); + xemaclite_writel(reg_data | XEL_TSR_PROG_MAC_ADDR, addr + XEL_TSR_OFFSET); /* Wait for EmacLite to finish with the MAC address update */ - while ((__raw_readl(addr + XEL_TSR_OFFSET) & + while ((xemaclite_readl(addr + XEL_TSR_OFFSET) & XEL_TSR_PROG_MAC_ADDR) != 0) ; } @@ -603,7 +615,7 @@ static void xemaclite_rx_handler(struct net_device *dev) skb_reserve(skb, 2); - len = xemaclite_recv_data(lp, (u8 *) skb->data); + len = xemaclite_recv_data(lp, (u8 *) skb->data, len); if (!len) { dev->stats.rx_errors++; @@ -640,32 +652,32 @@ static irqreturn_t xemaclite_interrupt(int irq, void *dev_id) u32 tx_status; /* Check if there is Rx Data available */ - if ((__raw_readl(base_addr + XEL_RSR_OFFSET) & + if ((xemaclite_readl(base_addr + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK) || - (__raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET) + (xemaclite_readl(base_addr + XEL_BUFFER_OFFSET + XEL_RSR_OFFSET) & XEL_RSR_RECV_DONE_MASK)) xemaclite_rx_handler(dev); /* Check if the Transmission for the first buffer is completed */ - tx_status = __raw_readl(base_addr + XEL_TSR_OFFSET); + tx_status = xemaclite_readl(base_addr + XEL_TSR_OFFSET); if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; - __raw_writel(tx_status, base_addr + XEL_TSR_OFFSET); + xemaclite_writel(tx_status, base_addr + XEL_TSR_OFFSET); tx_complete = true; } /* Check if the Transmission for the second buffer is completed */ - tx_status = __raw_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + tx_status = xemaclite_readl(base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); if (((tx_status & XEL_TSR_XMIT_BUSY_MASK) == 0) && (tx_status & XEL_TSR_XMIT_ACTIVE_MASK) != 0) { tx_status &= ~XEL_TSR_XMIT_ACTIVE_MASK; - __raw_writel(tx_status, base_addr + XEL_BUFFER_OFFSET + - XEL_TSR_OFFSET); + xemaclite_writel(tx_status, base_addr + XEL_BUFFER_OFFSET + + XEL_TSR_OFFSET); tx_complete = true; } @@ -698,7 +710,7 @@ static int xemaclite_mdio_wait(struct net_local *lp) /* wait for the MDIO interface to not be busy or timeout after some time. */ - while (__raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) & + while (xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET) & XEL_MDIOCTRL_MDIOSTS_MASK) { if (time_before_eq(end, jiffies)) { WARN_ON(1); @@ -734,17 +746,17 @@ static int xemaclite_mdio_read(struct mii_bus *bus, int phy_id, int reg) * MDIO Address register. Set the Status bit in the MDIO Control * register to start a MDIO read transaction. */ - ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET); - __raw_writel(XEL_MDIOADDR_OP_MASK | - ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg), - lp->base_addr + XEL_MDIOADDR_OFFSET); - __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, - lp->base_addr + XEL_MDIOCTRL_OFFSET); + ctrl_reg = xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET); + xemaclite_writel(XEL_MDIOADDR_OP_MASK | + ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg), + lp->base_addr + XEL_MDIOADDR_OFFSET); + xemaclite_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, + lp->base_addr + XEL_MDIOCTRL_OFFSET); if (xemaclite_mdio_wait(lp)) return -ETIMEDOUT; - rc = __raw_readl(lp->base_addr + XEL_MDIORD_OFFSET); + rc = xemaclite_readl(lp->base_addr + XEL_MDIORD_OFFSET); dev_dbg(&lp->ndev->dev, "xemaclite_mdio_read(phy_id=%i, reg=%x) == %x\n", @@ -781,13 +793,13 @@ static int xemaclite_mdio_write(struct mii_bus *bus, int phy_id, int reg, * Data register. Finally, set the Status bit in the MDIO Control * register to start a MDIO write transaction. */ - ctrl_reg = __raw_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET); - __raw_writel(~XEL_MDIOADDR_OP_MASK & - ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg), - lp->base_addr + XEL_MDIOADDR_OFFSET); - __raw_writel(val, lp->base_addr + XEL_MDIOWR_OFFSET); - __raw_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, - lp->base_addr + XEL_MDIOCTRL_OFFSET); + ctrl_reg = xemaclite_readl(lp->base_addr + XEL_MDIOCTRL_OFFSET); + xemaclite_writel(~XEL_MDIOADDR_OP_MASK & + ((phy_id << XEL_MDIOADDR_PHYADR_SHIFT) | reg), + lp->base_addr + XEL_MDIOADDR_OFFSET); + xemaclite_writel(val, lp->base_addr + XEL_MDIOWR_OFFSET); + xemaclite_writel(ctrl_reg | XEL_MDIOCTRL_MDIOSTS_MASK, + lp->base_addr + XEL_MDIOCTRL_OFFSET); return 0; } @@ -834,8 +846,8 @@ static int xemaclite_mdio_setup(struct net_local *lp, struct device *dev) /* Enable the MDIO bus by asserting the enable bit in MDIO Control * register. */ - __raw_writel(XEL_MDIOCTRL_MDIOEN_MASK, - lp->base_addr + XEL_MDIOCTRL_OFFSET); + xemaclite_writel(XEL_MDIOCTRL_MDIOEN_MASK, + lp->base_addr + XEL_MDIOCTRL_OFFSET); bus = mdiobus_alloc(); if (!bus) { @@ -1140,8 +1152,8 @@ static int xemaclite_of_probe(struct platform_device *ofdev) } /* Clear the Tx CSR's in case this is a restart */ - __raw_writel(0, lp->base_addr + XEL_TSR_OFFSET); - __raw_writel(0, lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); + xemaclite_writel(0, lp->base_addr + XEL_TSR_OFFSET); + xemaclite_writel(0, lp->base_addr + XEL_BUFFER_OFFSET + XEL_TSR_OFFSET); /* Set the MAC address in the EmacLite device */ xemaclite_update_address(lp, ndev->dev_addr); diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 8b6810bad54b..99d3df788ce8 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -69,7 +69,6 @@ struct gtp_dev { struct socket *sock0; struct socket *sock1u; - struct net *net; struct net_device *dev; unsigned int hash_size; @@ -316,7 +315,7 @@ static int gtp_encap_recv(struct sock *sk, struct sk_buff *skb) netdev_dbg(gtp->dev, "encap_recv sk=%p\n", sk); - xnet = !net_eq(gtp->net, dev_net(gtp->dev)); + xnet = !net_eq(sock_net(sk), dev_net(gtp->dev)); switch (udp_sk(sk)->encap_type) { case UDP_ENCAP_GTP0: @@ -612,7 +611,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev) pktinfo.fl4.saddr, pktinfo.fl4.daddr, pktinfo.iph->tos, ip4_dst_hoplimit(&pktinfo.rt->dst), - htons(IP_DF), + 0, pktinfo.gtph_port, pktinfo.gtph_port, true, false); break; @@ -658,7 +657,7 @@ static void gtp_link_setup(struct net_device *dev) static int gtp_hashtable_new(struct gtp_dev *gtp, int hsize); static void gtp_hashtable_free(struct gtp_dev *gtp); static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1, struct net *src_net); + int fd_gtp0, int fd_gtp1); static int gtp_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) @@ -675,7 +674,7 @@ static int gtp_newlink(struct net *src_net, struct net_device *dev, fd0 = nla_get_u32(data[IFLA_GTP_FD0]); fd1 = nla_get_u32(data[IFLA_GTP_FD1]); - err = gtp_encap_enable(dev, gtp, fd0, fd1, src_net); + err = gtp_encap_enable(dev, gtp, fd0, fd1); if (err < 0) goto out_err; @@ -821,7 +820,7 @@ static void gtp_hashtable_free(struct gtp_dev *gtp) } static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, - int fd_gtp0, int fd_gtp1, struct net *src_net) + int fd_gtp0, int fd_gtp1) { struct udp_tunnel_sock_cfg tuncfg = {NULL}; struct socket *sock0, *sock1u; @@ -858,7 +857,6 @@ static int gtp_encap_enable(struct net_device *dev, struct gtp_dev *gtp, gtp->sock0 = sock0; gtp->sock1u = sock1u; - gtp->net = src_net; tuncfg.sk_user_data = gtp; tuncfg.encap_rcv = gtp_encap_recv; @@ -1376,3 +1374,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte <hwelte@sysmocom.de>"); MODULE_DESCRIPTION("Interface driver for GTP encapsulated traffic"); MODULE_ALIAS_RTNL_LINK("gtp"); +MODULE_ALIAS_GENL_FAMILY("gtp"); diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index ece59c54a653..4a40a3d825b4 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -648,8 +648,8 @@ static void ax_setup(struct net_device *dev) { /* Finish setting up the DEVICE info. */ dev->mtu = AX_MTU; - dev->hard_header_len = 0; - dev->addr_len = 0; + dev->hard_header_len = AX25_MAX_HEADER_LEN; + dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_AX25; dev->tx_queue_len = 10; dev->header_ops = &ax25_header_ops; diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 5a1cc089acb7..86e5749226ef 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -1295,6 +1295,9 @@ void netvsc_channel_cb(void *context) ndev = hv_get_drvdata(device); buffer = get_per_channel_state(channel); + /* commit_rd_index() -> hv_signal_on_read() needs this. */ + init_cached_read_index(channel); + do { desc = get_next_pkt_raw(channel); if (desc != NULL) { @@ -1347,6 +1350,9 @@ void netvsc_channel_cb(void *context) bufferlen = bytes_recvd; } + + init_cached_read_index(channel); + } while (1); if (bufferlen > NETVSC_PACKET_SIZE) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index c9414c054852..fcab8019dda0 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -659,6 +659,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, * policy filters on the host). Deliver these via the VF * interface in the guest. */ + rcu_read_lock(); vf_netdev = rcu_dereference(net_device_ctx->vf_netdev); if (vf_netdev && (vf_netdev->flags & IFF_UP)) net = vf_netdev; @@ -667,6 +668,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, skb = netvsc_alloc_recv_skb(net, packet, csum_info, *data, vlan_tci); if (unlikely(!skb)) { ++net->stats.rx_dropped; + rcu_read_unlock(); return NVSP_STAT_FAIL; } @@ -696,6 +698,7 @@ int netvsc_recv_callback(struct hv_device *device_obj, * TODO - use NAPI? */ netif_rx(skb); + rcu_read_unlock(); return 0; } diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 46d53a6c8cf8..76ba7ecfe142 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1715,9 +1715,9 @@ static int at86rf230_probe(struct spi_device *spi) /* Reset */ if (gpio_is_valid(rstn)) { udelay(1); - gpio_set_value(rstn, 0); + gpio_set_value_cansleep(rstn, 0); udelay(1); - gpio_set_value(rstn, 1); + gpio_set_value_cansleep(rstn, 1); usleep_range(120, 240); } diff --git a/drivers/net/ieee802154/atusb.c b/drivers/net/ieee802154/atusb.c index 1253f864737a..ef688518ad77 100644 --- a/drivers/net/ieee802154/atusb.c +++ b/drivers/net/ieee802154/atusb.c @@ -117,13 +117,26 @@ static int atusb_read_reg(struct atusb *atusb, uint8_t reg) { struct usb_device *usb_dev = atusb->usb_dev; int ret; + uint8_t *buffer; uint8_t value; + buffer = kmalloc(1, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + dev_dbg(&usb_dev->dev, "atusb: reg = 0x%x\n", reg); ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), ATUSB_REG_READ, ATUSB_REQ_FROM_DEV, - 0, reg, &value, 1, 1000); - return ret >= 0 ? value : ret; + 0, reg, buffer, 1, 1000); + + if (ret >= 0) { + value = buffer[0]; + kfree(buffer); + return value; + } else { + kfree(buffer); + return ret; + } } static int atusb_write_subreg(struct atusb *atusb, uint8_t reg, uint8_t mask, @@ -549,13 +562,6 @@ static int atusb_set_frame_retries(struct ieee802154_hw *hw, s8 retries) { struct atusb *atusb = hw->priv; - struct device *dev = &atusb->usb_dev->dev; - - if (atusb->fw_ver_maj == 0 && atusb->fw_ver_min < 3) { - dev_info(dev, "Automatic frame retransmission is only available from " - "firmware version 0.3. Please update if you want this feature."); - return -EINVAL; - } return atusb_write_subreg(atusb, SR_MAX_FRAME_RETRIES, retries); } @@ -608,9 +614,13 @@ static const struct ieee802154_ops atusb_ops = { static int atusb_get_and_show_revision(struct atusb *atusb) { struct usb_device *usb_dev = atusb->usb_dev; - unsigned char buffer[3]; + unsigned char *buffer; int ret; + buffer = kmalloc(3, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + /* Get a couple of the ATMega Firmware values */ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), ATUSB_ID, ATUSB_REQ_FROM_DEV, 0, 0, @@ -631,15 +641,20 @@ static int atusb_get_and_show_revision(struct atusb *atusb) dev_info(&usb_dev->dev, "Please update to version 0.2 or newer"); } + kfree(buffer); return ret; } static int atusb_get_and_show_build(struct atusb *atusb) { struct usb_device *usb_dev = atusb->usb_dev; - char build[ATUSB_BUILD_SIZE + 1]; + char *build; int ret; + build = kmalloc(ATUSB_BUILD_SIZE + 1, GFP_KERNEL); + if (!build) + return -ENOMEM; + ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), ATUSB_BUILD, ATUSB_REQ_FROM_DEV, 0, 0, build, ATUSB_BUILD_SIZE, 1000); @@ -648,6 +663,7 @@ static int atusb_get_and_show_build(struct atusb *atusb) dev_info(&usb_dev->dev, "Firmware: build %s\n", build); } + kfree(build); return ret; } @@ -698,7 +714,7 @@ fail: static int atusb_set_extended_addr(struct atusb *atusb) { struct usb_device *usb_dev = atusb->usb_dev; - unsigned char buffer[IEEE802154_EXTENDED_ADDR_LEN]; + unsigned char *buffer; __le64 extended_addr; u64 addr; int ret; @@ -710,12 +726,20 @@ static int atusb_set_extended_addr(struct atusb *atusb) return 0; } + buffer = kmalloc(IEEE802154_EXTENDED_ADDR_LEN, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + /* Firmware is new enough so we fetch the address from EEPROM */ ret = atusb_control_msg(atusb, usb_rcvctrlpipe(usb_dev, 0), ATUSB_EUI64_READ, ATUSB_REQ_FROM_DEV, 0, 0, buffer, IEEE802154_EXTENDED_ADDR_LEN, 1000); - if (ret < 0) - dev_err(&usb_dev->dev, "failed to fetch extended address\n"); + if (ret < 0) { + dev_err(&usb_dev->dev, "failed to fetch extended address, random address set\n"); + ieee802154_random_extended_addr(&atusb->hw->phy->perm_extended_addr); + kfree(buffer); + return ret; + } memcpy(&extended_addr, buffer, IEEE802154_EXTENDED_ADDR_LEN); /* Check if read address is not empty and the unicast bit is set correctly */ @@ -729,6 +753,7 @@ static int atusb_set_extended_addr(struct atusb *atusb) &addr); } + kfree(buffer); return ret; } @@ -770,8 +795,7 @@ static int atusb_probe(struct usb_interface *interface, hw->parent = &usb_dev->dev; hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AFILT | - IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS | - IEEE802154_HW_FRAME_RETRIES; + IEEE802154_HW_PROMISCUOUS | IEEE802154_HW_CSMA_PARAMS; hw->phy->flags = WPAN_PHY_FLAG_TXPOWER | WPAN_PHY_FLAG_CCA_ED_LEVEL | WPAN_PHY_FLAG_CCA_MODE; @@ -800,6 +824,9 @@ static int atusb_probe(struct usb_interface *interface, atusb_get_and_show_build(atusb); atusb_set_extended_addr(atusb); + if (atusb->fw_ver_maj >= 0 && atusb->fw_ver_min >= 3) + hw->flags |= IEEE802154_HW_FRAME_RETRIES; + ret = atusb_get_and_clear_error(atusb); if (ret) { dev_err(&atusb->usb_dev->dev, diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 1e05b7c2d157..0844f8496413 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -164,6 +164,7 @@ static void loopback_setup(struct net_device *dev) { dev->mtu = 64 * 1024; dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->min_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 5c26653eceb5..c27011bbe30c 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -681,7 +681,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, size_t linear; if (q->flags & IFF_VNET_HDR) { - vnet_hdr_len = q->vnet_hdr_sz; + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); err = -EINVAL; if (len < vnet_hdr_len) @@ -820,12 +820,12 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q, if (q->flags & IFF_VNET_HDR) { struct virtio_net_hdr vnet_hdr; - vnet_hdr_len = q->vnet_hdr_sz; + vnet_hdr_len = READ_ONCE(q->vnet_hdr_sz); if (iov_iter_count(iter) < vnet_hdr_len) return -EINVAL; if (virtio_net_hdr_from_skb(skb, &vnet_hdr, - macvtap_is_little_endian(q))) + macvtap_is_little_endian(q), true)) BUG(); if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) != diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d361835b315d..8dbd59baa34d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -279,6 +279,7 @@ config MARVELL_PHY config MESON_GXL_PHY tristate "Amlogic Meson GXL Internal PHY" + depends on ARCH_MESON || COMPILE_TEST ---help--- Currently has a driver for the Amlogic Meson GXL Internal PHY diff --git a/drivers/net/phy/bcm63xx.c b/drivers/net/phy/bcm63xx.c index e741bf614c4e..b0492ef2cdaa 100644 --- a/drivers/net/phy/bcm63xx.c +++ b/drivers/net/phy/bcm63xx.c @@ -21,6 +21,23 @@ MODULE_DESCRIPTION("Broadcom 63xx internal PHY driver"); MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); MODULE_LICENSE("GPL"); +static int bcm63xx_config_intr(struct phy_device *phydev) +{ + int reg, err; + + reg = phy_read(phydev, MII_BCM63XX_IR); + if (reg < 0) + return reg; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + reg &= ~MII_BCM63XX_IR_GMASK; + else + reg |= MII_BCM63XX_IR_GMASK; + + err = phy_write(phydev, MII_BCM63XX_IR, reg); + return err; +} + static int bcm63xx_config_init(struct phy_device *phydev) { int reg, err; @@ -55,7 +72,7 @@ static struct phy_driver bcm63xx_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = bcm_phy_ack_intr, - .config_intr = bcm_phy_config_intr, + .config_intr = bcm63xx_config_intr, }, { /* same phy as above, with just a different OUI */ .phy_id = 0x002bdc00, @@ -67,7 +84,7 @@ static struct phy_driver bcm63xx_driver[] = { .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = bcm_phy_ack_intr, - .config_intr = bcm_phy_config_intr, + .config_intr = bcm63xx_config_intr, } }; module_phy_driver(bcm63xx_driver); diff --git a/drivers/net/phy/dp83848.c b/drivers/net/phy/dp83848.c index 800b39f06279..a10d0e7fc5f7 100644 --- a/drivers/net/phy/dp83848.c +++ b/drivers/net/phy/dp83848.c @@ -17,6 +17,7 @@ #include <linux/phy.h> #define TI_DP83848C_PHY_ID 0x20005ca0 +#define TI_DP83620_PHY_ID 0x20005ce0 #define NS_DP83848C_PHY_ID 0x20005c90 #define TLK10X_PHY_ID 0x2000a210 #define TI_DP83822_PHY_ID 0x2000a240 @@ -77,6 +78,7 @@ static int dp83848_config_intr(struct phy_device *phydev) static struct mdio_device_id __maybe_unused dp83848_tbl[] = { { TI_DP83848C_PHY_ID, 0xfffffff0 }, { NS_DP83848C_PHY_ID, 0xfffffff0 }, + { TI_DP83620_PHY_ID, 0xfffffff0 }, { TLK10X_PHY_ID, 0xfffffff0 }, { TI_DP83822_PHY_ID, 0xfffffff0 }, { } @@ -106,6 +108,7 @@ MODULE_DEVICE_TABLE(mdio, dp83848_tbl); static struct phy_driver dp83848_driver[] = { DP83848_PHY_DRIVER(TI_DP83848C_PHY_ID, "TI DP83848C 10/100 Mbps PHY"), DP83848_PHY_DRIVER(NS_DP83848C_PHY_ID, "NS DP83848C 10/100 Mbps PHY"), + DP83848_PHY_DRIVER(TI_DP83620_PHY_ID, "TI DP83620 10/100 Mbps PHY"), DP83848_PHY_DRIVER(TLK10X_PHY_ID, "TI TLK10X 10/100 Mbps PHY"), DP83848_PHY_DRIVER(TI_DP83822_PHY_ID, "TI DP83822 10/100 Mbps PHY"), }; diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 1b639242f9e2..ca1b462bf7b2 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -29,6 +29,7 @@ #define MII_DP83867_MICR 0x12 #define MII_DP83867_ISR 0x13 #define DP83867_CTRL 0x1f +#define DP83867_CFG3 0x1e /* Extended Registers */ #define DP83867_RGMIICTL 0x0032 @@ -98,6 +99,8 @@ static int dp83867_config_intr(struct phy_device *phydev) micr_status |= (MII_DP83867_MICR_AN_ERR_INT_EN | MII_DP83867_MICR_SPEED_CHNG_INT_EN | + MII_DP83867_MICR_AUTONEG_COMP_INT_EN | + MII_DP83867_MICR_LINK_STS_CHNG_INT_EN | MII_DP83867_MICR_DUP_MODE_CHNG_INT_EN | MII_DP83867_MICR_SLEEP_MODE_CHNG_INT_EN); @@ -129,12 +132,16 @@ static int dp83867_of_init(struct phy_device *phydev) ret = of_property_read_u32(of_node, "ti,rx-internal-delay", &dp83867->rx_id_delay); - if (ret) + if (ret && + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)) return ret; ret = of_property_read_u32(of_node, "ti,tx-internal-delay", &dp83867->tx_id_delay); - if (ret) + if (ret && + (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID || + phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) return ret; return of_property_read_u32(of_node, "ti,fifo-depth", @@ -214,6 +221,13 @@ static int dp83867_config_init(struct phy_device *phydev) } } + /* Enable Interrupt output INT_OE in CFG3 register */ + if (phy_interrupt_is_valid(phydev)) { + val = phy_read(phydev, DP83867_CFG3); + val |= BIT(7); + phy_write(phydev, DP83867_CFG3, val); + } + return 0; } diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index e269262471a4..ed0d235cf850 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -1192,7 +1192,8 @@ static int marvell_read_status(struct phy_device *phydev) int err; /* Check the fiber mode first */ - if (phydev->supported & SUPPORTED_FIBRE) { + if (phydev->supported & SUPPORTED_FIBRE && + phydev->interface != PHY_INTERFACE_MODE_SGMII) { err = phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_M1111_FIBER); if (err < 0) goto error; @@ -1678,6 +1679,8 @@ static struct phy_driver marvell_drivers[] = { .ack_interrupt = &marvell_ack_interrupt, .config_intr = &marvell_config_intr, .did_interrupt = &m88e1121_did_interrupt, + .get_wol = &m88e1318_get_wol, + .set_wol = &m88e1318_set_wol, .resume = &marvell_resume, .suspend = &marvell_suspend, .get_sset_count = marvell_get_sset_count, diff --git a/drivers/net/phy/mdio-bcm-iproc.c b/drivers/net/phy/mdio-bcm-iproc.c index c0b4e65267af..46fe1ae919a3 100644 --- a/drivers/net/phy/mdio-bcm-iproc.c +++ b/drivers/net/phy/mdio-bcm-iproc.c @@ -81,8 +81,6 @@ static int iproc_mdio_read(struct mii_bus *bus, int phy_id, int reg) if (rc) return rc; - iproc_mdio_config_clk(priv->base); - /* Prepare the read operation */ cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | (reg << MII_DATA_RA_SHIFT) | @@ -112,8 +110,6 @@ static int iproc_mdio_write(struct mii_bus *bus, int phy_id, if (rc) return rc; - iproc_mdio_config_clk(priv->base); - /* Prepare the write operation */ cmd = (MII_DATA_TA_VAL << MII_DATA_TA_SHIFT) | (reg << MII_DATA_RA_SHIFT) | @@ -163,6 +159,8 @@ static int iproc_mdio_probe(struct platform_device *pdev) bus->read = iproc_mdio_read; bus->write = iproc_mdio_write; + iproc_mdio_config_clk(priv->base); + rc = of_mdiobus_register(bus, pdev->dev.of_node); if (rc) { dev_err(&pdev->dev, "MDIO bus registration failed\n"); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 9a77289109b7..6742070ca676 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -1008,6 +1008,20 @@ static struct phy_driver ksphy_driver[] = { .get_stats = kszphy_get_stats, .suspend = genphy_suspend, .resume = genphy_resume, +}, { + .phy_id = PHY_ID_KSZ8795, + .phy_id_mask = MICREL_PHY_ID_MASK, + .name = "Micrel KSZ8795", + .features = PHY_BASIC_FEATURES, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = kszphy_config_init, + .config_aneg = ksz8873mll_config_aneg, + .read_status = ksz8873mll_read_status, + .get_sset_count = kszphy_get_sset_count, + .get_strings = kszphy_get_strings, + .get_stats = kszphy_get_stats, + .suspend = genphy_suspend, + .resume = genphy_resume, } }; module_phy_driver(ksphy_driver); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 25f93a98863b..7cc1b7dcfe05 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -29,6 +29,7 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/phy_led_triggers.h> #include <linux/timer.h> #include <linux/workqueue.h> #include <linux/mdio.h> @@ -649,14 +650,18 @@ void phy_start_machine(struct phy_device *phydev) * phy_trigger_machine - trigger the state machine to run * * @phydev: the phy_device struct + * @sync: indicate whether we should wait for the workqueue cancelation * * Description: There has been a change in state which requires that the * state machine runs. */ -static void phy_trigger_machine(struct phy_device *phydev) +static void phy_trigger_machine(struct phy_device *phydev, bool sync) { - cancel_delayed_work_sync(&phydev->state_queue); + if (sync) + cancel_delayed_work_sync(&phydev->state_queue); + else + cancel_delayed_work(&phydev->state_queue); queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 0); } @@ -693,7 +698,7 @@ static void phy_error(struct phy_device *phydev) phydev->state = PHY_HALTED; mutex_unlock(&phydev->lock); - phy_trigger_machine(phydev); + phy_trigger_machine(phydev, false); } /** @@ -840,7 +845,7 @@ void phy_change(struct phy_device *phydev) } /* reschedule state queue work to run as soon as possible */ - phy_trigger_machine(phydev); + phy_trigger_machine(phydev, true); return; ignore: @@ -942,7 +947,7 @@ void phy_start(struct phy_device *phydev) if (do_resume) phy_resume(phydev); - phy_trigger_machine(phydev); + phy_trigger_machine(phydev, true); } EXPORT_SYMBOL(phy_start); @@ -1065,6 +1070,15 @@ void phy_state_machine(struct work_struct *work) if (old_link != phydev->link) phydev->state = PHY_CHANGELINK; } + /* + * Failsafe: check that nobody set phydev->link=0 between two + * poll cycles, otherwise we won't leave RUNNING state as long + * as link remains down. + */ + if (!phydev->link && phydev->state == PHY_RUNNING) { + phydev->state = PHY_CHANGELINK; + phydev_err(phydev, "no link in PHY_RUNNING\n"); + } break; case PHY_CHANGELINK: err = phy_read_status(phydev); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 92b08383cafa..8c8e15b8739d 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -908,6 +908,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, struct module *ndev_owner = dev->dev.parent->driver->owner; struct mii_bus *bus = phydev->mdio.bus; struct device *d = &phydev->mdio.dev; + bool using_genphy = false; int err; /* For Ethernet device drivers that register their own MDIO bus, we @@ -933,12 +934,22 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, d->driver = &genphy_driver[GENPHY_DRV_1G].mdiodrv.driver; + using_genphy = true; + } + + if (!try_module_get(d->driver->owner)) { + dev_err(&dev->dev, "failed to get the device driver module\n"); + err = -EIO; + goto error_put_device; + } + + if (using_genphy) { err = d->driver->probe(d); if (err >= 0) err = device_bind_driver(d); if (err) - goto error; + goto error_module_put; } if (phydev->attached_dev) { @@ -975,7 +986,13 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, return err; error: + /* phy_detach() does all of the cleanup below */ phy_detach(phydev); + return err; + +error_module_put: + module_put(d->driver->owner); +error_put_device: put_device(d); if (ndev_owner != bus->owner) module_put(bus->owner); @@ -1039,6 +1056,8 @@ void phy_detach(struct phy_device *phydev) phy_led_triggers_unregister(phydev); + module_put(phydev->mdio.dev.driver->owner); + /* If the device had no specific driver before (i.e. - it * was using the generic driver), we unbind the device * from the generic driver so that there's a chance a diff --git a/drivers/net/phy/phy_led_triggers.c b/drivers/net/phy/phy_led_triggers.c index fa62bdf2f526..94ca42e630bb 100644 --- a/drivers/net/phy/phy_led_triggers.c +++ b/drivers/net/phy/phy_led_triggers.c @@ -12,6 +12,7 @@ */ #include <linux/leds.h> #include <linux/phy.h> +#include <linux/phy_led_triggers.h> #include <linux/netdevice.h> static struct phy_led_trigger *phy_speed_to_led_trigger(struct phy_device *phy, @@ -102,8 +103,10 @@ int phy_led_triggers_register(struct phy_device *phy) sizeof(struct phy_led_trigger) * phy->phy_num_led_triggers, GFP_KERNEL); - if (!phy->phy_led_triggers) - return -ENOMEM; + if (!phy->phy_led_triggers) { + err = -ENOMEM; + goto out_clear; + } for (i = 0; i < phy->phy_num_led_triggers; i++) { err = phy_led_trigger_register(phy, &phy->phy_led_triggers[i], @@ -120,6 +123,8 @@ out_unreg: while (i--) phy_led_trigger_unregister(&phy->phy_led_triggers[i]); devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); +out_clear: + phy->phy_num_led_triggers = 0; return err; } EXPORT_SYMBOL_GPL(phy_led_triggers_register); diff --git a/drivers/net/tun.c b/drivers/net/tun.c index cd8e02c94be0..bfabe180053e 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1170,9 +1170,11 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, } if (tun->flags & IFF_VNET_HDR) { - if (len < tun->vnet_hdr_sz) + int vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); + + if (len < vnet_hdr_sz) return -EINVAL; - len -= tun->vnet_hdr_sz; + len -= vnet_hdr_sz; if (!copy_from_iter_full(&gso, sizeof(gso), from)) return -EFAULT; @@ -1183,7 +1185,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, if (tun16_to_cpu(tun, gso.hdr_len) > len) return -EINVAL; - iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso)); + iov_iter_advance(from, vnet_hdr_sz - sizeof(gso)); } if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) { @@ -1335,7 +1337,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, vlan_hlen = VLAN_HLEN; if (tun->flags & IFF_VNET_HDR) - vnet_hdr_sz = tun->vnet_hdr_sz; + vnet_hdr_sz = READ_ONCE(tun->vnet_hdr_sz); total = skb->len + vlan_hlen + vnet_hdr_sz; @@ -1360,7 +1362,7 @@ static ssize_t tun_put_user(struct tun_struct *tun, return -EINVAL; if (virtio_net_hdr_from_skb(skb, &gso, - tun_is_little_endian(tun))) { + tun_is_little_endian(tun), true)) { struct skb_shared_info *sinfo = skb_shinfo(skb); pr_err("unexpected GSO type: " "0x%x, gso_size %d, hdr_len %d\n", diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 6c646e228833..6e98ede997d3 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -1367,6 +1367,7 @@ static struct usb_driver asix_driver = { .probe = usbnet_probe, .suspend = asix_suspend, .resume = asix_resume, + .reset_resume = asix_resume, .disconnect = usbnet_disconnect, .supports_autosuspend = 1, .disable_hub_initiated_lpm = 1, diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 3daa41bdd4ea..0acc9b640419 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -776,7 +776,7 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id struct net_device *netdev; struct catc *catc; u8 broadcast[ETH_ALEN]; - int i, pktsz; + int pktsz, ret; if (usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 1)) { @@ -811,12 +811,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { dev_err(&intf->dev, "No free urbs available.\n"); - usb_free_urb(catc->ctrl_urb); - usb_free_urb(catc->tx_urb); - usb_free_urb(catc->rx_urb); - usb_free_urb(catc->irq_urb); - free_netdev(netdev); - return -ENOMEM; + ret = -ENOMEM; + goto fail_free; } /* The F5U011 has the same vendor/product as the netmate but a device version of 0x130 */ @@ -844,15 +840,24 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id catc->irq_buf, 2, catc_irq_done, catc, 1); if (!catc->is_f5u011) { + u32 *buf; + int i; + dev_dbg(dev, "Checking memory size\n"); - i = 0x12345678; - catc_write_mem(catc, 0x7a80, &i, 4); - i = 0x87654321; - catc_write_mem(catc, 0xfa80, &i, 4); - catc_read_mem(catc, 0x7a80, &i, 4); + buf = kmalloc(4, GFP_KERNEL); + if (!buf) { + ret = -ENOMEM; + goto fail_free; + } + + *buf = 0x12345678; + catc_write_mem(catc, 0x7a80, buf, 4); + *buf = 0x87654321; + catc_write_mem(catc, 0xfa80, buf, 4); + catc_read_mem(catc, 0x7a80, buf, 4); - switch (i) { + switch (*buf) { case 0x12345678: catc_set_reg(catc, TxBufCount, 8); catc_set_reg(catc, RxBufCount, 32); @@ -867,6 +872,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id dev_dbg(dev, "32k Memory\n"); break; } + + kfree(buf); dev_dbg(dev, "Getting MAC from SEEROM.\n"); @@ -913,16 +920,21 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id usb_set_intfdata(intf, catc); SET_NETDEV_DEV(netdev, &intf->dev); - if (register_netdev(netdev) != 0) { - usb_set_intfdata(intf, NULL); - usb_free_urb(catc->ctrl_urb); - usb_free_urb(catc->tx_urb); - usb_free_urb(catc->rx_urb); - usb_free_urb(catc->irq_urb); - free_netdev(netdev); - return -EIO; - } + ret = register_netdev(netdev); + if (ret) + goto fail_clear_intfdata; + return 0; + +fail_clear_intfdata: + usb_set_intfdata(intf, NULL); +fail_free: + usb_free_urb(catc->ctrl_urb); + usb_free_urb(catc->tx_urb); + usb_free_urb(catc->rx_urb); + usb_free_urb(catc->irq_urb); + free_netdev(netdev); + return ret; } static void catc_disconnect(struct usb_interface *intf) diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index fe7b2886cb6b..86144f9a80ee 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -531,6 +531,7 @@ static const struct driver_info wwan_info = { #define SAMSUNG_VENDOR_ID 0x04e8 #define LENOVO_VENDOR_ID 0x17ef #define NVIDIA_VENDOR_ID 0x0955 +#define HP_VENDOR_ID 0x03f0 static const struct usb_device_id products[] = { /* BLACKLIST !! @@ -677,6 +678,13 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, +/* HP lt2523 (Novatel E371) - handled by qmi_wwan */ +{ + USB_DEVICE_AND_INTERFACE_INFO(HP_VENDOR_ID, 0x421d, USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), + .driver_info = 0, +}, + /* AnyDATA ADU960S - handled by qmi_wwan */ { USB_DEVICE_AND_INTERFACE_INFO(0x16d5, 0x650a, USB_CLASS_COMM, diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 24e803fe9a53..36674484c6fb 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -126,40 +126,61 @@ static void async_ctrl_callback(struct urb *urb) static int get_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) { + u8 *buf; int ret; + buf = kmalloc(size, GFP_NOIO); + if (!buf) + return -ENOMEM; + ret = usb_control_msg(pegasus->usb, usb_rcvctrlpipe(pegasus->usb, 0), PEGASUS_REQ_GET_REGS, PEGASUS_REQT_READ, 0, - indx, data, size, 1000); + indx, buf, size, 1000); if (ret < 0) netif_dbg(pegasus, drv, pegasus->net, "%s returned %d\n", __func__, ret); + else if (ret <= size) + memcpy(data, buf, ret); + kfree(buf); return ret; } -static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, void *data) +static int set_registers(pegasus_t *pegasus, __u16 indx, __u16 size, + const void *data) { + u8 *buf; int ret; + buf = kmemdup(data, size, GFP_NOIO); + if (!buf) + return -ENOMEM; + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), PEGASUS_REQ_SET_REGS, PEGASUS_REQT_WRITE, 0, - indx, data, size, 100); + indx, buf, size, 100); if (ret < 0) netif_dbg(pegasus, drv, pegasus->net, "%s returned %d\n", __func__, ret); + kfree(buf); return ret; } static int set_register(pegasus_t *pegasus, __u16 indx, __u8 data) { + u8 *buf; int ret; + buf = kmemdup(&data, 1, GFP_NOIO); + if (!buf) + return -ENOMEM; + ret = usb_control_msg(pegasus->usb, usb_sndctrlpipe(pegasus->usb, 0), PEGASUS_REQ_SET_REG, PEGASUS_REQT_WRITE, data, - indx, &data, 1, 1000); + indx, buf, 1, 1000); if (ret < 0) netif_dbg(pegasus, drv, pegasus->net, "%s returned %d\n", __func__, ret); + kfree(buf); return ret; } diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6fe1cdb0174f..24d5272cdce5 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -654,6 +654,13 @@ static const struct usb_device_id products[] = { USB_CDC_PROTO_NONE), .driver_info = (unsigned long)&qmi_wwan_info, }, + { /* HP lt2523 (Novatel E371) */ + USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, + USB_CLASS_COMM, + USB_CDC_SUBCLASS_ETHERNET, + USB_CDC_PROTO_NONE), + .driver_info = (unsigned long)&qmi_wwan_info, + }, { /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x581d, USB_CLASS_VENDOR_SPEC, 1, 7), .driver_info = (unsigned long)&qmi_wwan_info, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 7dc61228c55b..ad42295356dd 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -32,7 +32,7 @@ #define NETNEXT_VERSION "08" /* Information for net */ -#define NET_VERSION "6" +#define NET_VERSION "8" #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" @@ -1730,7 +1730,7 @@ static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) u8 checksum = CHECKSUM_NONE; u32 opts2, opts3; - if (tp->version == RTL_VER_01 || tp->version == RTL_VER_02) + if (!(tp->netdev->features & NETIF_F_RXCSUM)) goto return_result; opts2 = le32_to_cpu(rx_desc->opts2); @@ -1936,6 +1936,9 @@ static int r8152_poll(struct napi_struct *napi, int budget) napi_complete(napi); if (!list_empty(&tp->rx_done)) napi_schedule(napi); + else if (!skb_queue_empty(&tp->tx_queue) && + !list_empty(&tp->tx_free)) + napi_schedule(napi); } return work_done; @@ -3155,10 +3158,13 @@ static void set_carrier(struct r8152 *tp) if (!netif_carrier_ok(netdev)) { tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); + netif_stop_queue(netdev); napi_disable(&tp->napi); netif_carrier_on(netdev); rtl_start_rx(tp); napi_enable(&tp->napi); + netif_wake_queue(netdev); + netif_info(tp, link, netdev, "carrier on\n"); } } else { if (netif_carrier_ok(netdev)) { @@ -3166,6 +3172,7 @@ static void set_carrier(struct r8152 *tp) napi_disable(&tp->napi); tp->rtl_ops.disable(tp); napi_enable(&tp->napi); + netif_info(tp, link, netdev, "carrier off\n"); } } } @@ -3515,12 +3522,12 @@ static int rtl8152_pre_reset(struct usb_interface *intf) if (!netif_running(netdev)) return 0; + netif_stop_queue(netdev); napi_disable(&tp->napi); clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); if (netif_carrier_ok(netdev)) { - netif_stop_queue(netdev); mutex_lock(&tp->control); tp->rtl_ops.disable(tp); mutex_unlock(&tp->control); @@ -3545,12 +3552,17 @@ static int rtl8152_post_reset(struct usb_interface *intf) if (netif_carrier_ok(netdev)) { mutex_lock(&tp->control); tp->rtl_ops.enable(tp); + rtl_start_rx(tp); rtl8152_set_rx_mode(netdev); mutex_unlock(&tp->control); - netif_wake_queue(netdev); } napi_enable(&tp->napi); + netif_wake_queue(netdev); + usb_submit_urb(tp->intr_urb, GFP_KERNEL); + + if (!list_empty(&tp->rx_done)) + napi_schedule(&tp->napi); return 0; } @@ -3572,43 +3584,98 @@ static bool delay_autosuspend(struct r8152 *tp) */ if (!sw_linking && tp->rtl_ops.in_nway(tp)) return true; + else if (!skb_queue_empty(&tp->tx_queue)) + return true; else return false; } -static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) +static int rtl8152_rumtime_suspend(struct r8152 *tp) { - struct r8152 *tp = usb_get_intfdata(intf); struct net_device *netdev = tp->netdev; int ret = 0; - mutex_lock(&tp->control); + set_bit(SELECTIVE_SUSPEND, &tp->flags); + smp_mb__after_atomic(); + + if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { + u32 rcr = 0; - if (PMSG_IS_AUTO(message)) { - if (netif_running(netdev) && delay_autosuspend(tp)) { + if (delay_autosuspend(tp)) { + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + smp_mb__after_atomic(); ret = -EBUSY; goto out1; } - set_bit(SELECTIVE_SUSPEND, &tp->flags); - } else { - netif_device_detach(netdev); + if (netif_carrier_ok(netdev)) { + u32 ocp_data; + + rcr = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); + ocp_data = rcr & ~RCR_ACPT_ALL; + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); + rxdy_gated_en(tp, true); + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, + PLA_OOB_CTRL); + if (!(ocp_data & RXFIFO_EMPTY)) { + rxdy_gated_en(tp, false); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + smp_mb__after_atomic(); + ret = -EBUSY; + goto out1; + } + } + + clear_bit(WORK_ENABLE, &tp->flags); + usb_kill_urb(tp->intr_urb); + + tp->rtl_ops.autosuspend_en(tp, true); + + if (netif_carrier_ok(netdev)) { + napi_disable(&tp->napi); + rtl_stop_rx(tp); + rxdy_gated_en(tp, false); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, rcr); + napi_enable(&tp->napi); + } } +out1: + return ret; +} + +static int rtl8152_system_suspend(struct r8152 *tp) +{ + struct net_device *netdev = tp->netdev; + int ret = 0; + + netif_device_detach(netdev); + if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); napi_disable(&tp->napi); - if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { - rtl_stop_rx(tp); - tp->rtl_ops.autosuspend_en(tp, true); - } else { - cancel_delayed_work_sync(&tp->schedule); - tp->rtl_ops.down(tp); - } + cancel_delayed_work_sync(&tp->schedule); + tp->rtl_ops.down(tp); napi_enable(&tp->napi); } -out1: + + return ret; +} + +static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct r8152 *tp = usb_get_intfdata(intf); + int ret; + + mutex_lock(&tp->control); + + if (PMSG_IS_AUTO(message)) + ret = rtl8152_rumtime_suspend(tp); + else + ret = rtl8152_system_suspend(tp); + mutex_unlock(&tp->control); return ret; @@ -3629,12 +3696,15 @@ static int rtl8152_resume(struct usb_interface *intf) if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) { if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { tp->rtl_ops.autosuspend_en(tp, false); - clear_bit(SELECTIVE_SUSPEND, &tp->flags); napi_disable(&tp->napi); set_bit(WORK_ENABLE, &tp->flags); if (netif_carrier_ok(tp->netdev)) rtl_start_rx(tp); napi_enable(&tp->napi); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + smp_mb__after_atomic(); + if (!list_empty(&tp->rx_done)) + napi_schedule(&tp->napi); } else { tp->rtl_ops.up(tp); netif_carrier_off(tp->netdev); @@ -4308,6 +4378,11 @@ static int rtl8152_probe(struct usb_interface *intf, NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + if (tp->version == RTL_VER_01) { + netdev->features &= ~NETIF_F_RXCSUM; + netdev->hw_features &= ~NETIF_F_RXCSUM; + } + netdev->ethtool_ops = &ops; netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 95b7bd0d7abc..c81c79110cef 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -155,16 +155,36 @@ static const char driver_name [] = "rtl8150"; */ static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) { - return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), - RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, - indx, 0, data, size, 500); + void *buf; + int ret; + + buf = kmalloc(size, GFP_NOIO); + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + RTL8150_REQ_GET_REGS, RTL8150_REQT_READ, + indx, 0, buf, size, 500); + if (ret > 0 && ret <= size) + memcpy(data, buf, ret); + kfree(buf); + return ret; } -static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) +static int set_registers(rtl8150_t * dev, u16 indx, u16 size, const void *data) { - return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), - RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, - indx, 0, data, size, 500); + void *buf; + int ret; + + buf = kmemdup(data, size, GFP_NOIO); + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE, + indx, 0, buf, size, 500); + kfree(buf); + return ret; } static void async_set_reg_cb(struct urb *urb) diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index 12071f1582df..d9440bc022f2 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -73,8 +73,6 @@ static atomic_t iface_counter = ATOMIC_INIT(0); /* Private data structure */ struct sierra_net_data { - u8 ethr_hdr_tmpl[ETH_HLEN]; /* ethernet header template for rx'd pkts */ - u16 link_up; /* air link up or down */ u8 tx_hdr_template[4]; /* part of HIP hdr for tx'd packets */ @@ -122,6 +120,7 @@ struct param { /* LSI Protocol types */ #define SIERRA_NET_PROTOCOL_UMTS 0x01 +#define SIERRA_NET_PROTOCOL_UMTS_DS 0x04 /* LSI Coverage */ #define SIERRA_NET_COVERAGE_NONE 0x00 #define SIERRA_NET_COVERAGE_NOPACKET 0x01 @@ -129,7 +128,8 @@ struct param { /* LSI Session */ #define SIERRA_NET_SESSION_IDLE 0x00 /* LSI Link types */ -#define SIERRA_NET_AS_LINK_TYPE_IPv4 0x00 +#define SIERRA_NET_AS_LINK_TYPE_IPV4 0x00 +#define SIERRA_NET_AS_LINK_TYPE_IPV6 0x02 struct lsi_umts { u8 protocol; @@ -137,9 +137,14 @@ struct lsi_umts { __be16 length; /* eventually use a union for the rest - assume umts for now */ u8 coverage; - u8 unused2[41]; + u8 network_len; /* network name len */ + u8 network[40]; /* network name (UCS2, bigendian) */ u8 session_state; u8 unused3[33]; +} __packed; + +struct lsi_umts_single { + struct lsi_umts lsi; u8 link_type; u8 pdp_addr_len; /* NW-supplied PDP address len */ u8 pdp_addr[16]; /* NW-supplied PDP address (bigendian)) */ @@ -158,10 +163,31 @@ struct lsi_umts { u8 reserved[8]; } __packed; +struct lsi_umts_dual { + struct lsi_umts lsi; + u8 pdp_addr4_len; /* NW-supplied PDP IPv4 address len */ + u8 pdp_addr4[4]; /* NW-supplied PDP IPv4 address (bigendian)) */ + u8 pdp_addr6_len; /* NW-supplied PDP IPv6 address len */ + u8 pdp_addr6[16]; /* NW-supplied PDP IPv6 address (bigendian)) */ + u8 unused4[23]; + u8 dns1_addr4_len; /* NW-supplied 1st DNS v4 address len (bigendian) */ + u8 dns1_addr4[4]; /* NW-supplied 1st DNS v4 address */ + u8 dns1_addr6_len; /* NW-supplied 1st DNS v6 address len */ + u8 dns1_addr6[16]; /* NW-supplied 1st DNS v6 address (bigendian)*/ + u8 dns2_addr4_len; /* NW-supplied 2nd DNS v4 address len (bigendian) */ + u8 dns2_addr4[4]; /* NW-supplied 2nd DNS v4 address */ + u8 dns2_addr6_len; /* NW-supplied 2nd DNS v6 address len */ + u8 dns2_addr6[16]; /* NW-supplied 2nd DNS v6 address (bigendian)*/ + u8 unused5[68]; +} __packed; + #define SIERRA_NET_LSI_COMMON_LEN 4 -#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts)) +#define SIERRA_NET_LSI_UMTS_LEN (sizeof(struct lsi_umts_single)) #define SIERRA_NET_LSI_UMTS_STATUS_LEN \ (SIERRA_NET_LSI_UMTS_LEN - SIERRA_NET_LSI_COMMON_LEN) +#define SIERRA_NET_LSI_UMTS_DS_LEN (sizeof(struct lsi_umts_dual)) +#define SIERRA_NET_LSI_UMTS_DS_STATUS_LEN \ + (SIERRA_NET_LSI_UMTS_DS_LEN - SIERRA_NET_LSI_COMMON_LEN) /* Forward definitions */ static void sierra_sync_timer(unsigned long syncdata); @@ -190,10 +216,11 @@ static inline void sierra_net_set_private(struct usbnet *dev, dev->data[0] = (unsigned long)priv; } -/* is packet IPv4 */ +/* is packet IPv4/IPv6 */ static inline int is_ip(struct sk_buff *skb) { - return skb->protocol == cpu_to_be16(ETH_P_IP); + return skb->protocol == cpu_to_be16(ETH_P_IP) || + skb->protocol == cpu_to_be16(ETH_P_IPV6); } /* @@ -349,49 +376,54 @@ static inline int sierra_net_is_valid_addrlen(u8 len) static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen) { struct lsi_umts *lsi = (struct lsi_umts *)data; + u32 expected_length; - if (datalen < sizeof(struct lsi_umts)) { - netdev_err(dev->net, "%s: Data length %d, exp %Zu\n", - __func__, datalen, - sizeof(struct lsi_umts)); + if (datalen < sizeof(struct lsi_umts_single)) { + netdev_err(dev->net, "%s: Data length %d, exp >= %Zu\n", + __func__, datalen, sizeof(struct lsi_umts_single)); return -1; } - if (lsi->length != cpu_to_be16(SIERRA_NET_LSI_UMTS_STATUS_LEN)) { - netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n", - __func__, be16_to_cpu(lsi->length), - (u32)SIERRA_NET_LSI_UMTS_STATUS_LEN); - return -1; + /* Validate the session state */ + if (lsi->session_state == SIERRA_NET_SESSION_IDLE) { + netdev_err(dev->net, "Session idle, 0x%02x\n", + lsi->session_state); + return 0; } /* Validate the protocol - only support UMTS for now */ - if (lsi->protocol != SIERRA_NET_PROTOCOL_UMTS) { + if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS) { + struct lsi_umts_single *single = (struct lsi_umts_single *)lsi; + + /* Validate the link type */ + if (single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV4 && + single->link_type != SIERRA_NET_AS_LINK_TYPE_IPV6) { + netdev_err(dev->net, "Link type unsupported: 0x%02x\n", + single->link_type); + return -1; + } + expected_length = SIERRA_NET_LSI_UMTS_STATUS_LEN; + } else if (lsi->protocol == SIERRA_NET_PROTOCOL_UMTS_DS) { + expected_length = SIERRA_NET_LSI_UMTS_DS_STATUS_LEN; + } else { netdev_err(dev->net, "Protocol unsupported, 0x%02x\n", - lsi->protocol); + lsi->protocol); return -1; } - /* Validate the link type */ - if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) { - netdev_err(dev->net, "Link type unsupported: 0x%02x\n", - lsi->link_type); + if (be16_to_cpu(lsi->length) != expected_length) { + netdev_err(dev->net, "%s: LSI_UMTS_STATUS_LEN %d, exp %u\n", + __func__, be16_to_cpu(lsi->length), expected_length); return -1; } /* Validate the coverage */ - if (lsi->coverage == SIERRA_NET_COVERAGE_NONE - || lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) { + if (lsi->coverage == SIERRA_NET_COVERAGE_NONE || + lsi->coverage == SIERRA_NET_COVERAGE_NOPACKET) { netdev_err(dev->net, "No coverage, 0x%02x\n", lsi->coverage); return 0; } - /* Validate the session state */ - if (lsi->session_state == SIERRA_NET_SESSION_IDLE) { - netdev_err(dev->net, "Session idle, 0x%02x\n", - lsi->session_state); - return 0; - } - /* Set link_sense true */ return 1; } @@ -652,7 +684,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) u8 numendpoints; u16 fwattr = 0; int status; - struct ethhdr *eth; struct sierra_net_data *priv; static const u8 sync_tmplate[sizeof(priv->sync_msg)] = { 0x00, 0x00, SIERRA_NET_HIP_MSYNC_ID, 0x00}; @@ -690,11 +721,6 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->dev_addr[ETH_ALEN-2] = atomic_inc_return(&iface_counter); dev->net->dev_addr[ETH_ALEN-1] = ifacenum; - /* we will have to manufacture ethernet headers, prepare template */ - eth = (struct ethhdr *)priv->ethr_hdr_tmpl; - memcpy(ð->h_dest, dev->net->dev_addr, ETH_ALEN); - eth->h_proto = cpu_to_be16(ETH_P_IP); - /* prepare shutdown message template */ memcpy(priv->shdwn_msg, shdwn_tmplate, sizeof(priv->shdwn_msg)); /* set context index initially to 0 - prepares tx hdr template */ @@ -824,9 +850,14 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb) skb_pull(skb, hh.hdrlen); - /* We are going to accept this packet, prepare it */ - memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl, - ETH_HLEN); + /* We are going to accept this packet, prepare it. + * In case protocol is IPv6, keep it, otherwise force IPv4. + */ + skb_reset_mac_header(skb); + if (eth_hdr(skb)->h_proto != cpu_to_be16(ETH_P_IPV6)) + eth_hdr(skb)->h_proto = cpu_to_be16(ETH_P_IP); + eth_zero_addr(eth_hdr(skb)->h_source); + memcpy(eth_hdr(skb)->h_dest, dev->net->dev_addr, ETH_ALEN); /* Last packet in batch handled by usbnet */ if (hh.payload_len.word == skb->len) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4a105006ca63..765c2d6358da 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -48,8 +48,16 @@ module_param(gso, bool, 0444); */ DECLARE_EWMA(pkt_len, 1, 64) +/* With mergeable buffers we align buffer address and use the low bits to + * encode its true size. Buffer size is up to 1 page so we need to align to + * square root of page size to ensure we reserve enough bits to encode the true + * size. + */ +#define MERGEABLE_BUFFER_MIN_ALIGN_SHIFT ((PAGE_SHIFT + 1) / 2) + /* Minimum alignment for mergeable packet buffers. */ -#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256) +#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, \ + 1 << MERGEABLE_BUFFER_MIN_ALIGN_SHIFT) #define VIRTNET_DRIVER_VERSION "1.0.0" @@ -1104,7 +1112,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) hdr = skb_vnet_hdr(skb); if (virtio_net_hdr_from_skb(skb, &hdr->hdr, - virtio_is_little_endian(vi->vdev))) + virtio_is_little_endian(vi->vdev), false)) BUG(); if (vi->mergeable_rx_bufs) @@ -1707,6 +1715,11 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog) u16 xdp_qp = 0, curr_qp; int i, err; + if (prog && prog->xdp_adjust_head) { + netdev_warn(dev, "Does not support bpf_xdp_adjust_head()\n"); + return -EOPNOTSUPP; + } + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) || @@ -1890,8 +1903,12 @@ static void free_receive_page_frags(struct virtnet_info *vi) put_page(vi->rq[i].alloc_frag.page); } -static bool is_xdp_queue(struct virtnet_info *vi, int q) +static bool is_xdp_raw_buffer_queue(struct virtnet_info *vi, int q) { + /* For small receive mode always use kfree_skb variants */ + if (!vi->mergeable_rx_bufs) + return false; + if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs)) return false; else if (q < vi->curr_queue_pairs) @@ -1908,7 +1925,7 @@ static void free_unused_bufs(struct virtnet_info *vi) for (i = 0; i < vi->max_queue_pairs; i++) { struct virtqueue *vq = vi->sq[i].vq; while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { - if (!is_xdp_queue(vi, i)) + if (!is_xdp_raw_buffer_queue(vi, i)) dev_kfree_skb(buf); else put_page(virt_to_head_page(buf)); diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 7532646c3b7b..454f907d419a 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -263,7 +263,9 @@ static netdev_tx_t vrf_process_v4_outbound(struct sk_buff *skb, .flowi4_iif = LOOPBACK_IFINDEX, .flowi4_tos = RT_TOS(ip4h->tos), .flowi4_flags = FLOWI_FLAG_ANYSRC | FLOWI_FLAG_SKIP_NH_OIF, + .flowi4_proto = ip4h->protocol, .daddr = ip4h->daddr, + .saddr = ip4h->saddr, }; struct net *net = dev_net(vrf_dev); struct rtable *rt; @@ -967,6 +969,7 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, */ need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr); if (!ipv6_ndisc_frame(skb) && !need_strict) { + vrf_rx_stats(vrf_dev, skb->len); skb->dev = vrf_dev; skb->skb_iif = vrf_dev->ifindex; @@ -1011,6 +1014,8 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev, goto out; } + vrf_rx_stats(vrf_dev, skb->len); + skb_push(skb, skb->mac_len); dev_queue_xmit_nit(skb, vrf_dev); skb_pull(skb, skb->mac_len); @@ -1247,6 +1252,8 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev, return -EINVAL; vrf->tb_id = nla_get_u32(data[IFLA_VRF_TABLE]); + if (vrf->tb_id == RT_TABLE_UNSPEC) + return -EINVAL; dev->priv_flags |= IFF_L3MDEV_MASTER; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index bb70dd5723b5..30b04cf2bb1e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1798,7 +1798,7 @@ static int vxlan_build_skb(struct sk_buff *skb, struct dst_entry *dst, static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, struct net_device *dev, struct vxlan_sock *sock4, struct sk_buff *skb, int oif, u8 tos, - __be32 daddr, __be32 *saddr, + __be32 daddr, __be32 *saddr, __be16 dport, __be16 sport, struct dst_cache *dst_cache, const struct ip_tunnel_info *info) { @@ -1824,6 +1824,8 @@ static struct rtable *vxlan_get_route(struct vxlan_dev *vxlan, struct net_device fl4.flowi4_proto = IPPROTO_UDP; fl4.daddr = daddr; fl4.saddr = *saddr; + fl4.fl4_dport = dport; + fl4.fl4_sport = sport; rt = ip_route_output_key(vxlan->net, &fl4); if (likely(!IS_ERR(rt))) { @@ -1851,6 +1853,7 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, __be32 label, const struct in6_addr *daddr, struct in6_addr *saddr, + __be16 dport, __be16 sport, struct dst_cache *dst_cache, const struct ip_tunnel_info *info) { @@ -1877,6 +1880,8 @@ static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan, fl6.flowlabel = ip6_make_flowinfo(RT_TOS(tos), label); fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = IPPROTO_UDP; + fl6.fl6_dport = dport; + fl6.fl6_sport = sport; err = ipv6_stub->ipv6_dst_lookup(vxlan->net, sock6->sock->sk, @@ -2068,6 +2073,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, rdst ? rdst->remote_ifindex : 0, tos, dst->sin.sin_addr.s_addr, &src->sin.sin_addr.s_addr, + dst_port, src_port, dst_cache, info); if (IS_ERR(rt)) { err = PTR_ERR(rt); @@ -2104,6 +2110,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, rdst ? rdst->remote_ifindex : 0, tos, label, &dst->sin6.sin6_addr, &src->sin6.sin6_addr, + dst_port, src_port, dst_cache, info); if (IS_ERR(ndst)) { err = PTR_ERR(ndst); @@ -2261,7 +2268,7 @@ static void vxlan_cleanup(unsigned long arg) = container_of(p, struct vxlan_fdb, hlist); unsigned long timeout; - if (f->state & NUD_PERMANENT) + if (f->state & (NUD_PERMANENT | NUD_NOARP)) continue; timeout = f->used + vxlan->cfg.age_interval * HZ; @@ -2347,7 +2354,7 @@ static int vxlan_open(struct net_device *dev) } /* Purge the forwarding table */ -static void vxlan_flush(struct vxlan_dev *vxlan) +static void vxlan_flush(struct vxlan_dev *vxlan, bool do_all) { unsigned int h; @@ -2357,6 +2364,8 @@ static void vxlan_flush(struct vxlan_dev *vxlan) hlist_for_each_safe(p, n, &vxlan->fdb_head[h]) { struct vxlan_fdb *f = container_of(p, struct vxlan_fdb, hlist); + if (!do_all && (f->state & (NUD_PERMANENT | NUD_NOARP))) + continue; /* the all_zeros_mac entry is deleted at vxlan_uninit */ if (!is_zero_ether_addr(f->eth_addr)) vxlan_fdb_destroy(vxlan, f); @@ -2378,7 +2387,7 @@ static int vxlan_stop(struct net_device *dev) del_timer_sync(&vxlan->age_timer); - vxlan_flush(vxlan); + vxlan_flush(vxlan, false); vxlan_sock_release(vxlan); return ret; @@ -2430,7 +2439,8 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) rt = vxlan_get_route(vxlan, dev, sock4, skb, 0, info->key.tos, info->key.u.ipv4.dst, - &info->key.u.ipv4.src, NULL, info); + &info->key.u.ipv4.src, dport, sport, + &info->dst_cache, info); if (IS_ERR(rt)) return PTR_ERR(rt); ip_rt_put(rt); @@ -2441,7 +2451,8 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) ndst = vxlan6_get_route(vxlan, dev, sock6, skb, 0, info->key.tos, info->key.label, &info->key.u.ipv6.dst, - &info->key.u.ipv6.src, NULL, info); + &info->key.u.ipv6.src, dport, sport, + &info->dst_cache, info); if (IS_ERR(ndst)) return PTR_ERR(ndst); dst_release(ndst); @@ -2883,7 +2894,7 @@ static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, memcpy(&vxlan->cfg, conf, sizeof(*conf)); if (!vxlan->cfg.dst_port) { if (conf->flags & VXLAN_F_GPE) - vxlan->cfg.dst_port = 4790; /* IANA assigned VXLAN-GPE port */ + vxlan->cfg.dst_port = htons(4790); /* IANA VXLAN-GPE port */ else vxlan->cfg.dst_port = default_port; } @@ -3051,6 +3062,8 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id); + vxlan_flush(vxlan, true); + spin_lock(&vn->sock_lock); if (!hlist_unhashed(&vxlan->hlist)) hlist_del_rcu(&vxlan->hlist); diff --git a/drivers/net/wan/slic_ds26522.c b/drivers/net/wan/slic_ds26522.c index b776a0ab106c..9d9b4e0def2a 100644 --- a/drivers/net/wan/slic_ds26522.c +++ b/drivers/net/wan/slic_ds26522.c @@ -218,7 +218,7 @@ static int slic_ds26522_probe(struct spi_device *spi) ret = slic_ds26522_init_configure(spi); if (ret == 0) - pr_info("DS26522 cs%d configurated\n", spi->chip_select); + pr_info("DS26522 cs%d configured\n", spi->chip_select); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c index d02ca1491d16..8d3e53fac1da 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-8000.c @@ -91,7 +91,7 @@ #define IWL8000_FW_PRE "iwlwifi-8000C-" #define IWL8000_MODULE_FIRMWARE(api) \ - IWL8000_FW_PRE "-" __stringify(api) ".ucode" + IWL8000_FW_PRE __stringify(api) ".ucode" #define IWL8265_FW_PRE "iwlwifi-8265-" #define IWL8265_MODULE_FIRMWARE(api) \ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 636c8b03e318..09e9e2e3ed04 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1164,9 +1164,10 @@ static void iwl_mvm_realloc_queues_after_restart(struct iwl_mvm *mvm, .frame_limit = IWL_FRAME_LIMIT, }; - /* Make sure reserved queue is still marked as such (or allocated) */ - mvm->queue_info[mvm_sta->reserved_queue].status = - IWL_MVM_QUEUE_RESERVED; + /* Make sure reserved queue is still marked as such (if allocated) */ + if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) + mvm->queue_info[mvm_sta->reserved_queue].status = + IWL_MVM_QUEUE_RESERVED; for (i = 0; i <= IWL_MAX_TID_COUNT; i++) { struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[i]; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c index 63a051be832e..bec7d9c46087 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c @@ -843,8 +843,10 @@ static void iwl_mvm_thermal_zone_unregister(struct iwl_mvm *mvm) return; IWL_DEBUG_TEMP(mvm, "Thermal zone device unregister\n"); - thermal_zone_device_unregister(mvm->tz_device.tzone); - mvm->tz_device.tzone = NULL; + if (mvm->tz_device.tzone) { + thermal_zone_device_unregister(mvm->tz_device.tzone); + mvm->tz_device.tzone = NULL; + } } static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm) @@ -853,8 +855,10 @@ static void iwl_mvm_cooling_device_unregister(struct iwl_mvm *mvm) return; IWL_DEBUG_TEMP(mvm, "Cooling device unregister\n"); - thermal_cooling_device_unregister(mvm->cooling_dev.cdev); - mvm->cooling_dev.cdev = NULL; + if (mvm->cooling_dev.cdev) { + thermal_cooling_device_unregister(mvm->cooling_dev.cdev); + mvm->cooling_dev.cdev = NULL; + } } #endif /* CONFIG_THERMAL */ diff --git a/drivers/net/wireless/intersil/orinoco/mic.c b/drivers/net/wireless/intersil/orinoco/mic.c index bc7397d709d3..08bc7822f820 100644 --- a/drivers/net/wireless/intersil/orinoco/mic.c +++ b/drivers/net/wireless/intersil/orinoco/mic.c @@ -16,7 +16,7 @@ /********************************************************************/ int orinoco_mic_init(struct orinoco_private *priv) { - priv->tx_tfm_mic = crypto_alloc_ahash("michael_mic", 0, + priv->tx_tfm_mic = crypto_alloc_shash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_mic)) { printk(KERN_DEBUG "orinoco_mic_init: could not allocate " @@ -25,7 +25,7 @@ int orinoco_mic_init(struct orinoco_private *priv) return -ENOMEM; } - priv->rx_tfm_mic = crypto_alloc_ahash("michael_mic", 0, + priv->rx_tfm_mic = crypto_alloc_shash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_mic)) { printk(KERN_DEBUG "orinoco_mic_init: could not allocate " @@ -40,17 +40,16 @@ int orinoco_mic_init(struct orinoco_private *priv) void orinoco_mic_free(struct orinoco_private *priv) { if (priv->tx_tfm_mic) - crypto_free_ahash(priv->tx_tfm_mic); + crypto_free_shash(priv->tx_tfm_mic); if (priv->rx_tfm_mic) - crypto_free_ahash(priv->rx_tfm_mic); + crypto_free_shash(priv->rx_tfm_mic); } -int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key, +int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *da, u8 *sa, u8 priority, u8 *data, size_t data_len, u8 *mic) { - AHASH_REQUEST_ON_STACK(req, tfm_michael); - struct scatterlist sg[2]; + SHASH_DESC_ON_STACK(desc, tfm_michael); u8 hdr[ETH_HLEN + 2]; /* size of header + padding */ int err; @@ -67,18 +66,27 @@ int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key, hdr[ETH_ALEN * 2 + 2] = 0; hdr[ETH_ALEN * 2 + 3] = 0; - /* Use scatter gather to MIC header and data in one go */ - sg_init_table(sg, 2); - sg_set_buf(&sg[0], hdr, sizeof(hdr)); - sg_set_buf(&sg[1], data, data_len); + desc->tfm = tfm_michael; + desc->flags = 0; - if (crypto_ahash_setkey(tfm_michael, key, MIC_KEYLEN)) - return -1; + err = crypto_shash_setkey(tfm_michael, key, MIC_KEYLEN); + if (err) + return err; + + err = crypto_shash_init(desc); + if (err) + return err; + + err = crypto_shash_update(desc, hdr, sizeof(hdr)); + if (err) + return err; + + err = crypto_shash_update(desc, data, data_len); + if (err) + return err; + + err = crypto_shash_final(desc, mic); + shash_desc_zero(desc); - ahash_request_set_tfm(req, tfm_michael); - ahash_request_set_callback(req, 0, NULL, NULL); - ahash_request_set_crypt(req, sg, mic, data_len + sizeof(hdr)); - err = crypto_ahash_digest(req); - ahash_request_zero(req); return err; } diff --git a/drivers/net/wireless/intersil/orinoco/mic.h b/drivers/net/wireless/intersil/orinoco/mic.h index ce731d05cc98..e8724e889219 100644 --- a/drivers/net/wireless/intersil/orinoco/mic.h +++ b/drivers/net/wireless/intersil/orinoco/mic.h @@ -6,6 +6,7 @@ #define _ORINOCO_MIC_H_ #include <linux/types.h> +#include <crypto/hash.h> #define MICHAEL_MIC_LEN 8 @@ -15,7 +16,7 @@ struct crypto_ahash; int orinoco_mic_init(struct orinoco_private *priv); void orinoco_mic_free(struct orinoco_private *priv); -int orinoco_mic(struct crypto_ahash *tfm_michael, u8 *key, +int orinoco_mic(struct crypto_shash *tfm_michael, u8 *key, u8 *da, u8 *sa, u8 priority, u8 *data, size_t data_len, u8 *mic); diff --git a/drivers/net/wireless/intersil/orinoco/orinoco.h b/drivers/net/wireless/intersil/orinoco/orinoco.h index 2f0c84b1c440..5fa1c3e3713f 100644 --- a/drivers/net/wireless/intersil/orinoco/orinoco.h +++ b/drivers/net/wireless/intersil/orinoco/orinoco.h @@ -152,8 +152,8 @@ struct orinoco_private { u8 *wpa_ie; int wpa_ie_len; - struct crypto_ahash *rx_tfm_mic; - struct crypto_ahash *tx_tfm_mic; + struct crypto_shash *rx_tfm_mic; + struct crypto_shash *tx_tfm_mic; unsigned int wpa_enabled:1; unsigned int tkip_cm_active:1; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index 691ddef1ae28..a33a06d58a9a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -92,7 +92,7 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - char *fw_name = "rtlwifi/rtl8192cfwU.bin"; + char *fw_name; rtl8192ce_bt_reg_init(hw); @@ -164,8 +164,13 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw) } /* request fw */ - if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) + if (IS_VENDOR_UMC_A_CUT(rtlhal->version) && + !IS_92C_SERIAL(rtlhal->version)) + fw_name = "rtlwifi/rtl8192cfwU.bin"; + else if (IS_81XXC_VENDOR_UMC_B_CUT(rtlhal->version)) fw_name = "rtlwifi/rtl8192cfwU_B.bin"; + else + fw_name = "rtlwifi/rtl8192cfw.bin"; rtlpriv->max_fw_size = 0x4000; pr_info("Using firmware %s\n", fw_name); diff --git a/drivers/net/wireless/realtek/rtlwifi/usb.c b/drivers/net/wireless/realtek/rtlwifi/usb.c index 0a508649903d..49015b05f3d1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/usb.c +++ b/drivers/net/wireless/realtek/rtlwifi/usb.c @@ -1063,6 +1063,7 @@ int rtl_usb_probe(struct usb_interface *intf, return -ENOMEM; } rtlpriv = hw->priv; + rtlpriv->hw = hw; rtlpriv->usb_data = kzalloc(RTL_USB_MAX_RX_COUNT * sizeof(u32), GFP_KERNEL); if (!rtlpriv->usb_data) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 3ce1f7da8647..530586be05b4 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -113,10 +113,10 @@ struct xenvif_stats { * A subset of struct net_device_stats that contains only the * fields that are updated in netback.c for each queue. */ - unsigned int rx_bytes; - unsigned int rx_packets; - unsigned int tx_bytes; - unsigned int tx_packets; + u64 rx_bytes; + u64 rx_packets; + u64 tx_bytes; + u64 tx_packets; /* Additional stats used by xenvif */ unsigned long rx_gso_checksum_fixup; diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index e30ffd29b7e9..50fa1692d985 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -221,18 +221,18 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); struct xenvif_queue *queue = NULL; - unsigned int num_queues = vif->num_queues; - unsigned long rx_bytes = 0; - unsigned long rx_packets = 0; - unsigned long tx_bytes = 0; - unsigned long tx_packets = 0; + u64 rx_bytes = 0; + u64 rx_packets = 0; + u64 tx_bytes = 0; + u64 tx_packets = 0; unsigned int index; + spin_lock(&vif->lock); if (vif->queues == NULL) goto out; /* Aggregate tx and rx stats from each queue */ - for (index = 0; index < num_queues; ++index) { + for (index = 0; index < vif->num_queues; ++index) { queue = &vif->queues[index]; rx_bytes += queue->stats.rx_bytes; rx_packets += queue->stats.rx_packets; @@ -241,6 +241,8 @@ static struct net_device_stats *xenvif_get_stats(struct net_device *dev) } out: + spin_unlock(&vif->lock); + vif->dev->stats.rx_bytes = rx_bytes; vif->dev->stats.rx_packets = rx_packets; vif->dev->stats.tx_bytes = tx_bytes; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 3124eaec9427..85b742e1c42f 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -493,11 +493,22 @@ static int backend_create_xenvif(struct backend_info *be) static void backend_disconnect(struct backend_info *be) { if (be->vif) { + unsigned int queue_index; + xen_unregister_watchers(be->vif); #ifdef CONFIG_DEBUG_FS xenvif_debugfs_delif(be->vif); #endif /* CONFIG_DEBUG_FS */ xenvif_disconnect_data(be->vif); + for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index) + xenvif_deinit_queue(&be->vif->queues[queue_index]); + + spin_lock(&be->vif->lock); + vfree(be->vif->queues); + be->vif->num_queues = 0; + be->vif->queues = NULL; + spin_unlock(&be->vif->lock); + xenvif_disconnect_ctrl(be->vif); } } @@ -1034,6 +1045,8 @@ static void connect(struct backend_info *be) err: if (be->vif->num_queues > 0) xenvif_disconnect_data(be->vif); /* Clean up existing queues */ + for (queue_index = 0; queue_index < be->vif->num_queues; ++queue_index) + xenvif_deinit_queue(&be->vif->queues[queue_index]); vfree(be->vif->queues); be->vif->queues = NULL; be->vif->num_queues = 0; diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index a479cd99911d..1e4125a98291 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -281,6 +281,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) { RING_IDX req_prod = queue->rx.req_prod_pvt; int notify; + int err = 0; if (unlikely(!netif_carrier_ok(queue->info->netdev))) return; @@ -295,8 +296,10 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) struct xen_netif_rx_request *req; skb = xennet_alloc_one_rx_buffer(queue); - if (!skb) + if (!skb) { + err = -ENOMEM; break; + } id = xennet_rxidx(req_prod); @@ -320,8 +323,13 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) queue->rx.req_prod_pvt = req_prod; - /* Not enough requests? Try again later. */ - if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN) { + /* Try again later if there are not enough requests or skb allocation + * failed. + * Enough requests is quantified as the sum of newly created slots and + * the unconsumed slots at the backend. + */ + if (req_prod - queue->rx.rsp_cons < NET_RX_SLOTS_MIN || + unlikely(err)) { mod_timer(&queue->rx_refill_timer, jiffies + (HZ/10)); return; } @@ -1379,6 +1387,8 @@ static void xennet_disconnect_backend(struct netfront_info *info) for (i = 0; i < num_queues && info->queues; ++i) { struct netfront_queue *queue = &info->queues[i]; + del_timer_sync(&queue->rx_refill_timer); + if (queue->tx_irq && (queue->tx_irq == queue->rx_irq)) unbind_from_irqhandler(queue->tx_irq, queue); if (queue->tx_irq && (queue->tx_irq != queue->rx_irq)) { @@ -1733,7 +1743,6 @@ static void xennet_destroy_queues(struct netfront_info *info) if (netif_running(info->netdev)) napi_disable(&queue->napi); - del_timer_sync(&queue->rx_refill_timer); netif_napi_del(&queue->napi); } @@ -1822,27 +1831,19 @@ static int talk_to_netback(struct xenbus_device *dev, xennet_destroy_queues(info); err = xennet_create_queues(info, &num_queues); - if (err < 0) - goto destroy_ring; + if (err < 0) { + xenbus_dev_fatal(dev, err, "creating queues"); + kfree(info->queues); + info->queues = NULL; + goto out; + } /* Create shared ring, alloc event channel -- for each queue */ for (i = 0; i < num_queues; ++i) { queue = &info->queues[i]; err = setup_netfront(dev, queue, feature_split_evtchn); - if (err) { - /* setup_netfront() will tidy up the current - * queue on error, but we need to clean up - * those already allocated. - */ - if (i > 0) { - rtnl_lock(); - netif_set_real_num_tx_queues(info->netdev, i); - rtnl_unlock(); - goto destroy_ring; - } else { - goto out; - } - } + if (err) + goto destroy_ring; } again: @@ -1932,9 +1933,10 @@ abort_transaction_no_dev_fatal: xenbus_transaction_end(xbt, 1); destroy_ring: xennet_disconnect_backend(info); - kfree(info->queues); - info->queues = NULL; + xennet_destroy_queues(info); out: + unregister_netdev(info->netdev); + xennet_free_netdev(info->netdev); return err; } diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index eca9688bf9d9..c00238491673 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -1629,6 +1629,28 @@ static void atom_deinit_dev(struct intel_ntb_dev *ndev) /* Skylake Xeon NTB */ +static int skx_poll_link(struct intel_ntb_dev *ndev) +{ + u16 reg_val; + int rc; + + ndev->reg->db_iowrite(ndev->db_link_mask, + ndev->self_mmio + + ndev->self_reg->db_clear); + + rc = pci_read_config_word(ndev->ntb.pdev, + SKX_LINK_STATUS_OFFSET, ®_val); + if (rc) + return 0; + + if (reg_val == ndev->lnk_sta) + return 0; + + ndev->lnk_sta = reg_val; + + return 1; +} + static u64 skx_db_ioread(void __iomem *mmio) { return ioread64(mmio); @@ -2852,7 +2874,7 @@ static struct intel_b2b_addr xeon_b2b_dsd_addr = { }; static const struct intel_ntb_reg skx_reg = { - .poll_link = xeon_poll_link, + .poll_link = skx_poll_link, .link_is_up = xeon_link_is_up, .db_ioread = skx_db_ioread, .db_iowrite = skx_db_iowrite, diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index f81aa4b18d9f..02ca45fdd892 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1802,7 +1802,7 @@ ntb_transport_create_queue(void *data, struct device *client_dev, node = dev_to_node(&ndev->dev); - free_queue = ffs(nt->qp_bitmap); + free_queue = ffs(nt->qp_bitmap_free); if (!free_queue) goto err; @@ -2273,9 +2273,8 @@ module_init(ntb_transport_init); static void __exit ntb_transport_exit(void) { - debugfs_remove_recursive(nt_debugfs_dir); - ntb_unregister_client(&ntb_transport_client); bus_unregister(&ntb_transport_bus); + debugfs_remove_recursive(nt_debugfs_dir); } module_exit(ntb_transport_exit); diff --git a/drivers/ntb/test/ntb_perf.c b/drivers/ntb/test/ntb_perf.c index e75d4fdc0866..434e1d474f33 100644 --- a/drivers/ntb/test/ntb_perf.c +++ b/drivers/ntb/test/ntb_perf.c @@ -265,6 +265,8 @@ static ssize_t perf_copy(struct pthr_ctx *pctx, char __iomem *dst, if (dma_submit_error(cookie)) goto err_set_unmap; + dmaengine_unmap_put(unmap); + atomic_inc(&pctx->dma_sync); dma_async_issue_pending(chan); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 6307088b375f..ce3e8dfa10ad 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -52,17 +52,17 @@ static void namespace_blk_release(struct device *dev) kfree(nsblk); } -static struct device_type namespace_io_device_type = { +static const struct device_type namespace_io_device_type = { .name = "nd_namespace_io", .release = namespace_io_release, }; -static struct device_type namespace_pmem_device_type = { +static const struct device_type namespace_pmem_device_type = { .name = "nd_namespace_pmem", .release = namespace_pmem_release, }; -static struct device_type namespace_blk_device_type = { +static const struct device_type namespace_blk_device_type = { .name = "nd_namespace_blk", .release = namespace_blk_release, }; @@ -957,25 +957,28 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) { resource_size_t allocated = 0, available = 0; struct nd_region *nd_region = to_nd_region(dev->parent); + struct nd_namespace_common *ndns = to_ndns(dev); struct nd_mapping *nd_mapping; struct nvdimm_drvdata *ndd; struct nd_label_id label_id; u32 flags = 0, remainder; + int rc, i, id = -1; u8 *uuid = NULL; - int rc, i; - if (dev->driver || to_ndns(dev)->claim) + if (dev->driver || ndns->claim) return -EBUSY; if (is_namespace_pmem(dev)) { struct nd_namespace_pmem *nspm = to_nd_namespace_pmem(dev); uuid = nspm->uuid; + id = nspm->id; } else if (is_namespace_blk(dev)) { struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev); uuid = nsblk->uuid; flags = NSLABEL_FLAG_LOCAL; + id = nsblk->id; } /* @@ -1034,20 +1037,17 @@ static ssize_t __size_store(struct device *dev, unsigned long long val) nd_namespace_pmem_set_resource(nd_region, nspm, val * nd_region->ndr_mappings); - } else if (is_namespace_blk(dev)) { - struct nd_namespace_blk *nsblk = to_nd_namespace_blk(dev); - - /* - * Try to delete the namespace if we deleted all of its - * allocation, this is not the seed device for the - * region, and it is not actively claimed by a btt - * instance. - */ - if (val == 0 && nd_region->ns_seed != dev - && !nsblk->common.claim) - nd_device_unregister(dev, ND_ASYNC); } + /* + * Try to delete the namespace if we deleted all of its + * allocation, this is not the seed or 0th device for the + * region, and it is not actively claimed by a btt, pfn, or dax + * instance. + */ + if (val == 0 && id != 0 && nd_region->ns_seed != dev && !ndns->claim) + nd_device_unregister(dev, ND_ASYNC); + return rc; } diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index a2ac9e641aa9..6c033c9a2f06 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -627,15 +627,12 @@ static int nd_pfn_init(struct nd_pfn *nd_pfn) size = resource_size(&nsio->res); npfns = (size - start_pad - end_trunc - SZ_8K) / SZ_4K; if (nd_pfn->mode == PFN_MODE_PMEM) { - unsigned long memmap_size; - /* * vmemmap_populate_hugepages() allocates the memmap array in * HPAGE_SIZE chunks. */ - memmap_size = ALIGN(64 * npfns, HPAGE_SIZE); - offset = ALIGN(start + SZ_8K + memmap_size + dax_label_reserve, - nd_pfn->align) - start; + offset = ALIGN(start + SZ_8K + 64 * npfns + dax_label_reserve, + max(nd_pfn->align, HPAGE_SIZE)) - start; } else if (nd_pfn->mode == PFN_MODE_RAM) offset = ALIGN(start + SZ_8K + dax_label_reserve, nd_pfn->align) - start; diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 7282d7495bf1..5b536be5a12e 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -90,7 +90,9 @@ static int read_pmem(struct page *page, unsigned int off, rc = memcpy_from_pmem(mem + off, pmem_addr, len); kunmap_atomic(mem); - return rc; + if (rc) + return -EIO; + return 0; } static int pmem_do_bvec(struct pmem_device *pmem, struct page *page, diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index b40cfb076f02..44a1a257e0b5 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -208,18 +208,18 @@ EXPORT_SYMBOL_GPL(nvme_requeue_req); struct request *nvme_alloc_request(struct request_queue *q, struct nvme_command *cmd, unsigned int flags, int qid) { + unsigned op = nvme_is_write(cmd) ? REQ_OP_DRV_OUT : REQ_OP_DRV_IN; struct request *req; if (qid == NVME_QID_ANY) { - req = blk_mq_alloc_request(q, nvme_is_write(cmd), flags); + req = blk_mq_alloc_request(q, op, flags); } else { - req = blk_mq_alloc_request_hctx(q, nvme_is_write(cmd), flags, + req = blk_mq_alloc_request_hctx(q, op, flags, qid ? qid - 1 : 0); } if (IS_ERR(req)) return req; - req->cmd_type = REQ_TYPE_DRV_PRIV; req->cmd_flags |= REQ_FAILFAST_DRIVER; nvme_req(req)->cmd = cmd; @@ -238,26 +238,38 @@ static inline void nvme_setup_flush(struct nvme_ns *ns, static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req, struct nvme_command *cmnd) { + unsigned short segments = blk_rq_nr_discard_segments(req), n = 0; struct nvme_dsm_range *range; - unsigned int nr_bytes = blk_rq_bytes(req); + struct bio *bio; - range = kmalloc(sizeof(*range), GFP_ATOMIC); + range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC); if (!range) return BLK_MQ_RQ_QUEUE_BUSY; - range->cattr = cpu_to_le32(0); - range->nlb = cpu_to_le32(nr_bytes >> ns->lba_shift); - range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); + __rq_for_each_bio(bio, req) { + u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector); + u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift; + + range[n].cattr = cpu_to_le32(0); + range[n].nlb = cpu_to_le32(nlb); + range[n].slba = cpu_to_le64(slba); + n++; + } + + if (WARN_ON_ONCE(n != segments)) { + kfree(range); + return BLK_MQ_RQ_QUEUE_ERROR; + } memset(cmnd, 0, sizeof(*cmnd)); cmnd->dsm.opcode = nvme_cmd_dsm; cmnd->dsm.nsid = cpu_to_le32(ns->ns_id); - cmnd->dsm.nr = 0; + cmnd->dsm.nr = segments - 1; cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); req->special_vec.bv_page = virt_to_page(range); req->special_vec.bv_offset = offset_in_page(range); - req->special_vec.bv_len = sizeof(*range); + req->special_vec.bv_len = sizeof(*range) * segments; req->rq_flags |= RQF_SPECIAL_PAYLOAD; return BLK_MQ_RQ_QUEUE_OK; @@ -309,17 +321,27 @@ int nvme_setup_cmd(struct nvme_ns *ns, struct request *req, { int ret = BLK_MQ_RQ_QUEUE_OK; - if (req->cmd_type == REQ_TYPE_DRV_PRIV) + switch (req_op(req)) { + case REQ_OP_DRV_IN: + case REQ_OP_DRV_OUT: memcpy(cmd, nvme_req(req)->cmd, sizeof(*cmd)); - else if (req_op(req) == REQ_OP_FLUSH) + break; + case REQ_OP_FLUSH: nvme_setup_flush(ns, cmd); - else if (req_op(req) == REQ_OP_DISCARD) + break; + case REQ_OP_DISCARD: ret = nvme_setup_discard(ns, req, cmd); - else + break; + case REQ_OP_READ: + case REQ_OP_WRITE: nvme_setup_rw(ns, req, cmd); + break; + default: + WARN_ON_ONCE(1); + return BLK_MQ_RQ_QUEUE_ERROR; + } cmd->common.command_id = req->tag; - return ret; } EXPORT_SYMBOL_GPL(nvme_setup_cmd); @@ -784,6 +806,13 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, return nvme_sg_io(ns, (void __user *)arg); #endif default: +#ifdef CONFIG_NVM + if (ns->ndev) + return nvme_nvm_ioctl(ns, cmd, arg); +#endif + if (is_sed_ioctl(cmd)) + return sed_ioctl(ns->ctrl->opal_dev, cmd, + (void __user *) arg); return -ENOTTY; } } @@ -861,6 +890,9 @@ static void nvme_config_discard(struct nvme_ns *ns) struct nvme_ctrl *ctrl = ns->ctrl; u32 logical_block_size = queue_logical_block_size(ns->queue); + BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) < + NVME_DSM_MAX_RANGES); + if (ctrl->quirks & NVME_QUIRK_DISCARD_ZEROES) ns->queue->limits.discard_zeroes_data = 1; else @@ -869,6 +901,7 @@ static void nvme_config_discard(struct nvme_ns *ns) ns->queue->limits.discard_alignment = logical_block_size; ns->queue->limits.discard_granularity = logical_block_size; blk_queue_max_discard_sectors(ns->queue, UINT_MAX); + blk_queue_max_discard_segments(ns->queue, NVME_DSM_MAX_RANGES); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); } @@ -1051,6 +1084,28 @@ static const struct pr_ops nvme_pr_ops = { .pr_clear = nvme_pr_clear, }; +#ifdef CONFIG_BLK_SED_OPAL +int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len, + bool send) +{ + struct nvme_ctrl *ctrl = data; + struct nvme_command cmd; + + memset(&cmd, 0, sizeof(cmd)); + if (send) + cmd.common.opcode = nvme_admin_security_send; + else + cmd.common.opcode = nvme_admin_security_recv; + cmd.common.nsid = 0; + cmd.common.cdw10[0] = cpu_to_le32(((u32)secp) << 24 | ((u32)spsp) << 8); + cmd.common.cdw10[1] = cpu_to_le32(len); + + return __nvme_submit_sync_cmd(ctrl->admin_q, &cmd, NULL, buffer, len, + ADMIN_TIMEOUT, NVME_QID_ANY, 1, 0); +} +EXPORT_SYMBOL_GPL(nvme_sec_submit); +#endif /* CONFIG_BLK_SED_OPAL */ + static const struct block_device_operations nvme_fops = { .owner = THIS_MODULE, .ioctl = nvme_ioctl, @@ -1106,12 +1161,7 @@ int nvme_disable_ctrl(struct nvme_ctrl *ctrl, u64 cap) if (ret) return ret; - /* Checking for ctrl->tagset is a trick to avoid sleeping on module - * load, since we only need the quirk on reset_controller. Notice - * that the HGST device needs this delay only in firmware activation - * procedure; unfortunately we have no (easy) way to verify this. - */ - if ((ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) && ctrl->tagset) + if (ctrl->quirks & NVME_QUIRK_DELAY_BEFORE_CHK_RDY) msleep(NVME_QUIRK_DELAY_AMOUNT); return nvme_wait_ready(ctrl, cap, false); @@ -1193,8 +1243,8 @@ static void nvme_set_queue_limits(struct nvme_ctrl *ctrl, blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors); blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX)); } - if (ctrl->stripe_size) - blk_queue_chunk_sectors(q, ctrl->stripe_size >> 9); + if (ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) + blk_queue_chunk_sectors(q, ctrl->max_hw_sectors); blk_queue_virt_boundary(q, ctrl->page_size - 1); if (ctrl->vwc & NVME_CTRL_VWC_PRESENT) vwc = true; @@ -1235,6 +1285,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) return -EIO; } + ctrl->oacs = le16_to_cpu(id->oacs); ctrl->vid = le16_to_cpu(id->vid); ctrl->oncs = le16_to_cpup(&id->oncs); atomic_set(&ctrl->abort_limit, id->acl + 1); @@ -1250,19 +1301,6 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) ctrl->max_hw_sectors = min_not_zero(ctrl->max_hw_sectors, max_hw_sectors); - if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) && id->vs[3]) { - unsigned int max_hw_sectors; - - ctrl->stripe_size = 1 << (id->vs[3] + page_shift); - max_hw_sectors = ctrl->stripe_size >> (page_shift - 9); - if (ctrl->max_hw_sectors) { - ctrl->max_hw_sectors = min(max_hw_sectors, - ctrl->max_hw_sectors); - } else { - ctrl->max_hw_sectors = max_hw_sectors; - } - } - nvme_set_queue_limits(ctrl, ctrl->admin_q); ctrl->sgls = le32_to_cpu(id->sgls); ctrl->kas = le16_to_cpu(id->kas); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 771e2e761872..fb51a8de9b29 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1491,19 +1491,20 @@ static int nvme_fc_create_hw_io_queues(struct nvme_fc_ctrl *ctrl, u16 qsize) { struct nvme_fc_queue *queue = &ctrl->queues[1]; - int i, j, ret; + int i, ret; for (i = 1; i < ctrl->queue_count; i++, queue++) { ret = __nvme_fc_create_hw_queue(ctrl, queue, i, qsize); - if (ret) { - for (j = i-1; j >= 0; j--) - __nvme_fc_delete_hw_queue(ctrl, - &ctrl->queues[j], j); - return ret; - } + if (ret) + goto delete_queues; } return 0; + +delete_queues: + for (; i >= 0; i--) + __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[i], i); + return ret; } static int @@ -1653,23 +1654,22 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq, struct nvme_fc_fcp_op *op) { struct nvmefc_fcp_req *freq = &op->fcp_req; - u32 map_len = nvme_map_len(rq); enum dma_data_direction dir; int ret; freq->sg_cnt = 0; - if (!map_len) + if (!blk_rq_payload_bytes(rq)) return 0; freq->sg_table.sgl = freq->first_sgl; - ret = sg_alloc_table_chained(&freq->sg_table, rq->nr_phys_segments, - freq->sg_table.sgl); + ret = sg_alloc_table_chained(&freq->sg_table, + blk_rq_nr_phys_segments(rq), freq->sg_table.sgl); if (ret) return -ENOMEM; op->nents = blk_rq_map_sg(rq->q, rq, freq->sg_table.sgl); - WARN_ON(op->nents > rq->nr_phys_segments); + WARN_ON(op->nents > blk_rq_nr_phys_segments(rq)); dir = (rq_data_dir(rq) == WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl, op->nents, dir); @@ -1853,7 +1853,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx, if (ret) return ret; - data_len = nvme_map_len(rq); + data_len = blk_rq_payload_bytes(rq); if (data_len) io_dir = ((rq_data_dir(rq) == WRITE) ? NVMEFC_FCP_WRITE : NVMEFC_FCP_READ); @@ -1937,7 +1937,7 @@ nvme_fc_complete_rq(struct request *rq) return; } - if (rq->cmd_type == REQ_TYPE_DRV_PRIV) + if (blk_rq_is_passthrough(rq)) error = rq->errors; else error = nvme_error_status(rq->errors); @@ -2401,8 +2401,8 @@ __nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, WARN_ON_ONCE(!changed); dev_info(ctrl->ctrl.device, - "NVME-FC{%d}: new ctrl: NQN \"%s\" (%p)\n", - ctrl->cnum, ctrl->ctrl.opts->subsysnqn, &ctrl); + "NVME-FC{%d}: new ctrl: NQN \"%s\"\n", + ctrl->cnum, ctrl->ctrl.opts->subsysnqn); kref_get(&ctrl->ctrl.kref); diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c index 588d4a34c083..21cac8523bd8 100644 --- a/drivers/nvme/host/lightnvm.c +++ b/drivers/nvme/host/lightnvm.c @@ -26,6 +26,8 @@ #include <linux/bitops.h> #include <linux/lightnvm.h> #include <linux/vmalloc.h> +#include <linux/sched/sysctl.h> +#include <uapi/linux/lightnvm.h> enum nvme_nvm_admin_opcode { nvme_nvm_admin_identity = 0xe2, @@ -248,50 +250,48 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id) { struct nvme_nvm_id_group *src; struct nvm_id_group *dst; - int i, end; - - end = min_t(u32, 4, nvm_id->cgrps); - - for (i = 0; i < end; i++) { - src = &nvme_nvm_id->groups[i]; - dst = &nvm_id->groups[i]; - - dst->mtype = src->mtype; - dst->fmtype = src->fmtype; - dst->num_ch = src->num_ch; - dst->num_lun = src->num_lun; - dst->num_pln = src->num_pln; - - dst->num_pg = le16_to_cpu(src->num_pg); - dst->num_blk = le16_to_cpu(src->num_blk); - dst->fpg_sz = le16_to_cpu(src->fpg_sz); - dst->csecs = le16_to_cpu(src->csecs); - dst->sos = le16_to_cpu(src->sos); - - dst->trdt = le32_to_cpu(src->trdt); - dst->trdm = le32_to_cpu(src->trdm); - dst->tprt = le32_to_cpu(src->tprt); - dst->tprm = le32_to_cpu(src->tprm); - dst->tbet = le32_to_cpu(src->tbet); - dst->tbem = le32_to_cpu(src->tbem); - dst->mpos = le32_to_cpu(src->mpos); - dst->mccap = le32_to_cpu(src->mccap); - - dst->cpar = le16_to_cpu(src->cpar); - - if (dst->fmtype == NVM_ID_FMTYPE_MLC) { - memcpy(dst->lptbl.id, src->lptbl.id, 8); - dst->lptbl.mlc.num_pairs = - le16_to_cpu(src->lptbl.mlc.num_pairs); - - if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) { - pr_err("nvm: number of MLC pairs not supported\n"); - return -EINVAL; - } - memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs, - dst->lptbl.mlc.num_pairs); + if (nvme_nvm_id->cgrps != 1) + return -EINVAL; + + src = &nvme_nvm_id->groups[0]; + dst = &nvm_id->grp; + + dst->mtype = src->mtype; + dst->fmtype = src->fmtype; + dst->num_ch = src->num_ch; + dst->num_lun = src->num_lun; + dst->num_pln = src->num_pln; + + dst->num_pg = le16_to_cpu(src->num_pg); + dst->num_blk = le16_to_cpu(src->num_blk); + dst->fpg_sz = le16_to_cpu(src->fpg_sz); + dst->csecs = le16_to_cpu(src->csecs); + dst->sos = le16_to_cpu(src->sos); + + dst->trdt = le32_to_cpu(src->trdt); + dst->trdm = le32_to_cpu(src->trdm); + dst->tprt = le32_to_cpu(src->tprt); + dst->tprm = le32_to_cpu(src->tprm); + dst->tbet = le32_to_cpu(src->tbet); + dst->tbem = le32_to_cpu(src->tbem); + dst->mpos = le32_to_cpu(src->mpos); + dst->mccap = le32_to_cpu(src->mccap); + + dst->cpar = le16_to_cpu(src->cpar); + + if (dst->fmtype == NVM_ID_FMTYPE_MLC) { + memcpy(dst->lptbl.id, src->lptbl.id, 8); + dst->lptbl.mlc.num_pairs = + le16_to_cpu(src->lptbl.mlc.num_pairs); + + if (dst->lptbl.mlc.num_pairs > NVME_NVM_LP_MLC_PAIRS) { + pr_err("nvm: number of MLC pairs not supported\n"); + return -EINVAL; } + + memcpy(dst->lptbl.mlc.pairs, src->lptbl.mlc.pairs, + dst->lptbl.mlc.num_pairs); } return 0; @@ -321,7 +321,6 @@ static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id) nvm_id->ver_id = nvme_nvm_id->ver_id; nvm_id->vmnt = nvme_nvm_id->vmnt; - nvm_id->cgrps = nvme_nvm_id->cgrps; nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap); nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom); memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf, @@ -372,7 +371,7 @@ static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb, } /* Transform physical address to target address space */ - nvmdev->mt->part_to_tgt(nvmdev, entries, cmd_nlb); + nvm_part_to_tgt(nvmdev, entries, cmd_nlb); if (update_l2p(cmd_slba, cmd_nlb, entries, priv)) { ret = -EINTR; @@ -485,7 +484,8 @@ static void nvme_nvm_end_io(struct request *rq, int error) struct nvm_rq *rqd = rq->end_io_data; rqd->ppa_status = nvme_req(rq)->result.u64; - nvm_end_io(rqd, error); + rqd->error = error; + nvm_end_io(rqd); kfree(nvme_req(rq)->cmd); blk_mq_free_request(rq); @@ -586,6 +586,224 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = { .max_phys_sect = 64, }; +static void nvme_nvm_end_user_vio(struct request *rq, int error) +{ + struct completion *waiting = rq->end_io_data; + + complete(waiting); +} + +static int nvme_nvm_submit_user_cmd(struct request_queue *q, + struct nvme_ns *ns, + struct nvme_nvm_command *vcmd, + void __user *ubuf, unsigned int bufflen, + void __user *meta_buf, unsigned int meta_len, + void __user *ppa_buf, unsigned int ppa_len, + u32 *result, u64 *status, unsigned int timeout) +{ + bool write = nvme_is_write((struct nvme_command *)vcmd); + struct nvm_dev *dev = ns->ndev; + struct gendisk *disk = ns->disk; + struct request *rq; + struct bio *bio = NULL; + __le64 *ppa_list = NULL; + dma_addr_t ppa_dma; + __le64 *metadata = NULL; + dma_addr_t metadata_dma; + DECLARE_COMPLETION_ONSTACK(wait); + int ret; + + rq = nvme_alloc_request(q, (struct nvme_command *)vcmd, 0, + NVME_QID_ANY); + if (IS_ERR(rq)) { + ret = -ENOMEM; + goto err_cmd; + } + + rq->timeout = timeout ? timeout : ADMIN_TIMEOUT; + + rq->cmd_flags &= ~REQ_FAILFAST_DRIVER; + rq->end_io_data = &wait; + + if (ppa_buf && ppa_len) { + ppa_list = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, &ppa_dma); + if (!ppa_list) { + ret = -ENOMEM; + goto err_rq; + } + if (copy_from_user(ppa_list, (void __user *)ppa_buf, + sizeof(u64) * (ppa_len + 1))) { + ret = -EFAULT; + goto err_ppa; + } + vcmd->ph_rw.spba = cpu_to_le64(ppa_dma); + } else { + vcmd->ph_rw.spba = cpu_to_le64((uintptr_t)ppa_buf); + } + + if (ubuf && bufflen) { + ret = blk_rq_map_user(q, rq, NULL, ubuf, bufflen, GFP_KERNEL); + if (ret) + goto err_ppa; + bio = rq->bio; + + if (meta_buf && meta_len) { + metadata = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, + &metadata_dma); + if (!metadata) { + ret = -ENOMEM; + goto err_map; + } + + if (write) { + if (copy_from_user(metadata, + (void __user *)meta_buf, + meta_len)) { + ret = -EFAULT; + goto err_meta; + } + } + vcmd->ph_rw.metadata = cpu_to_le64(metadata_dma); + } + + if (!disk) + goto submit; + + bio->bi_bdev = bdget_disk(disk, 0); + if (!bio->bi_bdev) { + ret = -ENODEV; + goto err_meta; + } + } + +submit: + blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_user_vio); + + wait_for_completion_io(&wait); + + ret = nvme_error_status(rq->errors); + if (result) + *result = rq->errors & 0x7ff; + if (status) + *status = le64_to_cpu(nvme_req(rq)->result.u64); + + if (metadata && !ret && !write) { + if (copy_to_user(meta_buf, (void *)metadata, meta_len)) + ret = -EFAULT; + } +err_meta: + if (meta_buf && meta_len) + dma_pool_free(dev->dma_pool, metadata, metadata_dma); +err_map: + if (bio) { + if (disk && bio->bi_bdev) + bdput(bio->bi_bdev); + blk_rq_unmap_user(bio); + } +err_ppa: + if (ppa_buf && ppa_len) + dma_pool_free(dev->dma_pool, ppa_list, ppa_dma); +err_rq: + blk_mq_free_request(rq); +err_cmd: + return ret; +} + +static int nvme_nvm_submit_vio(struct nvme_ns *ns, + struct nvm_user_vio __user *uvio) +{ + struct nvm_user_vio vio; + struct nvme_nvm_command c; + unsigned int length; + int ret; + + if (copy_from_user(&vio, uvio, sizeof(vio))) + return -EFAULT; + if (vio.flags) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.ph_rw.opcode = vio.opcode; + c.ph_rw.nsid = cpu_to_le32(ns->ns_id); + c.ph_rw.control = cpu_to_le16(vio.control); + c.ph_rw.length = cpu_to_le16(vio.nppas); + + length = (vio.nppas + 1) << ns->lba_shift; + + ret = nvme_nvm_submit_user_cmd(ns->queue, ns, &c, + (void __user *)(uintptr_t)vio.addr, length, + (void __user *)(uintptr_t)vio.metadata, + vio.metadata_len, + (void __user *)(uintptr_t)vio.ppa_list, vio.nppas, + &vio.result, &vio.status, 0); + + if (ret && copy_to_user(uvio, &vio, sizeof(vio))) + return -EFAULT; + + return ret; +} + +static int nvme_nvm_user_vcmd(struct nvme_ns *ns, int admin, + struct nvm_passthru_vio __user *uvcmd) +{ + struct nvm_passthru_vio vcmd; + struct nvme_nvm_command c; + struct request_queue *q; + unsigned int timeout = 0; + int ret; + + if (copy_from_user(&vcmd, uvcmd, sizeof(vcmd))) + return -EFAULT; + if ((vcmd.opcode != 0xF2) && (!capable(CAP_SYS_ADMIN))) + return -EACCES; + if (vcmd.flags) + return -EINVAL; + + memset(&c, 0, sizeof(c)); + c.common.opcode = vcmd.opcode; + c.common.nsid = cpu_to_le32(ns->ns_id); + c.common.cdw2[0] = cpu_to_le32(vcmd.cdw2); + c.common.cdw2[1] = cpu_to_le32(vcmd.cdw3); + /* cdw11-12 */ + c.ph_rw.length = cpu_to_le16(vcmd.nppas); + c.ph_rw.control = cpu_to_le32(vcmd.control); + c.common.cdw10[3] = cpu_to_le32(vcmd.cdw13); + c.common.cdw10[4] = cpu_to_le32(vcmd.cdw14); + c.common.cdw10[5] = cpu_to_le32(vcmd.cdw15); + + if (vcmd.timeout_ms) + timeout = msecs_to_jiffies(vcmd.timeout_ms); + + q = admin ? ns->ctrl->admin_q : ns->queue; + + ret = nvme_nvm_submit_user_cmd(q, ns, + (struct nvme_nvm_command *)&c, + (void __user *)(uintptr_t)vcmd.addr, vcmd.data_len, + (void __user *)(uintptr_t)vcmd.metadata, + vcmd.metadata_len, + (void __user *)(uintptr_t)vcmd.ppa_list, vcmd.nppas, + &vcmd.result, &vcmd.status, timeout); + + if (ret && copy_to_user(uvcmd, &vcmd, sizeof(vcmd))) + return -EFAULT; + + return ret; +} + +int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case NVME_NVM_IOCTL_ADMIN_VIO: + return nvme_nvm_user_vcmd(ns, 1, (void __user *)arg); + case NVME_NVM_IOCTL_IO_VIO: + return nvme_nvm_user_vcmd(ns, 0, (void __user *)arg); + case NVME_NVM_IOCTL_SUBMIT_VIO: + return nvme_nvm_submit_vio(ns, (void __user *)arg); + default: + return -ENOTTY; + } +} + int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node) { struct request_queue *q = ns->queue; @@ -622,7 +840,7 @@ static ssize_t nvm_dev_attr_show(struct device *dev, return 0; id = &ndev->identity; - grp = &id->groups[0]; + grp = &id->grp; attr = &dattr->attr; if (strcmp(attr->name, "version") == 0) { @@ -633,10 +851,9 @@ static ssize_t nvm_dev_attr_show(struct device *dev, return scnprintf(page, PAGE_SIZE, "%u\n", id->cap); } else if (strcmp(attr->name, "device_mode") == 0) { return scnprintf(page, PAGE_SIZE, "%u\n", id->dom); + /* kept for compatibility */ } else if (strcmp(attr->name, "media_manager") == 0) { - if (!ndev->mt) - return scnprintf(page, PAGE_SIZE, "%s\n", "none"); - return scnprintf(page, PAGE_SIZE, "%s\n", ndev->mt->name); + return scnprintf(page, PAGE_SIZE, "%s\n", "gennvm"); } else if (strcmp(attr->name, "ppa_format") == 0) { return scnprintf(page, PAGE_SIZE, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bd5321441d12..14cfc6f7facb 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -19,6 +19,7 @@ #include <linux/kref.h> #include <linux/blk-mq.h> #include <linux/lightnvm.h> +#include <linux/sed-opal.h> enum { /* @@ -125,6 +126,8 @@ struct nvme_ctrl { struct list_head node; struct ida ns_ida; + struct opal_dev *opal_dev; + char name[12]; char serial[20]; char model[40]; @@ -135,9 +138,9 @@ struct nvme_ctrl { u32 page_size; u32 max_hw_sectors; - u32 stripe_size; u16 oncs; u16 vid; + u16 oacs; atomic_t abort_limit; u8 event_limit; u8 vwc; @@ -226,14 +229,6 @@ static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector) return (sector >> (ns->lba_shift - 9)); } -static inline unsigned nvme_map_len(struct request *rq) -{ - if (req_op(rq) == REQ_OP_DISCARD) - return sizeof(struct nvme_dsm_range); - else - return blk_rq_bytes(rq); -} - static inline void nvme_cleanup_cmd(struct request *req) { if (req->rq_flags & RQF_SPECIAL_PAYLOAD) { @@ -276,6 +271,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl); void nvme_queue_scan(struct nvme_ctrl *ctrl); void nvme_remove_namespaces(struct nvme_ctrl *ctrl); +int nvme_sec_submit(void *data, u16 spsp, u8 secp, void *buffer, size_t len, + bool send); + #define NVME_NR_AERS 1 void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status, union nvme_result *res); @@ -327,6 +325,7 @@ int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node); void nvme_nvm_unregister(struct nvme_ns *ns); int nvme_nvm_register_sysfs(struct nvme_ns *ns); void nvme_nvm_unregister_sysfs(struct nvme_ns *ns); +int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, unsigned long arg); #else static inline int nvme_nvm_register(struct nvme_ns *ns, char *disk_name, int node) @@ -344,6 +343,11 @@ static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *i { return 0; } +static inline int nvme_nvm_ioctl(struct nvme_ns *ns, unsigned int cmd, + unsigned long arg) +{ + return -ENOTTY; +} #endif /* CONFIG_NVM */ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev) diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 3d21a154dce7..ddc51adb594d 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -43,6 +43,7 @@ #include <linux/types.h> #include <linux/io-64-nonatomic-lo-hi.h> #include <asm/unaligned.h> +#include <linux/sed-opal.h> #include "nvme.h" @@ -306,11 +307,11 @@ static __le64 **iod_list(struct request *req) return (__le64 **)(iod->sg + blk_rq_nr_phys_segments(req)); } -static int nvme_init_iod(struct request *rq, unsigned size, - struct nvme_dev *dev) +static int nvme_init_iod(struct request *rq, struct nvme_dev *dev) { struct nvme_iod *iod = blk_mq_rq_to_pdu(rq); int nseg = blk_rq_nr_phys_segments(rq); + unsigned int size = blk_rq_payload_bytes(rq); if (nseg > NVME_INT_PAGES || size > NVME_INT_BYTES(dev)) { iod->sg = kmalloc(nvme_iod_alloc_size(dev, size, nseg), GFP_ATOMIC); @@ -420,12 +421,11 @@ static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi) } #endif -static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req, - int total_len) +static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); struct dma_pool *pool; - int length = total_len; + int length = blk_rq_payload_bytes(req); struct scatterlist *sg = iod->sg; int dma_len = sg_dma_len(sg); u64 dma_addr = sg_dma_address(sg); @@ -501,7 +501,7 @@ static bool nvme_setup_prps(struct nvme_dev *dev, struct request *req, } static int nvme_map_data(struct nvme_dev *dev, struct request *req, - unsigned size, struct nvme_command *cmnd) + struct nvme_command *cmnd) { struct nvme_iod *iod = blk_mq_rq_to_pdu(req); struct request_queue *q = req->q; @@ -519,7 +519,7 @@ static int nvme_map_data(struct nvme_dev *dev, struct request *req, DMA_ATTR_NO_WARN)) goto out; - if (!nvme_setup_prps(dev, req, size)) + if (!nvme_setup_prps(dev, req)) goto out_unmap; ret = BLK_MQ_RQ_QUEUE_ERROR; @@ -580,7 +580,6 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, struct nvme_dev *dev = nvmeq->dev; struct request *req = bd->rq; struct nvme_command cmnd; - unsigned map_len; int ret = BLK_MQ_RQ_QUEUE_OK; /* @@ -590,7 +589,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, */ if (ns && ns->ms && !blk_integrity_rq(req)) { if (!(ns->pi_type && ns->ms == 8) && - req->cmd_type != REQ_TYPE_DRV_PRIV) { + !blk_rq_is_passthrough(req)) { blk_mq_end_request(req, -EFAULT); return BLK_MQ_RQ_QUEUE_OK; } @@ -600,13 +599,12 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx, if (ret != BLK_MQ_RQ_QUEUE_OK) return ret; - map_len = nvme_map_len(req); - ret = nvme_init_iod(req, map_len, dev); + ret = nvme_init_iod(req, dev); if (ret != BLK_MQ_RQ_QUEUE_OK) goto out_free_cmd; if (blk_rq_nr_phys_segments(req)) - ret = nvme_map_data(dev, req, map_len, &cmnd); + ret = nvme_map_data(dev, req, &cmnd); if (ret != BLK_MQ_RQ_QUEUE_OK) goto out_cleanup_iod; @@ -648,7 +646,7 @@ static void nvme_complete_rq(struct request *req) return; } - if (req->cmd_type == REQ_TYPE_DRV_PRIV) + if (blk_rq_is_passthrough(req)) error = req->errors; else error = nvme_error_status(req->errors); @@ -712,15 +710,8 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag) req = blk_mq_tag_to_rq(*nvmeq->tags, cqe.command_id); nvme_req(req)->result = cqe.result; blk_mq_complete_request(req, le16_to_cpu(cqe.status) >> 1); - } - /* If the controller ignores the cq head doorbell and continuously - * writes to the queue, it is theoretically possible to wrap around - * the queue twice and mistakenly return IRQ_NONE. Linux only - * requires that 0.1% of your interrupts are handled, so this isn't - * a big problem. - */ if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return; @@ -905,12 +896,11 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved) return BLK_EH_HANDLED; } - iod->aborted = 1; - if (atomic_dec_return(&dev->ctrl.abort_limit) < 0) { atomic_inc(&dev->ctrl.abort_limit); return BLK_EH_RESET_TIMER; } + iod->aborted = 1; memset(&cmd, 0, sizeof(cmd)); cmd.abort.opcode = nvme_admin_abort_cmd; @@ -1188,6 +1178,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev) dev->admin_tagset.timeout = ADMIN_TIMEOUT; dev->admin_tagset.numa_node = dev_to_node(dev->dev); dev->admin_tagset.cmd_size = nvme_cmd_size(dev); + dev->admin_tagset.flags = BLK_MQ_F_NO_SCHED; dev->admin_tagset.driver_data = dev; if (blk_mq_alloc_tag_set(&dev->admin_tagset)) @@ -1748,6 +1739,7 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) if (dev->ctrl.admin_q) blk_put_queue(dev->ctrl.admin_q); kfree(dev->queues); + kfree(dev->ctrl.opal_dev); kfree(dev); } @@ -1764,6 +1756,7 @@ static void nvme_remove_dead_ctrl(struct nvme_dev *dev, int status) static void nvme_reset_work(struct work_struct *work) { struct nvme_dev *dev = container_of(work, struct nvme_dev, reset_work); + bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL); int result = -ENODEV; if (WARN_ON(dev->ctrl.state == NVME_CTRL_RESETTING)) @@ -1796,6 +1789,14 @@ static void nvme_reset_work(struct work_struct *work) if (result) goto out; + if ((dev->ctrl.oacs & NVME_CTRL_OACS_SEC_SUPP) && !dev->ctrl.opal_dev) { + dev->ctrl.opal_dev = + init_opal_dev(&dev->ctrl, &nvme_sec_submit); + } + + if (was_suspend) + opal_unlock_from_suspend(dev->ctrl.opal_dev); + result = nvme_setup_io_queues(dev); if (result) goto out; @@ -1909,10 +1910,10 @@ static int nvme_dev_map(struct nvme_dev *dev) if (!dev->bar) goto release; - return 0; + return 0; release: - pci_release_mem_regions(pdev); - return -ENODEV; + pci_release_mem_regions(pdev); + return -ENODEV; } static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index f587af345889..a75e95d42b3f 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -981,8 +981,7 @@ static int nvme_rdma_map_sg_fr(struct nvme_rdma_queue *queue, } static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, - struct request *rq, unsigned int map_len, - struct nvme_command *c) + struct request *rq, struct nvme_command *c) { struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq); struct nvme_rdma_device *dev = queue->device; @@ -1014,9 +1013,9 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, } if (count == 1) { - if (rq_data_dir(rq) == WRITE && - map_len <= nvme_rdma_inline_data_size(queue) && - nvme_rdma_queue_idx(queue)) + if (rq_data_dir(rq) == WRITE && nvme_rdma_queue_idx(queue) && + blk_rq_payload_bytes(rq) <= + nvme_rdma_inline_data_size(queue)) return nvme_rdma_map_sg_inline(queue, req, c); if (dev->pd->flags & IB_PD_UNSAFE_GLOBAL_RKEY) @@ -1422,9 +1421,9 @@ static inline bool nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue, struct request *rq) { if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) { - struct nvme_command *cmd = (struct nvme_command *)rq->cmd; + struct nvme_command *cmd = nvme_req(rq)->cmd; - if (rq->cmd_type != REQ_TYPE_DRV_PRIV || + if (!blk_rq_is_passthrough(rq) || cmd->common.opcode != nvme_fabrics_command || cmd->fabrics.fctype != nvme_fabrics_type_connect) return false; @@ -1444,7 +1443,6 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, struct nvme_command *c = sqe->data; bool flush = false; struct ib_device *dev; - unsigned int map_len; int ret; WARN_ON_ONCE(rq->tag < 0); @@ -1462,8 +1460,7 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, blk_mq_start_request(rq); - map_len = nvme_map_len(rq); - ret = nvme_rdma_map_data(queue, rq, map_len, c); + ret = nvme_rdma_map_data(queue, rq, c); if (ret < 0) { dev_err(queue->ctrl->ctrl.device, "Failed to map data (%d)\n", ret); @@ -1474,7 +1471,7 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, ib_dma_sync_single_for_device(dev, sqe->dma, sizeof(struct nvme_command), DMA_TO_DEVICE); - if (rq->cmd_type == REQ_TYPE_FS && req_op(rq) == REQ_OP_FLUSH) + if (req_op(rq) == REQ_OP_FLUSH) flush = true; ret = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge, req->mr->need_inval ? &req->reg_wr.wr : NULL, flush); @@ -1525,7 +1522,7 @@ static void nvme_rdma_complete_rq(struct request *rq) return; } - if (rq->cmd_type == REQ_TYPE_DRV_PRIV) + if (blk_rq_is_passthrough(rq)) error = rq->errors; else error = nvme_error_status(rq->errors); diff --git a/drivers/nvme/host/scsi.c b/drivers/nvme/host/scsi.c index b71e95044b43..f49ae2758bb7 100644 --- a/drivers/nvme/host/scsi.c +++ b/drivers/nvme/host/scsi.c @@ -43,6 +43,7 @@ #include <asm/unaligned.h> #include <scsi/sg.h> #include <scsi/scsi.h> +#include <scsi/scsi_request.h> #include "nvme.h" @@ -2160,30 +2161,6 @@ static int nvme_trans_synchronize_cache(struct nvme_ns *ns, return nvme_trans_status_code(hdr, nvme_sc); } -static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr, - u8 *cmd) -{ - u8 immed, no_flush; - - immed = cmd[1] & 0x01; - no_flush = cmd[4] & 0x04; - - if (immed != 0) { - return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION, - ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB, - SCSI_ASCQ_CAUSE_NOT_REPORTABLE); - } else { - if (no_flush == 0) { - /* Issue NVME FLUSH command prior to START STOP UNIT */ - int res = nvme_trans_synchronize_cache(ns, hdr); - if (res) - return res; - } - - return 0; - } -} - static int nvme_trans_format_unit(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 *cmd) { @@ -2371,12 +2348,14 @@ static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr, static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) { - u8 cmd[BLK_MAX_CDB]; + u8 cmd[16]; int retcode; unsigned int opcode; if (hdr->cmdp == NULL) return -EMSGSIZE; + if (hdr->cmd_len > sizeof(cmd)) + return -EINVAL; if (copy_from_user(cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; @@ -2439,9 +2418,6 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) case SECURITY_PROTOCOL_OUT: retcode = nvme_trans_security_protocol(ns, hdr, cmd); break; - case START_STOP: - retcode = nvme_trans_start_stop(ns, hdr, cmd); - break; case SYNCHRONIZE_CACHE: retcode = nvme_trans_synchronize_cache(ns, hdr); break; @@ -2478,8 +2454,6 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr) return -EFAULT; if (hdr.interface_id != 'S') return -EINVAL; - if (hdr.cmd_len > BLK_MAX_CDB) - return -EINVAL; /* * A positive return code means a NVMe status, which has been diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index ec1ad2aa0a4c..95ae52390478 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -382,7 +382,6 @@ static void nvmet_execute_set_features(struct nvmet_req *req) { struct nvmet_subsys *subsys = req->sq->ctrl->subsys; u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10[0]); - u64 val; u32 val32; u16 status = 0; @@ -392,8 +391,7 @@ static void nvmet_execute_set_features(struct nvmet_req *req) (subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16)); break; case NVME_FEAT_KATO: - val = le64_to_cpu(req->cmd->prop_set.value); - val32 = val & 0xffff; + val32 = le32_to_cpu(req->cmd->common.cdw10[1]); req->sq->ctrl->kato = DIV_ROUND_UP(val32, 1000); nvmet_set_result(req, req->sq->ctrl->kato); break; diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index 6f5074153dcd..be8c800078e2 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -631,6 +631,7 @@ static void nvmet_subsys_release(struct config_item *item) { struct nvmet_subsys *subsys = to_subsys(item); + nvmet_subsys_del_ctrls(subsys); nvmet_subsys_put(subsys); } diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index b1d66ed655c9..fc5ba2f9e15f 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -200,7 +200,7 @@ static void nvmet_keep_alive_timer(struct work_struct *work) pr_err("ctrl %d keep-alive timer (%d seconds) expired!\n", ctrl->cntlid, ctrl->kato); - ctrl->ops->delete_ctrl(ctrl); + nvmet_ctrl_fatal_error(ctrl); } static void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl) @@ -816,6 +816,9 @@ static void nvmet_ctrl_free(struct kref *ref) list_del(&ctrl->subsys_entry); mutex_unlock(&subsys->lock); + flush_work(&ctrl->async_event_work); + cancel_work_sync(&ctrl->fatal_err_work); + ida_simple_remove(&subsys->cntlid_ida, ctrl->cntlid); nvmet_subsys_put(subsys); @@ -935,6 +938,16 @@ static void nvmet_subsys_free(struct kref *ref) kfree(subsys); } +void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys) +{ + struct nvmet_ctrl *ctrl; + + mutex_lock(&subsys->lock); + list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) + ctrl->ops->delete_ctrl(ctrl); + mutex_unlock(&subsys->lock); +} + void nvmet_subsys_put(struct nvmet_subsys *subsys) { kref_put(&subsys->ref, nvmet_subsys_free); diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 173e842f19c9..ba57f9852bde 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -1314,7 +1314,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, (struct fcnvme_ls_disconnect_rqst *)iod->rqstbuf; struct fcnvme_ls_disconnect_acc *acc = (struct fcnvme_ls_disconnect_acc *)iod->rspbuf; - struct nvmet_fc_tgt_queue *queue; + struct nvmet_fc_tgt_queue *queue = NULL; struct nvmet_fc_tgt_assoc *assoc; int ret = 0; bool del_assoc = false; @@ -1348,7 +1348,18 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, assoc = nvmet_fc_find_target_assoc(tgtport, be64_to_cpu(rqst->associd.association_id)); iod->assoc = assoc; - if (!assoc) + if (assoc) { + if (rqst->discon_cmd.scope == + FCNVME_DISCONN_CONNECTION) { + queue = nvmet_fc_find_target_queue(tgtport, + be64_to_cpu( + rqst->discon_cmd.id)); + if (!queue) { + nvmet_fc_tgt_a_put(assoc); + ret = VERR_NO_CONN; + } + } + } else ret = VERR_NO_ASSOC; } @@ -1373,21 +1384,18 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, FCNVME_LS_DISCONNECT); - if (rqst->discon_cmd.scope == FCNVME_DISCONN_CONNECTION) { - queue = nvmet_fc_find_target_queue(tgtport, - be64_to_cpu(rqst->discon_cmd.id)); - if (queue) { - int qid = queue->qid; + /* are we to delete a Connection ID (queue) */ + if (queue) { + int qid = queue->qid; - nvmet_fc_delete_target_queue(queue); + nvmet_fc_delete_target_queue(queue); - /* release the get taken by find_target_queue */ - nvmet_fc_tgt_q_put(queue); + /* release the get taken by find_target_queue */ + nvmet_fc_tgt_q_put(queue); - /* tear association down if io queue terminated */ - if (!qid) - del_assoc = true; - } + /* tear association down if io queue terminated */ + if (!qid) + del_assoc = true; } /* release get taken in nvmet_fc_find_target_assoc */ diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index bcb8ebeb01c5..4e8e6a22bce1 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -845,7 +845,7 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr, rport->lport = nport->lport; nport->rport = rport; - return ret ? ret : count; + return count; } @@ -952,7 +952,7 @@ fcloop_create_target_port(struct device *dev, struct device_attribute *attr, tport->lport = nport->lport; nport->tport = tport; - return ret ? ret : count; + return count; } diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c index 9aaa70071ae5..f3862e38f574 100644 --- a/drivers/nvme/target/loop.c +++ b/drivers/nvme/target/loop.c @@ -104,7 +104,7 @@ static void nvme_loop_complete_rq(struct request *req) return; } - if (req->cmd_type == REQ_TYPE_DRV_PRIV) + if (blk_rq_is_passthrough(req)) error = req->errors; else error = nvme_error_status(req->errors); diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 23d5eb1c944f..cc7ad06b43a7 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -282,6 +282,7 @@ void nvmet_ctrl_put(struct nvmet_ctrl *ctrl); struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, enum nvme_subsys_type type); void nvmet_subsys_put(struct nvmet_subsys *subsys); +void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys); struct nvmet_ns *nvmet_find_namespace(struct nvmet_ctrl *ctrl, __le32 nsid); void nvmet_put_namespace(struct nvmet_ns *ns); diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index 8c3760a78ac0..60990220bd83 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -438,6 +438,10 @@ static int nvmet_rdma_post_recv(struct nvmet_rdma_device *ndev, { struct ib_recv_wr *bad_wr; + ib_dma_sync_single_for_device(ndev->device, + cmd->sge[0].addr, cmd->sge[0].length, + DMA_FROM_DEVICE); + if (ndev->srq) return ib_post_srq_recv(ndev->srq, &cmd->wr, &bad_wr); return ib_post_recv(cmd->queue->cm_id->qp, &cmd->wr, &bad_wr); @@ -538,6 +542,11 @@ static void nvmet_rdma_queue_response(struct nvmet_req *req) first_wr = &rsp->send_wr; nvmet_rdma_post_recv(rsp->queue->dev, rsp->cmd); + + ib_dma_sync_single_for_device(rsp->queue->dev->device, + rsp->send_sge.addr, rsp->send_sge.length, + DMA_TO_DEVICE); + if (ib_post_send(cm_id->qp, first_wr, &bad_wr)) { pr_err("sending cmd response failed\n"); nvmet_rdma_release_rsp(rsp); @@ -698,6 +707,14 @@ static void nvmet_rdma_handle_command(struct nvmet_rdma_queue *queue, cmd->n_rdma = 0; cmd->req.port = queue->port; + + ib_dma_sync_single_for_cpu(queue->dev->device, + cmd->cmd->sge[0].addr, cmd->cmd->sge[0].length, + DMA_FROM_DEVICE); + ib_dma_sync_single_for_cpu(queue->dev->device, + cmd->send_sge.addr, cmd->send_sge.length, + DMA_TO_DEVICE); + if (!nvmet_req_init(&cmd->req, &queue->nvme_cq, &queue->nvme_sq, &nvmet_rdma_ops)) return; diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 965911d9b36a..398ea7f54826 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -981,8 +981,8 @@ static int __nvmem_cell_read(struct nvmem_device *nvmem, * @cell: nvmem cell to be read. * @len: pointer to length of cell which will be populated on successful read. * - * Return: ERR_PTR() on error or a valid pointer to a char * buffer on success. - * The buffer should be freed by the consumer with a kfree(). + * Return: ERR_PTR() on error or a valid pointer to a buffer on success. The + * buffer should be freed by the consumer with a kfree(). */ void *nvmem_cell_read(struct nvmem_cell *cell, size_t *len) { diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index ac27b9bac3b9..8e7b120696fa 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -71,7 +71,7 @@ static struct nvmem_config imx_ocotp_nvmem_config = { static const struct of_device_id imx_ocotp_dt_ids[] = { { .compatible = "fsl,imx6q-ocotp", (void *)128 }, - { .compatible = "fsl,imx6sl-ocotp", (void *)32 }, + { .compatible = "fsl,imx6sl-ocotp", (void *)64 }, { .compatible = "fsl,imx6sx-ocotp", (void *)128 }, { }, }; diff --git a/drivers/nvmem/qfprom.c b/drivers/nvmem/qfprom.c index b5305f08b184..2bdb6c389328 100644 --- a/drivers/nvmem/qfprom.c +++ b/drivers/nvmem/qfprom.c @@ -21,11 +21,11 @@ static int qfprom_reg_read(void *context, unsigned int reg, void *_val, size_t bytes) { void __iomem *base = context; - u32 *val = _val; - int i = 0, words = bytes / 4; + u8 *val = _val; + int i = 0, words = bytes; while (words--) - *val++ = readl(base + reg + (i++ * 4)); + *val++ = readb(base + reg + i++); return 0; } @@ -34,11 +34,11 @@ static int qfprom_reg_write(void *context, unsigned int reg, void *_val, size_t bytes) { void __iomem *base = context; - u32 *val = _val; - int i = 0, words = bytes / 4; + u8 *val = _val; + int i = 0, words = bytes; while (words--) - writel(*val++, base + reg + (i++ * 4)); + writeb(*val++, base + reg + i++); return 0; } @@ -53,7 +53,7 @@ static int qfprom_remove(struct platform_device *pdev) static struct nvmem_config econfig = { .name = "qfprom", .owner = THIS_MODULE, - .stride = 4, + .stride = 1, .word_size = 1, .reg_read = qfprom_reg_read, .reg_write = qfprom_reg_write, diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index dd6d4ccb41e4..3858b87fd0bb 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -293,7 +293,7 @@ struct parport *parport_gsc_probe_port(unsigned long base, p->irq = PARPORT_IRQ_NONE; } if (p->irq != PARPORT_IRQ_NONE) { - printk(", irq %d", p->irq); + pr_cont(", irq %d", p->irq); if (p->dma == PARPORT_DMA_AUTO) { p->dma = PARPORT_DMA_NONE; @@ -303,8 +303,8 @@ struct parport *parport_gsc_probe_port(unsigned long base, is mandatory (see above) */ p->dma = PARPORT_DMA_NONE; - printk(" ["); -#define printmode(x) {if(p->modes&PARPORT_MODE_##x){printk("%s%s",f?",":"",#x);f++;}} + pr_cont(" ["); +#define printmode(x) {if(p->modes&PARPORT_MODE_##x){pr_cont("%s%s",f?",":"",#x);f++;}} { int f = 0; printmode(PCSPP); @@ -315,7 +315,7 @@ struct parport *parport_gsc_probe_port(unsigned long base, // printmode(DMA); } #undef printmode - printk("]\n"); + pr_cont("]\n"); if (p->irq != PARPORT_IRQ_NONE) { if (request_irq (p->irq, parport_irq_handler, diff --git a/drivers/pci/host/pci-xgene-msi.c b/drivers/pci/host/pci-xgene-msi.c index 1f38d0836751..f1b633bce525 100644 --- a/drivers/pci/host/pci-xgene-msi.c +++ b/drivers/pci/host/pci-xgene-msi.c @@ -517,7 +517,7 @@ static int xgene_msi_probe(struct platform_device *pdev) rc = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "pci/xgene:online", xgene_msi_hwirq_alloc, NULL); - if (rc) + if (rc < 0) goto err_cpuhp; pci_xgene_online = rc; rc = cpuhp_setup_state(CPUHP_PCI_XGENE_DEAD, "pci/xgene:dead", NULL, diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c index bed19994c1e9..af8f6e92e885 100644 --- a/drivers/pci/host/pcie-designware.c +++ b/drivers/pci/host/pcie-designware.c @@ -807,11 +807,6 @@ void dw_pcie_setup_rc(struct pcie_port *pp) { u32 val; - /* get iATU unroll support */ - pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp); - dev_dbg(pp->dev, "iATU unroll: %s\n", - pp->iatu_unroll_enabled ? "enabled" : "disabled"); - /* set the number of lanes */ val = dw_pcie_readl_rc(pp, PCIE_PORT_LINK_CONTROL); val &= ~PORT_LINK_MODE_MASK; @@ -882,6 +877,11 @@ void dw_pcie_setup_rc(struct pcie_port *pp) * we should not program the ATU here. */ if (!pp->ops->rd_other_conf) { + /* get iATU unroll support */ + pp->iatu_unroll_enabled = dw_pcie_iatu_unroll_enabled(pp); + dev_dbg(pp->dev, "iATU unroll: %s\n", + pp->iatu_unroll_enabled ? "enabled" : "disabled"); + dw_pcie_prog_outbound_atu(pp, PCIE_ATU_REGION_INDEX0, PCIE_ATU_TYPE_MEM, pp->mem_base, pp->mem_bus_addr, pp->mem_size); diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index 10c9c0ba8ff2..ec0b4c11ccd9 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -31,7 +31,6 @@ #include <linux/kernel.h> #include <linux/types.h> #include <linux/slab.h> -#include <linux/pm_runtime.h> #include <linux/pci.h> #include "../pci.h" #include "pciehp.h" @@ -99,7 +98,6 @@ static int board_added(struct slot *p_slot) pciehp_green_led_blink(p_slot); /* Check link training status */ - pm_runtime_get_sync(&ctrl->pcie->port->dev); retval = pciehp_check_link_status(ctrl); if (retval) { ctrl_err(ctrl, "Failed to check link status\n"); @@ -120,14 +118,12 @@ static int board_added(struct slot *p_slot) if (retval != -EEXIST) goto err_exit; } - pm_runtime_put(&ctrl->pcie->port->dev); pciehp_green_led_on(p_slot); pciehp_set_attention_status(p_slot, 0); return 0; err_exit: - pm_runtime_put(&ctrl->pcie->port->dev); set_slot_off(ctrl, p_slot); return retval; } @@ -141,9 +137,7 @@ static int remove_board(struct slot *p_slot) int retval; struct controller *ctrl = p_slot->ctrl; - pm_runtime_get_sync(&ctrl->pcie->port->dev); retval = pciehp_unconfigure_device(p_slot); - pm_runtime_put(&ctrl->pcie->port->dev); if (retval) return retval; diff --git a/drivers/pci/hotplug/pnv_php.c b/drivers/pci/hotplug/pnv_php.c index 56efaf72d08e..d2961ef39a3a 100644 --- a/drivers/pci/hotplug/pnv_php.c +++ b/drivers/pci/hotplug/pnv_php.c @@ -155,7 +155,7 @@ static void pnv_php_detach_device_nodes(struct device_node *parent) pnv_php_detach_device_nodes(dn); of_node_put(dn); - refcount = atomic_read(&dn->kobj.kref.refcount); + refcount = kref_read(&dn->kobj.kref); if (refcount != 1) pr_warn("Invalid refcount %d on <%s>\n", refcount, of_node_full_name(dn)); diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 50c5003295ca..7f73bacf13ed 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1206,6 +1206,16 @@ int pci_alloc_irq_vectors_affinity(struct pci_dev *dev, unsigned int min_vecs, if (flags & PCI_IRQ_AFFINITY) { if (!affd) affd = &msi_default_affd; + + if (affd->pre_vectors + affd->post_vectors > min_vecs) + return -EINVAL; + + /* + * If there aren't any vectors left after applying the pre/post + * vectors don't bother with assigning affinity. + */ + if (affd->pre_vectors + affd->post_vectors == min_vecs) + affd = NULL; } else { if (WARN_ON(affd)) affd = NULL; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a881c0d3d2e8..7904d02ffdb9 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2241,10 +2241,13 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) return false; /* - * Hotplug ports handled by firmware in System Management Mode + * Hotplug interrupts cannot be delivered if the link is down, + * so parents of a hotplug port must stay awake. In addition, + * hotplug ports handled by firmware in System Management Mode * may not be put into D3 by the OS (Thunderbolt on non-Macs). + * For simplicity, disallow in general for now. */ - if (bridge->is_hotplug_bridge && !pciehp_is_native(bridge)) + if (bridge->is_hotplug_bridge) return false; if (pci_bridge_d3_force) @@ -2276,10 +2279,7 @@ static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) !pci_pme_capable(dev, PCI_D3cold)) || /* If it is a bridge it must be allowed to go to D3. */ - !pci_power_manageable(dev) || - - /* Hotplug interrupts cannot be delivered if the link is down. */ - dev->is_hotplug_bridge) + !pci_power_manageable(dev)) *d3cold_ok = false; diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 17ac1dce3286..3dd8bcbb3011 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -532,25 +532,32 @@ static struct pcie_link_state *alloc_pcie_link_state(struct pci_dev *pdev) link = kzalloc(sizeof(*link), GFP_KERNEL); if (!link) return NULL; + INIT_LIST_HEAD(&link->sibling); INIT_LIST_HEAD(&link->children); INIT_LIST_HEAD(&link->link); link->pdev = pdev; - if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) { + + /* + * Root Ports and PCI/PCI-X to PCIe Bridges are roots of PCIe + * hierarchies. + */ + if (pci_pcie_type(pdev) == PCI_EXP_TYPE_ROOT_PORT || + pci_pcie_type(pdev) == PCI_EXP_TYPE_PCIE_BRIDGE) { + link->root = link; + } else { struct pcie_link_state *parent; + parent = pdev->bus->parent->self->link_state; if (!parent) { kfree(link); return NULL; } + link->parent = parent; + link->root = link->parent->root; list_add(&link->link, &parent->children); } - /* Setup a pointer to the root port link */ - if (!link->parent) - link->root = link; - else - link->root = link->parent->root; list_add(&link->sibling, &link_list); pdev->link_state = link; diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 717529331dac..2dd1c68e6de8 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -433,6 +433,17 @@ static int pcie_pme_resume(struct pcie_device *srv) return 0; } +/** + * pcie_pme_remove - Prepare PCIe PME service device for removal. + * @srv - PCIe service device to remove. + */ +static void pcie_pme_remove(struct pcie_device *srv) +{ + pcie_pme_suspend(srv); + free_irq(srv->irq, srv); + kfree(get_service_data(srv)); +} + static struct pcie_port_service_driver pcie_pme_driver = { .name = "pcie_pme", .port_type = PCI_EXP_TYPE_ROOT_PORT, @@ -441,6 +452,7 @@ static struct pcie_port_service_driver pcie_pme_driver = { .probe = pcie_pme_probe, .suspend = pcie_pme_suspend, .resume = pcie_pme_resume, + .remove = pcie_pme_remove, }; /** diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index e164b5c9f0f0..204960e70333 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1169,6 +1169,7 @@ void set_pcie_port_type(struct pci_dev *pdev) pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); if (!pos) return; + pdev->pcie_cap = pos; pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); pdev->pcie_flags_reg = reg16; @@ -1176,13 +1177,14 @@ void set_pcie_port_type(struct pci_dev *pdev) pdev->pcie_mpss = reg16 & PCI_EXP_DEVCAP_PAYLOAD; /* - * A Root Port is always the upstream end of a Link. No PCIe - * component has two Links. Two Links are connected by a Switch - * that has a Port on each Link and internal logic to connect the - * two Ports. + * A Root Port or a PCI-to-PCIe bridge is always the upstream end + * of a Link. No PCIe component has two Links. Two Links are + * connected by a Switch that has a Port on each Link and internal + * logic to connect the two Ports. */ type = pci_pcie_type(pdev); - if (type == PCI_EXP_TYPE_ROOT_PORT) + if (type == PCI_EXP_TYPE_ROOT_PORT || + type == PCI_EXP_TYPE_PCIE_BRIDGE) pdev->has_secondary_link = 1; else if (type == PCI_EXP_TYPE_UPSTREAM || type == PCI_EXP_TYPE_DOWNSTREAM) { diff --git a/drivers/pci/slot.c b/drivers/pci/slot.c index 429d34c348b9..e42909524dee 100644 --- a/drivers/pci/slot.c +++ b/drivers/pci/slot.c @@ -345,7 +345,7 @@ EXPORT_SYMBOL_GPL(pci_create_slot); void pci_destroy_slot(struct pci_slot *slot) { dev_dbg(&slot->bus->dev, "dev %02x, dec refcount to %d\n", - slot->number, atomic_read(&slot->kobj.kref.refcount) - 1); + slot->number, kref_read(&slot->kobj.kref) - 1); mutex_lock(&pci_slot_mutex); kobject_put(&slot->kobj); diff --git a/drivers/pinctrl/berlin/berlin-bg4ct.c b/drivers/pinctrl/berlin/berlin-bg4ct.c index 09172043d589..c617ec49e9ed 100644 --- a/drivers/pinctrl/berlin/berlin-bg4ct.c +++ b/drivers/pinctrl/berlin/berlin-bg4ct.c @@ -217,7 +217,7 @@ static const struct berlin_desc_group berlin4ct_soc_pinctrl_groups[] = { BERLIN_PINCTRL_GROUP("SCRD0_CRD_PRES", 0xc, 0x3, 0x15, BERLIN_PINCTRL_FUNCTION(0x0, "gpio"), /* GPIO20 */ BERLIN_PINCTRL_FUNCTION(0x1, "scrd0"), /* crd pres */ - BERLIN_PINCTRL_FUNCTION(0x1, "sd1a")), /* DAT3 */ + BERLIN_PINCTRL_FUNCTION(0x3, "sd1a")), /* DAT3 */ BERLIN_PINCTRL_GROUP("SPI1_SS0n", 0xc, 0x3, 0x18, BERLIN_PINCTRL_FUNCTION(0x0, "spi1"), /* SS0n */ BERLIN_PINCTRL_FUNCTION(0x1, "gpio"), /* GPIO37 */ diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 37300634b7d2..d94aef17348b 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -731,16 +731,23 @@ static void __iomem *byt_gpio_reg(struct byt_gpio *vg, unsigned int offset, int reg) { struct byt_community *comm = byt_get_community(vg, offset); - u32 reg_offset = 0; + u32 reg_offset; if (!comm) return NULL; offset -= comm->pin_base; - if (reg == BYT_INT_STAT_REG) + switch (reg) { + case BYT_INT_STAT_REG: reg_offset = (offset / 32) * 4; - else + break; + case BYT_DEBOUNCE_REG: + reg_offset = 0; + break; + default: reg_offset = comm->pad_map[offset] * 16; + break; + } return comm->reg_base + reg_offset + reg; } @@ -1092,6 +1099,7 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset, enum pin_config_param param = pinconf_to_config_param(*config); void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG); void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG); + void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG); unsigned long flags; u32 conf, pull, val, debounce; u16 arg = 0; @@ -1128,7 +1136,7 @@ static int byt_pin_config_get(struct pinctrl_dev *pctl_dev, unsigned int offset, return -EINVAL; raw_spin_lock_irqsave(&vg->lock, flags); - debounce = readl(byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG)); + debounce = readl(db_reg); raw_spin_unlock_irqrestore(&vg->lock, flags); switch (debounce & BYT_DEBOUNCE_PULSE_MASK) { @@ -1176,6 +1184,7 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev, unsigned int param, arg; void __iomem *conf_reg = byt_gpio_reg(vg, offset, BYT_CONF0_REG); void __iomem *val_reg = byt_gpio_reg(vg, offset, BYT_VAL_REG); + void __iomem *db_reg = byt_gpio_reg(vg, offset, BYT_DEBOUNCE_REG); unsigned long flags; u32 conf, val, debounce; int i, ret = 0; @@ -1238,36 +1247,44 @@ static int byt_pin_config_set(struct pinctrl_dev *pctl_dev, break; case PIN_CONFIG_INPUT_DEBOUNCE: - debounce = readl(byt_gpio_reg(vg, offset, - BYT_DEBOUNCE_REG)); - conf &= ~BYT_DEBOUNCE_PULSE_MASK; + debounce = readl(db_reg); + debounce &= ~BYT_DEBOUNCE_PULSE_MASK; + + if (arg) + conf |= BYT_DEBOUNCE_EN; + else + conf &= ~BYT_DEBOUNCE_EN; switch (arg) { case 375: - conf |= BYT_DEBOUNCE_PULSE_375US; + debounce |= BYT_DEBOUNCE_PULSE_375US; break; case 750: - conf |= BYT_DEBOUNCE_PULSE_750US; + debounce |= BYT_DEBOUNCE_PULSE_750US; break; case 1500: - conf |= BYT_DEBOUNCE_PULSE_1500US; + debounce |= BYT_DEBOUNCE_PULSE_1500US; break; case 3000: - conf |= BYT_DEBOUNCE_PULSE_3MS; + debounce |= BYT_DEBOUNCE_PULSE_3MS; break; case 6000: - conf |= BYT_DEBOUNCE_PULSE_6MS; + debounce |= BYT_DEBOUNCE_PULSE_6MS; break; case 12000: - conf |= BYT_DEBOUNCE_PULSE_12MS; + debounce |= BYT_DEBOUNCE_PULSE_12MS; break; case 24000: - conf |= BYT_DEBOUNCE_PULSE_24MS; + debounce |= BYT_DEBOUNCE_PULSE_24MS; break; default: - ret = -EINVAL; + if (arg) + ret = -EINVAL; + break; } + if (!ret) + writel(debounce, db_reg); break; default: ret = -ENOTSUPP; @@ -1606,7 +1623,9 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) continue; } + raw_spin_lock(&vg->lock); pending = readl(reg); + raw_spin_unlock(&vg->lock); for_each_set_bit(pin, &pending, 32) { virq = irq_find_mapping(vg->chip.irqdomain, base + pin); generic_handle_irq(virq); @@ -1617,6 +1636,8 @@ static void byt_gpio_irq_handler(struct irq_desc *desc) static void byt_gpio_irq_init_hw(struct byt_gpio *vg) { + struct gpio_chip *gc = &vg->chip; + struct device *dev = &vg->pdev->dev; void __iomem *reg; u32 base, value; int i; @@ -1638,10 +1659,12 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg) } value = readl(reg); - if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i) && - !(value & BYT_DIRECT_IRQ_EN)) { + if (value & BYT_DIRECT_IRQ_EN) { + clear_bit(i, gc->irq_valid_mask); + dev_dbg(dev, "excluding GPIO %d from IRQ domain\n", i); + } else if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i)) { byt_gpio_clear_triggering(vg, i); - dev_dbg(&vg->pdev->dev, "disabling GPIO %d\n", i); + dev_dbg(dev, "disabling GPIO %d\n", i); } } @@ -1680,6 +1703,7 @@ static int byt_gpio_probe(struct byt_gpio *vg) gc->can_sleep = false; gc->parent = &vg->pdev->dev; gc->ngpio = vg->soc_data->npins; + gc->irq_need_valid_mask = true; #ifdef CONFIG_PM_SLEEP vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio, diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c index 59cb7a6fc5be..901b356b09d7 100644 --- a/drivers/pinctrl/intel/pinctrl-broxton.c +++ b/drivers/pinctrl/intel/pinctrl-broxton.c @@ -19,7 +19,7 @@ #define BXT_PAD_OWN 0x020 #define BXT_HOSTSW_OWN 0x080 -#define BXT_PADCFGLOCK 0x090 +#define BXT_PADCFGLOCK 0x060 #define BXT_GPI_IE 0x110 #define BXT_COMMUNITY(s, e) \ diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 1e139672f1af..6df35dcb29ae 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -353,6 +353,21 @@ static int intel_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, return 0; } +static void __intel_gpio_set_direction(void __iomem *padcfg0, bool input) +{ + u32 value; + + value = readl(padcfg0); + if (input) { + value &= ~PADCFG0_GPIORXDIS; + value |= PADCFG0_GPIOTXDIS; + } else { + value &= ~PADCFG0_GPIOTXDIS; + value |= PADCFG0_GPIORXDIS; + } + writel(value, padcfg0); +} + static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned pin) @@ -375,11 +390,11 @@ static int intel_gpio_request_enable(struct pinctrl_dev *pctldev, /* Disable SCI/SMI/NMI generation */ value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI); value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI); - /* Disable TX buffer and enable RX (this will be input) */ - value &= ~PADCFG0_GPIORXDIS; - value |= PADCFG0_GPIOTXDIS; writel(value, padcfg0); + /* Disable TX buffer and enable RX (this will be input) */ + __intel_gpio_set_direction(padcfg0, true); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; @@ -392,18 +407,11 @@ static int intel_gpio_set_direction(struct pinctrl_dev *pctldev, struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); void __iomem *padcfg0; unsigned long flags; - u32 value; raw_spin_lock_irqsave(&pctrl->lock, flags); padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0); - - value = readl(padcfg0); - if (input) - value |= PADCFG0_GPIOTXDIS; - else - value &= ~PADCFG0_GPIOTXDIS; - writel(value, padcfg0); + __intel_gpio_set_direction(padcfg0, input); raw_spin_unlock_irqrestore(&pctrl->lock, flags); diff --git a/drivers/pinctrl/intel/pinctrl-merrifield.c b/drivers/pinctrl/intel/pinctrl-merrifield.c index b21896126f76..4d4ef42a39b5 100644 --- a/drivers/pinctrl/intel/pinctrl-merrifield.c +++ b/drivers/pinctrl/intel/pinctrl-merrifield.c @@ -794,6 +794,9 @@ static int mrfld_config_set(struct pinctrl_dev *pctldev, unsigned int pin, unsigned int i; int ret; + if (!mrfld_buf_available(mp, pin)) + return -ENOTSUPP; + for (i = 0; i < nconfigs; i++) { switch (pinconf_to_config_param(configs[i])) { case PIN_CONFIG_BIAS_DISABLE: diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c index c3928aa3fefa..e0bca4df2a2f 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxbb.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxbb.c @@ -253,9 +253,8 @@ static const unsigned int uart_tx_ao_a_pins[] = { PIN(GPIOAO_0, 0) }; static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) }; static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) }; static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) }; -static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_0, 0) }; -static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_1, 0), - PIN(GPIOAO_5, 0) }; +static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_4, 0) }; +static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_5, 0) }; static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) }; static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) }; @@ -498,7 +497,7 @@ static struct meson_pmx_group meson_gxbb_aobus_groups[] = { GPIO_GROUP(GPIOAO_13, 0), /* bank AO */ - GROUP(uart_tx_ao_b, 0, 26), + GROUP(uart_tx_ao_b, 0, 24), GROUP(uart_rx_ao_b, 0, 25), GROUP(uart_tx_ao_a, 0, 12), GROUP(uart_rx_ao_a, 0, 11), diff --git a/drivers/pinctrl/meson/pinctrl-meson-gxl.c b/drivers/pinctrl/meson/pinctrl-meson-gxl.c index 25694f7094c7..b69743b07a1d 100644 --- a/drivers/pinctrl/meson/pinctrl-meson-gxl.c +++ b/drivers/pinctrl/meson/pinctrl-meson-gxl.c @@ -214,9 +214,8 @@ static const unsigned int uart_tx_ao_a_pins[] = { PIN(GPIOAO_0, 0) }; static const unsigned int uart_rx_ao_a_pins[] = { PIN(GPIOAO_1, 0) }; static const unsigned int uart_cts_ao_a_pins[] = { PIN(GPIOAO_2, 0) }; static const unsigned int uart_rts_ao_a_pins[] = { PIN(GPIOAO_3, 0) }; -static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_0, 0) }; -static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_1, 0), - PIN(GPIOAO_5, 0) }; +static const unsigned int uart_tx_ao_b_pins[] = { PIN(GPIOAO_4, 0) }; +static const unsigned int uart_rx_ao_b_pins[] = { PIN(GPIOAO_5, 0) }; static const unsigned int uart_cts_ao_b_pins[] = { PIN(GPIOAO_2, 0) }; static const unsigned int uart_rts_ao_b_pins[] = { PIN(GPIOAO_3, 0) }; @@ -409,7 +408,7 @@ static struct meson_pmx_group meson_gxl_aobus_groups[] = { GPIO_GROUP(GPIOAO_9, 0), /* bank AO */ - GROUP(uart_tx_ao_b, 0, 26), + GROUP(uart_tx_ao_b, 0, 24), GROUP(uart_rx_ao_b, 0, 25), GROUP(uart_tx_ao_a, 0, 12), GROUP(uart_rx_ao_a, 0, 11), diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index a579126832af..620c231a2889 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -212,7 +212,7 @@ static int meson_pmx_request_gpio(struct pinctrl_dev *pcdev, { struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev); - meson_pmx_disable_other_groups(pc, range->pin_base + offset, -1); + meson_pmx_disable_other_groups(pc, offset, -1); return 0; } diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index aea310a91821..537b52055756 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -202,6 +202,8 @@ static void amd_gpio_dbg_show(struct seq_file *s, struct gpio_chip *gc) i = 128; pin_num = AMD_GPIO_PINS_BANK2 + i; break; + default: + return; } for (; i < pin_num; i++) { @@ -382,26 +384,21 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) { int ret = 0; u32 pin_reg; - unsigned long flags; - bool level_trig; - u32 active_level; + unsigned long flags, irq_flags; struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct amd_gpio *gpio_dev = gpiochip_get_data(gc); spin_lock_irqsave(&gpio_dev->lock, flags); pin_reg = readl(gpio_dev->base + (d->hwirq)*4); - /* - * When level_trig is set EDGE and active_level is set HIGH in BIOS - * default settings, ignore incoming settings from client and use - * BIOS settings to configure GPIO register. + /* Ignore the settings coming from the client and + * read the values from the ACPI tables + * while setting the trigger type */ - level_trig = !(pin_reg & (LEVEL_TRIGGER << LEVEL_TRIG_OFF)); - active_level = pin_reg & (ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); - if(level_trig && - ((active_level >> ACTIVE_LEVEL_OFF) == ACTIVE_HIGH)) - type = IRQ_TYPE_EDGE_FALLING; + irq_flags = irq_get_trigger_type(d->irq); + if (irq_flags != IRQ_TYPE_NONE) + type = irq_flags; switch (type & IRQ_TYPE_SENSE_MASK) { case IRQ_TYPE_EDGE_RISING: diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 12f7d1eb65bc..07409fde02b2 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -56,6 +56,17 @@ static const struct samsung_pin_bank_type bank_type_alive = { .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, }; +/* Exynos5433 has the 4bit widths for PINCFG_TYPE_DRV bitfields. */ +static const struct samsung_pin_bank_type exynos5433_bank_type_off = { + .fld_width = { 4, 1, 2, 4, 2, 2, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, }, +}; + +static const struct samsung_pin_bank_type exynos5433_bank_type_alive = { + .fld_width = { 4, 1, 2, 4, }, + .reg_offset = { 0x00, 0x04, 0x08, 0x0c, }, +}; + static void exynos_irq_mask(struct irq_data *irqd) { struct irq_chip *chip = irq_data_get_irq_chip(irqd); @@ -1335,82 +1346,82 @@ const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = { /* pin banks of exynos5433 pin-controller - ALIVE */ static const struct samsung_pin_bank_data exynos5433_pin_banks0[] = { - EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), - EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), - EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), - EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), - EXYNOS_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 1), - EXYNOS_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 1), - EXYNOS_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 1), - EXYNOS_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 1), - EXYNOS_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 1), + EXYNOS5433_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00), + EXYNOS5433_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04), + EXYNOS5433_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08), + EXYNOS5433_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c), + EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x020, "gpf1", 0x1004, 1), + EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x040, "gpf2", 0x1008, 1), + EXYNOS5433_PIN_BANK_EINTW_EXT(4, 0x060, "gpf3", 0x100c, 1), + EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x080, "gpf4", 0x1010, 1), + EXYNOS5433_PIN_BANK_EINTW_EXT(8, 0x0a0, "gpf5", 0x1014, 1), }; /* pin banks of exynos5433 pin-controller - AUD */ static const struct samsung_pin_bank_data exynos5433_pin_banks1[] = { - EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00), - EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04), + EXYNOS5433_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00), + EXYNOS5433_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04), }; /* pin banks of exynos5433 pin-controller - CPIF */ static const struct samsung_pin_bank_data exynos5433_pin_banks2[] = { - EXYNOS_PIN_BANK_EINTG(2, 0x000, "gpv6", 0x00), + EXYNOS5433_PIN_BANK_EINTG(2, 0x000, "gpv6", 0x00), }; /* pin banks of exynos5433 pin-controller - eSE */ static const struct samsung_pin_bank_data exynos5433_pin_banks3[] = { - EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj2", 0x00), + EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj2", 0x00), }; /* pin banks of exynos5433 pin-controller - FINGER */ static const struct samsung_pin_bank_data exynos5433_pin_banks4[] = { - EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpd5", 0x00), + EXYNOS5433_PIN_BANK_EINTG(4, 0x000, "gpd5", 0x00), }; /* pin banks of exynos5433 pin-controller - FSYS */ static const struct samsung_pin_bank_data exynos5433_pin_banks5[] = { - EXYNOS_PIN_BANK_EINTG(6, 0x000, "gph1", 0x00), - EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpr4", 0x04), - EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr0", 0x08), - EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr1", 0x0c), - EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpr2", 0x10), - EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpr3", 0x14), + EXYNOS5433_PIN_BANK_EINTG(6, 0x000, "gph1", 0x00), + EXYNOS5433_PIN_BANK_EINTG(7, 0x020, "gpr4", 0x04), + EXYNOS5433_PIN_BANK_EINTG(5, 0x040, "gpr0", 0x08), + EXYNOS5433_PIN_BANK_EINTG(8, 0x060, "gpr1", 0x0c), + EXYNOS5433_PIN_BANK_EINTG(2, 0x080, "gpr2", 0x10), + EXYNOS5433_PIN_BANK_EINTG(8, 0x0a0, "gpr3", 0x14), }; /* pin banks of exynos5433 pin-controller - IMEM */ static const struct samsung_pin_bank_data exynos5433_pin_banks6[] = { - EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00), + EXYNOS5433_PIN_BANK_EINTG(8, 0x000, "gpf0", 0x00), }; /* pin banks of exynos5433 pin-controller - NFC */ static const struct samsung_pin_bank_data exynos5433_pin_banks7[] = { - EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00), + EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00), }; /* pin banks of exynos5433 pin-controller - PERIC */ static const struct samsung_pin_bank_data exynos5433_pin_banks8[] = { - EXYNOS_PIN_BANK_EINTG(6, 0x000, "gpv7", 0x00), - EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpb0", 0x04), - EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpc0", 0x08), - EXYNOS_PIN_BANK_EINTG(2, 0x060, "gpc1", 0x0c), - EXYNOS_PIN_BANK_EINTG(6, 0x080, "gpc2", 0x10), - EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpc3", 0x14), - EXYNOS_PIN_BANK_EINTG(2, 0x0c0, "gpg0", 0x18), - EXYNOS_PIN_BANK_EINTG(4, 0x0e0, "gpd0", 0x1c), - EXYNOS_PIN_BANK_EINTG(6, 0x100, "gpd1", 0x20), - EXYNOS_PIN_BANK_EINTG(8, 0x120, "gpd2", 0x24), - EXYNOS_PIN_BANK_EINTG(5, 0x140, "gpd4", 0x28), - EXYNOS_PIN_BANK_EINTG(2, 0x160, "gpd8", 0x2c), - EXYNOS_PIN_BANK_EINTG(7, 0x180, "gpd6", 0x30), - EXYNOS_PIN_BANK_EINTG(3, 0x1a0, "gpd7", 0x34), - EXYNOS_PIN_BANK_EINTG(5, 0x1c0, "gpg1", 0x38), - EXYNOS_PIN_BANK_EINTG(2, 0x1e0, "gpg2", 0x3c), - EXYNOS_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40), + EXYNOS5433_PIN_BANK_EINTG(6, 0x000, "gpv7", 0x00), + EXYNOS5433_PIN_BANK_EINTG(5, 0x020, "gpb0", 0x04), + EXYNOS5433_PIN_BANK_EINTG(8, 0x040, "gpc0", 0x08), + EXYNOS5433_PIN_BANK_EINTG(2, 0x060, "gpc1", 0x0c), + EXYNOS5433_PIN_BANK_EINTG(6, 0x080, "gpc2", 0x10), + EXYNOS5433_PIN_BANK_EINTG(8, 0x0a0, "gpc3", 0x14), + EXYNOS5433_PIN_BANK_EINTG(2, 0x0c0, "gpg0", 0x18), + EXYNOS5433_PIN_BANK_EINTG(4, 0x0e0, "gpd0", 0x1c), + EXYNOS5433_PIN_BANK_EINTG(6, 0x100, "gpd1", 0x20), + EXYNOS5433_PIN_BANK_EINTG(8, 0x120, "gpd2", 0x24), + EXYNOS5433_PIN_BANK_EINTG(5, 0x140, "gpd4", 0x28), + EXYNOS5433_PIN_BANK_EINTG(2, 0x160, "gpd8", 0x2c), + EXYNOS5433_PIN_BANK_EINTG(7, 0x180, "gpd6", 0x30), + EXYNOS5433_PIN_BANK_EINTG(3, 0x1a0, "gpd7", 0x34), + EXYNOS5433_PIN_BANK_EINTG(5, 0x1c0, "gpg1", 0x38), + EXYNOS5433_PIN_BANK_EINTG(2, 0x1e0, "gpg2", 0x3c), + EXYNOS5433_PIN_BANK_EINTG(8, 0x200, "gpg3", 0x40), }; /* pin banks of exynos5433 pin-controller - TOUCH */ static const struct samsung_pin_bank_data exynos5433_pin_banks9[] = { - EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00), + EXYNOS5433_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00), }; /* diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h index 5821525a2c84..a473092fb8d2 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.h +++ b/drivers/pinctrl/samsung/pinctrl-exynos.h @@ -90,6 +90,37 @@ .pctl_res_idx = pctl_idx, \ } \ +#define EXYNOS5433_PIN_BANK_EINTG(pins, reg, id, offs) \ + { \ + .type = &exynos5433_bank_type_off, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_GPIO, \ + .eint_offset = offs, \ + .name = id \ + } + +#define EXYNOS5433_PIN_BANK_EINTW(pins, reg, id, offs) \ + { \ + .type = &exynos5433_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id \ + } + +#define EXYNOS5433_PIN_BANK_EINTW_EXT(pins, reg, id, offs, pctl_idx) \ + { \ + .type = &exynos5433_bank_type_alive, \ + .pctl_offset = reg, \ + .nr_pins = pins, \ + .eint_type = EINT_TYPE_WKUP, \ + .eint_offset = offs, \ + .name = id, \ + .pctl_res_idx = pctl_idx, \ + } \ + /** * struct exynos_weint_data: irq specific data for all the wakeup interrupts * generated by the external wakeup interrupt controller. diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 0eb51e33cb1b..207a8de4e1ed 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -564,8 +564,7 @@ static int sunxi_pconf_group_set(struct pinctrl_dev *pctldev, val = arg / 10 - 1; break; case PIN_CONFIG_BIAS_DISABLE: - val = 0; - break; + continue; case PIN_CONFIG_BIAS_PULL_UP: if (arg == 0) return -EINVAL; diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c index aa8bd9794683..96686336e3a3 100644 --- a/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-ld20.c @@ -561,7 +561,7 @@ static const int ether_rgmii_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const unsigned ether_rmii_pins[] = {30, 31, 32, 33, 34, 35, 36, 37, 39, 41, 42, 45}; -static const int ether_rmii_muxvals[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; +static const int ether_rmii_muxvals[] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}; static const unsigned i2c0_pins[] = {63, 64}; static const int i2c0_muxvals[] = {0, 0}; static const unsigned i2c1_pins[] = {65, 66}; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 5fe8be089b8b..49a594855f98 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -816,13 +816,6 @@ config INTEL_SCU_IPC_UTIL low level access for debug work and updating the firmware. Say N unless you will be doing this on an Intel MID platform. -config GPIO_INTEL_PMIC - bool "Intel PMIC GPIO support" - depends on INTEL_SCU_IPC && GPIOLIB - ---help--- - Say Y here to support GPIO via the SCU IPC interface - on Intel MID platforms. - config INTEL_MID_POWER_BUTTON tristate "power button driver for Intel MID platforms" depends on INTEL_SCU_IPC && INPUT @@ -1034,7 +1027,7 @@ config SURFACE_PRO3_BUTTON config SURFACE_3_BUTTON tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet" - depends on ACPI && KEYBOARD_GPIO + depends on ACPI && KEYBOARD_GPIO && I2C ---help--- This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet. diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d4111f0f8a78..b2f52a7690af 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -50,7 +50,6 @@ obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o obj-$(CONFIG_INTEL_IPS) += intel_ips.o -obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o obj-$(CONFIG_IBM_RTL) += ibm_rtl.o diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 61f39abf5dc8..82d67715ce76 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -177,43 +177,43 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event); #if IS_ENABLED(CONFIG_LEDS_CLASS) static enum led_brightness logolamp_get(struct led_classdev *cdev); -static void logolamp_set(struct led_classdev *cdev, +static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness); static struct led_classdev logolamp_led = { .name = "fujitsu::logolamp", .brightness_get = logolamp_get, - .brightness_set = logolamp_set + .brightness_set_blocking = logolamp_set }; static enum led_brightness kblamps_get(struct led_classdev *cdev); -static void kblamps_set(struct led_classdev *cdev, +static int kblamps_set(struct led_classdev *cdev, enum led_brightness brightness); static struct led_classdev kblamps_led = { .name = "fujitsu::kblamps", .brightness_get = kblamps_get, - .brightness_set = kblamps_set + .brightness_set_blocking = kblamps_set }; static enum led_brightness radio_led_get(struct led_classdev *cdev); -static void radio_led_set(struct led_classdev *cdev, +static int radio_led_set(struct led_classdev *cdev, enum led_brightness brightness); static struct led_classdev radio_led = { .name = "fujitsu::radio_led", .brightness_get = radio_led_get, - .brightness_set = radio_led_set + .brightness_set_blocking = radio_led_set }; static enum led_brightness eco_led_get(struct led_classdev *cdev); -static void eco_led_set(struct led_classdev *cdev, +static int eco_led_set(struct led_classdev *cdev, enum led_brightness brightness); static struct led_classdev eco_led = { .name = "fujitsu::eco_led", .brightness_get = eco_led_get, - .brightness_set = eco_led_set + .brightness_set_blocking = eco_led_set }; #endif @@ -267,48 +267,48 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2) #if IS_ENABLED(CONFIG_LEDS_CLASS) /* LED class callbacks */ -static void logolamp_set(struct led_classdev *cdev, +static int logolamp_set(struct led_classdev *cdev, enum led_brightness brightness) { if (brightness >= LED_FULL) { call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); } else if (brightness >= LED_HALF) { call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); } else { - call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); + return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); } } -static void kblamps_set(struct led_classdev *cdev, +static int kblamps_set(struct led_classdev *cdev, enum led_brightness brightness) { if (brightness >= LED_FULL) - call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); + return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); else - call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); + return call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); } -static void radio_led_set(struct led_classdev *cdev, +static int radio_led_set(struct led_classdev *cdev, enum led_brightness brightness) { if (brightness >= LED_FULL) - call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON); + return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON); else - call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0); + return call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0); } -static void eco_led_set(struct led_classdev *cdev, +static int eco_led_set(struct led_classdev *cdev, enum led_brightness brightness) { int curr; curr = call_fext_func(FUNC_LEDS, 0x2, ECO_LED, 0x0); if (brightness >= LED_FULL) - call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); + return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr | ECO_LED_ON); else - call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); + return call_fext_func(FUNC_LEDS, 0x1, ECO_LED, curr & ~ECO_LED_ON); } static enum led_brightness logolamp_get(struct led_classdev *cdev) diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 410741acb3c9..f46ece2ce3c4 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -813,6 +813,7 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) case 8: case 7: case 6: + case 1: ideapad_input_report(priv, vpc_bit); break; case 5: diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 1fc0de870ff8..361770568ad0 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c @@ -77,7 +77,7 @@ static int mfld_pb_probe(struct platform_device *pdev) input_set_capability(input, EV_KEY, KEY_POWER); - error = request_threaded_irq(irq, NULL, mfld_pb_isr, 0, + error = request_threaded_irq(irq, NULL, mfld_pb_isr, IRQF_ONESHOT, DRIVER_NAME, input); if (error) { dev_err(&pdev->dev, "Unable to request irq %d for mfld power" diff --git a/drivers/platform/x86/intel_pmic_gpio.c b/drivers/platform/x86/intel_pmic_gpio.c deleted file mode 100644 index 91ae58510d92..000000000000 --- a/drivers/platform/x86/intel_pmic_gpio.c +++ /dev/null @@ -1,326 +0,0 @@ -/* Moorestown PMIC GPIO (access through IPC) driver - * Copyright (c) 2008 - 2009, Intel Corporation. - * - * Author: Alek Du <alek.du@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -/* Supports: - * Moorestown platform PMIC chip - */ - -#define pr_fmt(fmt) "%s: " fmt, __func__ - -#include <linux/kernel.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/stddef.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/init.h> -#include <linux/io.h> -#include <linux/gpio/driver.h> -#include <asm/intel_scu_ipc.h> -#include <linux/device.h> -#include <linux/intel_pmic_gpio.h> -#include <linux/platform_device.h> - -#define DRIVER_NAME "pmic_gpio" - -/* register offset that IPC driver should use - * 8 GPIO + 8 GPOSW (6 controllable) + 8GPO - */ -enum pmic_gpio_register { - GPIO0 = 0xE0, - GPIO7 = 0xE7, - GPIOINT = 0xE8, - GPOSWCTL0 = 0xEC, - GPOSWCTL5 = 0xF1, - GPO = 0xF4, -}; - -/* bits definition for GPIO & GPOSW */ -#define GPIO_DRV 0x01 -#define GPIO_DIR 0x02 -#define GPIO_DIN 0x04 -#define GPIO_DOU 0x08 -#define GPIO_INTCTL 0x30 -#define GPIO_DBC 0xc0 - -#define GPOSW_DRV 0x01 -#define GPOSW_DOU 0x08 -#define GPOSW_RDRV 0x30 - -#define GPIO_UPDATE_TYPE 0x80000000 - -#define NUM_GPIO 24 - -struct pmic_gpio { - struct mutex buslock; - struct gpio_chip chip; - void *gpiointr; - int irq; - unsigned irq_base; - unsigned int update_type; - u32 trigger_type; -}; - -static void pmic_program_irqtype(int gpio, int type) -{ - if (type & IRQ_TYPE_EDGE_RISING) - intel_scu_ipc_update_register(GPIO0 + gpio, 0x20, 0x20); - else - intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x20); - - if (type & IRQ_TYPE_EDGE_FALLING) - intel_scu_ipc_update_register(GPIO0 + gpio, 0x10, 0x10); - else - intel_scu_ipc_update_register(GPIO0 + gpio, 0x00, 0x10); -}; - -static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned offset) -{ - if (offset >= 8) { - pr_err("only pin 0-7 support input\n"); - return -1;/* we only have 8 GPIO can use as input */ - } - return intel_scu_ipc_update_register(GPIO0 + offset, - GPIO_DIR, GPIO_DIR); -} - -static int pmic_gpio_direction_output(struct gpio_chip *chip, - unsigned offset, int value) -{ - int rc = 0; - - if (offset < 8)/* it is GPIO */ - rc = intel_scu_ipc_update_register(GPIO0 + offset, - GPIO_DRV | (value ? GPIO_DOU : 0), - GPIO_DRV | GPIO_DOU | GPIO_DIR); - else if (offset < 16)/* it is GPOSW */ - rc = intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, - GPOSW_DRV | (value ? GPOSW_DOU : 0), - GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV); - else if (offset > 15 && offset < 24)/* it is GPO */ - rc = intel_scu_ipc_update_register(GPO, - value ? 1 << (offset - 16) : 0, - 1 << (offset - 16)); - else { - pr_err("invalid PMIC GPIO pin %d!\n", offset); - WARN_ON(1); - } - - return rc; -} - -static int pmic_gpio_get(struct gpio_chip *chip, unsigned offset) -{ - u8 r; - int ret; - - /* we only have 8 GPIO pins we can use as input */ - if (offset >= 8) - return -EOPNOTSUPP; - ret = intel_scu_ipc_ioread8(GPIO0 + offset, &r); - if (ret < 0) - return ret; - return r & GPIO_DIN; -} - -static void pmic_gpio_set(struct gpio_chip *chip, unsigned offset, int value) -{ - if (offset < 8)/* it is GPIO */ - intel_scu_ipc_update_register(GPIO0 + offset, - GPIO_DRV | (value ? GPIO_DOU : 0), - GPIO_DRV | GPIO_DOU); - else if (offset < 16)/* it is GPOSW */ - intel_scu_ipc_update_register(GPOSWCTL0 + offset - 8, - GPOSW_DRV | (value ? GPOSW_DOU : 0), - GPOSW_DRV | GPOSW_DOU | GPOSW_RDRV); - else if (offset > 15 && offset < 24) /* it is GPO */ - intel_scu_ipc_update_register(GPO, - value ? 1 << (offset - 16) : 0, - 1 << (offset - 16)); -} - -/* - * This is called from genirq with pg->buslock locked and - * irq_desc->lock held. We can not access the scu bus here, so we - * store the change and update in the bus_sync_unlock() function below - */ -static int pmic_irq_type(struct irq_data *data, unsigned type) -{ - struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); - u32 gpio = data->irq - pg->irq_base; - - if (gpio >= pg->chip.ngpio) - return -EINVAL; - - pg->trigger_type = type; - pg->update_type = gpio | GPIO_UPDATE_TYPE; - return 0; -} - -static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct pmic_gpio *pg = gpiochip_get_data(chip); - - return pg->irq_base + offset; -} - -static void pmic_bus_lock(struct irq_data *data) -{ - struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); - - mutex_lock(&pg->buslock); -} - -static void pmic_bus_sync_unlock(struct irq_data *data) -{ - struct pmic_gpio *pg = irq_data_get_irq_chip_data(data); - - if (pg->update_type) { - unsigned int gpio = pg->update_type & ~GPIO_UPDATE_TYPE; - - pmic_program_irqtype(gpio, pg->trigger_type); - pg->update_type = 0; - } - mutex_unlock(&pg->buslock); -} - -/* the gpiointr register is read-clear, so just do nothing. */ -static void pmic_irq_unmask(struct irq_data *data) { } - -static void pmic_irq_mask(struct irq_data *data) { } - -static struct irq_chip pmic_irqchip = { - .name = "PMIC-GPIO", - .irq_mask = pmic_irq_mask, - .irq_unmask = pmic_irq_unmask, - .irq_set_type = pmic_irq_type, - .irq_bus_lock = pmic_bus_lock, - .irq_bus_sync_unlock = pmic_bus_sync_unlock, -}; - -static irqreturn_t pmic_irq_handler(int irq, void *data) -{ - struct pmic_gpio *pg = data; - u8 intsts = *((u8 *)pg->gpiointr + 4); - int gpio; - irqreturn_t ret = IRQ_NONE; - - for (gpio = 0; gpio < 8; gpio++) { - if (intsts & (1 << gpio)) { - pr_debug("pmic pin %d triggered\n", gpio); - generic_handle_irq(pg->irq_base + gpio); - ret = IRQ_HANDLED; - } - } - return ret; -} - -static int platform_pmic_gpio_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - int irq = platform_get_irq(pdev, 0); - struct intel_pmic_gpio_platform_data *pdata = dev->platform_data; - - struct pmic_gpio *pg; - int retval; - int i; - - if (irq < 0) { - dev_dbg(dev, "no IRQ line\n"); - return -EINVAL; - } - - if (!pdata || !pdata->gpio_base || !pdata->irq_base) { - dev_dbg(dev, "incorrect or missing platform data\n"); - return -EINVAL; - } - - pg = kzalloc(sizeof(*pg), GFP_KERNEL); - if (!pg) - return -ENOMEM; - - dev_set_drvdata(dev, pg); - - pg->irq = irq; - /* setting up SRAM mapping for GPIOINT register */ - pg->gpiointr = ioremap_nocache(pdata->gpiointr, 8); - if (!pg->gpiointr) { - pr_err("Can not map GPIOINT\n"); - retval = -EINVAL; - goto err2; - } - pg->irq_base = pdata->irq_base; - pg->chip.label = "intel_pmic"; - pg->chip.direction_input = pmic_gpio_direction_input; - pg->chip.direction_output = pmic_gpio_direction_output; - pg->chip.get = pmic_gpio_get; - pg->chip.set = pmic_gpio_set; - pg->chip.to_irq = pmic_gpio_to_irq; - pg->chip.base = pdata->gpio_base; - pg->chip.ngpio = NUM_GPIO; - pg->chip.can_sleep = 1; - pg->chip.parent = dev; - - mutex_init(&pg->buslock); - - pg->chip.parent = dev; - retval = gpiochip_add_data(&pg->chip, pg); - if (retval) { - pr_err("Can not add pmic gpio chip\n"); - goto err; - } - - retval = request_irq(pg->irq, pmic_irq_handler, 0, "pmic", pg); - if (retval) { - pr_warn("Interrupt request failed\n"); - goto fail_request_irq; - } - - for (i = 0; i < 8; i++) { - irq_set_chip_and_handler_name(i + pg->irq_base, - &pmic_irqchip, - handle_simple_irq, - "demux"); - irq_set_chip_data(i + pg->irq_base, pg); - } - return 0; - -fail_request_irq: - gpiochip_remove(&pg->chip); -err: - iounmap(pg->gpiointr); -err2: - kfree(pg); - return retval; -} - -/* at the same time, register a platform driver - * this supports the sfi 0.81 fw */ -static struct platform_driver platform_pmic_gpio_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = platform_pmic_gpio_probe, -}; - -static int __init platform_pmic_gpio_init(void) -{ - return platform_driver_register(&platform_pmic_gpio_driver); -} -subsys_initcall(platform_pmic_gpio_init); diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index 97b4c3a219c0..25f15df5c2d7 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -326,7 +326,7 @@ static int __init mlxplat_init(void) return 0; fail_platform_mux_register: - for (i--; i > 0 ; i--) + while (--i >= 0) platform_device_unregister(priv->pdev_mux[i]); platform_device_unregister(priv->pdev_i2c); fail_alloc: diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c index cbf4d83a7271..25b176996cb7 100644 --- a/drivers/platform/x86/surface3-wmi.c +++ b/drivers/platform/x86/surface3-wmi.c @@ -139,7 +139,7 @@ static acpi_status s3_wmi_attach_spi_device(acpi_handle handle, static int s3_wmi_check_platform_device(struct device *dev, void *data) { - struct acpi_device *adev, *ts_adev; + struct acpi_device *adev, *ts_adev = NULL; acpi_handle handle; acpi_status status; @@ -244,13 +244,11 @@ static int s3_wmi_remove(struct platform_device *device) return 0; } -#ifdef CONFIG_PM -static int s3_wmi_resume(struct device *dev) +static int __maybe_unused s3_wmi_resume(struct device *dev) { s3_wmi_send_lid_state(); return 0; } -#endif static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume); static struct platform_driver s3_wmi_driver = { diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index abeb77217a21..b8cacccf18c8 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -32,7 +32,7 @@ config POWER_RESET_AT91_RESET config POWER_RESET_AT91_SAMA5D2_SHDWC tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver" - depends on ARCH_AT91 || COMPILE_TEST + depends on ARCH_AT91 default SOC_SAMA5 help This driver supports the alternate shutdown controller for some Atmel diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c index a85dd4d233af..c6c3beea72f9 100644 --- a/drivers/power/reset/at91-poweroff.c +++ b/drivers/power/reset/at91-poweroff.c @@ -14,9 +14,12 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/printk.h> +#include <soc/at91/at91sam9_ddrsdr.h> + #define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ #define AT91_SHDW_SHDW BIT(0) /* Shut Down command */ #define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */ @@ -50,6 +53,7 @@ static const char *shdwc_wakeup_modes[] = { static void __iomem *at91_shdwc_base; static struct clk *sclk; +static void __iomem *mpddrc_base; static void __init at91_wakeup_status(void) { @@ -73,6 +77,29 @@ static void at91_poweroff(void) writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR); } +static void at91_lpddr_poweroff(void) +{ + asm volatile( + /* Align to cache lines */ + ".balign 32\n\t" + + /* Ensure AT91_SHDW_CR is in the TLB by reading it */ + " ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" + + /* Power down SDRAM0 */ + " str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + /* Shutdown CPU */ + " str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" + + " b .\n\t" + : + : "r" (mpddrc_base), + "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF), + "r" (at91_shdwc_base), + "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW) + : "r0"); +} + static int at91_poweroff_get_wakeup_mode(struct device_node *np) { const char *pm; @@ -124,6 +151,8 @@ static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev) static int __init at91_poweroff_probe(struct platform_device *pdev) { struct resource *res; + struct device_node *np; + u32 ddr_type; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -150,12 +179,30 @@ static int __init at91_poweroff_probe(struct platform_device *pdev) pm_power_off = at91_poweroff; + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc"); + if (!np) + return 0; + + mpddrc_base = of_iomap(np, 0); + of_node_put(np); + + if (!mpddrc_base) + return 0; + + ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; + if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) || + (ddr_type == AT91_DDRSDRC_MD_LPDDR3)) + pm_power_off = at91_lpddr_poweroff; + else + iounmap(mpddrc_base); + return 0; } static int __exit at91_poweroff_remove(struct platform_device *pdev) { - if (pm_power_off == at91_poweroff) + if (pm_power_off == at91_poweroff || + pm_power_off == at91_lpddr_poweroff) pm_power_off = NULL; clk_disable_unprepare(sclk); @@ -163,6 +210,11 @@ static int __exit at91_poweroff_remove(struct platform_device *pdev) return 0; } +static const struct of_device_id at91_ramc_of_match[] = { + { .compatible = "atmel,sama5d3-ddramc", }, + { /* sentinel */ } +}; + static const struct of_device_id at91_poweroff_of_match[] = { { .compatible = "atmel,at91sam9260-shdwc", }, { .compatible = "atmel,at91sam9rl-shdwc", }, diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 568580cf0655..b99769f8ab15 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -134,6 +134,15 @@ static int sama5d3_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } +static int samx7_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PROCRST), + at91_rstc_base); + + return NOTIFY_DONE; +} + static void __init at91_reset_status(struct platform_device *pdev) { u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); @@ -173,6 +182,7 @@ static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, + { .compatible = "atmel,samx7-rstc", .data = samx7_restart }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, at91_reset_of_match); @@ -238,20 +248,12 @@ static int __exit at91_reset_remove(struct platform_device *pdev) return 0; } -static const struct platform_device_id at91_reset_plat_match[] = { - { "at91-sam9260-reset", (unsigned long)at91sam9260_restart }, - { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(platform, at91_reset_plat_match); - static struct platform_driver at91_reset_driver = { .remove = __exit_p(at91_reset_remove), .driver = { .name = "at91-reset", .of_match_table = at91_reset_of_match, }, - .id_table = at91_reset_plat_match, }; module_platform_driver_probe(at91_reset_driver, at91_reset_probe); diff --git a/drivers/power/reset/at91-sama5d2_shdwc.c b/drivers/power/reset/at91-sama5d2_shdwc.c index 8a5ac9706c9c..90b0b5a70ce5 100644 --- a/drivers/power/reset/at91-sama5d2_shdwc.c +++ b/drivers/power/reset/at91-sama5d2_shdwc.c @@ -22,9 +22,12 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/platform_device.h> #include <linux/printk.h> +#include <soc/at91/at91sam9_ddrsdr.h> + #define SLOW_CLOCK_FREQ 32768 #define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ @@ -75,6 +78,7 @@ struct shdwc { */ static struct shdwc *at91_shdwc; static struct clk *sclk; +static void __iomem *mpddrc_base; static const unsigned long long sdwc_dbc_period[] = { 0, 3, 32, 512, 4096, 32768, @@ -108,6 +112,29 @@ static void at91_poweroff(void) at91_shdwc->at91_shdwc_base + AT91_SHDW_CR); } +static void at91_lpddr_poweroff(void) +{ + asm volatile( + /* Align to cache lines */ + ".balign 32\n\t" + + /* Ensure AT91_SHDW_CR is in the TLB by reading it */ + " ldr r6, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" + + /* Power down SDRAM0 */ + " str %1, [%0, #" __stringify(AT91_DDRSDRC_LPR) "]\n\t" + /* Shutdown CPU */ + " str %3, [%2, #" __stringify(AT91_SHDW_CR) "]\n\t" + + " b .\n\t" + : + : "r" (mpddrc_base), + "r" cpu_to_le32(AT91_DDRSDRC_LPDDR2_PWOFF), + "r" (at91_shdwc->at91_shdwc_base), + "r" cpu_to_le32(AT91_SHDW_KEY | AT91_SHDW_SHDW) + : "r0"); +} + static u32 at91_shdwc_debouncer_value(struct platform_device *pdev, u32 in_period_us) { @@ -212,6 +239,8 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) { struct resource *res; const struct of_device_id *match; + struct device_node *np; + u32 ddr_type; int ret; if (!pdev->dev.of_node) @@ -249,6 +278,23 @@ static int __init at91_shdwc_probe(struct platform_device *pdev) pm_power_off = at91_poweroff; + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d3-ddramc"); + if (!np) + return 0; + + mpddrc_base = of_iomap(np, 0); + of_node_put(np); + + if (!mpddrc_base) + return 0; + + ddr_type = readl(mpddrc_base + AT91_DDRSDRC_MDR) & AT91_DDRSDRC_MD; + if ((ddr_type == AT91_DDRSDRC_MD_LPDDR2) || + (ddr_type == AT91_DDRSDRC_MD_LPDDR3)) + pm_power_off = at91_lpddr_poweroff; + else + iounmap(mpddrc_base); + return 0; } @@ -256,7 +302,8 @@ static int __exit at91_shdwc_remove(struct platform_device *pdev) { struct shdwc *shdw = platform_get_drvdata(pdev); - if (pm_power_off == at91_poweroff) + if (pm_power_off == at91_poweroff || + pm_power_off == at91_lpddr_poweroff) pm_power_off = NULL; /* Reset values to disable wake-up features */ diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 76806a0be820..da54ac88f068 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -164,6 +164,12 @@ config BATTERY_SBS Say Y to include support for SBS battery driver for SBS-compliant gas gauges. +config CHARGER_SBS + tristate "SBS Compliant charger" + depends on I2C + help + Say Y to include support for SBS compilant battery chargers. + config BATTERY_BQ27XXX tristate "BQ27xxx battery driver" help @@ -214,6 +220,18 @@ config BATTERY_DA9150 This driver can also be built as a module. If so, the module will be called da9150-fg. +config CHARGER_AXP20X + tristate "X-Powers AXP20X and AXP22X AC power supply driver" + depends on MFD_AXP20X + depends on AXP20X_ADC + depends on IIO + help + Say Y here to enable support for X-Powers AXP20X and AXP22X PMICs' AC + power supply. + + This driver can also be built as a module. If so, the module will be + called axp20x_ac_power. + config AXP288_CHARGER tristate "X-Powers AXP288 Charger" depends on MFD_AXP20X && EXTCON_AXP288 @@ -292,13 +310,6 @@ config BATTERY_JZ4740 This driver can be build as a module. If so, the module will be called jz4740-battery. -config BATTERY_INTEL_MID - tristate "Battery driver for Intel MID platforms" - depends on INTEL_SCU_IPC && SPI - help - Say Y here to enable the battery driver on Intel MID - platforms. - config BATTERY_RX51 tristate "Nokia RX-51 (N900) battery driver" depends on TWL4030_MADC @@ -370,6 +381,16 @@ config CHARGER_MAX14577 Say Y to enable support for the battery charger control sysfs and platform data of MAX14577/77836 MUICs. +config CHARGER_DETECTOR_MAX14656 + tristate "Maxim MAX14656 USB charger detector" + depends on I2C + depends on OF + help + Say Y to enable support for the Maxim MAX14656 USB charger detector. + The device is compliant with the USB Battery Charging Specification + Revision 1.2 and can be found e.g. in Kindle 4/5th generation + readers and certain LG devices. + config CHARGER_MAX77693 tristate "Maxim MAX77693 battery charger driver" depends on MFD_MAX77693 @@ -395,6 +416,7 @@ config CHARGER_QCOM_SMBB depends on MFD_SPMI_PMIC || COMPILE_TEST depends on OF depends on EXTCON + depends on REGULATOR help Say Y to include support for the Switch-Mode Battery Charger and Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 36c599d9a495..3789a2c06fdf 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_TEST_POWER) += test_power.o obj-$(CONFIG_BATTERY_88PM860X) += 88pm860x_battery.o obj-$(CONFIG_BATTERY_ACT8945A) += act8945a_charger.o +obj-$(CONFIG_CHARGER_AXP20X) += axp20x_ac_power.o obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o @@ -31,6 +32,7 @@ obj-$(CONFIG_BATTERY_COLLIE) += collie_battery.o obj-$(CONFIG_BATTERY_IPAQ_MICRO) += ipaq_micro_battery.o obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o obj-$(CONFIG_BATTERY_SBS) += sbs-battery.o +obj-$(CONFIG_CHARGER_SBS) += sbs-charger.o obj-$(CONFIG_BATTERY_BQ27XXX) += bq27xxx_battery.o obj-$(CONFIG_BATTERY_BQ27XXX_I2C) += bq27xxx_battery_i2c.o obj-$(CONFIG_BATTERY_DA9030) += da9030_battery.o @@ -47,7 +49,6 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o -obj-$(CONFIG_BATTERY_INTEL_MID) += intel_mid_battery.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o pm2301_charger.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o @@ -58,6 +59,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o +obj-$(CONFIG_CHARGER_DETECTOR_MAX14656) += max14656_charger_detector.o obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 6ffdc18f2599..f7a35ebfbab2 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -76,8 +76,8 @@ struct ab8500_btemp_ranges { * @dev: Pointer to the structure device * @node: List of AB8500 BTEMPs, hence prepared for reentrance * @curr_source: What current source we use, in uA - * @bat_temp: Dispatched battery temperature in degree Celcius - * @prev_bat_temp Last measured battery temperature in degree Celcius + * @bat_temp: Dispatched battery temperature in degree Celsius + * @prev_bat_temp Last measured battery temperature in degree Celsius * @parent: Pointer to the struct ab8500 * @gpadc: Pointer to the struct gpadc * @fg: Pointer to the struct fg @@ -123,10 +123,7 @@ static LIST_HEAD(ab8500_btemp_list); */ struct ab8500_btemp *ab8500_btemp_get(void) { - struct ab8500_btemp *btemp; - btemp = list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node); - - return btemp; + return list_first_entry(&ab8500_btemp_list, struct ab8500_btemp, node); } EXPORT_SYMBOL(ab8500_btemp_get); @@ -464,13 +461,13 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) * @tbl_size: size of the resistance to temperature table * @res: resistance to calculate the temperature from * - * This function returns the battery temperature in degrees Celcius + * This function returns the battery temperature in degrees Celsius * based on the NTC resistance. */ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, const struct abx500_res_to_temp *tbl, int tbl_size, int res) { - int i, temp; + int i; /* * Calculate the formula for the straight line * Simple interpolation if we are within @@ -488,9 +485,8 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, i++; } - temp = tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) * + return tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) * (res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist); - return temp; } /** diff --git a/drivers/power/supply/axp20x_ac_power.c b/drivers/power/supply/axp20x_ac_power.c new file mode 100644 index 000000000000..38f4e87cf24d --- /dev/null +++ b/drivers/power/supply/axp20x_ac_power.c @@ -0,0 +1,253 @@ +/* + * AXP20X and AXP22X PMICs' ACIN power supply driver + * + * Copyright (C) 2016 Free Electrons + * Quentin Schulz <quentin.schulz@free-electrons.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/mfd/axp20x.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/iio/consumer.h> + +#define AXP20X_PWR_STATUS_ACIN_PRESENT BIT(7) +#define AXP20X_PWR_STATUS_ACIN_AVAIL BIT(6) + +#define DRVNAME "axp20x-ac-power-supply" + +struct axp20x_ac_power { + struct regmap *regmap; + struct power_supply *supply; + struct iio_channel *acin_v; + struct iio_channel *acin_i; +}; + +static irqreturn_t axp20x_ac_power_irq(int irq, void *devid) +{ + struct axp20x_ac_power *power = devid; + + power_supply_changed(power->supply); + + return IRQ_HANDLED; +} + +static int axp20x_ac_power_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct axp20x_ac_power *power = power_supply_get_drvdata(psy); + int ret, reg; + + switch (psp) { + case POWER_SUPPLY_PROP_HEALTH: + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®); + if (ret) + return ret; + + if (reg & AXP20X_PWR_STATUS_ACIN_PRESENT) { + val->intval = POWER_SUPPLY_HEALTH_GOOD; + return 0; + } + + val->intval = POWER_SUPPLY_HEALTH_UNKNOWN; + return 0; + + case POWER_SUPPLY_PROP_PRESENT: + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®); + if (ret) + return ret; + + val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_PRESENT); + return 0; + + case POWER_SUPPLY_PROP_ONLINE: + ret = regmap_read(power->regmap, AXP20X_PWR_INPUT_STATUS, ®); + if (ret) + return ret; + + val->intval = !!(reg & AXP20X_PWR_STATUS_ACIN_AVAIL); + return 0; + + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + ret = iio_read_channel_processed(power->acin_v, &val->intval); + if (ret) + return ret; + + /* IIO framework gives mV but Power Supply framework gives uV */ + val->intval *= 1000; + + return 0; + + case POWER_SUPPLY_PROP_CURRENT_NOW: + ret = iio_read_channel_processed(power->acin_i, &val->intval); + if (ret) + return ret; + + /* IIO framework gives mA but Power Supply framework gives uA */ + val->intval *= 1000; + + return 0; + + default: + return -EINVAL; + } + + return -EINVAL; +} + +static enum power_supply_property axp20x_ac_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, +}; + +static enum power_supply_property axp22x_ac_power_properties[] = { + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, +}; + +static const struct power_supply_desc axp20x_ac_power_desc = { + .name = "axp20x-ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = axp20x_ac_power_properties, + .num_properties = ARRAY_SIZE(axp20x_ac_power_properties), + .get_property = axp20x_ac_power_get_property, +}; + +static const struct power_supply_desc axp22x_ac_power_desc = { + .name = "axp22x-ac", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = axp22x_ac_power_properties, + .num_properties = ARRAY_SIZE(axp22x_ac_power_properties), + .get_property = axp20x_ac_power_get_property, +}; + +struct axp_data { + const struct power_supply_desc *power_desc; + bool acin_adc; +}; + +static const struct axp_data axp20x_data = { + .power_desc = &axp20x_ac_power_desc, + .acin_adc = true, +}; + +static const struct axp_data axp22x_data = { + .power_desc = &axp22x_ac_power_desc, + .acin_adc = false, +}; + +static int axp20x_ac_power_probe(struct platform_device *pdev) +{ + struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); + struct power_supply_config psy_cfg = {}; + struct axp20x_ac_power *power; + struct axp_data *axp_data; + static const char * const irq_names[] = { "ACIN_PLUGIN", "ACIN_REMOVAL", + NULL }; + int i, irq, ret; + + if (!of_device_is_available(pdev->dev.of_node)) + return -ENODEV; + + if (!axp20x) { + dev_err(&pdev->dev, "Parent drvdata not set\n"); + return -EINVAL; + } + + power = devm_kzalloc(&pdev->dev, sizeof(*power), GFP_KERNEL); + if (!power) + return -ENOMEM; + + axp_data = (struct axp_data *)of_device_get_match_data(&pdev->dev); + + if (axp_data->acin_adc) { + power->acin_v = devm_iio_channel_get(&pdev->dev, "acin_v"); + if (IS_ERR(power->acin_v)) { + if (PTR_ERR(power->acin_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->acin_v); + } + + power->acin_i = devm_iio_channel_get(&pdev->dev, "acin_i"); + if (IS_ERR(power->acin_i)) { + if (PTR_ERR(power->acin_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->acin_i); + } + } + + power->regmap = dev_get_regmap(pdev->dev.parent, NULL); + + platform_set_drvdata(pdev, power); + + psy_cfg.of_node = pdev->dev.of_node; + psy_cfg.drv_data = power; + + power->supply = devm_power_supply_register(&pdev->dev, + axp_data->power_desc, + &psy_cfg); + if (IS_ERR(power->supply)) + return PTR_ERR(power->supply); + + /* Request irqs after registering, as irqs may trigger immediately */ + for (i = 0; irq_names[i]; i++) { + irq = platform_get_irq_byname(pdev, irq_names[i]); + if (irq < 0) { + dev_warn(&pdev->dev, "No IRQ for %s: %d\n", + irq_names[i], irq); + continue; + } + irq = regmap_irq_get_virq(axp20x->regmap_irqc, irq); + ret = devm_request_any_context_irq(&pdev->dev, irq, + axp20x_ac_power_irq, 0, + DRVNAME, power); + if (ret < 0) + dev_warn(&pdev->dev, "Error requesting %s IRQ: %d\n", + irq_names[i], ret); + } + + return 0; +} + +static const struct of_device_id axp20x_ac_power_match[] = { + { + .compatible = "x-powers,axp202-ac-power-supply", + .data = (void *)&axp20x_data, + }, { + .compatible = "x-powers,axp221-ac-power-supply", + .data = (void *)&axp22x_data, + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, axp20x_ac_power_match); + +static struct platform_driver axp20x_ac_power_driver = { + .probe = axp20x_ac_power_probe, + .driver = { + .name = DRVNAME, + .of_match_table = axp20x_ac_power_match, + }, +}; + +module_platform_driver(axp20x_ac_power_driver); + +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>"); +MODULE_DESCRIPTION("AXP20X and AXP22X PMICs' AC power supply driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/axp20x_usb_power.c b/drivers/power/supply/axp20x_usb_power.c index 6af6feb7058d..2397c482656e 100644 --- a/drivers/power/supply/axp20x_usb_power.c +++ b/drivers/power/supply/axp20x_usb_power.c @@ -17,10 +17,12 @@ #include <linux/mfd/axp20x.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/regmap.h> #include <linux/slab.h> +#include <linux/iio/consumer.h> #define DRVNAME "axp20x-usb-power-supply" @@ -30,6 +32,8 @@ #define AXP20X_USB_STATUS_VBUS_VALID BIT(2) #define AXP20X_VBUS_VHOLD_uV(b) (4000000 + (((b) >> 3) & 7) * 100000) +#define AXP20X_VBUS_VHOLD_MASK GENMASK(5, 3) +#define AXP20X_VBUS_VHOLD_OFFSET 3 #define AXP20X_VBUS_CLIMIT_MASK 3 #define AXP20X_VBUC_CLIMIT_900mA 0 #define AXP20X_VBUC_CLIMIT_500mA 1 @@ -45,6 +49,9 @@ struct axp20x_usb_power { struct device_node *np; struct regmap *regmap; struct power_supply *supply; + enum axp20x_variants axp20x_id; + struct iio_channel *vbus_v; + struct iio_channel *vbus_i; }; static irqreturn_t axp20x_usb_power_irq(int irq, void *devid) @@ -72,6 +79,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, val->intval = AXP20X_VBUS_VHOLD_uV(v); return 0; case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (IS_ENABLED(CONFIG_AXP20X_ADC)) { + ret = iio_read_channel_processed(power->vbus_v, + &val->intval); + if (ret) + return ret; + + /* + * IIO framework gives mV but Power Supply framework + * gives uV. + */ + val->intval *= 1000; + return 0; + } + ret = axp20x_read_variable_width(power->regmap, AXP20X_VBUS_V_ADC_H, 12); if (ret < 0) @@ -86,12 +107,10 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, switch (v & AXP20X_VBUS_CLIMIT_MASK) { case AXP20X_VBUC_CLIMIT_100mA: - if (of_device_is_compatible(power->np, - "x-powers,axp202-usb-power-supply")) { - val->intval = 100000; - } else { + if (power->axp20x_id == AXP221_ID) val->intval = -1; /* No 100mA limit */ - } + else + val->intval = 100000; break; case AXP20X_VBUC_CLIMIT_500mA: val->intval = 500000; @@ -105,6 +124,20 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, } return 0; case POWER_SUPPLY_PROP_CURRENT_NOW: + if (IS_ENABLED(CONFIG_AXP20X_ADC)) { + ret = iio_read_channel_processed(power->vbus_i, + &val->intval); + if (ret) + return ret; + + /* + * IIO framework gives mA but Power Supply framework + * gives uA. + */ + val->intval *= 1000; + return 0; + } + ret = axp20x_read_variable_width(power->regmap, AXP20X_VBUS_I_ADC_H, 12); if (ret < 0) @@ -130,8 +163,7 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, val->intval = POWER_SUPPLY_HEALTH_GOOD; - if (of_device_is_compatible(power->np, - "x-powers,axp202-usb-power-supply")) { + if (power->axp20x_id == AXP202_ID) { ret = regmap_read(power->regmap, AXP20X_USB_OTG_STATUS, &v); if (ret) @@ -155,6 +187,81 @@ static int axp20x_usb_power_get_property(struct power_supply *psy, return 0; } +static int axp20x_usb_power_set_voltage_min(struct axp20x_usb_power *power, + int intval) +{ + int val; + + switch (intval) { + case 4000000: + case 4100000: + case 4200000: + case 4300000: + case 4400000: + case 4500000: + case 4600000: + case 4700000: + val = (intval - 4000000) / 100000; + return regmap_update_bits(power->regmap, + AXP20X_VBUS_IPSOUT_MGMT, + AXP20X_VBUS_VHOLD_MASK, + val << AXP20X_VBUS_VHOLD_OFFSET); + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int axp20x_usb_power_set_current_max(struct axp20x_usb_power *power, + int intval) +{ + int val; + + switch (intval) { + case 100000: + if (power->axp20x_id == AXP221_ID) + return -EINVAL; + case 500000: + case 900000: + val = (900000 - intval) / 400000; + return regmap_update_bits(power->regmap, + AXP20X_VBUS_IPSOUT_MGMT, + AXP20X_VBUS_CLIMIT_MASK, val); + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int axp20x_usb_power_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct axp20x_usb_power *power = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_VOLTAGE_MIN: + return axp20x_usb_power_set_voltage_min(power, val->intval); + + case POWER_SUPPLY_PROP_CURRENT_MAX: + return axp20x_usb_power_set_current_max(power, val->intval); + + default: + return -EINVAL; + } + + return -EINVAL; +} + +static int axp20x_usb_power_prop_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + return psp == POWER_SUPPLY_PROP_VOLTAGE_MIN || + psp == POWER_SUPPLY_PROP_CURRENT_MAX; +} + static enum power_supply_property axp20x_usb_power_properties[] = { POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, @@ -178,7 +285,9 @@ static const struct power_supply_desc axp20x_usb_power_desc = { .type = POWER_SUPPLY_TYPE_USB, .properties = axp20x_usb_power_properties, .num_properties = ARRAY_SIZE(axp20x_usb_power_properties), + .property_is_writeable = axp20x_usb_power_prop_writeable, .get_property = axp20x_usb_power_get_property, + .set_property = axp20x_usb_power_set_property, }; static const struct power_supply_desc axp22x_usb_power_desc = { @@ -186,9 +295,41 @@ static const struct power_supply_desc axp22x_usb_power_desc = { .type = POWER_SUPPLY_TYPE_USB, .properties = axp22x_usb_power_properties, .num_properties = ARRAY_SIZE(axp22x_usb_power_properties), + .property_is_writeable = axp20x_usb_power_prop_writeable, .get_property = axp20x_usb_power_get_property, + .set_property = axp20x_usb_power_set_property, }; +static int configure_iio_channels(struct platform_device *pdev, + struct axp20x_usb_power *power) +{ + power->vbus_v = devm_iio_channel_get(&pdev->dev, "vbus_v"); + if (IS_ERR(power->vbus_v)) { + if (PTR_ERR(power->vbus_v) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->vbus_v); + } + + power->vbus_i = devm_iio_channel_get(&pdev->dev, "vbus_i"); + if (IS_ERR(power->vbus_i)) { + if (PTR_ERR(power->vbus_i) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(power->vbus_i); + } + + return 0; +} + +static int configure_adc_registers(struct axp20x_usb_power *power) +{ + /* Enable vbus voltage and current measurement */ + return regmap_update_bits(power->regmap, AXP20X_ADC_EN1, + AXP20X_ADC_EN1_VBUS_CURR | + AXP20X_ADC_EN1_VBUS_VOLT, + AXP20X_ADC_EN1_VBUS_CURR | + AXP20X_ADC_EN1_VBUS_VOLT); +} + static int axp20x_usb_power_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); @@ -214,11 +355,13 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (!power) return -ENOMEM; + power->axp20x_id = (enum axp20x_variants)of_device_get_match_data( + &pdev->dev); + power->np = pdev->dev.of_node; power->regmap = axp20x->regmap; - if (of_device_is_compatible(power->np, - "x-powers,axp202-usb-power-supply")) { + if (power->axp20x_id == AXP202_ID) { /* Enable vbus valid checking */ ret = regmap_update_bits(power->regmap, AXP20X_VBUS_MON, AXP20X_VBUS_MON_VBUS_VALID, @@ -226,17 +369,18 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) if (ret) return ret; - /* Enable vbus voltage and current measurement */ - ret = regmap_update_bits(power->regmap, AXP20X_ADC_EN1, - AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT, - AXP20X_ADC_EN1_VBUS_CURR | AXP20X_ADC_EN1_VBUS_VOLT); + if (IS_ENABLED(CONFIG_AXP20X_ADC)) + ret = configure_iio_channels(pdev, power); + else + ret = configure_adc_registers(power); + if (ret) return ret; usb_power_desc = &axp20x_usb_power_desc; irq_names = axp20x_irq_names; - } else if (of_device_is_compatible(power->np, - "x-powers,axp221-usb-power-supply")) { + } else if (power->axp20x_id == AXP221_ID || + power->axp20x_id == AXP223_ID) { usb_power_desc = &axp22x_usb_power_desc; irq_names = axp22x_irq_names; } else { @@ -273,9 +417,16 @@ static int axp20x_usb_power_probe(struct platform_device *pdev) } static const struct of_device_id axp20x_usb_power_match[] = { - { .compatible = "x-powers,axp202-usb-power-supply" }, - { .compatible = "x-powers,axp221-usb-power-supply" }, - { } + { + .compatible = "x-powers,axp202-usb-power-supply", + .data = (void *)AXP202_ID, + }, { + .compatible = "x-powers,axp221-usb-power-supply", + .data = (void *)AXP221_ID, + }, { + .compatible = "x-powers,axp223-usb-power-supply", + .data = (void *)AXP223_ID, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, axp20x_usb_power_match); diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index 75b8e0c7402b..6be2fe27bb07 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -90,20 +90,6 @@ #define CHRG_VLTFC_0C 0xA5 /* 0 DegC */ #define CHRG_VHTFC_45C 0x1F /* 45 DegC */ -#define BAT_IRQ_CFG_CHRG_DONE (1 << 2) -#define BAT_IRQ_CFG_CHRG_START (1 << 3) -#define BAT_IRQ_CFG_BAT_SAFE_EXIT (1 << 4) -#define BAT_IRQ_CFG_BAT_SAFE_ENTER (1 << 5) -#define BAT_IRQ_CFG_BAT_DISCON (1 << 6) -#define BAT_IRQ_CFG_BAT_CONN (1 << 7) -#define BAT_IRQ_CFG_BAT_MASK 0xFC - -#define TEMP_IRQ_CFG_QCBTU (1 << 4) -#define TEMP_IRQ_CFG_CBTU (1 << 5) -#define TEMP_IRQ_CFG_QCBTO (1 << 6) -#define TEMP_IRQ_CFG_CBTO (1 << 7) -#define TEMP_IRQ_CFG_MASK 0xF0 - #define FG_CNTL_OCV_ADJ_EN (1 << 3) #define CV_4100MV 4100 /* 4100mV */ @@ -127,6 +113,10 @@ #define ILIM_3000MA 3000 /* 3000mA */ #define AXP288_EXTCON_DEV_NAME "axp288_extcon" +#define USB_HOST_EXTCON_DEV_NAME "INT3496:00" + +static const unsigned int cable_ids[] = + { EXTCON_CHG_USB_SDP, EXTCON_CHG_USB_CDP, EXTCON_CHG_USB_DCP }; enum { VBUS_OV_IRQ = 0, @@ -143,7 +133,6 @@ enum { struct axp288_chrg_info { struct platform_device *pdev; - struct axp20x_chrg_pdata *pdata; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; int irq[CHRG_INTR_END]; @@ -163,20 +152,16 @@ struct axp288_chrg_info { struct extcon_dev *edev; bool connected; enum power_supply_type chg_type; - struct notifier_block nb; + struct notifier_block nb[ARRAY_SIZE(cable_ids)]; struct work_struct work; } cable; - int health; int inlmt; int cc; int cv; int max_cc; int max_cv; - bool online; - bool present; - bool enable_charger; - bool is_charger_enabled; + int is_charger_enabled; }; static inline int axp288_charger_set_cc(struct axp288_chrg_info *info, int cc) @@ -305,6 +290,9 @@ static int axp288_charger_enable_charger(struct axp288_chrg_info *info, { int ret; + if ((int)enable == info->is_charger_enabled) + return 0; + if (enable) ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1, CHRG_CCCV_CHG_EN, CHRG_CCCV_CHG_EN); @@ -430,8 +418,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy, ret = axp288_charger_is_present(info); if (ret < 0) goto psy_get_prop_fail; - info->present = ret; - val->intval = info->present; + val->intval = ret; break; case POWER_SUPPLY_PROP_ONLINE: /* Check for OTG case first */ @@ -442,8 +429,7 @@ static int axp288_charger_usb_get_property(struct power_supply *psy, ret = axp288_charger_is_online(info); if (ret < 0) goto psy_get_prop_fail; - info->online = ret; - val->intval = info->online; + val->intval = ret; break; case POWER_SUPPLY_PROP_HEALTH: val->intval = axp288_get_charger_health(info); @@ -576,20 +562,20 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) struct axp288_chrg_info *info = container_of(work, struct axp288_chrg_info, cable.work); int ret, current_limit; - bool changed = false; struct extcon_dev *edev = info->cable.edev; bool old_connected = info->cable.connected; + enum power_supply_type old_chg_type = info->cable.chg_type; /* Determine cable/charger type */ - if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0) { + if (extcon_get_state(edev, EXTCON_CHG_USB_SDP) > 0) { dev_dbg(&info->pdev->dev, "USB SDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB; - } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0) { + } else if (extcon_get_state(edev, EXTCON_CHG_USB_CDP) > 0) { dev_dbg(&info->pdev->dev, "USB CDP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP; - } else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0) { + } else if (extcon_get_state(edev, EXTCON_CHG_USB_DCP) > 0) { dev_dbg(&info->pdev->dev, "USB DCP charger is connected"); info->cable.connected = true; info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP; @@ -601,22 +587,15 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) } /* Cable status changed */ - if (old_connected != info->cable.connected) - changed = true; - - if (!changed) + if (old_connected == info->cable.connected && + old_chg_type == info->cable.chg_type) return; mutex_lock(&info->lock); - if (info->is_charger_enabled && !info->cable.connected) { - info->enable_charger = false; - ret = axp288_charger_enable_charger(info, info->enable_charger); - if (ret < 0) - dev_err(&info->pdev->dev, - "cannot disable charger (%d)", ret); + if (info->cable.connected) { + axp288_charger_enable_charger(info, false); - } else if (!info->is_charger_enabled && info->cable.connected) { switch (info->cable.chg_type) { case POWER_SUPPLY_TYPE_USB: current_limit = ILIM_500MA; @@ -635,36 +614,49 @@ static void axp288_charger_extcon_evt_worker(struct work_struct *work) /* Set vbus current limit first, then enable charger */ ret = axp288_charger_set_vbus_inlmt(info, current_limit); - if (ret < 0) { + if (ret == 0) + axp288_charger_enable_charger(info, true); + else dev_err(&info->pdev->dev, "error setting current limit (%d)", ret); - } else { - info->enable_charger = (current_limit > 0); - ret = axp288_charger_enable_charger(info, - info->enable_charger); - if (ret < 0) - dev_err(&info->pdev->dev, - "cannot enable charger (%d)", ret); - } + } else { + axp288_charger_enable_charger(info, false); } - if (changed) - info->health = axp288_get_charger_health(info); - mutex_unlock(&info->lock); - if (changed) - power_supply_changed(info->psy_usb); + power_supply_changed(info->psy_usb); } -static int axp288_charger_handle_cable_evt(struct notifier_block *nb, - unsigned long event, void *param) +/* + * We need 3 copies of this, because there is no way to find out for which + * cable id we are being called from the passed in arguments; and we must + * have a separate nb for each extcon_register_notifier call. + */ +static int axp288_charger_handle_cable0_evt(struct notifier_block *nb, + unsigned long event, void *param) { struct axp288_chrg_info *info = - container_of(nb, struct axp288_chrg_info, cable.nb); + container_of(nb, struct axp288_chrg_info, cable.nb[0]); + schedule_work(&info->cable.work); + return NOTIFY_OK; +} +static int axp288_charger_handle_cable1_evt(struct notifier_block *nb, + unsigned long event, void *param) +{ + struct axp288_chrg_info *info = + container_of(nb, struct axp288_chrg_info, cable.nb[1]); schedule_work(&info->cable.work); + return NOTIFY_OK; +} +static int axp288_charger_handle_cable2_evt(struct notifier_block *nb, + unsigned long event, void *param) +{ + struct axp288_chrg_info *info = + container_of(nb, struct axp288_chrg_info, cable.nb[2]); + schedule_work(&info->cable.work); return NOTIFY_OK; } @@ -672,7 +664,17 @@ static void axp288_charger_otg_evt_worker(struct work_struct *work) { struct axp288_chrg_info *info = container_of(work, struct axp288_chrg_info, otg.work); - int ret; + struct extcon_dev *edev = info->otg.cable; + int ret, usb_host = extcon_get_state(edev, EXTCON_USB_HOST); + + dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", + usb_host ? "attached" : "detached"); + + /* + * Set usb_id_short flag to avoid running charger detection logic + * in case usb host. + */ + info->otg.id_short = usb_host; /* Disable VBUS path before enabling the 5V boost */ ret = axp288_charger_vbus_path_select(info, !info->otg.id_short); @@ -685,135 +687,109 @@ static int axp288_charger_handle_otg_evt(struct notifier_block *nb, { struct axp288_chrg_info *info = container_of(nb, struct axp288_chrg_info, otg.id_nb); - struct extcon_dev *edev = info->otg.cable; - int usb_host = extcon_get_cable_state_(edev, EXTCON_USB_HOST); - dev_dbg(&info->pdev->dev, "external connector USB-Host is %s\n", - usb_host ? "attached" : "detached"); - - /* - * Set usb_id_short flag to avoid running charger detection logic - * in case usb host. - */ - info->otg.id_short = usb_host; schedule_work(&info->otg.work); return NOTIFY_OK; } -static void charger_init_hw_regs(struct axp288_chrg_info *info) +static int charger_init_hw_regs(struct axp288_chrg_info *info) { int ret, cc, cv; unsigned int val; /* Program temperature thresholds */ ret = regmap_write(info->regmap, AXP20X_V_LTF_CHRG, CHRG_VLTFC_0C); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", + if (ret < 0) { + dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", AXP20X_V_LTF_CHRG, ret); + return ret; + } ret = regmap_write(info->regmap, AXP20X_V_HTF_CHRG, CHRG_VHTFC_45C); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", + if (ret < 0) { + dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", AXP20X_V_HTF_CHRG, ret); + return ret; + } /* Do not turn-off charger o/p after charge cycle ends */ ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL2, - CNTL2_CHG_OUT_TURNON, 1); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", + CNTL2_CHG_OUT_TURNON, CNTL2_CHG_OUT_TURNON); + if (ret < 0) { + dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", AXP20X_CHRG_CTRL2, ret); - - /* Enable interrupts */ - ret = regmap_update_bits(info->regmap, - AXP20X_IRQ2_EN, - BAT_IRQ_CFG_BAT_MASK, 1); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", - AXP20X_IRQ2_EN, ret); - - ret = regmap_update_bits(info->regmap, AXP20X_IRQ3_EN, - TEMP_IRQ_CFG_MASK, 1); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", - AXP20X_IRQ3_EN, ret); + return ret; + } /* Setup ending condition for charging to be 10% of I(chrg) */ ret = regmap_update_bits(info->regmap, AXP20X_CHRG_CTRL1, CHRG_CCCV_ITERM_20P, 0); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", + if (ret < 0) { + dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", AXP20X_CHRG_CTRL1, ret); + return ret; + } /* Disable OCV-SOC curve calibration */ ret = regmap_update_bits(info->regmap, AXP20X_CC_CTRL, FG_CNTL_OCV_ADJ_EN, 0); - if (ret < 0) - dev_warn(&info->pdev->dev, "register(%x) write error(%d)\n", + if (ret < 0) { + dev_err(&info->pdev->dev, "register(%x) write error(%d)\n", AXP20X_CC_CTRL, ret); - - /* Init charging current and voltage */ - info->max_cc = info->pdata->max_cc; - info->max_cv = info->pdata->max_cv; + return ret; + } /* Read current charge voltage and current limit */ ret = regmap_read(info->regmap, AXP20X_CHRG_CTRL1, &val); if (ret < 0) { - /* Assume default if cannot read */ - info->cc = info->pdata->def_cc; - info->cv = info->pdata->def_cv; - } else { - /* Determine charge voltage */ - cv = (val & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS; - switch (cv) { - case CHRG_CCCV_CV_4100MV: - info->cv = CV_4100MV; - break; - case CHRG_CCCV_CV_4150MV: - info->cv = CV_4150MV; - break; - case CHRG_CCCV_CV_4200MV: - info->cv = CV_4200MV; - break; - case CHRG_CCCV_CV_4350MV: - info->cv = CV_4350MV; - break; - default: - info->cv = INT_MAX; - break; - } + dev_err(&info->pdev->dev, "register(%x) read error(%d)\n", + AXP20X_CHRG_CTRL1, ret); + return ret; + } - /* Determine charge current limit */ - cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; - cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; - info->cc = cc; + /* Determine charge voltage */ + cv = (val & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS; + switch (cv) { + case CHRG_CCCV_CV_4100MV: + info->cv = CV_4100MV; + break; + case CHRG_CCCV_CV_4150MV: + info->cv = CV_4150MV; + break; + case CHRG_CCCV_CV_4200MV: + info->cv = CV_4200MV; + break; + case CHRG_CCCV_CV_4350MV: + info->cv = CV_4350MV; + break; + } - /* Program default charging voltage and current */ - cc = min(info->pdata->def_cc, info->max_cc); - cv = min(info->pdata->def_cv, info->max_cv); + /* Determine charge current limit */ + cc = (ret & CHRG_CCCV_CC_MASK) >> CHRG_CCCV_CC_BIT_POS; + cc = (cc * CHRG_CCCV_CC_LSB_RES) + CHRG_CCCV_CC_OFFSET; + info->cc = cc; - ret = axp288_charger_set_cc(info, cc); - if (ret < 0) - dev_warn(&info->pdev->dev, - "error(%d) in setting CC\n", ret); + /* + * Do not allow the user to configure higher settings then those + * set by the firmware + */ + info->max_cv = info->cv; + info->max_cc = info->cc; - ret = axp288_charger_set_cv(info, cv); - if (ret < 0) - dev_warn(&info->pdev->dev, - "error(%d) in setting CV\n", ret); - } + return 0; } static int axp288_charger_probe(struct platform_device *pdev) { int ret, i, pirq; struct axp288_chrg_info *info; + struct device *dev = &pdev->dev; struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct power_supply_config charger_cfg = {}; - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -821,15 +797,8 @@ static int axp288_charger_probe(struct platform_device *pdev) info->pdev = pdev; info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; - info->pdata = pdev->dev.platform_data; - - if (!info->pdata) { - /* Try ACPI provided pdata via device properties */ - if (!device_property_present(&pdev->dev, - "axp288_charger_data\n")) - dev_err(&pdev->dev, "failed to get platform data\n"); - return -ENODEV; - } + info->cable.chg_type = -1; + info->is_charger_enabled = -1; info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME); if (info->cable.edev == NULL) { @@ -838,63 +807,55 @@ static int axp288_charger_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - /* Register for extcon notification */ - INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); - info->cable.nb.notifier_call = axp288_charger_handle_cable_evt; - ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, - &info->cable.nb); - if (ret) { - dev_err(&info->pdev->dev, - "failed to register extcon notifier for SDP %d\n", ret); - return ret; - } - - ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, - &info->cable.nb); - if (ret) { - dev_err(&info->pdev->dev, - "failed to register extcon notifier for CDP %d\n", ret); - extcon_unregister_notifier(info->cable.edev, - EXTCON_CHG_USB_SDP, &info->cable.nb); - return ret; - } - - ret = extcon_register_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, - &info->cable.nb); - if (ret) { - dev_err(&info->pdev->dev, - "failed to register extcon notifier for DCP %d\n", ret); - extcon_unregister_notifier(info->cable.edev, - EXTCON_CHG_USB_SDP, &info->cable.nb); - extcon_unregister_notifier(info->cable.edev, - EXTCON_CHG_USB_CDP, &info->cable.nb); - return ret; + info->otg.cable = extcon_get_extcon_dev(USB_HOST_EXTCON_DEV_NAME); + if (info->otg.cable == NULL) { + dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n"); + return -EPROBE_DEFER; } platform_set_drvdata(pdev, info); mutex_init(&info->lock); + ret = charger_init_hw_regs(info); + if (ret) + return ret; + /* Register with power supply class */ charger_cfg.drv_data = info; - info->psy_usb = power_supply_register(&pdev->dev, &axp288_charger_desc, - &charger_cfg); + info->psy_usb = devm_power_supply_register(dev, &axp288_charger_desc, + &charger_cfg); if (IS_ERR(info->psy_usb)) { - dev_err(&pdev->dev, "failed to register power supply charger\n"); ret = PTR_ERR(info->psy_usb); - goto psy_reg_failed; + dev_err(dev, "failed to register power supply: %d\n", ret); + return ret; + } + + /* Register for extcon notification */ + INIT_WORK(&info->cable.work, axp288_charger_extcon_evt_worker); + info->cable.nb[0].notifier_call = axp288_charger_handle_cable0_evt; + info->cable.nb[1].notifier_call = axp288_charger_handle_cable1_evt; + info->cable.nb[2].notifier_call = axp288_charger_handle_cable2_evt; + for (i = 0; i < ARRAY_SIZE(cable_ids); i++) { + ret = devm_extcon_register_notifier(dev, info->cable.edev, + cable_ids[i], &info->cable.nb[i]); + if (ret) { + dev_err(dev, "failed to register extcon notifier for %u: %d\n", + cable_ids[i], ret); + return ret; + } } + schedule_work(&info->cable.work); /* Register for OTG notification */ INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; - ret = extcon_register_notifier(info->otg.cable, EXTCON_USB_HOST, - &info->otg.id_nb); - if (ret) - dev_warn(&pdev->dev, "failed to register otg notifier\n"); - - if (info->otg.cable) - info->otg.id_short = extcon_get_cable_state_( - info->otg.cable, EXTCON_USB_HOST); + ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable, + EXTCON_USB_HOST, &info->otg.id_nb); + if (ret) { + dev_err(dev, "failed to register EXTCON_USB_HOST notifier\n"); + return ret; + } + schedule_work(&info->otg.work); /* Register charger interrupts */ for (i = 0; i < CHRG_INTR_END; i++) { @@ -903,8 +864,7 @@ static int axp288_charger_probe(struct platform_device *pdev) if (info->irq[i] < 0) { dev_warn(&info->pdev->dev, "failed to get virtual interrupt=%d\n", pirq); - ret = info->irq[i]; - goto intr_reg_failed; + return info->irq[i]; } ret = devm_request_threaded_irq(&info->pdev->dev, info->irq[i], NULL, axp288_charger_irq_thread_handler, @@ -912,51 +872,22 @@ static int axp288_charger_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request interrupt=%d\n", info->irq[i]); - goto intr_reg_failed; + return ret; } } - charger_init_hw_regs(info); - return 0; - -intr_reg_failed: - if (info->otg.cable) - extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, - &info->otg.id_nb); - power_supply_unregister(info->psy_usb); -psy_reg_failed: - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, - &info->cable.nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, - &info->cable.nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, - &info->cable.nb); - return ret; } -static int axp288_charger_remove(struct platform_device *pdev) -{ - struct axp288_chrg_info *info = dev_get_drvdata(&pdev->dev); - - if (info->otg.cable) - extcon_unregister_notifier(info->otg.cable, EXTCON_USB_HOST, - &info->otg.id_nb); - - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_SDP, - &info->cable.nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_CDP, - &info->cable.nb); - extcon_unregister_notifier(info->cable.edev, EXTCON_CHG_USB_DCP, - &info->cable.nb); - power_supply_unregister(info->psy_usb); - - return 0; -} +static const struct platform_device_id axp288_charger_id_table[] = { + { .name = "axp288_charger" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, axp288_charger_id_table); static struct platform_driver axp288_charger_driver = { .probe = axp288_charger_probe, - .remove = axp288_charger_remove, + .id_table = axp288_charger_id_table, .driver = { .name = "axp288_charger", }, diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 539eb41504bb..a8dcabc32721 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -29,6 +29,7 @@ #include <linux/iio/consumer.h> #include <linux/debugfs.h> #include <linux/seq_file.h> +#include <asm/unaligned.h> #define CHRG_STAT_BAT_SAFE_MODE (1 << 3) #define CHRG_STAT_BAT_VALID (1 << 4) @@ -49,23 +50,6 @@ #define CHRG_CCCV_CV_4350MV 0x3 /* 4.35V */ #define CHRG_CCCV_CHG_EN (1 << 7) -#define CV_4100 4100 /* 4100mV */ -#define CV_4150 4150 /* 4150mV */ -#define CV_4200 4200 /* 4200mV */ -#define CV_4350 4350 /* 4350mV */ - -#define TEMP_IRQ_CFG_QWBTU (1 << 0) -#define TEMP_IRQ_CFG_WBTU (1 << 1) -#define TEMP_IRQ_CFG_QWBTO (1 << 2) -#define TEMP_IRQ_CFG_WBTO (1 << 3) -#define TEMP_IRQ_CFG_MASK 0xf - -#define FG_IRQ_CFG_LOWBATT_WL2 (1 << 0) -#define FG_IRQ_CFG_LOWBATT_WL1 (1 << 1) -#define FG_IRQ_CFG_LOWBATT_MASK 0x3 -#define LOWBAT_IRQ_STAT_LOWBATT_WL2 (1 << 0) -#define LOWBAT_IRQ_STAT_LOWBATT_WL1 (1 << 1) - #define FG_CNTL_OCV_ADJ_STAT (1 << 2) #define FG_CNTL_OCV_ADJ_EN (1 << 3) #define FG_CNTL_CAP_ADJ_STAT (1 << 4) @@ -73,17 +57,15 @@ #define FG_CNTL_CC_EN (1 << 6) #define FG_CNTL_GAUGE_EN (1 << 7) +#define FG_15BIT_WORD_VALID (1 << 15) +#define FG_15BIT_VAL_MASK 0x7fff + #define FG_REP_CAP_VALID (1 << 7) #define FG_REP_CAP_VAL_MASK 0x7F #define FG_DES_CAP1_VALID (1 << 7) -#define FG_DES_CAP1_VAL_MASK 0x7F -#define FG_DES_CAP0_VAL_MASK 0xFF #define FG_DES_CAP_RES_LSB 1456 /* 1.456mAhr */ -#define FG_CC_MTR1_VALID (1 << 7) -#define FG_CC_MTR1_VAL_MASK 0x7F -#define FG_CC_MTR0_VAL_MASK 0xFF #define FG_DES_CC_RES_LSB 1456 /* 1.456mAhr */ #define FG_OCV_CAP_VALID (1 << 7) @@ -104,9 +86,7 @@ /* 1.1mV per LSB expressed in uV */ #define VOLTAGE_FROM_ADC(a) ((a * 11) / 10) -/* properties converted to tenths of degrees, uV, uA, uW */ -#define PROP_TEMP(a) ((a) * 10) -#define UNPROP_TEMP(a) ((a) / 10) +/* properties converted to uV, uA */ #define PROP_VOLT(a) ((a) * 1000) #define PROP_CURR(a) ((a) * 1000) @@ -122,13 +102,13 @@ enum { struct axp288_fg_info { struct platform_device *pdev; - struct axp20x_fg_pdata *pdata; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; int irq[AXP288_FG_INTR_NUM]; struct power_supply *bat; struct mutex lock; int status; + int max_volt; struct delayed_work status_monitor; struct dentry *debug_file; }; @@ -138,22 +118,14 @@ static enum power_supply_property fuel_gauge_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_VOLTAGE_OCV, POWER_SUPPLY_PROP_CURRENT_NOW, POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, - POWER_SUPPLY_PROP_TEMP, - POWER_SUPPLY_PROP_TEMP_MAX, - POWER_SUPPLY_PROP_TEMP_MIN, - POWER_SUPPLY_PROP_TEMP_ALERT_MIN, - POWER_SUPPLY_PROP_TEMP_ALERT_MAX, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_MODEL_NAME, }; static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg) @@ -169,8 +141,10 @@ static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg) break; } - if (ret < 0) + if (ret < 0) { dev_err(&info->pdev->dev, "axp288 reg read err:%d\n", ret); + return ret; + } return val; } @@ -187,6 +161,44 @@ static int fuel_gauge_reg_writeb(struct axp288_fg_info *info, int reg, u8 val) return ret; } +static int fuel_gauge_read_15bit_word(struct axp288_fg_info *info, int reg) +{ + unsigned char buf[2]; + int ret; + + ret = regmap_bulk_read(info->regmap, reg, buf, 2); + if (ret < 0) { + dev_err(&info->pdev->dev, "Error reading reg 0x%02x err: %d\n", + reg, ret); + return ret; + } + + ret = get_unaligned_be16(buf); + if (!(ret & FG_15BIT_WORD_VALID)) { + dev_err(&info->pdev->dev, "Error reg 0x%02x contents not valid\n", + reg); + return -ENXIO; + } + + return ret & FG_15BIT_VAL_MASK; +} + +static int fuel_gauge_read_12bit_word(struct axp288_fg_info *info, int reg) +{ + unsigned char buf[2]; + int ret; + + ret = regmap_bulk_read(info->regmap, reg, buf, 2); + if (ret < 0) { + dev_err(&info->pdev->dev, "Error reading reg 0x%02x err: %d\n", + reg, ret); + return ret; + } + + /* 12-bit data values have upper 8 bits in buf[0], lower 4 in buf[1] */ + return (buf[0] << 4) | ((buf[1] >> 4) & 0x0f); +} + static int pmic_read_adc_val(const char *name, int *raw_val, struct axp288_fg_info *info) { @@ -247,24 +259,15 @@ static int fuel_gauge_debug_show(struct seq_file *s, void *data) seq_printf(s, " FG_RDC0[%02x] : %02x\n", AXP288_FG_RDC0_REG, fuel_gauge_reg_readb(info, AXP288_FG_RDC0_REG)); - seq_printf(s, " FG_OCVH[%02x] : %02x\n", + seq_printf(s, " FG_OCV[%02x] : %04x\n", AXP288_FG_OCVH_REG, - fuel_gauge_reg_readb(info, AXP288_FG_OCVH_REG)); - seq_printf(s, " FG_OCVL[%02x] : %02x\n", - AXP288_FG_OCVL_REG, - fuel_gauge_reg_readb(info, AXP288_FG_OCVL_REG)); - seq_printf(s, "FG_DES_CAP1[%02x] : %02x\n", + fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG)); + seq_printf(s, " FG_DES_CAP[%02x] : %04x\n", AXP288_FG_DES_CAP1_REG, - fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG)); - seq_printf(s, "FG_DES_CAP0[%02x] : %02x\n", - AXP288_FG_DES_CAP0_REG, - fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP0_REG)); - seq_printf(s, " FG_CC_MTR1[%02x] : %02x\n", + fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG)); + seq_printf(s, " FG_CC_MTR[%02x] : %04x\n", AXP288_FG_CC_MTR1_REG, - fuel_gauge_reg_readb(info, AXP288_FG_CC_MTR1_REG)); - seq_printf(s, " FG_CC_MTR0[%02x] : %02x\n", - AXP288_FG_CC_MTR0_REG, - fuel_gauge_reg_readb(info, AXP288_FG_CC_MTR0_REG)); + fuel_gauge_read_15bit_word(info, AXP288_FG_CC_MTR1_REG)); seq_printf(s, " FG_OCV_CAP[%02x] : %02x\n", AXP288_FG_OCV_CAP_REG, fuel_gauge_reg_readb(info, AXP288_FG_OCV_CAP_REG)); @@ -417,143 +420,27 @@ current_read_fail: return ret; } -static int temp_to_adc(struct axp288_fg_info *info, int tval) -{ - int rntc = 0, i, ret, adc_val; - int rmin, rmax, tmin, tmax; - int tcsz = info->pdata->tcsz; - - /* get the Rntc resitance value for this temp */ - if (tval > info->pdata->thermistor_curve[0][1]) { - rntc = info->pdata->thermistor_curve[0][0]; - } else if (tval <= info->pdata->thermistor_curve[tcsz-1][1]) { - rntc = info->pdata->thermistor_curve[tcsz-1][0]; - } else { - for (i = 1; i < tcsz; i++) { - if (tval > info->pdata->thermistor_curve[i][1]) { - rmin = info->pdata->thermistor_curve[i-1][0]; - rmax = info->pdata->thermistor_curve[i][0]; - tmin = info->pdata->thermistor_curve[i-1][1]; - tmax = info->pdata->thermistor_curve[i][1]; - rntc = rmin + ((rmax - rmin) * - (tval - tmin) / (tmax - tmin)); - break; - } - } - } - - /* we need the current to calculate the proper adc voltage */ - ret = fuel_gauge_reg_readb(info, AXP20X_ADC_RATE); - if (ret < 0) { - dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret); - ret = 0x30; - } - - /* - * temperature is proportional to NTS thermistor resistance - * ADC_RATE[5-4] determines current, 00=20uA,01=40uA,10=60uA,11=80uA - * [12-bit ADC VAL] = R_NTC(Ω) * current / 800 - */ - adc_val = rntc * (20 + (20 * ((ret >> 4) & 0x3))) / 800; - - return adc_val; -} - -static int adc_to_temp(struct axp288_fg_info *info, int adc_val) -{ - int ret, r, i, tval = 0; - int rmin, rmax, tmin, tmax; - int tcsz = info->pdata->tcsz; - - ret = fuel_gauge_reg_readb(info, AXP20X_ADC_RATE); - if (ret < 0) { - dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret); - ret = 0x30; - } - - /* - * temperature is proportional to NTS thermistor resistance - * ADC_RATE[5-4] determines current, 00=20uA,01=40uA,10=60uA,11=80uA - * R_NTC(Ω) = [12-bit ADC VAL] * 800 / current - */ - r = adc_val * 800 / (20 + (20 * ((ret >> 4) & 0x3))); - - if (r < info->pdata->thermistor_curve[0][0]) { - tval = info->pdata->thermistor_curve[0][1]; - } else if (r >= info->pdata->thermistor_curve[tcsz-1][0]) { - tval = info->pdata->thermistor_curve[tcsz-1][1]; - } else { - for (i = 1; i < tcsz; i++) { - if (r < info->pdata->thermistor_curve[i][0]) { - rmin = info->pdata->thermistor_curve[i-1][0]; - rmax = info->pdata->thermistor_curve[i][0]; - tmin = info->pdata->thermistor_curve[i-1][1]; - tmax = info->pdata->thermistor_curve[i][1]; - tval = tmin + ((tmax - tmin) * - (r - rmin) / (rmax - rmin)); - break; - } - } - } - - return tval; -} - -static int fuel_gauge_get_btemp(struct axp288_fg_info *info, int *btemp) -{ - int ret, raw_val = 0; - - ret = pmic_read_adc_val("axp288-batt-temp", &raw_val, info); - if (ret < 0) - goto temp_read_fail; - - *btemp = adc_to_temp(info, raw_val); - -temp_read_fail: - return ret; -} - static int fuel_gauge_get_vocv(struct axp288_fg_info *info, int *vocv) { - int ret, value; - - /* 12-bit data value, upper 8 in OCVH, lower 4 in OCVL */ - ret = fuel_gauge_reg_readb(info, AXP288_FG_OCVH_REG); - if (ret < 0) - goto vocv_read_fail; - value = ret << 4; + int ret; - ret = fuel_gauge_reg_readb(info, AXP288_FG_OCVL_REG); - if (ret < 0) - goto vocv_read_fail; - value |= (ret & 0xf); + ret = fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG); + if (ret >= 0) + *vocv = VOLTAGE_FROM_ADC(ret); - *vocv = VOLTAGE_FROM_ADC(value); -vocv_read_fail: return ret; } static int fuel_gauge_battery_health(struct axp288_fg_info *info) { - int temp, vocv; - int ret, health = POWER_SUPPLY_HEALTH_UNKNOWN; - - ret = fuel_gauge_get_btemp(info, &temp); - if (ret < 0) - goto health_read_fail; + int ret, vocv, health = POWER_SUPPLY_HEALTH_UNKNOWN; ret = fuel_gauge_get_vocv(info, &vocv); if (ret < 0) goto health_read_fail; - if (vocv > info->pdata->max_volt) + if (vocv > info->max_volt) health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - else if (temp > info->pdata->max_temp) - health = POWER_SUPPLY_HEALTH_OVERHEAT; - else if (temp < info->pdata->min_temp) - health = POWER_SUPPLY_HEALTH_COLD; - else if (vocv < info->pdata->min_volt) - health = POWER_SUPPLY_HEALTH_DEAD; else health = POWER_SUPPLY_HEALTH_GOOD; @@ -561,28 +448,6 @@ health_read_fail: return health; } -static int fuel_gauge_set_high_btemp_alert(struct axp288_fg_info *info) -{ - int ret, adc_val; - - /* program temperature threshold as 1/16 ADC value */ - adc_val = temp_to_adc(info, info->pdata->max_temp); - ret = fuel_gauge_reg_writeb(info, AXP20X_V_HTF_DISCHRG, adc_val >> 4); - - return ret; -} - -static int fuel_gauge_set_low_btemp_alert(struct axp288_fg_info *info) -{ - int ret, adc_val; - - /* program temperature threshold as 1/16 ADC value */ - adc_val = temp_to_adc(info, info->pdata->min_temp); - ret = fuel_gauge_reg_writeb(info, AXP20X_V_LTF_DISCHRG, adc_val >> 4); - - return ret; -} - static int fuel_gauge_get_property(struct power_supply *ps, enum power_supply_property prop, union power_supply_propval *val) @@ -643,58 +508,25 @@ static int fuel_gauge_get_property(struct power_supply *ps, goto fuel_gauge_read_err; val->intval = (ret & 0x0f); break; - case POWER_SUPPLY_PROP_TEMP: - ret = fuel_gauge_get_btemp(info, &value); - if (ret < 0) - goto fuel_gauge_read_err; - val->intval = PROP_TEMP(value); - break; - case POWER_SUPPLY_PROP_TEMP_MAX: - case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: - val->intval = PROP_TEMP(info->pdata->max_temp); - break; - case POWER_SUPPLY_PROP_TEMP_MIN: - case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: - val->intval = PROP_TEMP(info->pdata->min_temp); - break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; case POWER_SUPPLY_PROP_CHARGE_NOW: - ret = fuel_gauge_reg_readb(info, AXP288_FG_CC_MTR1_REG); + ret = fuel_gauge_read_15bit_word(info, AXP288_FG_CC_MTR1_REG); if (ret < 0) goto fuel_gauge_read_err; - value = (ret & FG_CC_MTR1_VAL_MASK) << 8; - ret = fuel_gauge_reg_readb(info, AXP288_FG_CC_MTR0_REG); - if (ret < 0) - goto fuel_gauge_read_err; - value |= (ret & FG_CC_MTR0_VAL_MASK); - val->intval = value * FG_DES_CAP_RES_LSB; + val->intval = ret * FG_DES_CAP_RES_LSB; break; case POWER_SUPPLY_PROP_CHARGE_FULL: - ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG); + ret = fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG); if (ret < 0) goto fuel_gauge_read_err; - value = (ret & FG_DES_CAP1_VAL_MASK) << 8; - ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP0_REG); - if (ret < 0) - goto fuel_gauge_read_err; - value |= (ret & FG_DES_CAP0_VAL_MASK); - val->intval = value * FG_DES_CAP_RES_LSB; - break; - case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - val->intval = PROP_CURR(info->pdata->design_cap); + val->intval = ret * FG_DES_CAP_RES_LSB; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - val->intval = PROP_VOLT(info->pdata->max_volt); - break; - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - val->intval = PROP_VOLT(info->pdata->min_volt); - break; - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = info->pdata->battid; + val->intval = PROP_VOLT(info->max_volt); break; default: mutex_unlock(&info->lock); @@ -718,35 +550,6 @@ static int fuel_gauge_set_property(struct power_supply *ps, mutex_lock(&info->lock); switch (prop) { - case POWER_SUPPLY_PROP_STATUS: - info->status = val->intval; - break; - case POWER_SUPPLY_PROP_TEMP_MIN: - case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: - if ((val->intval < PD_DEF_MIN_TEMP) || - (val->intval > PD_DEF_MAX_TEMP)) { - ret = -EINVAL; - break; - } - info->pdata->min_temp = UNPROP_TEMP(val->intval); - ret = fuel_gauge_set_low_btemp_alert(info); - if (ret < 0) - dev_err(&info->pdev->dev, - "temp alert min set fail:%d\n", ret); - break; - case POWER_SUPPLY_PROP_TEMP_MAX: - case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: - if ((val->intval < PD_DEF_MIN_TEMP) || - (val->intval > PD_DEF_MAX_TEMP)) { - ret = -EINVAL; - break; - } - info->pdata->max_temp = UNPROP_TEMP(val->intval); - ret = fuel_gauge_set_high_btemp_alert(info); - if (ret < 0) - dev_err(&info->pdev->dev, - "temp alert max set fail:%d\n", ret); - break; case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: if ((val->intval < 0) || (val->intval > 15)) { ret = -EINVAL; @@ -774,11 +577,6 @@ static int fuel_gauge_property_is_writeable(struct power_supply *psy, int ret; switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - case POWER_SUPPLY_PROP_TEMP_MIN: - case POWER_SUPPLY_PROP_TEMP_ALERT_MIN: - case POWER_SUPPLY_PROP_TEMP_MAX: - case POWER_SUPPLY_PROP_TEMP_ALERT_MAX: case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: ret = 1; break; @@ -863,158 +661,6 @@ static const struct power_supply_desc fuel_gauge_desc = { .external_power_changed = fuel_gauge_external_power_changed, }; -static int fuel_gauge_set_lowbatt_thresholds(struct axp288_fg_info *info) -{ - int ret; - u8 reg_val; - - ret = fuel_gauge_reg_readb(info, AXP20X_FG_RES); - if (ret < 0) { - dev_err(&info->pdev->dev, "%s:read err:%d\n", __func__, ret); - return ret; - } - ret = (ret & FG_REP_CAP_VAL_MASK); - - if (ret > FG_LOW_CAP_WARN_THR) - reg_val = FG_LOW_CAP_WARN_THR; - else if (ret > FG_LOW_CAP_CRIT_THR) - reg_val = FG_LOW_CAP_CRIT_THR; - else - reg_val = FG_LOW_CAP_SHDN_THR; - - reg_val |= FG_LOW_CAP_THR1_VAL; - ret = fuel_gauge_reg_writeb(info, AXP288_FG_LOW_CAP_REG, reg_val); - if (ret < 0) - dev_err(&info->pdev->dev, "%s:write err:%d\n", __func__, ret); - - return ret; -} - -static int fuel_gauge_program_vbatt_full(struct axp288_fg_info *info) -{ - int ret; - u8 val; - - ret = fuel_gauge_reg_readb(info, AXP20X_CHRG_CTRL1); - if (ret < 0) - goto fg_prog_ocv_fail; - else - val = (ret & ~CHRG_CCCV_CV_MASK); - - switch (info->pdata->max_volt) { - case CV_4100: - val |= (CHRG_CCCV_CV_4100MV << CHRG_CCCV_CV_BIT_POS); - break; - case CV_4150: - val |= (CHRG_CCCV_CV_4150MV << CHRG_CCCV_CV_BIT_POS); - break; - case CV_4200: - val |= (CHRG_CCCV_CV_4200MV << CHRG_CCCV_CV_BIT_POS); - break; - case CV_4350: - val |= (CHRG_CCCV_CV_4350MV << CHRG_CCCV_CV_BIT_POS); - break; - default: - val |= (CHRG_CCCV_CV_4200MV << CHRG_CCCV_CV_BIT_POS); - break; - } - - ret = fuel_gauge_reg_writeb(info, AXP20X_CHRG_CTRL1, val); -fg_prog_ocv_fail: - return ret; -} - -static int fuel_gauge_program_design_cap(struct axp288_fg_info *info) -{ - int ret; - - ret = fuel_gauge_reg_writeb(info, - AXP288_FG_DES_CAP1_REG, info->pdata->cap1); - if (ret < 0) - goto fg_prog_descap_fail; - - ret = fuel_gauge_reg_writeb(info, - AXP288_FG_DES_CAP0_REG, info->pdata->cap0); - -fg_prog_descap_fail: - return ret; -} - -static int fuel_gauge_program_ocv_curve(struct axp288_fg_info *info) -{ - int ret = 0, i; - - for (i = 0; i < OCV_CURVE_SIZE; i++) { - ret = fuel_gauge_reg_writeb(info, - AXP288_FG_OCV_CURVE_REG + i, info->pdata->ocv_curve[i]); - if (ret < 0) - goto fg_prog_ocv_fail; - } - -fg_prog_ocv_fail: - return ret; -} - -static int fuel_gauge_program_rdc_vals(struct axp288_fg_info *info) -{ - int ret; - - ret = fuel_gauge_reg_writeb(info, - AXP288_FG_RDC1_REG, info->pdata->rdc1); - if (ret < 0) - goto fg_prog_ocv_fail; - - ret = fuel_gauge_reg_writeb(info, - AXP288_FG_RDC0_REG, info->pdata->rdc0); - -fg_prog_ocv_fail: - return ret; -} - -static void fuel_gauge_init_config_regs(struct axp288_fg_info *info) -{ - int ret; - - /* - * check if the config data is already - * programmed and if so just return. - */ - - ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG); - if (ret < 0) { - dev_warn(&info->pdev->dev, "CAP1 reg read err!!\n"); - } else if (!(ret & FG_DES_CAP1_VALID)) { - dev_info(&info->pdev->dev, "FG data needs to be initialized\n"); - } else { - dev_info(&info->pdev->dev, "FG data is already initialized\n"); - return; - } - - ret = fuel_gauge_program_vbatt_full(info); - if (ret < 0) - dev_err(&info->pdev->dev, "set vbatt full fail:%d\n", ret); - - ret = fuel_gauge_program_design_cap(info); - if (ret < 0) - dev_err(&info->pdev->dev, "set design cap fail:%d\n", ret); - - ret = fuel_gauge_program_rdc_vals(info); - if (ret < 0) - dev_err(&info->pdev->dev, "set rdc fail:%d\n", ret); - - ret = fuel_gauge_program_ocv_curve(info); - if (ret < 0) - dev_err(&info->pdev->dev, "set ocv curve fail:%d\n", ret); - - ret = fuel_gauge_set_lowbatt_thresholds(info); - if (ret < 0) - dev_err(&info->pdev->dev, "lowbatt thr set fail:%d\n", ret); - - ret = fuel_gauge_reg_writeb(info, AXP20X_CC_CTRL, 0xef); - if (ret < 0) - dev_err(&info->pdev->dev, "gauge cntl set fail:%d\n", ret); -} - static void fuel_gauge_init_irq(struct axp288_fg_info *info) { int ret, i, pirq; @@ -1052,29 +698,6 @@ intr_failed: } } -static void fuel_gauge_init_hw_regs(struct axp288_fg_info *info) -{ - int ret; - unsigned int val; - - ret = fuel_gauge_set_high_btemp_alert(info); - if (ret < 0) - dev_err(&info->pdev->dev, "high batt temp set fail:%d\n", ret); - - ret = fuel_gauge_set_low_btemp_alert(info); - if (ret < 0) - dev_err(&info->pdev->dev, "low batt temp set fail:%d\n", ret); - - /* enable interrupts */ - val = fuel_gauge_reg_readb(info, AXP20X_IRQ3_EN); - val |= TEMP_IRQ_CFG_MASK; - fuel_gauge_reg_writeb(info, AXP20X_IRQ3_EN, val); - - val = fuel_gauge_reg_readb(info, AXP20X_IRQ4_EN); - val |= FG_IRQ_CFG_LOWBATT_MASK; - val = fuel_gauge_reg_writeb(info, AXP20X_IRQ4_EN, val); -} - static int axp288_fuel_gauge_probe(struct platform_device *pdev) { int ret = 0; @@ -1090,15 +713,39 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->status = POWER_SUPPLY_STATUS_UNKNOWN; - info->pdata = pdev->dev.platform_data; - if (!info->pdata) - return -ENODEV; platform_set_drvdata(pdev, info); mutex_init(&info->lock); INIT_DELAYED_WORK(&info->status_monitor, fuel_gauge_status_monitor); + ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG); + if (ret < 0) + return ret; + + if (!(ret & FG_DES_CAP1_VALID)) { + dev_err(&pdev->dev, "axp288 not configured by firmware\n"); + return -ENODEV; + } + + ret = fuel_gauge_reg_readb(info, AXP20X_CHRG_CTRL1); + if (ret < 0) + return ret; + switch ((ret & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS) { + case CHRG_CCCV_CV_4100MV: + info->max_volt = 4100; + break; + case CHRG_CCCV_CV_4150MV: + info->max_volt = 4150; + break; + case CHRG_CCCV_CV_4200MV: + info->max_volt = 4200; + break; + case CHRG_CCCV_CV_4350MV: + info->max_volt = 4350; + break; + } + psy_cfg.drv_data = info; info->bat = power_supply_register(&pdev->dev, &fuel_gauge_desc, &psy_cfg); if (IS_ERR(info->bat)) { @@ -1108,12 +755,10 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) } fuel_gauge_create_debugfs(info); - fuel_gauge_init_config_regs(info); fuel_gauge_init_irq(info); - fuel_gauge_init_hw_regs(info); schedule_delayed_work(&info->status_monitor, STATUS_MON_DELAY_JIFFIES); - return ret; + return 0; } static const struct platform_device_id axp288_fg_id_table[] = { diff --git a/drivers/power/supply/bq2415x_charger.c b/drivers/power/supply/bq2415x_charger.c index 73e2f0b79dd4..c4770a94cc8e 100644 --- a/drivers/power/supply/bq2415x_charger.c +++ b/drivers/power/supply/bq2415x_charger.c @@ -1569,6 +1569,11 @@ static int bq2415x_probe(struct i2c_client *client, acpi_id = acpi_match_device(client->dev.driver->acpi_match_table, &client->dev); + if (!acpi_id) { + dev_err(&client->dev, "failed to match device name\n"); + ret = -ENODEV; + goto error_1; + } name = kasprintf(GFP_KERNEL, "%s-%d", acpi_id->id, num); } if (!name) { diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index e9584330aeed..a4f08492abeb 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -144,10 +144,7 @@ * so the first read after a fault returns the latched value and subsequent * reads return the current value. In order to return the fault status * to the user, have the interrupt handler save the reg's value and retrieve - * it in the appropriate health/status routine. Each routine has its own - * flag indicating whether it should use the value stored by the last run - * of the interrupt handler or do an actual reg read. That way each routine - * can report back whatever fault may have occured. + * it in the appropriate health/status routine. */ struct bq24190_dev_info { struct i2c_client *client; @@ -159,10 +156,6 @@ struct bq24190_dev_info { unsigned int gpio_int; unsigned int irq; struct mutex f_reg_lock; - bool first_time; - bool charger_health_valid; - bool battery_health_valid; - bool battery_status_valid; u8 f_reg; u8 ss_reg; u8 watchdog; @@ -199,7 +192,7 @@ static const int bq24190_cvc_vreg_values[] = { 4400000 }; -/* REG06[1:0] (TREG) in tenths of degrees Celcius */ +/* REG06[1:0] (TREG) in tenths of degrees Celsius */ static const int bq24190_ictrc_treg_values[] = { 600, 800, 1000, 1200 }; @@ -636,21 +629,11 @@ static int bq24190_charger_get_health(struct bq24190_dev_info *bdi, union power_supply_propval *val) { u8 v; - int health, ret; + int health; mutex_lock(&bdi->f_reg_lock); - - if (bdi->charger_health_valid) { - v = bdi->f_reg; - bdi->charger_health_valid = false; - mutex_unlock(&bdi->f_reg_lock); - } else { - mutex_unlock(&bdi->f_reg_lock); - - ret = bq24190_read(bdi, BQ24190_REG_F, &v); - if (ret < 0) - return ret; - } + v = bdi->f_reg; + mutex_unlock(&bdi->f_reg_lock); if (v & BQ24190_REG_F_BOOST_FAULT_MASK) { /* @@ -937,18 +920,8 @@ static int bq24190_battery_get_status(struct bq24190_dev_info *bdi, int status, ret; mutex_lock(&bdi->f_reg_lock); - - if (bdi->battery_status_valid) { - chrg_fault = bdi->f_reg; - bdi->battery_status_valid = false; - mutex_unlock(&bdi->f_reg_lock); - } else { - mutex_unlock(&bdi->f_reg_lock); - - ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault); - if (ret < 0) - return ret; - } + chrg_fault = bdi->f_reg; + mutex_unlock(&bdi->f_reg_lock); chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK; chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT; @@ -996,21 +969,11 @@ static int bq24190_battery_get_health(struct bq24190_dev_info *bdi, union power_supply_propval *val) { u8 v; - int health, ret; + int health; mutex_lock(&bdi->f_reg_lock); - - if (bdi->battery_health_valid) { - v = bdi->f_reg; - bdi->battery_health_valid = false; - mutex_unlock(&bdi->f_reg_lock); - } else { - mutex_unlock(&bdi->f_reg_lock); - - ret = bq24190_read(bdi, BQ24190_REG_F, &v); - if (ret < 0) - return ret; - } + v = bdi->f_reg; + mutex_unlock(&bdi->f_reg_lock); if (v & BQ24190_REG_F_BAT_FAULT_MASK) { health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; @@ -1197,9 +1160,12 @@ static const struct power_supply_desc bq24190_battery_desc = { static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) { struct bq24190_dev_info *bdi = data; - bool alert_userspace = false; + const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK; + const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK + | BQ24190_REG_F_NTC_FAULT_MASK; + bool alert_charger = false, alert_battery = false; u8 ss_reg = 0, f_reg = 0; - int ret; + int i, ret; pm_runtime_get_sync(bdi->dev); @@ -1209,6 +1175,32 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) goto out; } + i = 0; + do { + ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg); + if (ret < 0) { + dev_err(bdi->dev, "Can't read F reg: %d\n", ret); + goto out; + } + } while (f_reg && ++i < 2); + + if (f_reg != bdi->f_reg) { + dev_info(bdi->dev, + "Fault: boost %d, charge %d, battery %d, ntc %d\n", + !!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK), + !!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK), + !!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK), + !!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK)); + + mutex_lock(&bdi->f_reg_lock); + if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f)) + alert_battery = true; + if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f)) + alert_charger = true; + bdi->f_reg = f_reg; + mutex_unlock(&bdi->f_reg_lock); + } + if (ss_reg != bdi->ss_reg) { /* * The device is in host mode so when PG_STAT goes from 1->0 @@ -1225,47 +1217,17 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data) ret); } + if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss)) + alert_battery = true; + if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss)) + alert_charger = true; bdi->ss_reg = ss_reg; - alert_userspace = true; - } - - mutex_lock(&bdi->f_reg_lock); - - ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg); - if (ret < 0) { - mutex_unlock(&bdi->f_reg_lock); - dev_err(bdi->dev, "Can't read F reg: %d\n", ret); - goto out; - } - - if (f_reg != bdi->f_reg) { - bdi->f_reg = f_reg; - bdi->charger_health_valid = true; - bdi->battery_health_valid = true; - bdi->battery_status_valid = true; - - alert_userspace = true; } - mutex_unlock(&bdi->f_reg_lock); - - /* - * Sometimes bq24190 gives a steady trickle of interrupts even - * though the watchdog timer is turned off and neither the STATUS - * nor FAULT registers have changed. Weed out these sprurious - * interrupts so userspace isn't alerted for no reason. - * In addition, the chip always generates an interrupt after - * register reset so we should ignore that one (the very first - * interrupt received). - */ - if (alert_userspace) { - if (!bdi->first_time) { - power_supply_changed(bdi->charger); - power_supply_changed(bdi->battery); - } else { - bdi->first_time = false; - } - } + if (alert_charger) + power_supply_changed(bdi->charger); + if (alert_battery) + power_supply_changed(bdi->battery); out: pm_runtime_put_sync(bdi->dev); @@ -1300,6 +1262,10 @@ static int bq24190_hw_init(struct bq24190_dev_info *bdi) goto out; ret = bq24190_set_mode_host(bdi); + if (ret < 0) + goto out; + + ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); out: pm_runtime_put_sync(bdi->dev); return ret; @@ -1375,10 +1341,8 @@ static int bq24190_probe(struct i2c_client *client, bdi->model = id->driver_data; strncpy(bdi->model_name, id->name, I2C_NAME_SIZE); mutex_init(&bdi->f_reg_lock); - bdi->first_time = true; - bdi->charger_health_valid = false; - bdi->battery_health_valid = false; - bdi->battery_status_valid = false; + bdi->f_reg = 0; + bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ i2c_set_clientdata(client, bdi); @@ -1392,22 +1356,13 @@ static int bq24190_probe(struct i2c_client *client, return -EINVAL; } - ret = devm_request_threaded_irq(dev, bdi->irq, NULL, - bq24190_irq_handler_thread, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "bq24190-charger", bdi); - if (ret < 0) { - dev_err(dev, "Can't set up irq handler\n"); - goto out1; - } - pm_runtime_enable(dev); pm_runtime_resume(dev); ret = bq24190_hw_init(bdi); if (ret < 0) { dev_err(dev, "Hardware init failed\n"); - goto out2; + goto out1; } charger_cfg.drv_data = bdi; @@ -1418,7 +1373,7 @@ static int bq24190_probe(struct i2c_client *client, if (IS_ERR(bdi->charger)) { dev_err(dev, "Can't register charger\n"); ret = PTR_ERR(bdi->charger); - goto out2; + goto out1; } battery_cfg.drv_data = bdi; @@ -1427,27 +1382,39 @@ static int bq24190_probe(struct i2c_client *client, if (IS_ERR(bdi->battery)) { dev_err(dev, "Can't register battery\n"); ret = PTR_ERR(bdi->battery); - goto out3; + goto out2; } ret = bq24190_sysfs_create_group(bdi); if (ret) { dev_err(dev, "Can't create sysfs entries\n"); + goto out3; + } + + ret = devm_request_threaded_irq(dev, bdi->irq, NULL, + bq24190_irq_handler_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "bq24190-charger", bdi); + if (ret < 0) { + dev_err(dev, "Can't set up irq handler\n"); goto out4; } return 0; out4: - power_supply_unregister(bdi->battery); + bq24190_sysfs_remove_group(bdi); + out3: - power_supply_unregister(bdi->charger); + power_supply_unregister(bdi->battery); + out2: - pm_runtime_disable(dev); + power_supply_unregister(bdi->charger); + out1: + pm_runtime_disable(dev); if (bdi->gpio_int) gpio_free(bdi->gpio_int); - return ret; } @@ -1488,12 +1455,13 @@ static int bq24190_pm_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct bq24190_dev_info *bdi = i2c_get_clientdata(client); - bdi->charger_health_valid = false; - bdi->battery_health_valid = false; - bdi->battery_status_valid = false; + bdi->f_reg = 0; + bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */ pm_runtime_get_sync(bdi->dev); bq24190_register_reset(bdi); + bq24190_set_mode_host(bdi); + bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg); pm_runtime_put_sync(bdi->dev); /* Things may have changed while suspended so alert upper layer */ diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c index eb7783b42e0a..eb0145380def 100644 --- a/drivers/power/supply/bq24735-charger.c +++ b/drivers/power/supply/bq24735-charger.c @@ -50,6 +50,8 @@ struct bq24735 { struct bq24735_platform *pdata; struct mutex lock; struct gpio_desc *status_gpio; + struct delayed_work poll; + u32 poll_interval; bool charging; }; @@ -105,26 +107,6 @@ static int bq24735_update_word(struct i2c_client *client, u8 reg, return bq24735_write_word(client, reg, tmp); } -static inline int bq24735_enable_charging(struct bq24735 *charger) -{ - if (charger->pdata->ext_control) - return 0; - - return bq24735_update_word(charger->client, BQ24735_CHG_OPT, - BQ24735_CHG_OPT_CHARGE_DISABLE, - ~BQ24735_CHG_OPT_CHARGE_DISABLE); -} - -static inline int bq24735_disable_charging(struct bq24735 *charger) -{ - if (charger->pdata->ext_control) - return 0; - - return bq24735_update_word(charger->client, BQ24735_CHG_OPT, - BQ24735_CHG_OPT_CHARGE_DISABLE, - BQ24735_CHG_OPT_CHARGE_DISABLE); -} - static int bq24735_config_charger(struct bq24735 *charger) { struct bq24735_platform *pdata = charger->pdata; @@ -176,6 +158,31 @@ static int bq24735_config_charger(struct bq24735 *charger) return 0; } +static inline int bq24735_enable_charging(struct bq24735 *charger) +{ + int ret; + + if (charger->pdata->ext_control) + return 0; + + ret = bq24735_config_charger(charger); + if (ret) + return ret; + + return bq24735_update_word(charger->client, BQ24735_CHG_OPT, + BQ24735_CHG_OPT_CHARGE_DISABLE, 0); +} + +static inline int bq24735_disable_charging(struct bq24735 *charger) +{ + if (charger->pdata->ext_control) + return 0; + + return bq24735_update_word(charger->client, BQ24735_CHG_OPT, + BQ24735_CHG_OPT_CHARGE_DISABLE, + BQ24735_CHG_OPT_CHARGE_DISABLE); +} + static bool bq24735_charger_is_present(struct bq24735 *charger) { if (charger->status_gpio) { @@ -185,7 +192,7 @@ static bool bq24735_charger_is_present(struct bq24735 *charger) ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT); if (ac < 0) { - dev_err(&charger->client->dev, + dev_dbg(&charger->client->dev, "Failed to read charger options : %d\n", ac); return false; @@ -210,11 +217,8 @@ static int bq24735_charger_is_charging(struct bq24735 *charger) return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE); } -static irqreturn_t bq24735_charger_isr(int irq, void *devid) +static void bq24735_update(struct bq24735 *charger) { - struct power_supply *psy = devid; - struct bq24735 *charger = to_bq24735(psy); - mutex_lock(&charger->lock); if (charger->charging && bq24735_charger_is_present(charger)) @@ -224,11 +228,29 @@ static irqreturn_t bq24735_charger_isr(int irq, void *devid) mutex_unlock(&charger->lock); - power_supply_changed(psy); + power_supply_changed(charger->charger); +} + +static irqreturn_t bq24735_charger_isr(int irq, void *devid) +{ + struct power_supply *psy = devid; + struct bq24735 *charger = to_bq24735(psy); + + bq24735_update(charger); return IRQ_HANDLED; } +static void bq24735_poll(struct work_struct *work) +{ + struct bq24735 *charger = container_of(work, struct bq24735, poll.work); + + bq24735_update(charger); + + schedule_delayed_work(&charger->poll, + msecs_to_jiffies(charger->poll_interval)); +} + static int bq24735_charger_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) @@ -276,7 +298,6 @@ static int bq24735_charger_set_property(struct power_supply *psy, mutex_unlock(&charger->lock); if (ret) return ret; - bq24735_config_charger(charger); break; case POWER_SUPPLY_STATUS_DISCHARGING: case POWER_SUPPLY_STATUS_NOT_CHARGING: @@ -395,7 +416,7 @@ static int bq24735_charger_probe(struct i2c_client *client, return ret; } - if (!charger->status_gpio || bq24735_charger_is_present(charger)) { + if (bq24735_charger_is_present(charger)) { ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID); if (ret < 0) { dev_err(&client->dev, "Failed to read manufacturer id : %d\n", @@ -416,16 +437,7 @@ static int bq24735_charger_probe(struct i2c_client *client, "device id mismatch. 0x000b != 0x%04x\n", ret); return -ENODEV; } - } - - ret = bq24735_config_charger(charger); - if (ret < 0) { - dev_err(&client->dev, "failed in configuring charger"); - return ret; - } - /* check for AC adapter presence */ - if (bq24735_charger_is_present(charger)) { ret = bq24735_enable_charging(charger); if (ret < 0) { dev_err(&client->dev, "Failed to enable charging\n"); @@ -456,11 +468,32 @@ static int bq24735_charger_probe(struct i2c_client *client, client->irq, ret); return ret; } + } else { + ret = device_property_read_u32(&client->dev, "poll-interval", + &charger->poll_interval); + if (ret) + return 0; + if (!charger->poll_interval) + return 0; + + INIT_DELAYED_WORK(&charger->poll, bq24735_poll); + schedule_delayed_work(&charger->poll, + msecs_to_jiffies(charger->poll_interval)); } return 0; } +static int bq24735_charger_remove(struct i2c_client *client) +{ + struct bq24735 *charger = i2c_get_clientdata(client); + + if (charger->poll_interval) + cancel_delayed_work_sync(&charger->poll); + + return 0; +} + static const struct i2c_device_id bq24735_charger_id[] = { { "bq24735-charger", 0 }, {} @@ -479,6 +512,7 @@ static struct i2c_driver bq24735_charger_driver = { .of_match_table = bq24735_match_ids, }, .probe = bq24735_charger_probe, + .remove = bq24735_charger_remove, .id_table = bq24735_charger_id, }; diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 08c36b8e04bd..398801a21b86 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -22,8 +22,14 @@ * http://www.ti.com/product/bq27010 * http://www.ti.com/product/bq27210 * http://www.ti.com/product/bq27500 + * http://www.ti.com/product/bq27510-g1 + * http://www.ti.com/product/bq27510-g2 * http://www.ti.com/product/bq27510-g3 * http://www.ti.com/product/bq27520-g4 + * http://www.ti.com/product/bq27520-g1 + * http://www.ti.com/product/bq27520-g2 + * http://www.ti.com/product/bq27520-g3 + * http://www.ti.com/product/bq27520-g4 * http://www.ti.com/product/bq27530-g1 * http://www.ti.com/product/bq27531-g1 * http://www.ti.com/product/bq27541-g1 @@ -145,7 +151,7 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_DCAP] = 0x76, [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }, - [BQ27500] = { + [BQ2750X] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -164,7 +170,83 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }, - [BQ27510] = { + [BQ2751X] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1a, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x1e, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x20, + [BQ27XXX_REG_DCAP] = 0x2e, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, + }, + [BQ27500] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27510G1] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27510G2] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27510G3] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, [BQ27XXX_REG_INT_TEMP] = 0x28, @@ -183,6 +265,82 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_DCAP] = 0x2e, [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }, + [BQ27520G1] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27520G2] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x36, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = 0x18, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27520G3] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x36, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = 0x26, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x2a, + [BQ27XXX_REG_AE] = 0x22, + [BQ27XXX_REG_SOC] = 0x2c, + [BQ27XXX_REG_DCAP] = 0x3c, + [BQ27XXX_REG_AP] = 0x24, + }, + [BQ27520G4] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1c, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x1e, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x20, + [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, + }, [BQ27530] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -303,6 +461,42 @@ static enum power_supply_property bq27010_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; +static enum power_supply_property bq2750x_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq2751x_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + static enum power_supply_property bq27500_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -312,6 +506,69 @@ static enum power_supply_property bq27500_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27510g1_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27510g2_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27510g3_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, @@ -321,7 +578,27 @@ static enum power_supply_property bq27500_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; -static enum power_supply_property bq27510_battery_props[] = { +static enum power_supply_property bq27520g1_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27520g2_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_VOLTAGE_NOW, @@ -330,11 +607,51 @@ static enum power_supply_property bq27510_battery_props[] = { POWER_SUPPLY_PROP_CAPACITY_LEVEL, POWER_SUPPLY_PROP_TEMP, POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27520g3_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_ENERGY_NOW, + POWER_SUPPLY_PROP_POWER_AVG, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static enum power_supply_property bq27520g4_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_MANUFACTURER, }; @@ -421,8 +738,16 @@ static struct { } bq27xxx_battery_props[] = { BQ27XXX_PROP(BQ27000, bq27000_battery_props), BQ27XXX_PROP(BQ27010, bq27010_battery_props), + BQ27XXX_PROP(BQ2750X, bq2750x_battery_props), + BQ27XXX_PROP(BQ2751X, bq2751x_battery_props), BQ27XXX_PROP(BQ27500, bq27500_battery_props), - BQ27XXX_PROP(BQ27510, bq27510_battery_props), + BQ27XXX_PROP(BQ27510G1, bq27510g1_battery_props), + BQ27XXX_PROP(BQ27510G2, bq27510g2_battery_props), + BQ27XXX_PROP(BQ27510G3, bq27510g3_battery_props), + BQ27XXX_PROP(BQ27520G1, bq27520g1_battery_props), + BQ27XXX_PROP(BQ27520G2, bq27520g2_battery_props), + BQ27XXX_PROP(BQ27520G3, bq27520g3_battery_props), + BQ27XXX_PROP(BQ27520G4, bq27520g4_battery_props), BQ27XXX_PROP(BQ27530, bq27530_battery_props), BQ27XXX_PROP(BQ27541, bq27541_battery_props), BQ27XXX_PROP(BQ27545, bq27545_battery_props), @@ -674,13 +999,26 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) */ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) { - if (di->chip == BQ27500 || di->chip == BQ27510 || - di->chip == BQ27541 || di->chip == BQ27545) + switch (di->chip) { + case BQ2750X: + case BQ2751X: + case BQ27500: + case BQ27510G1: + case BQ27510G2: + case BQ27510G3: + case BQ27520G1: + case BQ27520G2: + case BQ27520G3: + case BQ27520G4: + case BQ27541: + case BQ27545: return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); - if (di->chip == BQ27530 || di->chip == BQ27421) + case BQ27530: + case BQ27421: return flags & BQ27XXX_FLAG_OT; - - return false; + default: + return false; + } } /* diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 5c5c3a6f9923..c68fbc3fe50a 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -148,9 +148,17 @@ static int bq27xxx_battery_i2c_remove(struct i2c_client *client) static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27200", BQ27000 }, { "bq27210", BQ27010 }, - { "bq27500", BQ27500 }, - { "bq27510", BQ27510 }, - { "bq27520", BQ27510 }, + { "bq27500", BQ2750X }, + { "bq27510", BQ2751X }, + { "bq27520", BQ2751X }, + { "bq27500-1", BQ27500 }, + { "bq27510g1", BQ27510G1 }, + { "bq27510g2", BQ27510G2 }, + { "bq27510g3", BQ27510G3 }, + { "bq27520g1", BQ27520G1 }, + { "bq27520g2", BQ27520G2 }, + { "bq27520g3", BQ27520G3 }, + { "bq27520g4", BQ27520G4 }, { "bq27530", BQ27530 }, { "bq27531", BQ27530 }, { "bq27541", BQ27541 }, @@ -173,6 +181,14 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { { .compatible = "ti,bq27500" }, { .compatible = "ti,bq27510" }, { .compatible = "ti,bq27520" }, + { .compatible = "ti,bq27500-1" }, + { .compatible = "ti,bq27510g1" }, + { .compatible = "ti,bq27510g2" }, + { .compatible = "ti,bq27510g3" }, + { .compatible = "ti,bq27520g1" }, + { .compatible = "ti,bq27520g2" }, + { .compatible = "ti,bq27520g3" }, + { .compatible = "ti,bq27520g4" }, { .compatible = "ti,bq27530" }, { .compatible = "ti,bq27531" }, { .compatible = "ti,bq27541" }, diff --git a/drivers/power/supply/gpio-charger.c b/drivers/power/supply/gpio-charger.c index c5869b1941ac..001731e88718 100644 --- a/drivers/power/supply/gpio-charger.c +++ b/drivers/power/supply/gpio-charger.c @@ -14,7 +14,7 @@ */ #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio.h> /* For legacy platform data */ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -23,7 +23,7 @@ #include <linux/power_supply.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/of_gpio.h> +#include <linux/gpio/consumer.h> #include <linux/power/gpio-charger.h> @@ -34,6 +34,8 @@ struct gpio_charger { struct power_supply *charger; struct power_supply_desc charger_desc; + struct gpio_desc *gpiod; + bool legacy_gpio_requested; }; static irqreturn_t gpio_charger_irq(int irq, void *devid) @@ -58,7 +60,8 @@ static int gpio_charger_get_property(struct power_supply *psy, switch (psp) { case POWER_SUPPLY_PROP_ONLINE: - val->intval = !!gpio_get_value_cansleep(pdata->gpio); + val->intval = gpiod_get_value_cansleep(gpio_charger->gpiod); + /* This xor is only ever used with legacy pdata GPIO */ val->intval ^= pdata->gpio_active_low; break; default: @@ -78,7 +81,6 @@ struct gpio_charger_platform_data *gpio_charger_parse_dt(struct device *dev) struct device_node *np = dev->of_node; struct gpio_charger_platform_data *pdata; const char *chargetype; - enum of_gpio_flags flags; int ret; if (!np) @@ -89,16 +91,6 @@ struct gpio_charger_platform_data *gpio_charger_parse_dt(struct device *dev) return ERR_PTR(-ENOMEM); pdata->name = np->name; - - pdata->gpio = of_get_gpio_flags(np, 0, &flags); - if (pdata->gpio < 0) { - if (pdata->gpio != -EPROBE_DEFER) - dev_err(dev, "could not get charger gpio\n"); - return ERR_PTR(pdata->gpio); - } - - pdata->gpio_active_low = !!(flags & OF_GPIO_ACTIVE_LOW); - pdata->type = POWER_SUPPLY_TYPE_UNKNOWN; ret = of_property_read_string(np, "charger-type", &chargetype); if (ret >= 0) { @@ -144,11 +136,6 @@ static int gpio_charger_probe(struct platform_device *pdev) } } - if (!gpio_is_valid(pdata->gpio)) { - dev_err(&pdev->dev, "Invalid gpio pin\n"); - return -EINVAL; - } - gpio_charger = devm_kzalloc(&pdev->dev, sizeof(*gpio_charger), GFP_KERNEL); if (!gpio_charger) { @@ -156,6 +143,45 @@ static int gpio_charger_probe(struct platform_device *pdev) return -ENOMEM; } + /* + * This will fetch a GPIO descriptor from device tree, ACPI or + * boardfile descriptor tables. It's good to try this first. + */ + gpio_charger->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN); + + /* + * If this fails and we're not using device tree, try the + * legacy platform data method. + */ + if (IS_ERR(gpio_charger->gpiod) && !pdev->dev.of_node) { + /* Non-DT: use legacy GPIO numbers */ + if (!gpio_is_valid(pdata->gpio)) { + dev_err(&pdev->dev, "Invalid gpio pin in pdata\n"); + return -EINVAL; + } + ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); + if (ret) { + dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", + ret); + return ret; + } + gpio_charger->legacy_gpio_requested = true; + ret = gpio_direction_input(pdata->gpio); + if (ret) { + dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", + ret); + goto err_gpio_free; + } + /* Then convert this to gpiod for now */ + gpio_charger->gpiod = gpio_to_desc(pdata->gpio); + } else if (IS_ERR(gpio_charger->gpiod)) { + /* Just try again if this happens */ + if (PTR_ERR(gpio_charger->gpiod) == -EPROBE_DEFER) + return -EPROBE_DEFER; + dev_err(&pdev->dev, "error getting GPIO descriptor\n"); + return PTR_ERR(gpio_charger->gpiod); + } + charger_desc = &gpio_charger->charger_desc; charger_desc->name = pdata->name ? pdata->name : "gpio-charger"; @@ -169,17 +195,6 @@ static int gpio_charger_probe(struct platform_device *pdev) psy_cfg.of_node = pdev->dev.of_node; psy_cfg.drv_data = gpio_charger; - ret = gpio_request(pdata->gpio, dev_name(&pdev->dev)); - if (ret) { - dev_err(&pdev->dev, "Failed to request gpio pin: %d\n", ret); - goto err_free; - } - ret = gpio_direction_input(pdata->gpio); - if (ret) { - dev_err(&pdev->dev, "Failed to set gpio to input: %d\n", ret); - goto err_gpio_free; - } - gpio_charger->pdata = pdata; gpio_charger->charger = power_supply_register(&pdev->dev, @@ -191,7 +206,7 @@ static int gpio_charger_probe(struct platform_device *pdev) goto err_gpio_free; } - irq = gpio_to_irq(pdata->gpio); + irq = gpiod_to_irq(gpio_charger->gpiod); if (irq > 0) { ret = request_any_context_irq(irq, gpio_charger_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, @@ -209,8 +224,8 @@ static int gpio_charger_probe(struct platform_device *pdev) return 0; err_gpio_free: - gpio_free(pdata->gpio); -err_free: + if (gpio_charger->legacy_gpio_requested) + gpio_free(pdata->gpio); return ret; } @@ -223,7 +238,8 @@ static int gpio_charger_remove(struct platform_device *pdev) power_supply_unregister(gpio_charger->charger); - gpio_free(gpio_charger->pdata->gpio); + if (gpio_charger->legacy_gpio_requested) + gpio_free(gpio_charger->pdata->gpio); return 0; } diff --git a/drivers/power/supply/intel_mid_battery.c b/drivers/power/supply/intel_mid_battery.c deleted file mode 100644 index dc7feef1bea4..000000000000 --- a/drivers/power/supply/intel_mid_battery.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - * intel_mid_battery.c - Intel MID PMIC Battery Driver - * - * Copyright (C) 2009 Intel Corporation - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * Author: Nithish Mahalingam <nithish.mahalingam@intel.com> - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/workqueue.h> -#include <linux/jiffies.h> -#include <linux/param.h> -#include <linux/device.h> -#include <linux/spi/spi.h> -#include <linux/platform_device.h> -#include <linux/power_supply.h> - -#include <asm/intel_scu_ipc.h> - -#define DRIVER_NAME "pmic_battery" - -/********************************************************************* - * Generic defines - *********************************************************************/ - -static int debug; -module_param(debug, int, 0444); -MODULE_PARM_DESC(debug, "Flag to enable PMIC Battery debug messages."); - -#define PMIC_BATT_DRV_INFO_UPDATED 1 -#define PMIC_BATT_PRESENT 1 -#define PMIC_BATT_NOT_PRESENT 0 -#define PMIC_USB_PRESENT PMIC_BATT_PRESENT -#define PMIC_USB_NOT_PRESENT PMIC_BATT_NOT_PRESENT - -/* pmic battery register related */ -#define PMIC_BATT_CHR_SCHRGINT_ADDR 0xD2 -#define PMIC_BATT_CHR_SBATOVP_MASK (1 << 1) -#define PMIC_BATT_CHR_STEMP_MASK (1 << 2) -#define PMIC_BATT_CHR_SCOMP_MASK (1 << 3) -#define PMIC_BATT_CHR_SUSBDET_MASK (1 << 4) -#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 0x86 - -#define PMIC_BATT_ADC_ACCCHRG_MASK (1 << 31) -#define PMIC_BATT_ADC_ACCCHRGVAL_MASK 0x7FFFFFFF - -/* pmic ipc related */ -#define PMIC_BATT_CHR_IPC_FCHRG_SUBID 0x4 -#define PMIC_BATT_CHR_IPC_TCHRG_SUBID 0x6 - -/* types of battery charging */ -enum batt_charge_type { - BATT_USBOTG_500MA_CHARGE, - BATT_USBOTG_TRICKLE_CHARGE, -}; - -/* valid battery events */ -enum batt_event { - BATT_EVENT_BATOVP_EXCPT, - BATT_EVENT_USBOVP_EXCPT, - BATT_EVENT_TEMP_EXCPT, - BATT_EVENT_DCLMT_EXCPT, - BATT_EVENT_EXCPT -}; - - -/********************************************************************* - * Battery properties - *********************************************************************/ - -/* - * pmic battery info - */ -struct pmic_power_module_info { - bool is_dev_info_updated; - struct device *dev; - /* pmic battery data */ - unsigned long update_time; /* jiffies when data read */ - unsigned int usb_is_present; - unsigned int batt_is_present; - unsigned int batt_health; - unsigned int usb_health; - unsigned int batt_status; - unsigned int batt_charge_now; /* in mAS */ - unsigned int batt_prev_charge_full; /* in mAS */ - unsigned int batt_charge_rate; /* in units per second */ - - struct power_supply *usb; - struct power_supply *batt; - int irq; /* GPE_ID or IRQ# */ - struct workqueue_struct *monitor_wqueue; - struct delayed_work monitor_battery; - struct work_struct handler; -}; - -static unsigned int delay_time = 2000; /* in ms */ - -/* - * pmic ac properties - */ -static enum power_supply_property pmic_usb_props[] = { - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_HEALTH, -}; - -/* - * pmic battery properties - */ -static enum power_supply_property pmic_battery_props[] = { - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CHARGE_FULL, -}; - - -/* - * Glue functions for talking to the IPC - */ - -struct battery_property { - u32 capacity; /* Charger capacity */ - u8 crnt; /* Quick charge current value*/ - u8 volt; /* Fine adjustment of constant charge voltage */ - u8 prot; /* CHRGPROT register value */ - u8 prot2; /* CHRGPROT1 register value */ - u8 timer; /* Charging timer */ -}; - -#define IPCMSG_BATTERY 0xEF - -/* Battery coulomb counter accumulator commands */ -#define IPC_CMD_CC_WR 0 /* Update coulomb counter value */ -#define IPC_CMD_CC_RD 1 /* Read coulomb counter value */ -#define IPC_CMD_BATTERY_PROPERTY 2 /* Read Battery property */ - -/** - * pmic_scu_ipc_battery_cc_read - read battery cc - * @value: battery coulomb counter read - * - * Reads the battery couloumb counter value, returns 0 on success, or - * an error code - * - * This function may sleep. Locking for SCU accesses is handled for - * the caller. - */ -static int pmic_scu_ipc_battery_cc_read(u32 *value) -{ - return intel_scu_ipc_command(IPCMSG_BATTERY, IPC_CMD_CC_RD, - NULL, 0, value, 1); -} - -/** - * pmic_scu_ipc_battery_property_get - fetch properties - * @prop: battery properties - * - * Retrieve the battery properties from the power management - * - * This function may sleep. Locking for SCU accesses is handled for - * the caller. - */ -static int pmic_scu_ipc_battery_property_get(struct battery_property *prop) -{ - u32 data[3]; - u8 *p = (u8 *)&data[1]; - int err = intel_scu_ipc_command(IPCMSG_BATTERY, - IPC_CMD_BATTERY_PROPERTY, NULL, 0, data, 3); - - prop->capacity = data[0]; - prop->crnt = *p++; - prop->volt = *p++; - prop->prot = *p++; - prop->prot2 = *p++; - prop->timer = *p++; - - return err; -} - -/** - * pmic_scu_ipc_set_charger - set charger - * @charger: charger to select - * - * Switch the charging mode for the SCU - */ - -static int pmic_scu_ipc_set_charger(int charger) -{ - return intel_scu_ipc_simple_command(IPCMSG_BATTERY, charger); -} - -/** - * pmic_battery_log_event - log battery events - * @event: battery event to be logged - * Context: can sleep - * - * There are multiple battery events which may be of interest to users; - * this battery function logs the different battery events onto the - * kernel log messages. - */ -static void pmic_battery_log_event(enum batt_event event) -{ - printk(KERN_WARNING "pmic-battery: "); - switch (event) { - case BATT_EVENT_BATOVP_EXCPT: - printk(KERN_CONT "battery overvoltage condition\n"); - break; - case BATT_EVENT_USBOVP_EXCPT: - printk(KERN_CONT "usb charger overvoltage condition\n"); - break; - case BATT_EVENT_TEMP_EXCPT: - printk(KERN_CONT "high battery temperature condition\n"); - break; - case BATT_EVENT_DCLMT_EXCPT: - printk(KERN_CONT "over battery charge current condition\n"); - break; - default: - printk(KERN_CONT "charger/battery exception %d\n", event); - break; - } -} - -/** - * pmic_battery_read_status - read battery status information - * @pbi: device info structure to update the read information - * Context: can sleep - * - * PMIC power source information need to be updated based on the data read - * from the PMIC battery registers. - * - */ -static void pmic_battery_read_status(struct pmic_power_module_info *pbi) -{ - unsigned int update_time_intrvl; - unsigned int chrg_val; - u32 ccval; - u8 r8; - struct battery_property batt_prop; - int batt_present = 0; - int usb_present = 0; - int batt_exception = 0; - - /* make sure the last batt_status read happened delay_time before */ - if (pbi->update_time && time_before(jiffies, pbi->update_time + - msecs_to_jiffies(delay_time))) - return; - - update_time_intrvl = jiffies_to_msecs(jiffies - pbi->update_time); - pbi->update_time = jiffies; - - /* read coulomb counter registers and schrgint register */ - if (pmic_scu_ipc_battery_cc_read(&ccval)) { - dev_warn(pbi->dev, "%s(): ipc config cmd failed\n", - __func__); - return; - } - - if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) { - dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", - __func__); - return; - } - - /* - * set pmic_power_module_info members based on pmic register values - * read. - */ - - /* set batt_is_present */ - if (r8 & PMIC_BATT_CHR_SBATDET_MASK) { - pbi->batt_is_present = PMIC_BATT_PRESENT; - batt_present = 1; - } else { - pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; - pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; - pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; - } - - /* set batt_health */ - if (batt_present) { - if (r8 & PMIC_BATT_CHR_SBATOVP_MASK) { - pbi->batt_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - 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_STEMP_MASK) { - pbi->batt_health = POWER_SUPPLY_HEALTH_OVERHEAT; - pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - pmic_battery_log_event(BATT_EVENT_TEMP_EXCPT); - 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); - } - } - } - - /* set usb_is_present */ - if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) { - pbi->usb_is_present = PMIC_USB_PRESENT; - usb_present = 1; - } else { - pbi->usb_is_present = PMIC_USB_NOT_PRESENT; - pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; - } - - if (usb_present) { - if (r8 & PMIC_BATT_CHR_SUSBOVP_MASK) { - pbi->usb_health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; - pmic_battery_log_event(BATT_EVENT_USBOVP_EXCPT); - } else { - pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; - } - } - - chrg_val = ccval & PMIC_BATT_ADC_ACCCHRGVAL_MASK; - - /* set batt_prev_charge_full to battery capacity the first time */ - if (!pbi->is_dev_info_updated) { - if (pmic_scu_ipc_battery_property_get(&batt_prop)) { - dev_warn(pbi->dev, "%s(): ipc config cmd failed\n", - __func__); - return; - } - pbi->batt_prev_charge_full = batt_prop.capacity; - } - - /* set batt_status */ - if (batt_present && !batt_exception) { - if (r8 & PMIC_BATT_CHR_SCOMP_MASK) { - pbi->batt_status = POWER_SUPPLY_STATUS_FULL; - pbi->batt_prev_charge_full = chrg_val; - } else if (ccval & PMIC_BATT_ADC_ACCCHRG_MASK) { - pbi->batt_status = POWER_SUPPLY_STATUS_DISCHARGING; - } else { - pbi->batt_status = POWER_SUPPLY_STATUS_CHARGING; - } - } - - /* set batt_charge_rate */ - if (pbi->is_dev_info_updated && batt_present && !batt_exception) { - if (pbi->batt_status == POWER_SUPPLY_STATUS_DISCHARGING) { - if (pbi->batt_charge_now - chrg_val) { - pbi->batt_charge_rate = ((pbi->batt_charge_now - - chrg_val) * 1000 * 60) / - update_time_intrvl; - } - } else if (pbi->batt_status == POWER_SUPPLY_STATUS_CHARGING) { - if (chrg_val - pbi->batt_charge_now) { - pbi->batt_charge_rate = ((chrg_val - - pbi->batt_charge_now) * 1000 * 60) / - update_time_intrvl; - } - } else - pbi->batt_charge_rate = 0; - } else { - pbi->batt_charge_rate = -1; - } - - /* batt_charge_now */ - if (batt_present && !batt_exception) - pbi->batt_charge_now = chrg_val; - else - pbi->batt_charge_now = -1; - - pbi->is_dev_info_updated = PMIC_BATT_DRV_INFO_UPDATED; -} - -/** - * pmic_usb_get_property - usb power source get property - * @psy: usb power supply context - * @psp: usb power source property - * @val: usb power source property value - * Context: can sleep - * - * PMIC usb power source property needs to be provided to power_supply - * subsytem for it to provide the information to users. - */ -static int pmic_usb_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct pmic_power_module_info *pbi = power_supply_get_drvdata(psy); - - /* update pmic_power_module_info members */ - pmic_battery_read_status(pbi); - - switch (psp) { - case POWER_SUPPLY_PROP_PRESENT: - val->intval = pbi->usb_is_present; - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = pbi->usb_health; - break; - default: - return -EINVAL; - } - - return 0; -} - -static inline unsigned long mAStouAh(unsigned long v) -{ - /* seconds to hours, mA to µA */ - return (v * 1000) / 3600; -} - -/** - * pmic_battery_get_property - battery power source get property - * @psy: battery power supply context - * @psp: battery power source property - * @val: battery power source property value - * Context: can sleep - * - * PMIC battery power source property needs to be provided to power_supply - * subsytem for it to provide the information to users. - */ -static int pmic_battery_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) -{ - struct pmic_power_module_info *pbi = power_supply_get_drvdata(psy); - - /* update pmic_power_module_info members */ - pmic_battery_read_status(pbi); - - switch (psp) { - case POWER_SUPPLY_PROP_STATUS: - val->intval = pbi->batt_status; - break; - case POWER_SUPPLY_PROP_HEALTH: - val->intval = pbi->batt_health; - break; - case POWER_SUPPLY_PROP_PRESENT: - val->intval = pbi->batt_is_present; - break; - case POWER_SUPPLY_PROP_CHARGE_NOW: - val->intval = mAStouAh(pbi->batt_charge_now); - break; - case POWER_SUPPLY_PROP_CHARGE_FULL: - val->intval = mAStouAh(pbi->batt_prev_charge_full); - break; - default: - return -EINVAL; - } - - return 0; -} - -/** - * pmic_battery_monitor - monitor battery status - * @work: work structure - * Context: can sleep - * - * PMIC battery status needs to be monitored for any change - * and information needs to be frequently updated. - */ -static void pmic_battery_monitor(struct work_struct *work) -{ - struct pmic_power_module_info *pbi = container_of(work, - struct pmic_power_module_info, monitor_battery.work); - - /* update pmic_power_module_info members */ - pmic_battery_read_status(pbi); - queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 10); -} - -/** - * pmic_battery_set_charger - set battery charger - * @pbi: device info structure - * @chrg: charge mode to set battery charger in - * Context: can sleep - * - * PMIC battery charger needs to be enabled based on the usb charge - * capabilities connected to the platform. - */ -static int pmic_battery_set_charger(struct pmic_power_module_info *pbi, - enum batt_charge_type chrg) -{ - int retval; - - /* set usblmt bits and chrgcntl register bits appropriately */ - switch (chrg) { - case BATT_USBOTG_500MA_CHARGE: - retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_FCHRG_SUBID); - break; - case BATT_USBOTG_TRICKLE_CHARGE: - retval = pmic_scu_ipc_set_charger(PMIC_BATT_CHR_IPC_TCHRG_SUBID); - break; - default: - dev_warn(pbi->dev, "%s(): out of range usb charger " - "charge detected\n", __func__); - return -EINVAL; - } - - if (retval) { - dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", - __func__); - return retval; - } - - return 0; -} - -/** - * pmic_battery_interrupt_handler - pmic battery interrupt handler - * Context: interrupt context - * - * PMIC battery interrupt handler which will be called with either - * battery full condition occurs or usb otg & battery connect - * condition occurs. - */ -static irqreturn_t pmic_battery_interrupt_handler(int id, void *dev) -{ - struct pmic_power_module_info *pbi = dev; - - schedule_work(&pbi->handler); - - return IRQ_HANDLED; -} - -/** - * pmic_battery_handle_intrpt - pmic battery service interrupt - * @work: work structure - * Context: can sleep - * - * PMIC battery needs to either update the battery status as full - * if it detects battery full condition caused the interrupt or needs - * to enable battery charger if it detects usb and battery detect - * caused the source of interrupt. - */ -static void pmic_battery_handle_intrpt(struct work_struct *work) -{ - struct pmic_power_module_info *pbi = container_of(work, - struct pmic_power_module_info, handler); - enum batt_charge_type chrg; - u8 r8; - - if (intel_scu_ipc_ioread8(PMIC_BATT_CHR_SCHRGINT_ADDR, &r8)) { - dev_warn(pbi->dev, "%s(): ipc pmic read failed\n", - __func__); - return; - } - /* find the cause of the interrupt */ - if (r8 & PMIC_BATT_CHR_SBATDET_MASK) { - pbi->batt_is_present = PMIC_BATT_PRESENT; - } else { - pbi->batt_is_present = PMIC_BATT_NOT_PRESENT; - pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; - pbi->batt_status = POWER_SUPPLY_STATUS_UNKNOWN; - return; - } - - if (r8 & PMIC_BATT_CHR_EXCPT_MASK) { - pbi->batt_health = POWER_SUPPLY_HEALTH_UNKNOWN; - pbi->batt_status = POWER_SUPPLY_STATUS_NOT_CHARGING; - pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; - pmic_battery_log_event(BATT_EVENT_EXCPT); - return; - } else { - pbi->batt_health = POWER_SUPPLY_HEALTH_GOOD; - pbi->usb_health = POWER_SUPPLY_HEALTH_GOOD; - } - - if (r8 & PMIC_BATT_CHR_SCOMP_MASK) { - u32 ccval; - pbi->batt_status = POWER_SUPPLY_STATUS_FULL; - - if (pmic_scu_ipc_battery_cc_read(&ccval)) { - dev_warn(pbi->dev, "%s(): ipc config cmd " - "failed\n", __func__); - return; - } - pbi->batt_prev_charge_full = ccval & - PMIC_BATT_ADC_ACCCHRGVAL_MASK; - return; - } - - if (r8 & PMIC_BATT_CHR_SUSBDET_MASK) { - pbi->usb_is_present = PMIC_USB_PRESENT; - } else { - pbi->usb_is_present = PMIC_USB_NOT_PRESENT; - pbi->usb_health = POWER_SUPPLY_HEALTH_UNKNOWN; - return; - } - - /* setup battery charging */ - -#if 0 - /* check usb otg power capability and set charger accordingly */ - retval = langwell_udc_maxpower(&power); - if (retval) { - dev_warn(pbi->dev, - "%s(): usb otg power query failed with error code %d\n", - __func__, retval); - return; - } - - if (power >= 500) - chrg = BATT_USBOTG_500MA_CHARGE; - else -#endif - chrg = BATT_USBOTG_TRICKLE_CHARGE; - - /* enable battery charging */ - if (pmic_battery_set_charger(pbi, chrg)) { - dev_warn(pbi->dev, - "%s(): failed to set up battery charging\n", __func__); - return; - } - - dev_dbg(pbi->dev, - "pmic-battery: %s() - setting up battery charger successful\n", - __func__); -} - -/* - * Description of power supplies - */ -static const struct power_supply_desc pmic_usb_desc = { - .name = "pmic-usb", - .type = POWER_SUPPLY_TYPE_USB, - .properties = pmic_usb_props, - .num_properties = ARRAY_SIZE(pmic_usb_props), - .get_property = pmic_usb_get_property, -}; - -static const struct power_supply_desc pmic_batt_desc = { - .name = "pmic-batt", - .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = pmic_battery_props, - .num_properties = ARRAY_SIZE(pmic_battery_props), - .get_property = pmic_battery_get_property, -}; - -/** - * pmic_battery_probe - pmic battery initialize - * @irq: pmic battery device irq - * @dev: pmic battery device structure - * Context: can sleep - * - * PMIC battery initializes its internal data structue and other - * infrastructure components for it to work as expected. - */ -static int probe(int irq, struct device *dev) -{ - int retval = 0; - struct pmic_power_module_info *pbi; - struct power_supply_config psy_cfg = {}; - - dev_dbg(dev, "pmic-battery: found pmic battery device\n"); - - pbi = kzalloc(sizeof(*pbi), GFP_KERNEL); - if (!pbi) { - dev_err(dev, "%s(): memory allocation failed\n", - __func__); - return -ENOMEM; - } - - pbi->dev = dev; - pbi->irq = irq; - dev_set_drvdata(dev, pbi); - psy_cfg.drv_data = pbi; - - /* initialize all required framework before enabling interrupts */ - INIT_WORK(&pbi->handler, pmic_battery_handle_intrpt); - INIT_DELAYED_WORK(&pbi->monitor_battery, pmic_battery_monitor); - pbi->monitor_wqueue = alloc_workqueue(dev_name(dev), WQ_MEM_RECLAIM, 0); - if (!pbi->monitor_wqueue) { - dev_err(dev, "%s(): wqueue init failed\n", __func__); - retval = -ESRCH; - goto wqueue_failed; - } - - /* register interrupt */ - retval = request_irq(pbi->irq, pmic_battery_interrupt_handler, - 0, DRIVER_NAME, pbi); - if (retval) { - dev_err(dev, "%s(): cannot get IRQ\n", __func__); - goto requestirq_failed; - } - - /* register pmic-batt with power supply subsystem */ - pbi->batt = power_supply_register(dev, &pmic_usb_desc, &psy_cfg); - if (IS_ERR(pbi->batt)) { - dev_err(dev, - "%s(): failed to register pmic battery device with power supply subsystem\n", - __func__); - retval = PTR_ERR(pbi->batt); - goto power_reg_failed; - } - - dev_dbg(dev, "pmic-battery: %s() - pmic battery device " - "registration with power supply subsystem successful\n", - __func__); - - queue_delayed_work(pbi->monitor_wqueue, &pbi->monitor_battery, HZ * 1); - - /* register pmic-usb with power supply subsystem */ - pbi->usb = power_supply_register(dev, &pmic_batt_desc, &psy_cfg); - if (IS_ERR(pbi->usb)) { - dev_err(dev, - "%s(): failed to register pmic usb device with power supply subsystem\n", - __func__); - retval = PTR_ERR(pbi->usb); - goto power_reg_failed_1; - } - - if (debug) - printk(KERN_INFO "pmic-battery: %s() - pmic usb device " - "registration with power supply subsystem successful\n", - __func__); - - return retval; - -power_reg_failed_1: - power_supply_unregister(pbi->batt); -power_reg_failed: - cancel_delayed_work_sync(&pbi->monitor_battery); -requestirq_failed: - destroy_workqueue(pbi->monitor_wqueue); -wqueue_failed: - kfree(pbi); - - return retval; -} - -static int platform_pmic_battery_probe(struct platform_device *pdev) -{ - return probe(pdev->id, &pdev->dev); -} - -/** - * pmic_battery_remove - pmic battery finalize - * @dev: pmic battery device structure - * Context: can sleep - * - * PMIC battery finalizes its internal data structue and other - * infrastructure components that it initialized in - * pmic_battery_probe. - */ - -static int platform_pmic_battery_remove(struct platform_device *pdev) -{ - struct pmic_power_module_info *pbi = platform_get_drvdata(pdev); - - free_irq(pbi->irq, pbi); - cancel_delayed_work_sync(&pbi->monitor_battery); - destroy_workqueue(pbi->monitor_wqueue); - - power_supply_unregister(pbi->usb); - power_supply_unregister(pbi->batt); - - cancel_work_sync(&pbi->handler); - kfree(pbi); - return 0; -} - -static struct platform_driver platform_pmic_battery_driver = { - .driver = { - .name = DRIVER_NAME, - }, - .probe = platform_pmic_battery_probe, - .remove = platform_pmic_battery_remove, -}; - -module_platform_driver(platform_pmic_battery_driver); - -MODULE_AUTHOR("Nithish Mahalingam <nithish.mahalingam@intel.com>"); -MODULE_DESCRIPTION("Intel Moorestown PMIC Battery Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/max14656_charger_detector.c b/drivers/power/supply/max14656_charger_detector.c new file mode 100644 index 000000000000..b91b1d2999dc --- /dev/null +++ b/drivers/power/supply/max14656_charger_detector.c @@ -0,0 +1,327 @@ +/* + * Maxim MAX14656 / AL32 USB Charger Detector driver + * + * Copyright (C) 2014 LG Electronics, Inc + * Copyright (C) 2016 Alexander Kurz <akurz@blala.de> + * + * Components from Maxim AL32 Charger detection Driver for MX50 Yoshi Board + * Copyright (C) Amazon Technologies Inc. All rights reserved. + * Manish Lachwani (lachwani@lab126.com) + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/of_gpio.h> +#include <linux/of_device.h> +#include <linux/workqueue.h> +#include <linux/power_supply.h> + +#define MAX14656_MANUFACTURER "Maxim Integrated" +#define MAX14656_NAME "max14656" + +#define MAX14656_DEVICE_ID 0x00 +#define MAX14656_INTERRUPT_1 0x01 +#define MAX14656_INTERRUPT_2 0x02 +#define MAX14656_STATUS_1 0x03 +#define MAX14656_STATUS_2 0x04 +#define MAX14656_INTMASK_1 0x05 +#define MAX14656_INTMASK_2 0x06 +#define MAX14656_CONTROL_1 0x07 +#define MAX14656_CONTROL_2 0x08 +#define MAX14656_CONTROL_3 0x09 + +#define DEVICE_VENDOR_MASK 0xf0 +#define DEVICE_REV_MASK 0x0f +#define INT_EN_REG_MASK BIT(4) +#define CHG_TYPE_INT_MASK BIT(0) +#define STATUS1_VB_VALID_MASK BIT(4) +#define STATUS1_CHG_TYPE_MASK 0xf +#define INT1_DCD_TIMEOUT_MASK BIT(7) +#define CONTROL1_DEFAULT 0x0d +#define CONTROL1_INT_EN BIT(4) +#define CONTROL1_INT_ACTIVE_HIGH BIT(5) +#define CONTROL1_EDGE BIT(7) +#define CONTROL2_DEFAULT 0x8e +#define CONTROL2_ADC_EN BIT(0) +#define CONTROL3_DEFAULT 0x8d + +enum max14656_chg_type { + MAX14656_NO_CHARGER = 0, + MAX14656_SDP_CHARGER, + MAX14656_CDP_CHARGER, + MAX14656_DCP_CHARGER, + MAX14656_APPLE_500MA_CHARGER, + MAX14656_APPLE_1A_CHARGER, + MAX14656_APPLE_2A_CHARGER, + MAX14656_SPECIAL_500MA_CHARGER, + MAX14656_APPLE_12W, + MAX14656_CHARGER_LAST +}; + +static const struct max14656_chg_type_props { + enum power_supply_type type; +} chg_type_props[] = { + { POWER_SUPPLY_TYPE_UNKNOWN }, + { POWER_SUPPLY_TYPE_USB }, + { POWER_SUPPLY_TYPE_USB_CDP }, + { POWER_SUPPLY_TYPE_USB_DCP }, + { POWER_SUPPLY_TYPE_USB_DCP }, + { POWER_SUPPLY_TYPE_USB_DCP }, + { POWER_SUPPLY_TYPE_USB_DCP }, + { POWER_SUPPLY_TYPE_USB_DCP }, + { POWER_SUPPLY_TYPE_USB }, +}; + +struct max14656_chip { + struct i2c_client *client; + struct power_supply *detect_psy; + struct power_supply_desc psy_desc; + struct delayed_work irq_work; + + int irq; + int online; +}; + +static int max14656_read_reg(struct i2c_client *client, int reg, u8 *val) +{ + s32 ret; + + ret = i2c_smbus_read_byte_data(client, reg); + if (ret < 0) { + dev_err(&client->dev, + "i2c read fail: can't read from %02x: %d\n", + reg, ret); + return ret; + } + *val = ret; + return 0; +} + +static int max14656_write_reg(struct i2c_client *client, int reg, u8 val) +{ + s32 ret; + + ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret < 0) { + dev_err(&client->dev, + "i2c write fail: can't write %02x to %02x: %d\n", + val, reg, ret); + return ret; + } + return 0; +} + +static int max14656_read_block_reg(struct i2c_client *client, u8 reg, + u8 length, u8 *val) +{ + int ret; + + ret = i2c_smbus_read_i2c_block_data(client, reg, length, val); + if (ret < 0) { + dev_err(&client->dev, "failed to block read reg 0x%x: %d\n", + reg, ret); + return ret; + } + + return 0; +} + +#define REG_TOTAL_NUM 5 +static void max14656_irq_worker(struct work_struct *work) +{ + struct max14656_chip *chip = + container_of(work, struct max14656_chip, irq_work.work); + + u8 buf[REG_TOTAL_NUM]; + u8 chg_type; + int ret = 0; + + ret = max14656_read_block_reg(chip->client, MAX14656_DEVICE_ID, + REG_TOTAL_NUM, buf); + + if ((buf[MAX14656_STATUS_1] & STATUS1_VB_VALID_MASK) && + (buf[MAX14656_STATUS_1] & STATUS1_CHG_TYPE_MASK)) { + chg_type = buf[MAX14656_STATUS_1] & STATUS1_CHG_TYPE_MASK; + if (chg_type < MAX14656_CHARGER_LAST) + chip->psy_desc.type = chg_type_props[chg_type].type; + else + chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN; + chip->online = 1; + } else { + chip->online = 0; + chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN; + } + + power_supply_changed(chip->detect_psy); +} + +static irqreturn_t max14656_irq(int irq, void *dev_id) +{ + struct max14656_chip *chip = dev_id; + + schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(100)); + + return IRQ_HANDLED; +} + +static int max14656_hw_init(struct max14656_chip *chip) +{ + uint8_t val = 0; + uint8_t rev; + struct i2c_client *client = chip->client; + + if (max14656_read_reg(client, MAX14656_DEVICE_ID, &val)) + return -ENODEV; + + if ((val & DEVICE_VENDOR_MASK) != 0x20) { + dev_err(&client->dev, "wrong vendor ID %d\n", + ((val & DEVICE_VENDOR_MASK) >> 4)); + return -ENODEV; + } + rev = val & DEVICE_REV_MASK; + + /* Turn on ADC_EN */ + if (max14656_write_reg(client, MAX14656_CONTROL_2, CONTROL2_ADC_EN)) + return -EINVAL; + + /* turn on interrupts and low power mode */ + if (max14656_write_reg(client, MAX14656_CONTROL_1, + CONTROL1_DEFAULT | + CONTROL1_INT_EN | + CONTROL1_INT_ACTIVE_HIGH | + CONTROL1_EDGE)) + return -EINVAL; + + if (max14656_write_reg(client, MAX14656_INTMASK_1, 0x3)) + return -EINVAL; + + if (max14656_write_reg(client, MAX14656_INTMASK_2, 0x1)) + return -EINVAL; + + dev_info(&client->dev, "detected revision %d\n", rev); + return 0; +} + +static int max14656_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct max14656_chip *chip = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + val->intval = chip->online; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = MAX14656_NAME; + break; + case POWER_SUPPLY_PROP_MANUFACTURER: + val->strval = MAX14656_MANUFACTURER; + break; + default: + return -EINVAL; + } + + return 0; +} + +static enum power_supply_property max14656_battery_props[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_MODEL_NAME, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + +static int max14656_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct device *dev = &client->dev; + struct power_supply_config psy_cfg = {}; + struct max14656_chip *chip; + int irq = client->irq; + int ret = 0; + + if (irq <= 0) { + dev_err(dev, "invalid irq number: %d\n", irq); + return -ENODEV; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(dev, "No support for SMBUS_BYTE_DATA\n"); + return -ENODEV; + } + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + psy_cfg.drv_data = chip; + chip->client = client; + chip->online = 0; + chip->psy_desc.name = MAX14656_NAME; + chip->psy_desc.type = POWER_SUPPLY_TYPE_UNKNOWN; + chip->psy_desc.properties = max14656_battery_props; + chip->psy_desc.num_properties = ARRAY_SIZE(max14656_battery_props); + chip->psy_desc.get_property = max14656_get_property; + chip->irq = irq; + + ret = max14656_hw_init(chip); + if (ret) + return -ENODEV; + + INIT_DELAYED_WORK(&chip->irq_work, max14656_irq_worker); + + ret = devm_request_irq(dev, chip->irq, max14656_irq, + IRQF_TRIGGER_FALLING, + MAX14656_NAME, chip); + if (ret) { + dev_err(dev, "request_irq %d failed\n", chip->irq); + return -EINVAL; + } + enable_irq_wake(chip->irq); + + chip->detect_psy = devm_power_supply_register(dev, + &chip->psy_desc, &psy_cfg); + if (IS_ERR(chip->detect_psy)) { + dev_err(dev, "power_supply_register failed\n"); + return -EINVAL; + } + + schedule_delayed_work(&chip->irq_work, msecs_to_jiffies(2000)); + + return 0; +} + +static const struct i2c_device_id max14656_id[] = { + { "max14656", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, max14656_id); + +static const struct of_device_id max14656_match_table[] = { + { .compatible = "maxim,max14656", }, + {} +}; +MODULE_DEVICE_TABLE(of, max14656_match_table); + +static struct i2c_driver max14656_i2c_driver = { + .driver = { + .name = "max14656", + .of_match_table = max14656_match_table, + }, + .probe = max14656_probe, + .id_table = max14656_id, +}; +module_i2c_driver(max14656_i2c_driver); + +MODULE_DESCRIPTION("MAX14656 USB charger detector"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/max8997_charger.c b/drivers/power/supply/max8997_charger.c index 290ddc12b040..fa861003fece 100644 --- a/drivers/power/supply/max8997_charger.c +++ b/drivers/power/supply/max8997_charger.c @@ -148,10 +148,8 @@ static int max8997_battery_probe(struct platform_device *pdev) charger = devm_kzalloc(&pdev->dev, sizeof(struct charger_data), GFP_KERNEL); - if (charger == NULL) { - dev_err(&pdev->dev, "Cannot allocate memory.\n"); + if (!charger) return -ENOMEM; - } platform_set_drvdata(pdev, charger); @@ -161,7 +159,7 @@ static int max8997_battery_probe(struct platform_device *pdev) psy_cfg.drv_data = charger; - charger->battery = power_supply_register(&pdev->dev, + charger->battery = devm_power_supply_register(&pdev->dev, &max8997_battery_desc, &psy_cfg); if (IS_ERR(charger->battery)) { @@ -172,14 +170,6 @@ static int max8997_battery_probe(struct platform_device *pdev) return 0; } -static int max8997_battery_remove(struct platform_device *pdev) -{ - struct charger_data *charger = platform_get_drvdata(pdev); - - power_supply_unregister(charger->battery); - return 0; -} - static const struct platform_device_id max8997_battery_id[] = { { "max8997-battery", 0 }, { } @@ -191,7 +181,6 @@ static struct platform_driver max8997_battery_driver = { .name = "max8997-battery", }, .probe = max8997_battery_probe, - .remove = max8997_battery_remove, .id_table = max8997_battery_id, }; diff --git a/drivers/power/supply/pcf50633-charger.c b/drivers/power/supply/pcf50633-charger.c index d05597b4e40f..b3c1873ad84d 100644 --- a/drivers/power/supply/pcf50633-charger.c +++ b/drivers/power/supply/pcf50633-charger.c @@ -393,7 +393,6 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) { struct power_supply_config psy_cfg = {}; struct pcf50633_mbc *mbc; - int ret; int i; u8 mbcs1; @@ -419,8 +418,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) &psy_cfg); if (IS_ERR(mbc->adapter)) { dev_err(mbc->pcf->dev, "failed to register adapter\n"); - ret = PTR_ERR(mbc->adapter); - return ret; + return PTR_ERR(mbc->adapter); } mbc->usb = power_supply_register(&pdev->dev, &pcf50633_mbc_usb_desc, @@ -428,8 +426,7 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) if (IS_ERR(mbc->usb)) { dev_err(mbc->pcf->dev, "failed to register usb\n"); power_supply_unregister(mbc->adapter); - ret = PTR_ERR(mbc->usb); - return ret; + return PTR_ERR(mbc->usb); } mbc->ac = power_supply_register(&pdev->dev, &pcf50633_mbc_ac_desc, @@ -438,12 +435,10 @@ static int pcf50633_mbc_probe(struct platform_device *pdev) dev_err(mbc->pcf->dev, "failed to register ac\n"); power_supply_unregister(mbc->adapter); power_supply_unregister(mbc->usb); - ret = PTR_ERR(mbc->ac); - return ret; + return PTR_ERR(mbc->ac); } - ret = sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group); - if (ret) + if (sysfs_create_group(&pdev->dev.kobj, &mbc_attr_group)) dev_err(mbc->pcf->dev, "failed to create sysfs entries\n"); mbcs1 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS1); diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index b5896ba2a602..f6a0d245731d 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -35,6 +35,7 @@ #include <linux/regmap.h> #include <linux/slab.h> #include <linux/extcon.h> +#include <linux/regulator/driver.h> #define SMBB_CHG_VMAX 0x040 #define SMBB_CHG_VSAFE 0x041 @@ -72,6 +73,8 @@ #define BTC_CTRL_HOT_EXT_N BIT(0) #define SMBB_USB_IMAX 0x344 +#define SMBB_USB_OTG_CTL 0x348 +#define OTG_CTL_EN BIT(0) #define SMBB_USB_ENUM_TIMER_STOP 0x34e #define ENUM_TIMER_STOP BIT(0) #define SMBB_USB_SEC_ACCESS 0x3d0 @@ -125,6 +128,9 @@ struct smbb_charger { struct power_supply *dc_psy; struct power_supply *bat_psy; struct regmap *regmap; + + struct regulator_desc otg_rdesc; + struct regulator_dev *otg_reg; }; static const unsigned int smbb_usb_extcon_cable[] = { @@ -378,7 +384,7 @@ static irqreturn_t smbb_usb_valid_handler(int irq, void *_data) struct smbb_charger *chg = _data; smbb_set_line_flag(chg, irq, STATUS_USBIN_VALID); - extcon_set_cable_state_(chg->edev, EXTCON_USB, + extcon_set_state_sync(chg->edev, EXTCON_USB, chg->status & STATUS_USBIN_VALID); power_supply_changed(chg->usb_psy); @@ -787,12 +793,56 @@ static const struct power_supply_desc dc_psy_desc = { .property_is_writeable = smbb_charger_writable_property, }; +static int smbb_chg_otg_enable(struct regulator_dev *rdev) +{ + struct smbb_charger *chg = rdev_get_drvdata(rdev); + int rc; + + rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, + OTG_CTL_EN, OTG_CTL_EN); + if (rc) + dev_err(chg->dev, "failed to update OTG_CTL\n"); + return rc; +} + +static int smbb_chg_otg_disable(struct regulator_dev *rdev) +{ + struct smbb_charger *chg = rdev_get_drvdata(rdev); + int rc; + + rc = regmap_update_bits(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, + OTG_CTL_EN, 0); + if (rc) + dev_err(chg->dev, "failed to update OTG_CTL\n"); + return rc; +} + +static int smbb_chg_otg_is_enabled(struct regulator_dev *rdev) +{ + struct smbb_charger *chg = rdev_get_drvdata(rdev); + unsigned int value = 0; + int rc; + + rc = regmap_read(chg->regmap, chg->addr + SMBB_USB_OTG_CTL, &value); + if (rc) + dev_err(chg->dev, "failed to read OTG_CTL\n"); + + return !!(value & OTG_CTL_EN); +} + +static const struct regulator_ops smbb_chg_otg_ops = { + .enable = smbb_chg_otg_enable, + .disable = smbb_chg_otg_disable, + .is_enabled = smbb_chg_otg_is_enabled, +}; + static int smbb_charger_probe(struct platform_device *pdev) { struct power_supply_config bat_cfg = {}; struct power_supply_config usb_cfg = {}; struct power_supply_config dc_cfg = {}; struct smbb_charger *chg; + struct regulator_config config = { }; int rc, i; chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL); @@ -905,6 +955,26 @@ static int smbb_charger_probe(struct platform_device *pdev) } } + /* + * otg regulator is used to control VBUS voltage direction + * when USB switches between host and gadget mode + */ + chg->otg_rdesc.id = -1; + chg->otg_rdesc.name = "otg-vbus"; + chg->otg_rdesc.ops = &smbb_chg_otg_ops; + chg->otg_rdesc.owner = THIS_MODULE; + chg->otg_rdesc.type = REGULATOR_VOLTAGE; + chg->otg_rdesc.supply_name = "usb-otg-in"; + chg->otg_rdesc.of_match = "otg-vbus"; + + config.dev = &pdev->dev; + config.driver_data = chg; + + chg->otg_reg = devm_regulator_register(&pdev->dev, &chg->otg_rdesc, + &config); + if (IS_ERR(chg->otg_reg)) + return PTR_ERR(chg->otg_reg); + chg->jeita_ext_temp = of_property_read_bool(pdev->dev.of_node, "qcom,jeita-extended-temp-range"); diff --git a/drivers/power/supply/sbs-charger.c b/drivers/power/supply/sbs-charger.c new file mode 100644 index 000000000000..353765a5f44c --- /dev/null +++ b/drivers/power/supply/sbs-charger.c @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2016, Prodys S.L. + * + * 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 adds support for sbs-charger compilant chips as defined here: + * http://sbs-forum.org/specs/sbc110.pdf + * + * Implemetation based on sbs-battery.c + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/power_supply.h> +#include <linux/i2c.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/regmap.h> +#include <linux/of_gpio.h> +#include <linux/bitops.h> + +#define SBS_CHARGER_REG_SPEC_INFO 0x11 +#define SBS_CHARGER_REG_STATUS 0x13 +#define SBS_CHARGER_REG_ALARM_WARNING 0x16 + +#define SBS_CHARGER_STATUS_CHARGE_INHIBITED BIT(1) +#define SBS_CHARGER_STATUS_RES_COLD BIT(9) +#define SBS_CHARGER_STATUS_RES_HOT BIT(10) +#define SBS_CHARGER_STATUS_BATTERY_PRESENT BIT(14) +#define SBS_CHARGER_STATUS_AC_PRESENT BIT(15) + +#define SBS_CHARGER_POLL_TIME 500 + +struct sbs_info { + struct i2c_client *client; + struct power_supply *power_supply; + struct regmap *regmap; + struct delayed_work work; + unsigned int last_state; +}; + +static int sbs_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct sbs_info *chip = power_supply_get_drvdata(psy); + unsigned int reg; + + reg = chip->last_state; + + switch (psp) { + case POWER_SUPPLY_PROP_PRESENT: + val->intval = !!(reg & SBS_CHARGER_STATUS_BATTERY_PRESENT); + break; + + case POWER_SUPPLY_PROP_ONLINE: + val->intval = !!(reg & SBS_CHARGER_STATUS_AC_PRESENT); + break; + + case POWER_SUPPLY_PROP_STATUS: + val->intval = POWER_SUPPLY_STATUS_UNKNOWN; + + if (!(reg & SBS_CHARGER_STATUS_BATTERY_PRESENT)) + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + else if (reg & SBS_CHARGER_STATUS_AC_PRESENT && + !(reg & SBS_CHARGER_STATUS_CHARGE_INHIBITED)) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + + break; + + case POWER_SUPPLY_PROP_HEALTH: + if (reg & SBS_CHARGER_STATUS_RES_COLD) + val->intval = POWER_SUPPLY_HEALTH_COLD; + if (reg & SBS_CHARGER_STATUS_RES_HOT) + val->intval = POWER_SUPPLY_HEALTH_OVERHEAT; + else + val->intval = POWER_SUPPLY_HEALTH_GOOD; + + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int sbs_check_state(struct sbs_info *chip) +{ + unsigned int reg; + int ret; + + ret = regmap_read(chip->regmap, SBS_CHARGER_REG_STATUS, ®); + if (!ret && reg != chip->last_state) { + chip->last_state = reg; + power_supply_changed(chip->power_supply); + return 1; + } + + return 0; +} + +static void sbs_delayed_work(struct work_struct *work) +{ + struct sbs_info *chip = container_of(work, struct sbs_info, work.work); + + sbs_check_state(chip); + + schedule_delayed_work(&chip->work, + msecs_to_jiffies(SBS_CHARGER_POLL_TIME)); +} + +static irqreturn_t sbs_irq_thread(int irq, void *data) +{ + struct sbs_info *chip = data; + int ret; + + ret = sbs_check_state(chip); + + return ret ? IRQ_HANDLED : IRQ_NONE; +} + +static enum power_supply_property sbs_properties[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_HEALTH, +}; + +static bool sbs_readable_reg(struct device *dev, unsigned int reg) +{ + if (reg < SBS_CHARGER_REG_SPEC_INFO) + return false; + else + return true; +} + +static bool sbs_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case SBS_CHARGER_REG_STATUS: + return true; + } + + return false; +} + +static const struct regmap_config sbs_regmap = { + .reg_bits = 8, + .val_bits = 16, + .max_register = SBS_CHARGER_REG_ALARM_WARNING, + .readable_reg = sbs_readable_reg, + .volatile_reg = sbs_volatile_reg, + .val_format_endian = REGMAP_ENDIAN_LITTLE, /* since based on SMBus */ +}; + +static const struct power_supply_desc sbs_desc = { + .name = "sbs-charger", + .type = POWER_SUPPLY_TYPE_MAINS, + .properties = sbs_properties, + .num_properties = ARRAY_SIZE(sbs_properties), + .get_property = sbs_get_property, +}; + +static int sbs_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct power_supply_config psy_cfg = {}; + struct sbs_info *chip; + int ret, val; + + chip = devm_kzalloc(&client->dev, sizeof(struct sbs_info), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->client = client; + psy_cfg.of_node = client->dev.of_node; + psy_cfg.drv_data = chip; + + i2c_set_clientdata(client, chip); + + chip->regmap = devm_regmap_init_i2c(client, &sbs_regmap); + if (IS_ERR(chip->regmap)) + return PTR_ERR(chip->regmap); + + /* + * Before we register, we need to make sure we can actually talk + * to the battery. + */ + ret = regmap_read(chip->regmap, SBS_CHARGER_REG_STATUS, &val); + if (ret) { + dev_err(&client->dev, "Failed to get device status\n"); + return ret; + } + chip->last_state = val; + + chip->power_supply = devm_power_supply_register(&client->dev, &sbs_desc, + &psy_cfg); + if (IS_ERR(chip->power_supply)) { + dev_err(&client->dev, "Failed to register power supply\n"); + return PTR_ERR(chip->power_supply); + } + + /* + * The sbs-charger spec doesn't impose the use of an interrupt. So in + * the case it wasn't provided we use polling in order get the charger's + * status. + */ + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, + NULL, sbs_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + dev_name(&client->dev), chip); + if (ret) { + dev_err(&client->dev, "Failed to request irq, %d\n", ret); + return ret; + } + } else { + INIT_DELAYED_WORK(&chip->work, sbs_delayed_work); + schedule_delayed_work(&chip->work, + msecs_to_jiffies(SBS_CHARGER_POLL_TIME)); + } + + dev_info(&client->dev, + "%s: smart charger device registered\n", client->name); + + return 0; +} + +static int sbs_remove(struct i2c_client *client) +{ + struct sbs_info *chip = i2c_get_clientdata(client); + + cancel_delayed_work_sync(&chip->work); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id sbs_dt_ids[] = { + { .compatible = "sbs,sbs-charger" }, + { }, +}; +MODULE_DEVICE_TABLE(of, sbs_dt_ids); +#endif + +static const struct i2c_device_id sbs_id[] = { + { "sbs-charger", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, sbs_id); + +static struct i2c_driver sbs_driver = { + .probe = sbs_probe, + .remove = sbs_remove, + .id_table = sbs_id, + .driver = { + .name = "sbs-charger", + .of_match_table = of_match_ptr(sbs_dt_ids), + }, +}; +module_i2c_driver(sbs_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne <nicolassaenzj@gmail.com>"); +MODULE_DESCRIPTION("SBS smart charger driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/tps65217_charger.c b/drivers/power/supply/tps65217_charger.c index 9fd019f9b88c..29b61e81b385 100644 --- a/drivers/power/supply/tps65217_charger.c +++ b/drivers/power/supply/tps65217_charger.c @@ -35,22 +35,22 @@ #include <linux/mfd/core.h> #include <linux/mfd/tps65217.h> +#define CHARGER_STATUS_PRESENT (TPS65217_STATUS_ACPWR | TPS65217_STATUS_USBPWR) +#define NUM_CHARGER_IRQS 2 #define POLL_INTERVAL (HZ * 2) struct tps65217_charger { struct tps65217 *tps; struct device *dev; - struct power_supply *ac; + struct power_supply *psy; - int ac_online; - int prev_ac_online; + int online; + int prev_online; struct task_struct *poll_task; - - int irq; }; -static enum power_supply_property tps65217_ac_props[] = { +static enum power_supply_property tps65217_charger_props[] = { POWER_SUPPLY_PROP_ONLINE, }; @@ -95,7 +95,7 @@ static int tps65217_enable_charging(struct tps65217_charger *charger) int ret; /* charger already enabled */ - if (charger->ac_online) + if (charger->online) return 0; dev_dbg(charger->dev, "%s: enable charging\n", __func__); @@ -110,19 +110,19 @@ static int tps65217_enable_charging(struct tps65217_charger *charger) return ret; } - charger->ac_online = 1; + charger->online = 1; return 0; } -static int tps65217_ac_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val) +static int tps65217_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) { struct tps65217_charger *charger = power_supply_get_drvdata(psy); if (psp == POWER_SUPPLY_PROP_ONLINE) { - val->intval = charger->ac_online; + val->intval = charger->online; return 0; } return -EINVAL; @@ -133,7 +133,7 @@ static irqreturn_t tps65217_charger_irq(int irq, void *dev) int ret, val; struct tps65217_charger *charger = dev; - charger->prev_ac_online = charger->ac_online; + charger->prev_online = charger->online; ret = tps65217_reg_read(charger->tps, TPS65217_REG_STATUS, &val); if (ret < 0) { @@ -144,8 +144,8 @@ static irqreturn_t tps65217_charger_irq(int irq, void *dev) dev_dbg(charger->dev, "%s: 0x%x\n", __func__, val); - /* check for AC status bit */ - if (val & TPS65217_STATUS_ACPWR) { + /* check for charger status bit */ + if (val & CHARGER_STATUS_PRESENT) { ret = tps65217_enable_charging(charger); if (ret) { dev_err(charger->dev, @@ -153,11 +153,11 @@ static irqreturn_t tps65217_charger_irq(int irq, void *dev) return IRQ_HANDLED; } } else { - charger->ac_online = 0; + charger->online = 0; } - if (charger->prev_ac_online != charger->ac_online) - power_supply_changed(charger->ac); + if (charger->prev_online != charger->online) + power_supply_changed(charger->psy); ret = tps65217_reg_read(charger->tps, TPS65217_REG_CHGCONFIG0, &val); if (ret < 0) { @@ -188,11 +188,11 @@ static int tps65217_charger_poll_task(void *data) } static const struct power_supply_desc tps65217_charger_desc = { - .name = "tps65217-ac", + .name = "tps65217-charger", .type = POWER_SUPPLY_TYPE_MAINS, - .get_property = tps65217_ac_get_property, - .properties = tps65217_ac_props, - .num_properties = ARRAY_SIZE(tps65217_ac_props), + .get_property = tps65217_charger_get_property, + .properties = tps65217_charger_props, + .num_properties = ARRAY_SIZE(tps65217_charger_props), }; static int tps65217_charger_probe(struct platform_device *pdev) @@ -200,8 +200,10 @@ static int tps65217_charger_probe(struct platform_device *pdev) struct tps65217 *tps = dev_get_drvdata(pdev->dev.parent); struct tps65217_charger *charger; struct power_supply_config cfg = {}; - int irq; + struct task_struct *poll_task; + int irq[NUM_CHARGER_IRQS]; int ret; + int i; dev_dbg(&pdev->dev, "%s\n", __func__); @@ -216,18 +218,16 @@ static int tps65217_charger_probe(struct platform_device *pdev) cfg.of_node = pdev->dev.of_node; cfg.drv_data = charger; - charger->ac = devm_power_supply_register(&pdev->dev, - &tps65217_charger_desc, - &cfg); - if (IS_ERR(charger->ac)) { + charger->psy = devm_power_supply_register(&pdev->dev, + &tps65217_charger_desc, + &cfg); + if (IS_ERR(charger->psy)) { dev_err(&pdev->dev, "failed: power supply register\n"); - return PTR_ERR(charger->ac); + return PTR_ERR(charger->psy); } - irq = platform_get_irq_byname(pdev, "AC"); - if (irq < 0) - irq = -ENXIO; - charger->irq = irq; + irq[0] = platform_get_irq_byname(pdev, "USB"); + irq[1] = platform_get_irq_byname(pdev, "AC"); ret = tps65217_config_charger(charger); if (ret < 0) { @@ -235,29 +235,36 @@ static int tps65217_charger_probe(struct platform_device *pdev) return ret; } - if (irq != -ENXIO) { - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + /* Create a polling thread if an interrupt is invalid */ + if (irq[0] < 0 || irq[1] < 0) { + poll_task = kthread_run(tps65217_charger_poll_task, + charger, "ktps65217charger"); + if (IS_ERR(poll_task)) { + ret = PTR_ERR(poll_task); + dev_err(charger->dev, + "Unable to run kthread err %d\n", ret); + return ret; + } + + charger->poll_task = poll_task; + return 0; + } + + /* Create IRQ threads for charger interrupts */ + for (i = 0; i < NUM_CHARGER_IRQS; i++) { + ret = devm_request_threaded_irq(&pdev->dev, irq[i], NULL, tps65217_charger_irq, 0, "tps65217-charger", charger); if (ret) { dev_err(charger->dev, - "Unable to register irq %d err %d\n", irq, + "Unable to register irq %d err %d\n", irq[i], ret); return ret; } /* Check current state */ - tps65217_charger_irq(irq, charger); - } else { - charger->poll_task = kthread_run(tps65217_charger_poll_task, - charger, "ktps65217charger"); - if (IS_ERR(charger->poll_task)) { - ret = PTR_ERR(charger->poll_task); - dev_err(charger->dev, - "Unable to run kthread err %d\n", ret); - return ret; - } + tps65217_charger_irq(-1, charger); } return 0; @@ -267,7 +274,7 @@ static int tps65217_charger_remove(struct platform_device *pdev) { struct tps65217_charger *charger = platform_get_drvdata(pdev); - if (charger->irq == -ENXIO) + if (charger->poll_task) kthread_stop(charger->poll_task); return 0; diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index e3edb31ac880..bd4f66651513 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -175,11 +175,6 @@ static int wm97xx_bat_probe(struct platform_device *dev) if (dev->id != -1) return -EINVAL; - if (!pdata) { - dev_err(&dev->dev, "No platform_data supplied\n"); - return -EINVAL; - } - if (gpio_is_valid(pdata->charge_gpio)) { ret = gpio_request(pdata->charge_gpio, "BATT CHRG"); if (ret) diff --git a/drivers/regulator/88pm800.c b/drivers/regulator/88pm800.c index a62a89674fb5..89bbd6e8bad1 100644 --- a/drivers/regulator/88pm800.c +++ b/drivers/regulator/88pm800.c @@ -180,7 +180,7 @@ static int pm800_get_current_limit(struct regulator_dev *rdev) return info->max_ua; } -static struct regulator_ops pm800_volt_range_ops = { +static const struct regulator_ops pm800_volt_range_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -191,7 +191,7 @@ static struct regulator_ops pm800_volt_range_ops = { .get_current_limit = pm800_get_current_limit, }; -static struct regulator_ops pm800_volt_table_ops = { +static const struct regulator_ops pm800_volt_table_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_iterate, .set_voltage_sel = regulator_set_voltage_sel_regmap, diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c index b100a63ff3b3..fd86446e499b 100644 --- a/drivers/regulator/88pm8607.c +++ b/drivers/regulator/88pm8607.c @@ -220,7 +220,7 @@ static int pm8607_list_voltage(struct regulator_dev *rdev, unsigned index) return ret; } -static struct regulator_ops pm8607_regulator_ops = { +static const struct regulator_ops pm8607_regulator_ops = { .list_voltage = pm8607_list_voltage, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -229,7 +229,7 @@ static struct regulator_ops pm8607_regulator_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops pm8606_preg_ops = { +static const struct regulator_ops pm8606_preg_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 936f7ccc9736..be06eb29c681 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -163,6 +163,13 @@ config REGULATOR_BCM590XX BCM590xx PMUs. This will enable support for the software controllable LDO/Switching regulators. +config REGULATOR_CPCAP + tristate "Motorola CPCAP regulator" + depends on MFD_CPCAP + help + Say y here for CPCAP regulator found on some Motorola phones + and tablets such as Droid 4. + config REGULATOR_DA903X tristate "Dialog Semiconductor DA9030/DA9034 regulators" depends on PMIC_DA903X diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 14294692beb9..ef7725e2592a 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_REGULATOR_USERSPACE_CONSUMER) += userspace-consumer.o obj-$(CONFIG_REGULATOR_88PM800) += 88pm800.o obj-$(CONFIG_REGULATOR_88PM8607) += 88pm8607.o +obj-$(CONFIG_REGULATOR_CPCAP) += cpcap-regulator.o obj-$(CONFIG_REGULATOR_AAT2870) += aat2870-regulator.o obj-$(CONFIG_REGULATOR_AB3100) += ab3100.o obj-$(CONFIG_REGULATOR_AB8500) += ab8500-ext.o ab8500.o diff --git a/drivers/regulator/aat2870-regulator.c b/drivers/regulator/aat2870-regulator.c index 9dfabda8f478..afc5b5900181 100644 --- a/drivers/regulator/aat2870-regulator.c +++ b/drivers/regulator/aat2870-regulator.c @@ -97,7 +97,7 @@ static int aat2870_ldo_is_enabled(struct regulator_dev *rdev) return val & ri->enable_mask ? 1 : 0; } -static struct regulator_ops aat2870_ldo_ops = { +static const struct regulator_ops aat2870_ldo_ops = { .list_voltage = regulator_list_voltage_table, .map_voltage = regulator_map_voltage_ascend, .set_voltage_sel = aat2870_ldo_set_voltage_sel, diff --git a/drivers/regulator/act8945a-regulator.c b/drivers/regulator/act8945a-regulator.c index 441864b9fece..43fda8b4455a 100644 --- a/drivers/regulator/act8945a-regulator.c +++ b/drivers/regulator/act8945a-regulator.c @@ -69,7 +69,7 @@ static const struct regulator_linear_range act8945a_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(2400000, 48, 63, 100000), }; -static struct regulator_ops act8945a_ops = { +static const struct regulator_ops act8945a_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, diff --git a/drivers/regulator/ad5398.c b/drivers/regulator/ad5398.c index 8b0f788a9bbb..11c1f880b7bb 100644 --- a/drivers/regulator/ad5398.c +++ b/drivers/regulator/ad5398.c @@ -181,7 +181,7 @@ static int ad5398_disable(struct regulator_dev *rdev) return ret; } -static struct regulator_ops ad5398_ops = { +static const struct regulator_ops ad5398_ops = { .get_current_limit = ad5398_get_current_limit, .set_current_limit = ad5398_set_current_limit, .enable = ad5398_enable, diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c index 3a6d0290c54c..b041f277a38b 100644 --- a/drivers/regulator/anatop-regulator.c +++ b/drivers/regulator/anatop-regulator.c @@ -301,7 +301,19 @@ static int anatop_regulator_probe(struct platform_device *pdev) return -EINVAL; } } else { + u32 enable_bit; + rdesc->ops = &anatop_rops; + + if (!of_property_read_u32(np, "anatop-enable-bit", + &enable_bit)) { + anatop_rops.enable = regulator_enable_regmap; + anatop_rops.disable = regulator_disable_regmap; + anatop_rops.is_enabled = regulator_is_enabled_regmap; + + rdesc->enable_reg = sreg->control_reg; + rdesc->enable_mask = BIT(enable_bit); + } } /* register regulator */ diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c index 302b57cb89c6..e76d094591e7 100644 --- a/drivers/regulator/arizona-ldo1.c +++ b/drivers/regulator/arizona-ldo1.c @@ -109,7 +109,7 @@ static int arizona_ldo1_hc_get_voltage_sel(struct regulator_dev *rdev) return (val & ARIZONA_LDO1_VSEL_MASK) >> ARIZONA_LDO1_VSEL_SHIFT; } -static struct regulator_ops arizona_ldo1_hc_ops = { +static const struct regulator_ops arizona_ldo1_hc_ops = { .list_voltage = arizona_ldo1_hc_list_voltage, .map_voltage = arizona_ldo1_hc_map_voltage, .get_voltage_sel = arizona_ldo1_hc_get_voltage_sel, @@ -135,7 +135,7 @@ static const struct regulator_desc arizona_ldo1_hc = { .owner = THIS_MODULE, }; -static struct regulator_ops arizona_ldo1_ops = { +static const struct regulator_ops arizona_ldo1_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .get_voltage_sel = regulator_get_voltage_sel_regmap, diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c index fcb98dbda837..22bd71407622 100644 --- a/drivers/regulator/arizona-micsupp.c +++ b/drivers/regulator/arizona-micsupp.c @@ -45,6 +45,7 @@ static void arizona_micsupp_check_cp(struct work_struct *work) struct arizona_micsupp *micsupp = container_of(work, struct arizona_micsupp, check_cp_work); struct snd_soc_dapm_context *dapm = micsupp->arizona->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct arizona *arizona = micsupp->arizona; struct regmap *regmap = arizona->regmap; unsigned int reg; @@ -59,9 +60,10 @@ static void arizona_micsupp_check_cp(struct work_struct *work) if (dapm) { if ((reg & (ARIZONA_CPMIC_ENA | ARIZONA_CPMIC_BYPASS)) == ARIZONA_CPMIC_ENA) - snd_soc_dapm_force_enable_pin(dapm, "MICSUPP"); + snd_soc_component_force_enable_pin(component, + "MICSUPP"); else - snd_soc_dapm_disable_pin(dapm, "MICSUPP"); + snd_soc_component_disable_pin(component, "MICSUPP"); snd_soc_dapm_sync(dapm); } @@ -104,7 +106,7 @@ static int arizona_micsupp_set_bypass(struct regulator_dev *rdev, bool ena) return ret; } -static struct regulator_ops arizona_micsupp_ops = { +static const struct regulator_ops arizona_micsupp_ops = { .enable = arizona_micsupp_enable, .disable = arizona_micsupp_disable, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/as3711-regulator.c b/drivers/regulator/as3711-regulator.c index c0e93b1332f7..874d415d6b4f 100644 --- a/drivers/regulator/as3711-regulator.c +++ b/drivers/regulator/as3711-regulator.c @@ -82,7 +82,7 @@ static unsigned int as3711_get_mode_sd(struct regulator_dev *rdev) return -EINVAL; } -static struct regulator_ops as3711_sd_ops = { +static const struct regulator_ops as3711_sd_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -94,7 +94,7 @@ static struct regulator_ops as3711_sd_ops = { .set_mode = as3711_set_mode_sd, }; -static struct regulator_ops as3711_aldo_ops = { +static const struct regulator_ops as3711_aldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -104,7 +104,7 @@ static struct regulator_ops as3711_aldo_ops = { .map_voltage = regulator_map_voltage_linear_range, }; -static struct regulator_ops as3711_dldo_ops = { +static const struct regulator_ops as3711_dldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c index e6a512ebeae2..0b9d4e3e52c7 100644 --- a/drivers/regulator/axp20x-regulator.c +++ b/drivers/regulator/axp20x-regulator.c @@ -128,11 +128,11 @@ .ops = &axp20x_ops_range, \ } -static struct regulator_ops axp20x_ops_fixed = { +static const struct regulator_ops axp20x_ops_fixed = { .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_ops axp20x_ops_range = { +static const struct regulator_ops axp20x_ops_range = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear_range, @@ -141,7 +141,7 @@ static struct regulator_ops axp20x_ops_range = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops axp20x_ops = { +static const struct regulator_ops axp20x_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, @@ -150,7 +150,7 @@ static struct regulator_ops axp20x_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops axp20x_ops_sw = { +static const struct regulator_ops axp20x_ops_sw = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -272,7 +272,7 @@ static const struct regulator_desc axp806_regulators[] = { 64, AXP806_DCDCD_V_CTRL, 0x3f, AXP806_PWR_OUT_CTRL1, BIT(3)), AXP_DESC(AXP806, DCDCE, "dcdce", "vine", 1100, 3400, 100, - AXP806_DCDCB_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)), + AXP806_DCDCE_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(4)), AXP_DESC(AXP806, ALDO1, "aldo1", "aldoin", 700, 3300, 100, AXP806_ALDO1_V_CTRL, 0x1f, AXP806_PWR_OUT_CTRL1, BIT(5)), AXP_DESC(AXP806, ALDO2, "aldo2", "aldoin", 700, 3400, 100, diff --git a/drivers/regulator/bcm590xx-regulator.c b/drivers/regulator/bcm590xx-regulator.c index 76b01835dcb4..9dd715407b39 100644 --- a/drivers/regulator/bcm590xx-regulator.c +++ b/drivers/regulator/bcm590xx-regulator.c @@ -250,7 +250,7 @@ static int bcm590xx_get_enable_register(int id) return reg; } -static struct regulator_ops bcm590xx_ops_ldo = { +static const struct regulator_ops bcm590xx_ops_ldo = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -260,7 +260,7 @@ static struct regulator_ops bcm590xx_ops_ldo = { .map_voltage = regulator_map_voltage_iterate, }; -static struct regulator_ops bcm590xx_ops_dcdc = { +static const struct regulator_ops bcm590xx_ops_dcdc = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -270,7 +270,7 @@ static struct regulator_ops bcm590xx_ops_dcdc = { .map_voltage = regulator_map_voltage_linear_range, }; -static struct regulator_ops bcm590xx_ops_vbus = { +static const struct regulator_ops bcm590xx_ops_vbus = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 04baac9a165b..53d4fc70dbd0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1455,12 +1455,14 @@ static struct regulator_dev *regulator_lookup_by_name(const char *name) * lookup could succeed in the future. * * If successful, returns a struct regulator_dev that corresponds to the name - * @supply and with the embedded struct device refcount incremented by one, - * or NULL on failure. The refcount must be dropped by calling put_device(). + * @supply and with the embedded struct device refcount incremented by one. + * The refcount must be dropped by calling put_device(). + * On failure one of the following ERR-PTR-encoded values is returned: + * -ENODEV if lookup fails permanently, -EPROBE_DEFER if lookup could succeed + * in the future. */ static struct regulator_dev *regulator_dev_lookup(struct device *dev, - const char *supply, - int *ret) + const char *supply) { struct regulator_dev *r; struct device_node *node; @@ -1476,16 +1478,12 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, r = of_find_regulator_by_node(node); if (r) return r; - *ret = -EPROBE_DEFER; - return NULL; - } else { + /* - * If we couldn't even get the node then it's - * not just that the device didn't register - * yet, there's no node and we'll never - * succeed. + * We have a node, but there is no device. + * assume it has not registered yet. */ - *ret = -ENODEV; + return ERR_PTR(-EPROBE_DEFER); } } @@ -1506,13 +1504,16 @@ static struct regulator_dev *regulator_dev_lookup(struct device *dev, if (strcmp(map->supply, supply) == 0 && get_device(&map->regulator->dev)) { - mutex_unlock(®ulator_list_mutex); - return map->regulator; + r = map->regulator; + break; } } mutex_unlock(®ulator_list_mutex); - return NULL; + if (r) + return r; + + return ERR_PTR(-ENODEV); } static int regulator_resolve_supply(struct regulator_dev *rdev) @@ -1529,8 +1530,10 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) if (rdev->supply) return 0; - r = regulator_dev_lookup(dev, rdev->supply_name, &ret); - if (!r) { + r = regulator_dev_lookup(dev, rdev->supply_name); + if (IS_ERR(r)) { + ret = PTR_ERR(r); + if (ret == -ENODEV) { /* * No supply was specified for this regulator and @@ -1553,6 +1556,19 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) } } + /* + * If the supply's parent device is not the same as the + * regulator's parent device, then ensure the parent device + * is bound before we resolve the supply, in case the parent + * device get probe deferred and unregisters the supply. + */ + if (r->dev.parent && r->dev.parent != rdev->dev.parent) { + if (!device_is_bound(r->dev.parent)) { + put_device(&r->dev); + return -EPROBE_DEFER; + } + } + /* Recursively resolve the supply of the supply */ ret = regulator_resolve_supply(r); if (ret < 0) { @@ -1580,69 +1596,72 @@ static int regulator_resolve_supply(struct regulator_dev *rdev) } /* Internal regulator request function */ -static struct regulator *_regulator_get(struct device *dev, const char *id, - bool exclusive, bool allow_dummy) +struct regulator *_regulator_get(struct device *dev, const char *id, + enum regulator_get_type get_type) { struct regulator_dev *rdev; - struct regulator *regulator = ERR_PTR(-EPROBE_DEFER); - const char *devname = NULL; + struct regulator *regulator; + const char *devname = dev ? dev_name(dev) : "deviceless"; int ret; + if (get_type >= MAX_GET_TYPE) { + dev_err(dev, "invalid type %d in %s\n", get_type, __func__); + return ERR_PTR(-EINVAL); + } + if (id == NULL) { pr_err("get() with no identifier\n"); return ERR_PTR(-EINVAL); } - if (dev) - devname = dev_name(dev); + rdev = regulator_dev_lookup(dev, id); + if (IS_ERR(rdev)) { + ret = PTR_ERR(rdev); - if (have_full_constraints()) - ret = -ENODEV; - else - ret = -EPROBE_DEFER; - - rdev = regulator_dev_lookup(dev, id, &ret); - if (rdev) - goto found; - - regulator = ERR_PTR(ret); + /* + * If regulator_dev_lookup() fails with error other + * than -ENODEV our job here is done, we simply return it. + */ + if (ret != -ENODEV) + return ERR_PTR(ret); - /* - * If we have return value from dev_lookup fail, we do not expect to - * succeed, so, quit with appropriate error value - */ - if (ret && ret != -ENODEV) - return regulator; + if (!have_full_constraints()) { + dev_warn(dev, + "incomplete constraints, dummy supplies not allowed\n"); + return ERR_PTR(-ENODEV); + } - if (!devname) - devname = "deviceless"; + switch (get_type) { + case NORMAL_GET: + /* + * Assume that a regulator is physically present and + * enabled, even if it isn't hooked up, and just + * provide a dummy. + */ + dev_warn(dev, + "%s supply %s not found, using dummy regulator\n", + devname, id); + rdev = dummy_regulator_rdev; + get_device(&rdev->dev); + break; - /* - * Assume that a regulator is physically present and enabled - * even if it isn't hooked up and just provide a dummy. - */ - if (have_full_constraints() && allow_dummy) { - pr_warn("%s supply %s not found, using dummy regulator\n", - devname, id); + case EXCLUSIVE_GET: + dev_warn(dev, + "dummy supplies not allowed for exclusive requests\n"); + /* fall through */ - rdev = dummy_regulator_rdev; - get_device(&rdev->dev); - goto found; - /* Don't log an error when called from regulator_get_optional() */ - } else if (!have_full_constraints() || exclusive) { - dev_warn(dev, "dummy supplies not allowed\n"); + default: + return ERR_PTR(-ENODEV); + } } - return regulator; - -found: if (rdev->exclusive) { regulator = ERR_PTR(-EPERM); put_device(&rdev->dev); return regulator; } - if (exclusive && rdev->open_count) { + if (get_type == EXCLUSIVE_GET && rdev->open_count) { regulator = ERR_PTR(-EBUSY); put_device(&rdev->dev); return regulator; @@ -1656,6 +1675,7 @@ found: } if (!try_module_get(rdev->owner)) { + regulator = ERR_PTR(-EPROBE_DEFER); put_device(&rdev->dev); return regulator; } @@ -1669,7 +1689,7 @@ found: } rdev->open_count++; - if (exclusive) { + if (get_type == EXCLUSIVE_GET) { rdev->exclusive = 1; ret = _regulator_is_enabled(rdev); @@ -1697,7 +1717,7 @@ found: */ struct regulator *regulator_get(struct device *dev, const char *id) { - return _regulator_get(dev, id, false, true); + return _regulator_get(dev, id, NORMAL_GET); } EXPORT_SYMBOL_GPL(regulator_get); @@ -1724,7 +1744,7 @@ EXPORT_SYMBOL_GPL(regulator_get); */ struct regulator *regulator_get_exclusive(struct device *dev, const char *id) { - return _regulator_get(dev, id, true, false); + return _regulator_get(dev, id, EXCLUSIVE_GET); } EXPORT_SYMBOL_GPL(regulator_get_exclusive); @@ -1750,7 +1770,7 @@ EXPORT_SYMBOL_GPL(regulator_get_exclusive); */ struct regulator *regulator_get_optional(struct device *dev, const char *id) { - return _regulator_get(dev, id, false, false); + return _regulator_get(dev, id, OPTIONAL_GET); } EXPORT_SYMBOL_GPL(regulator_get_optional); @@ -3660,7 +3680,7 @@ err: for (++i; i < num_consumers; ++i) { r = regulator_enable(consumers[i].consumer); if (r != 0) - pr_err("Failed to reename %s: %d\n", + pr_err("Failed to re-enable %s: %d\n", consumers[i].supply, r); } @@ -3686,21 +3706,17 @@ int regulator_bulk_force_disable(int num_consumers, struct regulator_bulk_data *consumers) { int i; - int ret; + int ret = 0; - for (i = 0; i < num_consumers; i++) + for (i = 0; i < num_consumers; i++) { consumers[i].ret = regulator_force_disable(consumers[i].consumer); - for (i = 0; i < num_consumers; i++) { - if (consumers[i].ret != 0) { + /* Store first error for reporting */ + if (consumers[i].ret && !ret) ret = consumers[i].ret; - goto out; - } } - return 0; -out: return ret; } EXPORT_SYMBOL_GPL(regulator_bulk_force_disable); @@ -4391,12 +4407,13 @@ static void regulator_summary_show_subtree(struct seq_file *s, seq_puts(s, "\n"); list_for_each_entry(consumer, &rdev->consumer_list, list) { - if (consumer->dev->class == ®ulator_class) + if (consumer->dev && consumer->dev->class == ®ulator_class) continue; seq_printf(s, "%*s%-*s ", (level + 1) * 3 + 1, "", - 30 - (level + 1) * 3, dev_name(consumer->dev)); + 30 - (level + 1) * 3, + consumer->dev ? dev_name(consumer->dev) : "deviceless"); switch (rdev->desc->type) { case REGULATOR_VOLTAGE: @@ -4540,6 +4557,16 @@ static int __init regulator_init_complete(void) if (of_have_populated_dt()) has_full_constraints = true; + /* + * Regulators may had failed to resolve their input supplies + * when were registered, either because the input supply was + * not registered yet or because its parent device was not + * bound yet. So attempt to resolve the input supplies for + * pending regulators before trying to disable unused ones. + */ + class_for_each_device(®ulator_class, NULL, NULL, + regulator_register_resolve_supply); + /* If we have a full configuration then disable any regulators * we have permission to change the status for and which are * not in use or always_on. This is effectively the default diff --git a/drivers/regulator/cpcap-regulator.c b/drivers/regulator/cpcap-regulator.c new file mode 100644 index 000000000000..cc98aceed1c1 --- /dev/null +++ b/drivers/regulator/cpcap-regulator.c @@ -0,0 +1,464 @@ +/* + * Motorola CPCAP PMIC regulator driver + * + * Based on cpcap-regulator.c from Motorola Linux kernel tree + * Copyright (C) 2009-2011 Motorola, Inc. + * + * Rewritten for mainline kernel to use device tree and regmap + * Copyright (C) 2017 Tony Lindgren <tony@atomide.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/err.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/of_regulator.h> +#include <linux/mfd/motorola-cpcap.h> + +/* + * Resource assignment register bits. These seem to control the state + * idle modes adn are used at least for omap4. + */ + +/* CPCAP_REG_ASSIGN2 bits - Resource Assignment 2 */ +#define CPCAP_BIT_VSDIO_SEL BIT(15) +#define CPCAP_BIT_VDIG_SEL BIT(14) +#define CPCAP_BIT_VCAM_SEL BIT(13) +#define CPCAP_BIT_SW6_SEL BIT(12) +#define CPCAP_BIT_SW5_SEL BIT(11) +#define CPCAP_BIT_SW4_SEL BIT(10) +#define CPCAP_BIT_SW3_SEL BIT(9) +#define CPCAP_BIT_SW2_SEL BIT(8) +#define CPCAP_BIT_SW1_SEL BIT(7) + +/* CPCAP_REG_ASSIGN3 bits - Resource Assignment 3 */ +#define CPCAP_BIT_VUSBINT2_SEL BIT(15) +#define CPCAP_BIT_VUSBINT1_SEL BIT(14) +#define CPCAP_BIT_VVIB_SEL BIT(13) +#define CPCAP_BIT_VWLAN1_SEL BIT(12) +#define CPCAP_BIT_VRF1_SEL BIT(11) +#define CPCAP_BIT_VHVIO_SEL BIT(10) +#define CPCAP_BIT_VDAC_SEL BIT(9) +#define CPCAP_BIT_VUSB_SEL BIT(8) +#define CPCAP_BIT_VSIM_SEL BIT(7) +#define CPCAP_BIT_VRFREF_SEL BIT(6) +#define CPCAP_BIT_VPLL_SEL BIT(5) +#define CPCAP_BIT_VFUSE_SEL BIT(4) +#define CPCAP_BIT_VCSI_SEL BIT(3) +#define CPCAP_BIT_SPARE_14_2 BIT(2) +#define CPCAP_BIT_VWLAN2_SEL BIT(1) +#define CPCAP_BIT_VRF2_SEL BIT(0) + +/* CPCAP_REG_ASSIGN4 bits - Resource Assignment 4 */ +#define CPCAP_BIT_VAUDIO_SEL BIT(0) + +/* + * Enable register bits. At least CPCAP_BIT_AUDIO_LOW_PWR is generic, + * and not limited to audio regulator. Let's use the Motorola kernel + * naming for now until we have a better understanding of the other + * enable register bits. No idea why BIT(3) is not defined. + */ +#define CPCAP_BIT_AUDIO_LOW_PWR BIT(6) +#define CPCAP_BIT_AUD_LOWPWR_SPEED BIT(5) +#define CPCAP_BIT_VAUDIOPRISTBY BIT(4) +#define CPCAP_BIT_VAUDIO_MODE1 BIT(2) +#define CPCAP_BIT_VAUDIO_MODE0 BIT(1) +#define CPCAP_BIT_V_AUDIO_EN BIT(0) + +/* + * Off mode configuration bit. Used currently only by SW5 on omap4. There's + * the following comment in Motorola Linux kernel tree for it: + * + * When set in the regulator mode, the regulator assignment will be changed + * to secondary when the regulator is disabled. The mode will be set back to + * primary when the regulator is turned on. + */ +#define CPCAP_REG_OFF_MODE_SEC BIT(15) + +/** + * SoC specific configuraion for CPCAP regulator. There are at least three + * different SoCs each with their own parameters: omap3, omap4 and tegra2. + * + * The assign_reg and assign_mask seem to allow toggling between primary + * and secondary mode that at least omap4 uses for off mode. + */ +struct cpcap_regulator { + struct regulator_desc rdesc; + const u16 assign_reg; + const u16 assign_mask; + const u16 vsel_shift; +}; + +#define CPCAP_REG(_ID, reg, assignment_reg, assignment_mask, val_tbl, \ + mode_mask, volt_mask, volt_shft, \ + mode_val, off_val, volt_trans_time) { \ + .rdesc = { \ + .name = #_ID, \ + .of_match = of_match_ptr(#_ID), \ + .ops = &cpcap_regulator_ops, \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = CPCAP_##_ID, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(val_tbl), \ + .volt_table = (val_tbl), \ + .vsel_reg = (reg), \ + .vsel_mask = (volt_mask), \ + .enable_reg = (reg), \ + .enable_mask = (mode_mask), \ + .enable_val = (mode_val), \ + .disable_val = (off_val), \ + .ramp_delay = (volt_trans_time), \ + }, \ + .assign_reg = (assignment_reg), \ + .assign_mask = (assignment_mask), \ + .vsel_shift = (volt_shft), \ +} + +struct cpcap_ddata { + struct regmap *reg; + struct device *dev; + const struct cpcap_regulator *soc; +}; + +enum cpcap_regulator_id { + CPCAP_SW1, + CPCAP_SW2, + CPCAP_SW3, + CPCAP_SW4, + CPCAP_SW5, + CPCAP_SW6, + CPCAP_VCAM, + CPCAP_VCSI, + CPCAP_VDAC, + CPCAP_VDIG, + CPCAP_VFUSE, + CPCAP_VHVIO, + CPCAP_VSDIO, + CPCAP_VPLL, + CPCAP_VRF1, + CPCAP_VRF2, + CPCAP_VRFREF, + CPCAP_VWLAN1, + CPCAP_VWLAN2, + CPCAP_VSIM, + CPCAP_VSIMCARD, + CPCAP_VVIB, + CPCAP_VUSB, + CPCAP_VAUDIO, + CPCAP_NR_REGULATORS, +}; + +/* + * We need to also configure regulator idle mode for SoC off mode if + * CPCAP_REG_OFF_MODE_SEC is set. + */ +static int cpcap_regulator_enable(struct regulator_dev *rdev) +{ + struct cpcap_regulator *regulator = rdev_get_drvdata(rdev); + int error, ignore; + + error = regulator_enable_regmap(rdev); + if (error) + return error; + + if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) { + error = regmap_update_bits(rdev->regmap, regulator->assign_reg, + regulator->assign_mask, + regulator->assign_mask); + if (error) + ignore = regulator_disable_regmap(rdev); + } + + return error; +} + +/* + * We need to also configure regulator idle mode for SoC off mode if + * CPCAP_REG_OFF_MODE_SEC is set. + */ +static int cpcap_regulator_disable(struct regulator_dev *rdev) +{ + struct cpcap_regulator *regulator = rdev_get_drvdata(rdev); + int error, ignore; + + if (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC) { + error = regmap_update_bits(rdev->regmap, regulator->assign_reg, + regulator->assign_mask, 0); + if (error) + return error; + } + + error = regulator_disable_regmap(rdev); + if (error && (rdev->desc->enable_val & CPCAP_REG_OFF_MODE_SEC)) { + ignore = regmap_update_bits(rdev->regmap, regulator->assign_reg, + regulator->assign_mask, + regulator->assign_mask); + } + + return error; +} + +static unsigned int cpcap_regulator_get_mode(struct regulator_dev *rdev) +{ + int value; + + regmap_read(rdev->regmap, rdev->desc->enable_reg, &value); + + if (!(value & CPCAP_BIT_AUDIO_LOW_PWR)) + return REGULATOR_MODE_STANDBY; + + return REGULATOR_MODE_NORMAL; +} + +static int cpcap_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + int value; + + switch (mode) { + case REGULATOR_MODE_NORMAL: + value = CPCAP_BIT_AUDIO_LOW_PWR; + break; + case REGULATOR_MODE_STANDBY: + value = 0; + break; + default: + return -EINVAL; + } + + return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg, + CPCAP_BIT_AUDIO_LOW_PWR, value); +} + +static struct regulator_ops cpcap_regulator_ops = { + .enable = cpcap_regulator_enable, + .disable = cpcap_regulator_disable, + .is_enabled = regulator_is_enabled_regmap, + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_mode = cpcap_regulator_get_mode, + .set_mode = cpcap_regulator_set_mode, +}; + +static const unsigned int unknown_val_tbl[] = { 0, }; +static const unsigned int sw5_val_tbl[] = { 0, 5050000, }; +static const unsigned int vcam_val_tbl[] = { 2600000, 2700000, 2800000, + 2900000, }; +static const unsigned int vcsi_val_tbl[] = { 1200000, 1800000, }; +static const unsigned int vdac_val_tbl[] = { 1200000, 1500000, 1800000, + 2500000,}; +static const unsigned int vdig_val_tbl[] = { 1200000, 1350000, 1500000, + 1875000, }; +static const unsigned int vfuse_val_tbl[] = { 1500000, 1600000, 1700000, + 1800000, 1900000, 2000000, + 2100000, 2200000, 2300000, + 2400000, 2500000, 2600000, + 2700000, 3150000, }; +static const unsigned int vhvio_val_tbl[] = { 2775000, }; +static const unsigned int vsdio_val_tbl[] = { 1500000, 1600000, 1800000, + 2600000, 2700000, 2800000, + 2900000, 3000000, }; +static const unsigned int vpll_val_tbl[] = { 1200000, 1300000, 1400000, + 1800000, }; +/* Quirk: 2775000 is before 2500000 for vrf1 regulator */ +static const unsigned int vrf1_val_tbl[] = { 2775000, 2500000, }; +static const unsigned int vrf2_val_tbl[] = { 0, 2775000, }; +static const unsigned int vrfref_val_tbl[] = { 2500000, 2775000, }; +static const unsigned int vwlan1_val_tbl[] = { 1800000, 1900000, }; +static const unsigned int vwlan2_val_tbl[] = { 2775000, 3000000, 3300000, + 3300000, }; +static const unsigned int vsim_val_tbl[] = { 1800000, 2900000, }; +static const unsigned int vsimcard_val_tbl[] = { 1800000, 2900000, }; +static const unsigned int vvib_val_tbl[] = { 1300000, 1800000, 2000000, + 3000000, }; +static const unsigned int vusb_val_tbl[] = { 0, 3300000, }; +static const unsigned int vaudio_val_tbl[] = { 0, 2775000, }; + +/** + * SoC specific configuration for omap4. The data below is comes from Motorola + * Linux kernel tree. It's basically the values of cpcap_regltr_data, + * cpcap_regulator_mode_values and cpcap_regulator_off_mode_values, see + * CPCAP_REG macro above. + * + * SW1 to SW4 and SW6 seems to be unused for mapphone. Note that VSIM and + * VSIMCARD have a shared resource assignment bit. + */ +static struct cpcap_regulator omap4_regulators[] = { + CPCAP_REG(SW1, CPCAP_REG_S1C1, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW1_SEL, unknown_val_tbl, + 0, 0, 0, 0, 0, 0), + CPCAP_REG(SW2, CPCAP_REG_S2C1, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW2_SEL, unknown_val_tbl, + 0, 0, 0, 0, 0, 0), + CPCAP_REG(SW3, CPCAP_REG_S3C, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW3_SEL, unknown_val_tbl, + 0, 0, 0, 0, 0, 0), + CPCAP_REG(SW4, CPCAP_REG_S4C1, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW4_SEL, unknown_val_tbl, + 0, 0, 0, 0, 0, 0), + CPCAP_REG(SW5, CPCAP_REG_S5C, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW5_SEL, sw5_val_tbl, + 0x28, 0, 0, 0x20 | CPCAP_REG_OFF_MODE_SEC, 0, 0), + CPCAP_REG(SW6, CPCAP_REG_S6C, CPCAP_REG_ASSIGN2, + CPCAP_BIT_SW6_SEL, unknown_val_tbl, + 0, 0, 0, 0, 0, 0), + CPCAP_REG(VCAM, CPCAP_REG_VCAMC, CPCAP_REG_ASSIGN2, + CPCAP_BIT_VCAM_SEL, vcam_val_tbl, + 0x87, 0x30, 4, 0x3, 0, 420), + CPCAP_REG(VCSI, CPCAP_REG_VCSIC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VCSI_SEL, vcsi_val_tbl, + 0x47, 0x10, 4, 0x43, 0x41, 350), + CPCAP_REG(VDAC, CPCAP_REG_VDACC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VDAC_SEL, vdac_val_tbl, + 0x87, 0x30, 4, 0x3, 0, 420), + CPCAP_REG(VDIG, CPCAP_REG_VDIGC, CPCAP_REG_ASSIGN2, + CPCAP_BIT_VDIG_SEL, vdig_val_tbl, + 0x87, 0x30, 4, 0x82, 0, 420), + CPCAP_REG(VFUSE, CPCAP_REG_VFUSEC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VFUSE_SEL, vfuse_val_tbl, + 0x80, 0xf, 0, 0x80, 0, 420), + CPCAP_REG(VHVIO, CPCAP_REG_VHVIOC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VHVIO_SEL, vhvio_val_tbl, + 0x17, 0, 0, 0, 0x12, 0), + CPCAP_REG(VSDIO, CPCAP_REG_VSDIOC, CPCAP_REG_ASSIGN2, + CPCAP_BIT_VSDIO_SEL, vsdio_val_tbl, + 0x87, 0x38, 3, 0x82, 0, 420), + CPCAP_REG(VPLL, CPCAP_REG_VPLLC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VPLL_SEL, vpll_val_tbl, + 0x43, 0x18, 3, 0x2, 0, 420), + CPCAP_REG(VRF1, CPCAP_REG_VRF1C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VRF1_SEL, vrf1_val_tbl, + 0xac, 0x2, 1, 0x4, 0, 10), + CPCAP_REG(VRF2, CPCAP_REG_VRF2C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VRF2_SEL, vrf2_val_tbl, + 0x23, 0x8, 3, 0, 0, 10), + CPCAP_REG(VRFREF, CPCAP_REG_VRFREFC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VRFREF_SEL, vrfref_val_tbl, + 0x23, 0x8, 3, 0, 0, 420), + CPCAP_REG(VWLAN1, CPCAP_REG_VWLAN1C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VWLAN1_SEL, vwlan1_val_tbl, + 0x47, 0x10, 4, 0, 0, 420), + CPCAP_REG(VWLAN2, CPCAP_REG_VWLAN2C, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VWLAN2_SEL, vwlan2_val_tbl, + 0x20c, 0xc0, 6, 0x20c, 0, 420), + CPCAP_REG(VSIM, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, + 0xffff, vsim_val_tbl, + 0x23, 0x8, 3, 0x3, 0, 420), + CPCAP_REG(VSIMCARD, CPCAP_REG_VSIMC, CPCAP_REG_ASSIGN3, + 0xffff, vsimcard_val_tbl, + 0x1e80, 0x8, 3, 0x1e00, 0, 420), + CPCAP_REG(VVIB, CPCAP_REG_VVIBC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VVIB_SEL, vvib_val_tbl, + 0x1, 0xc, 2, 0x1, 0, 500), + CPCAP_REG(VUSB, CPCAP_REG_VUSBC, CPCAP_REG_ASSIGN3, + CPCAP_BIT_VUSB_SEL, vusb_val_tbl, + 0x11c, 0x40, 6, 0xc, 0, 0), + CPCAP_REG(VAUDIO, CPCAP_REG_VAUDIOC, CPCAP_REG_ASSIGN4, + CPCAP_BIT_VAUDIO_SEL, vaudio_val_tbl, + 0x16, 0x1, 0, 0x4, 0, 0), + { /* sentinel */ }, +}; + +static const struct of_device_id cpcap_regulator_id_table[] = { + { + .compatible = "motorola,cpcap-regulator", + }, + { + .compatible = "motorola,mapphone-cpcap-regulator", + .data = omap4_regulators, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cpcap_regulator_id_table); + +static int cpcap_regulator_probe(struct platform_device *pdev) +{ + struct cpcap_ddata *ddata; + const struct of_device_id *match; + struct regulator_config config; + struct regulator_init_data init_data; + int i; + + match = of_match_device(of_match_ptr(cpcap_regulator_id_table), + &pdev->dev); + if (!match) + return -EINVAL; + + if (!match->data) { + dev_err(&pdev->dev, "no configuration data found\n"); + + return -ENODEV; + } + + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->reg = dev_get_regmap(pdev->dev.parent, NULL); + if (!ddata->reg) + return -ENODEV; + + ddata->dev = &pdev->dev; + ddata->soc = match->data; + platform_set_drvdata(pdev, ddata); + + memset(&config, 0, sizeof(config)); + memset(&init_data, 0, sizeof(init_data)); + config.dev = &pdev->dev; + config.regmap = ddata->reg; + config.init_data = &init_data; + + for (i = 0; i < CPCAP_NR_REGULATORS; i++) { + const struct cpcap_regulator *regulator = &ddata->soc[i]; + struct regulator_dev *rdev; + + if (!regulator->rdesc.name) + break; + + if (regulator->rdesc.volt_table == unknown_val_tbl) + continue; + + config.driver_data = (void *)regulator; + rdev = devm_regulator_register(&pdev->dev, + ®ulator->rdesc, + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register regulator %s\n", + regulator->rdesc.name); + + return PTR_ERR(rdev); + } + } + + return 0; +} + +static struct platform_driver cpcap_regulator_driver = { + .probe = cpcap_regulator_probe, + .driver = { + .name = "cpcap-regulator", + .of_match_table = of_match_ptr(cpcap_regulator_id_table), + }, +}; + +module_platform_driver(cpcap_regulator_driver); + +MODULE_ALIAS("platform:cpcap-regulator"); +MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>"); +MODULE_DESCRIPTION("CPCAP regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index 6ec1d400adae..784e3bf32210 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -19,12 +19,6 @@ #include "internal.h" -enum { - NORMAL_GET, - EXCLUSIVE_GET, - OPTIONAL_GET, -}; - static void devm_regulator_release(struct device *dev, void *res) { regulator_put(*(struct regulator **)res); @@ -39,20 +33,7 @@ static struct regulator *_devm_regulator_get(struct device *dev, const char *id, if (!ptr) return ERR_PTR(-ENOMEM); - switch (get_type) { - case NORMAL_GET: - regulator = regulator_get(dev, id); - break; - case EXCLUSIVE_GET: - regulator = regulator_get_exclusive(dev, id); - break; - case OPTIONAL_GET: - regulator = regulator_get_optional(dev, id); - break; - default: - regulator = ERR_PTR(-EINVAL); - } - + regulator = _regulator_get(dev, id, get_type); if (!IS_ERR(regulator)) { *ptr = regulator; devres_add(dev, ptr); @@ -139,6 +120,18 @@ void devm_regulator_put(struct regulator *regulator) } EXPORT_SYMBOL_GPL(devm_regulator_put); +struct regulator_bulk_devres { + struct regulator_bulk_data *consumers; + int num_consumers; +}; + +static void devm_regulator_bulk_release(struct device *dev, void *res) +{ + struct regulator_bulk_devres *devres = res; + + regulator_bulk_free(devres->num_consumers, devres->consumers); +} + /** * devm_regulator_bulk_get - managed get multiple regulator consumers * @@ -157,29 +150,22 @@ EXPORT_SYMBOL_GPL(devm_regulator_put); int devm_regulator_bulk_get(struct device *dev, int num_consumers, struct regulator_bulk_data *consumers) { - int i; + struct regulator_bulk_devres *devres; int ret; - for (i = 0; i < num_consumers; i++) - consumers[i].consumer = NULL; - - for (i = 0; i < num_consumers; i++) { - consumers[i].consumer = devm_regulator_get(dev, - consumers[i].supply); - if (IS_ERR(consumers[i].consumer)) { - ret = PTR_ERR(consumers[i].consumer); - dev_err(dev, "Failed to get supply '%s': %d\n", - consumers[i].supply, ret); - consumers[i].consumer = NULL; - goto err; - } - } - - return 0; + devres = devres_alloc(devm_regulator_bulk_release, + sizeof(*devres), GFP_KERNEL); + if (!devres) + return -ENOMEM; -err: - for (i = 0; i < num_consumers && consumers[i].consumer; i++) - devm_regulator_put(consumers[i].consumer); + ret = regulator_bulk_get(dev, num_consumers, consumers); + if (!ret) { + devres->consumers = consumers; + devres->num_consumers = num_consumers; + devres_add(dev, devres); + } else { + devres_free(devres); + } return ret; } diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c index d7da81a875cf..60f431831582 100644 --- a/drivers/regulator/fan53555.c +++ b/drivers/regulator/fan53555.c @@ -202,7 +202,7 @@ static int fan53555_set_ramp(struct regulator_dev *rdev, int ramp) CTL_SLEW_MASK, regval << CTL_SLEW_SHIFT); } -static struct regulator_ops fan53555_regulator_ops = { +static const struct regulator_ops fan53555_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_time_sel = regulator_set_voltage_time_sel, diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index a43b0e8a438d..988a7472c2ab 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -30,9 +30,6 @@ #include <linux/of_gpio.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> -#include <linux/acpi.h> -#include <linux/property.h> -#include <linux/gpio/consumer.h> struct fixed_voltage_data { struct regulator_desc desc; @@ -97,44 +94,6 @@ of_get_fixed_voltage_config(struct device *dev, return config; } -/** - * acpi_get_fixed_voltage_config - extract fixed_voltage_config structure info - * @dev: device requesting for fixed_voltage_config - * @desc: regulator description - * - * Populates fixed_voltage_config structure by extracting data through ACPI - * interface, returns a pointer to the populated structure of NULL if memory - * alloc fails. - */ -static struct fixed_voltage_config * -acpi_get_fixed_voltage_config(struct device *dev, - const struct regulator_desc *desc) -{ - struct fixed_voltage_config *config; - const char *supply_name; - struct gpio_desc *gpiod; - int ret; - - config = devm_kzalloc(dev, sizeof(*config), GFP_KERNEL); - if (!config) - return ERR_PTR(-ENOMEM); - - ret = device_property_read_string(dev, "supply-name", &supply_name); - if (!ret) - config->supply_name = supply_name; - - gpiod = gpiod_get(dev, "gpio", GPIOD_ASIS); - if (IS_ERR(gpiod)) - return ERR_PTR(-ENODEV); - - config->gpio = desc_to_gpio(gpiod); - config->enable_high = device_property_read_bool(dev, - "enable-active-high"); - gpiod_put(gpiod); - - return config; -} - static struct regulator_ops fixed_voltage_ops = { }; @@ -155,11 +114,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) &drvdata->desc); if (IS_ERR(config)) return PTR_ERR(config); - } else if (ACPI_HANDLE(&pdev->dev)) { - config = acpi_get_fixed_voltage_config(&pdev->dev, - &drvdata->desc); - if (IS_ERR(config)) - return PTR_ERR(config); } else { config = dev_get_platdata(&pdev->dev); } diff --git a/drivers/regulator/hi655x-regulator.c b/drivers/regulator/hi655x-regulator.c index aca18466f522..065c100e9a03 100644 --- a/drivers/regulator/hi655x-regulator.c +++ b/drivers/regulator/hi655x-regulator.c @@ -96,7 +96,7 @@ static int hi655x_disable(struct regulator_dev *rdev) return ret; } -static struct regulator_ops hi655x_regulator_ops = { +static const struct regulator_ops hi655x_regulator_ops = { .enable = regulator_enable_regmap, .disable = hi655x_disable, .is_enabled = hi655x_is_enabled, @@ -105,7 +105,7 @@ static struct regulator_ops hi655x_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, }; -static struct regulator_ops hi655x_ldo_linear_ops = { +static const struct regulator_ops hi655x_ldo_linear_ops = { .enable = regulator_enable_regmap, .disable = hi655x_disable, .is_enabled = hi655x_is_enabled, diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h index c74ac8734023..1dd575b28564 100644 --- a/drivers/regulator/internal.h +++ b/drivers/regulator/internal.h @@ -51,4 +51,14 @@ regulator_of_get_init_data(struct device *dev, } #endif +enum regulator_get_type { + NORMAL_GET, + EXCLUSIVE_GET, + OPTIONAL_GET, + MAX_GET_TYPE +}; + +struct regulator *_regulator_get(struct device *dev, const char *id, + enum regulator_get_type get_type); + #endif diff --git a/drivers/regulator/lp8755.c b/drivers/regulator/lp8755.c index d6773da925ba..db34e1da75ef 100644 --- a/drivers/regulator/lp8755.c +++ b/drivers/regulator/lp8755.c @@ -227,7 +227,7 @@ err_i2c: return ret; } -static struct regulator_ops lp8755_buck_ops = { +static const struct regulator_ops lp8755_buck_ops = { .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 47bef328fb58..a7a1a0313bbf 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -161,7 +161,7 @@ static int ltc3589_set_suspend_mode(struct regulator_dev *rdev, } /* SW1, SW2, SW3, LDO2 */ -static struct regulator_ops ltc3589_linear_regulator_ops = { +static const struct regulator_ops ltc3589_linear_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -175,18 +175,18 @@ static struct regulator_ops ltc3589_linear_regulator_ops = { }; /* BB_OUT, LDO3 */ -static struct regulator_ops ltc3589_fixed_regulator_ops = { +static const struct regulator_ops ltc3589_fixed_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, }; /* LDO1 */ -static struct regulator_ops ltc3589_fixed_standby_regulator_ops = { +static const struct regulator_ops ltc3589_fixed_standby_regulator_ops = { }; /* LDO4 */ -static struct regulator_ops ltc3589_table_regulator_ops = { +static const struct regulator_ops ltc3589_table_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/ltc3676.c b/drivers/regulator/ltc3676.c index e2b476ca2b4d..503cd90eba39 100644 --- a/drivers/regulator/ltc3676.c +++ b/drivers/regulator/ltc3676.c @@ -161,7 +161,7 @@ static int ltc3676_of_parse_cb(struct device_node *np, } /* SW1, SW2, SW3, SW4 linear 0.8V-3.3V with scalar via R1/R2 feeback res */ -static struct regulator_ops ltc3676_linear_regulator_ops = { +static const struct regulator_ops ltc3676_linear_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -173,11 +173,11 @@ static struct regulator_ops ltc3676_linear_regulator_ops = { }; /* LDO1 always on fixed 0.8V-3.3V via scalar via R1/R2 feeback res */ -static struct regulator_ops ltc3676_fixed_standby_regulator_ops = { +static const struct regulator_ops ltc3676_fixed_standby_regulator_ops = { }; /* LDO2, LDO3 fixed (LDO2 has external scalar via R1/R2 feedback res) */ -static struct regulator_ops ltc3676_fixed_regulator_ops = { +static const struct regulator_ops ltc3676_fixed_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/max14577-regulator.c b/drivers/regulator/max14577-regulator.c index c9ff26199711..0db288ce319c 100644 --- a/drivers/regulator/max14577-regulator.c +++ b/drivers/regulator/max14577-regulator.c @@ -85,14 +85,14 @@ static int max14577_reg_set_current_limit(struct regulator_dev *rdev, reg_data); } -static struct regulator_ops max14577_safeout_ops = { +static const struct regulator_ops max14577_safeout_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_ops max14577_charger_ops = { +static const struct regulator_ops max14577_charger_ops = { .is_enabled = max14577_reg_is_enabled, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -130,7 +130,7 @@ static const struct regulator_desc max14577_supported_regulators[] = { [MAX14577_CHARGER] = MAX14577_CHARGER_REG, }; -static struct regulator_ops max77836_ldo_ops = { +static const struct regulator_ops max77836_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/max77620-regulator.c b/drivers/regulator/max77620-regulator.c index d088a7c79e60..b94e3a721721 100644 --- a/drivers/regulator/max77620-regulator.c +++ b/drivers/regulator/max77620-regulator.c @@ -644,7 +644,7 @@ static int max77620_of_parse_cb(struct device_node *np, return max77620_init_pmic(pmic, desc->id); } -static struct regulator_ops max77620_regulator_ops = { +static const struct regulator_ops max77620_regulator_ops = { .is_enabled = max77620_regulator_is_enabled, .enable = max77620_regulator_enable, .disable = max77620_regulator_disable, diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index ac4fa581e0a5..c301f3733475 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -289,7 +289,7 @@ static int max77686_of_parse_cb(struct device_node *np, return 0; } -static struct regulator_ops max77686_ops = { +static const struct regulator_ops max77686_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -301,7 +301,7 @@ static struct regulator_ops max77686_ops = { .set_suspend_mode = max77686_set_suspend_mode, }; -static struct regulator_ops max77686_ldo_ops = { +static const struct regulator_ops max77686_ldo_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -314,7 +314,7 @@ static struct regulator_ops max77686_ldo_ops = { .set_suspend_disable = max77686_set_suspend_disable, }; -static struct regulator_ops max77686_buck1_ops = { +static const struct regulator_ops max77686_buck1_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -326,7 +326,7 @@ static struct regulator_ops max77686_buck1_ops = { .set_suspend_disable = max77686_set_suspend_disable, }; -static struct regulator_ops max77686_buck_dvs_ops = { +static const struct regulator_ops max77686_buck_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/max77693-regulator.c b/drivers/regulator/max77693-regulator.c index cfbb9512e486..3fce67982682 100644 --- a/drivers/regulator/max77693-regulator.c +++ b/drivers/regulator/max77693-regulator.c @@ -141,7 +141,7 @@ static const unsigned int max77693_safeout_table[] = { 3300000, }; -static struct regulator_ops max77693_safeout_ops = { +static const struct regulator_ops max77693_safeout_ops = { .list_voltage = regulator_list_voltage_table, .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, diff --git a/drivers/regulator/max77802-regulator.c b/drivers/regulator/max77802-regulator.c index 1d3539324d9a..b6261903818c 100644 --- a/drivers/regulator/max77802-regulator.c +++ b/drivers/regulator/max77802-regulator.c @@ -288,7 +288,7 @@ static int max77802_set_ramp_delay_4bit(struct regulator_dev *rdev, /* * LDOs 2, 4-19, 22-35 */ -static struct regulator_ops max77802_ldo_ops_logic1 = { +static const struct regulator_ops max77802_ldo_ops_logic1 = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -304,7 +304,7 @@ static struct regulator_ops max77802_ldo_ops_logic1 = { /* * LDOs 1, 20, 21, 3 */ -static struct regulator_ops max77802_ldo_ops_logic2 = { +static const struct regulator_ops max77802_ldo_ops_logic2 = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -319,7 +319,7 @@ static struct regulator_ops max77802_ldo_ops_logic2 = { }; /* BUCKS 1, 6 */ -static struct regulator_ops max77802_buck_16_dvs_ops = { +static const struct regulator_ops max77802_buck_16_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -333,7 +333,7 @@ static struct regulator_ops max77802_buck_16_dvs_ops = { }; /* BUCKs 2-4 */ -static struct regulator_ops max77802_buck_234_ops = { +static const struct regulator_ops max77802_buck_234_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, @@ -348,7 +348,7 @@ static struct regulator_ops max77802_buck_234_ops = { }; /* BUCKs 5, 7-10 */ -static struct regulator_ops max77802_buck_dvs_ops = { +static const struct regulator_ops max77802_buck_dvs_ops = { .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/max8907-regulator.c b/drivers/regulator/max8907-regulator.c index 5e941db5ccaf..860400d2cd85 100644 --- a/drivers/regulator/max8907-regulator.c +++ b/drivers/regulator/max8907-regulator.c @@ -109,7 +109,7 @@ struct max8907_regulator { #define LDO_650_25(id, supply, base) REG_LDO(id, supply, (base), \ 650000, 2225000, 25000) -static struct regulator_ops max8907_mbatt_ops = { +static const struct regulator_ops max8907_mbatt_ops = { }; static struct regulator_ops max8907_ldo_ops = { @@ -121,13 +121,13 @@ static struct regulator_ops max8907_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops max8907_ldo_hwctl_ops = { +static const struct regulator_ops max8907_ldo_hwctl_ops = { .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static struct regulator_ops max8907_fixed_ops = { +static const struct regulator_ops max8907_fixed_ops = { .list_voltage = regulator_list_voltage_linear, }; @@ -138,11 +138,11 @@ static struct regulator_ops max8907_out5v_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops max8907_out5v_hwctl_ops = { +static const struct regulator_ops max8907_out5v_hwctl_ops = { .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_ops max8907_bbat_ops = { +static const struct regulator_ops max8907_bbat_ops = { .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, diff --git a/drivers/regulator/max8925-regulator.c b/drivers/regulator/max8925-regulator.c index c802f0239dc7..39b63ddefeb2 100644 --- a/drivers/regulator/max8925-regulator.c +++ b/drivers/regulator/max8925-regulator.c @@ -132,7 +132,7 @@ static int max8925_set_dvm_disable(struct regulator_dev *rdev) return max8925_set_bits(info->i2c, info->vol_reg, 1 << SD1_DVM_EN, 0); } -static struct regulator_ops max8925_regulator_sdv_ops = { +static const struct regulator_ops max8925_regulator_sdv_ops = { .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = max8925_set_voltage_sel, @@ -145,7 +145,7 @@ static struct regulator_ops max8925_regulator_sdv_ops = { .set_suspend_disable = max8925_set_dvm_disable, }; -static struct regulator_ops max8925_regulator_ldo_ops = { +static const struct regulator_ops max8925_regulator_ldo_ops = { .map_voltage = regulator_map_voltage_linear, .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = max8925_set_voltage_sel, diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c index 1af8f4a2ab86..1096546c05e9 100644 --- a/drivers/regulator/max8952.c +++ b/drivers/regulator/max8952.c @@ -113,7 +113,7 @@ static int max8952_set_voltage_sel(struct regulator_dev *rdev, return 0; } -static struct regulator_ops max8952_ops = { +static const struct regulator_ops max8952_ops = { .list_voltage = max8952_list_voltage, .get_voltage_sel = max8952_get_voltage_sel, .set_voltage_sel = max8952_set_voltage_sel, diff --git a/drivers/regulator/palmas-regulator.c b/drivers/regulator/palmas-regulator.c index f11d41dad9c1..31ae5ee3a80d 100644 --- a/drivers/regulator/palmas-regulator.c +++ b/drivers/regulator/palmas-regulator.c @@ -528,7 +528,7 @@ static int palmas_smps_set_ramp_delay(struct regulator_dev *rdev, return ret; } -static struct regulator_ops palmas_ops_smps = { +static const struct regulator_ops palmas_ops_smps = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -542,7 +542,7 @@ static struct regulator_ops palmas_ops_smps = { .set_ramp_delay = palmas_smps_set_ramp_delay, }; -static struct regulator_ops palmas_ops_ext_control_smps = { +static const struct regulator_ops palmas_ops_ext_control_smps = { .set_mode = palmas_set_mode_smps, .get_mode = palmas_get_mode_smps, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -553,7 +553,7 @@ static struct regulator_ops palmas_ops_ext_control_smps = { .set_ramp_delay = palmas_smps_set_ramp_delay, }; -static struct regulator_ops palmas_ops_smps10 = { +static const struct regulator_ops palmas_ops_smps10 = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -565,7 +565,7 @@ static struct regulator_ops palmas_ops_smps10 = { .get_bypass = regulator_get_bypass_regmap, }; -static struct regulator_ops tps65917_ops_smps = { +static const struct regulator_ops tps65917_ops_smps = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -578,7 +578,7 @@ static struct regulator_ops tps65917_ops_smps = { .set_voltage_time_sel = regulator_set_voltage_time_sel, }; -static struct regulator_ops tps65917_ops_ext_control_smps = { +static const struct regulator_ops tps65917_ops_ext_control_smps = { .set_mode = palmas_set_mode_smps, .get_mode = palmas_get_mode_smps, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -602,7 +602,7 @@ static int palmas_is_enabled_ldo(struct regulator_dev *dev) return !!(reg); } -static struct regulator_ops palmas_ops_ldo = { +static const struct regulator_ops palmas_ops_ldo = { .is_enabled = palmas_is_enabled_ldo, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -612,7 +612,7 @@ static struct regulator_ops palmas_ops_ldo = { .map_voltage = regulator_map_voltage_linear, }; -static struct regulator_ops palmas_ops_ldo9 = { +static const struct regulator_ops palmas_ops_ldo9 = { .is_enabled = palmas_is_enabled_ldo, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -624,23 +624,23 @@ static struct regulator_ops palmas_ops_ldo9 = { .get_bypass = regulator_get_bypass_regmap, }; -static struct regulator_ops palmas_ops_ext_control_ldo = { +static const struct regulator_ops palmas_ops_ext_control_ldo = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, .map_voltage = regulator_map_voltage_linear, }; -static struct regulator_ops palmas_ops_extreg = { +static const struct regulator_ops palmas_ops_extreg = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, }; -static struct regulator_ops palmas_ops_ext_control_extreg = { +static const struct regulator_ops palmas_ops_ext_control_extreg = { }; -static struct regulator_ops tps65917_ops_ldo = { +static const struct regulator_ops tps65917_ops_ldo = { .is_enabled = palmas_is_enabled_ldo, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -651,7 +651,7 @@ static struct regulator_ops tps65917_ops_ldo = { .set_voltage_time_sel = regulator_set_voltage_time_sel, }; -static struct regulator_ops tps65917_ops_ldo_1_2 = { +static const struct regulator_ops tps65917_ops_ldo_1_2 = { .is_enabled = palmas_is_enabled_ldo, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c index f9d74d63be7c..0cb76ba29e84 100644 --- a/drivers/regulator/pbias-regulator.c +++ b/drivers/regulator/pbias-regulator.c @@ -54,7 +54,7 @@ static const unsigned int pbias_volt_table[] = { 3000000 }; -static struct regulator_ops pbias_regulator_voltage_ops = { +static const struct regulator_ops pbias_regulator_voltage_ops = { .list_voltage = regulator_list_voltage_table, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, diff --git a/drivers/regulator/pcap-regulator.c b/drivers/regulator/pcap-regulator.c index 9b16e6158f15..79cb971a69bb 100644 --- a/drivers/regulator/pcap-regulator.c +++ b/drivers/regulator/pcap-regulator.c @@ -210,7 +210,7 @@ static int pcap_regulator_is_enabled(struct regulator_dev *rdev) return (tmp >> vreg->en) & 1; } -static struct regulator_ops pcap_regulator_ops = { +static const struct regulator_ops pcap_regulator_ops = { .list_voltage = regulator_list_voltage_table, .set_voltage_sel = pcap_regulator_set_voltage_sel, .get_voltage_sel = pcap_regulator_get_voltage_sel, diff --git a/drivers/regulator/pcf50633-regulator.c b/drivers/regulator/pcf50633-regulator.c index 134f90ec9ca1..762e18447cae 100644 --- a/drivers/regulator/pcf50633-regulator.c +++ b/drivers/regulator/pcf50633-regulator.c @@ -41,7 +41,7 @@ .enable_mask = PCF50633_REGULATOR_ON, \ } -static struct regulator_ops pcf50633_regulator_ops = { +static const struct regulator_ops pcf50633_regulator_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index cb18b5c4f2db..e193bbbb8ffc 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -126,7 +126,7 @@ static int pfuze100_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) return ret; } -static struct regulator_ops pfuze100_ldo_regulator_ops = { +static const struct regulator_ops pfuze100_ldo_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -135,14 +135,14 @@ static struct regulator_ops pfuze100_ldo_regulator_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, }; -static struct regulator_ops pfuze100_fixed_regulator_ops = { +static const struct regulator_ops pfuze100_fixed_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, .list_voltage = regulator_list_voltage_linear, }; -static struct regulator_ops pfuze100_sw_regulator_ops = { +static const struct regulator_ops pfuze100_sw_regulator_ops = { .list_voltage = regulator_list_voltage_linear, .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -150,7 +150,7 @@ static struct regulator_ops pfuze100_sw_regulator_ops = { .set_ramp_delay = pfuze100_set_ramp_delay, }; -static struct regulator_ops pfuze100_swb_regulator_ops = { +static const struct regulator_ops pfuze100_swb_regulator_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .list_voltage = regulator_list_voltage_table, diff --git a/drivers/regulator/pv88060-regulator.c b/drivers/regulator/pv88060-regulator.c index 6c4afc73ecac..a9446056435f 100644 --- a/drivers/regulator/pv88060-regulator.c +++ b/drivers/regulator/pv88060-regulator.c @@ -162,7 +162,7 @@ static int pv88060_get_current_limit(struct regulator_dev *rdev) return info->current_limits[data]; } -static struct regulator_ops pv88060_buck_ops = { +static const struct regulator_ops pv88060_buck_ops = { .get_mode = pv88060_buck_get_mode, .set_mode = pv88060_buck_set_mode, .enable = regulator_enable_regmap, @@ -175,7 +175,7 @@ static struct regulator_ops pv88060_buck_ops = { .get_current_limit = pv88060_get_current_limit, }; -static struct regulator_ops pv88060_ldo_ops = { +static const struct regulator_ops pv88060_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/pv88080-regulator.c b/drivers/regulator/pv88080-regulator.c index 954a20eeb26f..9a08cb2de501 100644 --- a/drivers/regulator/pv88080-regulator.c +++ b/drivers/regulator/pv88080-regulator.c @@ -306,7 +306,7 @@ static int pv88080_get_current_limit(struct regulator_dev *rdev) return info->current_limits[data]; } -static struct regulator_ops pv88080_buck_ops = { +static const struct regulator_ops pv88080_buck_ops = { .get_mode = pv88080_buck_get_mode, .set_mode = pv88080_buck_set_mode, .enable = regulator_enable_regmap, @@ -319,7 +319,7 @@ static struct regulator_ops pv88080_buck_ops = { .get_current_limit = pv88080_get_current_limit, }; -static struct regulator_ops pv88080_hvbuck_ops = { +static const struct regulator_ops pv88080_hvbuck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/pv88090-regulator.c b/drivers/regulator/pv88090-regulator.c index 421641175352..ab51e254d13a 100644 --- a/drivers/regulator/pv88090-regulator.c +++ b/drivers/regulator/pv88090-regulator.c @@ -184,7 +184,7 @@ static int pv88090_get_current_limit(struct regulator_dev *rdev) return info->current_limits[data]; } -static struct regulator_ops pv88090_buck_ops = { +static const struct regulator_ops pv88090_buck_ops = { .get_mode = pv88090_buck_get_mode, .set_mode = pv88090_buck_set_mode, .enable = regulator_enable_regmap, @@ -197,7 +197,7 @@ static struct regulator_ops pv88090_buck_ops = { .get_current_limit = pv88090_get_current_limit, }; -static struct regulator_ops pv88090_ldo_ops = { +static const struct regulator_ops pv88090_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/qcom_smd-regulator.c b/drivers/regulator/qcom_smd-regulator.c index 8ed46a9a55c8..f35994a2a5be 100644 --- a/drivers/regulator/qcom_smd-regulator.c +++ b/drivers/regulator/qcom_smd-regulator.c @@ -305,6 +305,56 @@ static const struct regulator_desc pm8916_buck_hvo_smps = { .ops = &rpm_smps_ldo_ops, }; +static const struct regulator_desc pm8994_hfsmps = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE( 375000, 0, 95, 12500), + REGULATOR_LINEAR_RANGE(1550000, 96, 158, 25000), + }, + .n_linear_ranges = 2, + .n_voltages = 159, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8994_ftsmps = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(350000, 0, 199, 5000), + REGULATOR_LINEAR_RANGE(700000, 200, 349, 10000), + }, + .n_linear_ranges = 2, + .n_voltages = 350, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8994_nldo = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE(750000, 0, 63, 12500), + }, + .n_linear_ranges = 1, + .n_voltages = 64, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8994_pldo = { + .linear_ranges = (struct regulator_linear_range[]) { + REGULATOR_LINEAR_RANGE( 750000, 0, 63, 12500), + REGULATOR_LINEAR_RANGE(1550000, 64, 126, 25000), + REGULATOR_LINEAR_RANGE(3100000, 127, 163, 50000), + }, + .n_linear_ranges = 3, + .n_voltages = 164, + .ops = &rpm_smps_ldo_ops, +}; + +static const struct regulator_desc pm8994_switch = { + .ops = &rpm_switch_ops, +}; + +static const struct regulator_desc pm8994_lnldo = { + .fixed_uV = 1740000, + .n_voltages = 1, + .ops = &rpm_smps_ldo_ops_fixed, +}; + struct rpm_regulator_data { const char *name; u32 type; @@ -443,10 +493,62 @@ static const struct rpm_regulator_data rpm_pma8084_regulators[] = { {} }; +static const struct rpm_regulator_data rpm_pm8994_regulators[] = { + { "s1", QCOM_SMD_RPM_SMPA, 1, &pm8994_ftsmps, "vdd_s1" }, + { "s2", QCOM_SMD_RPM_SMPA, 2, &pm8994_ftsmps, "vdd_s2" }, + { "s3", QCOM_SMD_RPM_SMPA, 3, &pm8994_hfsmps, "vdd_s3" }, + { "s4", QCOM_SMD_RPM_SMPA, 4, &pm8994_hfsmps, "vdd_s4" }, + { "s5", QCOM_SMD_RPM_SMPA, 5, &pm8994_hfsmps, "vdd_s5" }, + { "s6", QCOM_SMD_RPM_SMPA, 6, &pm8994_ftsmps, "vdd_s6" }, + { "s7", QCOM_SMD_RPM_SMPA, 7, &pm8994_hfsmps, "vdd_s7" }, + { "s8", QCOM_SMD_RPM_SMPA, 8, &pm8994_ftsmps, "vdd_s8" }, + { "s9", QCOM_SMD_RPM_SMPA, 9, &pm8994_ftsmps, "vdd_s9" }, + { "s10", QCOM_SMD_RPM_SMPA, 10, &pm8994_ftsmps, "vdd_s10" }, + { "s11", QCOM_SMD_RPM_SMPA, 11, &pm8994_ftsmps, "vdd_s11" }, + { "s12", QCOM_SMD_RPM_SMPA, 12, &pm8994_ftsmps, "vdd_s12" }, + { "l1", QCOM_SMD_RPM_LDOA, 1, &pm8994_nldo, "vdd_l1" }, + { "l2", QCOM_SMD_RPM_LDOA, 2, &pm8994_nldo, "vdd_l2_l26_l28" }, + { "l3", QCOM_SMD_RPM_LDOA, 3, &pm8994_nldo, "vdd_l3_l11" }, + { "l4", QCOM_SMD_RPM_LDOA, 4, &pm8994_nldo, "vdd_l4_l27_l31" }, + { "l5", QCOM_SMD_RPM_LDOA, 5, &pm8994_lnldo, "vdd_l5_l7" }, + { "l6", QCOM_SMD_RPM_LDOA, 6, &pm8994_pldo, "vdd_l6_l12_l32" }, + { "l7", QCOM_SMD_RPM_LDOA, 7, &pm8994_lnldo, "vdd_l5_l7" }, + { "l8", QCOM_SMD_RPM_LDOA, 8, &pm8994_pldo, "vdd_l8_l16_l30" }, + { "l9", QCOM_SMD_RPM_LDOA, 9, &pm8994_pldo, "vdd_l9_l10_l18_l22" }, + { "l10", QCOM_SMD_RPM_LDOA, 10, &pm8994_pldo, "vdd_l9_l10_l18_l22" }, + { "l11", QCOM_SMD_RPM_LDOA, 11, &pm8994_nldo, "vdd_l3_l11" }, + { "l12", QCOM_SMD_RPM_LDOA, 12, &pm8994_pldo, "vdd_l6_l12_l32" }, + { "l13", QCOM_SMD_RPM_LDOA, 13, &pm8994_pldo, "vdd_l13_l19_l23_l24" }, + { "l14", QCOM_SMD_RPM_LDOA, 14, &pm8994_pldo, "vdd_l14_l15" }, + { "l15", QCOM_SMD_RPM_LDOA, 15, &pm8994_pldo, "vdd_l14_l15" }, + { "l16", QCOM_SMD_RPM_LDOA, 16, &pm8994_pldo, "vdd_l8_l16_l30" }, + { "l17", QCOM_SMD_RPM_LDOA, 17, &pm8994_pldo, "vdd_l17_l29" }, + { "l18", QCOM_SMD_RPM_LDOA, 18, &pm8994_pldo, "vdd_l9_l10_l18_l22" }, + { "l19", QCOM_SMD_RPM_LDOA, 19, &pm8994_pldo, "vdd_l13_l19_l23_l24" }, + { "l20", QCOM_SMD_RPM_LDOA, 20, &pm8994_pldo, "vdd_l20_l21" }, + { "l21", QCOM_SMD_RPM_LDOA, 21, &pm8994_pldo, "vdd_l20_l21" }, + { "l22", QCOM_SMD_RPM_LDOA, 22, &pm8994_pldo, "vdd_l9_l10_l18_l22" }, + { "l23", QCOM_SMD_RPM_LDOA, 23, &pm8994_pldo, "vdd_l13_l19_l23_l24" }, + { "l24", QCOM_SMD_RPM_LDOA, 24, &pm8994_pldo, "vdd_l13_l19_l23_l24" }, + { "l25", QCOM_SMD_RPM_LDOA, 25, &pm8994_pldo, "vdd_l25" }, + { "l26", QCOM_SMD_RPM_LDOA, 26, &pm8994_nldo, "vdd_l2_l26_l28" }, + { "l27", QCOM_SMD_RPM_LDOA, 27, &pm8994_nldo, "vdd_l4_l27_l31" }, + { "l28", QCOM_SMD_RPM_LDOA, 28, &pm8994_nldo, "vdd_l2_l26_l28" }, + { "l29", QCOM_SMD_RPM_LDOA, 29, &pm8994_pldo, "vdd_l17_l29" }, + { "l30", QCOM_SMD_RPM_LDOA, 30, &pm8994_pldo, "vdd_l8_l16_l30" }, + { "l31", QCOM_SMD_RPM_LDOA, 31, &pm8994_nldo, "vdd_l4_l27_l31" }, + { "l32", QCOM_SMD_RPM_LDOA, 32, &pm8994_pldo, "vdd_l6_l12_l32" }, + { "lvs1", QCOM_SMD_RPM_VSA, 1, &pm8994_switch, "vdd_lvs1_2" }, + { "lvs2", QCOM_SMD_RPM_VSA, 2, &pm8994_switch, "vdd_lvs1_2" }, + + {} +}; + static const struct of_device_id rpm_of_match[] = { { .compatible = "qcom,rpm-pm8841-regulators", .data = &rpm_pm8841_regulators }, { .compatible = "qcom,rpm-pm8916-regulators", .data = &rpm_pm8916_regulators }, { .compatible = "qcom,rpm-pm8941-regulators", .data = &rpm_pm8941_regulators }, + { .compatible = "qcom,rpm-pm8994-regulators", .data = &rpm_pm8994_regulators }, { .compatible = "qcom,rpm-pma8084-regulators", .data = &rpm_pma8084_regulators }, {} }; diff --git a/drivers/regulator/rc5t583-regulator.c b/drivers/regulator/rc5t583-regulator.c index d2e67c512195..d0f1340168b1 100644 --- a/drivers/regulator/rc5t583-regulator.c +++ b/drivers/regulator/rc5t583-regulator.c @@ -61,7 +61,7 @@ static int rc5t583_regulator_enable_time(struct regulator_dev *rdev) return DIV_ROUND_UP(curr_uV, reg->reg_info->enable_uv_per_us); } -static struct regulator_ops rc5t583_ops = { +static const struct regulator_ops rc5t583_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c index 9c930eb68cda..8d2819e36654 100644 --- a/drivers/regulator/rn5t618-regulator.c +++ b/drivers/regulator/rn5t618-regulator.c @@ -19,7 +19,7 @@ #include <linux/regulator/driver.h> #include <linux/regulator/of_regulator.h> -static struct regulator_ops rn5t618_reg_ops = { +static const struct regulator_ops rn5t618_reg_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c index 92f88753bfed..38ee97a085f9 100644 --- a/drivers/regulator/s2mpa01.c +++ b/drivers/regulator/s2mpa01.c @@ -26,6 +26,7 @@ #define S2MPA01_REGULATOR_CNT ARRAY_SIZE(regulators) struct s2mpa01_info { + struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX]; int ramp_delay24; int ramp_delay3; int ramp_delay5; @@ -341,9 +342,9 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev) { struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent); struct sec_platform_data *pdata = dev_get_platdata(iodev->dev); - struct of_regulator_match rdata[S2MPA01_REGULATOR_MAX] = { }; struct device_node *reg_np = NULL; struct regulator_config config = { }; + struct of_regulator_match *rdata; struct s2mpa01_info *s2mpa01; int i; @@ -351,6 +352,7 @@ static int s2mpa01_pmic_probe(struct platform_device *pdev) if (!s2mpa01) return -ENOMEM; + rdata = s2mpa01->rdata; for (i = 0; i < S2MPA01_REGULATOR_CNT; i++) rdata[i].name = regulators[i].name; diff --git a/drivers/regulator/tps65086-regulator.c b/drivers/regulator/tps65086-regulator.c index ecb0371780af..45e96e154690 100644 --- a/drivers/regulator/tps65086-regulator.c +++ b/drivers/regulator/tps65086-regulator.c @@ -157,19 +157,19 @@ static struct tps65086_regulator regulators[] = { VDOA23_VID_MASK, TPS65086_LDOA3CTRL, BIT(0), tps65086_ldoa23_ranges, 0, 0), TPS65086_SWITCH("SWA1", "swa1", SWA1, TPS65086_SWVTT_EN, BIT(5)), - TPS65086_SWITCH("SWB1", "swa2", SWB1, TPS65086_SWVTT_EN, BIT(6)), - TPS65086_SWITCH("SWB2", "swa3", SWB2, TPS65086_SWVTT_EN, BIT(7)), + TPS65086_SWITCH("SWB1", "swb1", SWB1, TPS65086_SWVTT_EN, BIT(6)), + TPS65086_SWITCH("SWB2", "swb2", SWB2, TPS65086_SWVTT_EN, BIT(7)), TPS65086_SWITCH("VTT", "vtt", VTT, TPS65086_SWVTT_EN, BIT(4)), }; -static int tps65086_of_parse_cb(struct device_node *dev, +static int tps65086_of_parse_cb(struct device_node *node, const struct regulator_desc *desc, struct regulator_config *config) { int ret; /* Check for 25mV step mode */ - if (of_property_read_bool(config->of_node, "ti,regulator-step-size-25mv")) { + if (of_property_read_bool(node, "ti,regulator-step-size-25mv")) { switch (desc->id) { case BUCK1: case BUCK2: @@ -193,7 +193,7 @@ static int tps65086_of_parse_cb(struct device_node *dev, } /* Check for decay mode */ - if (desc->id <= BUCK6 && of_property_read_bool(config->of_node, "ti,regulator-decay")) { + if (desc->id <= BUCK6 && of_property_read_bool(node, "ti,regulator-decay")) { ret = regmap_write_bits(config->regmap, regulators[desc->id].decay_reg, regulators[desc->id].decay_mask, diff --git a/drivers/regulator/tps65217-regulator.c b/drivers/regulator/tps65217-regulator.c index 2d12b9af3540..5324dc9e6d6e 100644 --- a/drivers/regulator/tps65217-regulator.c +++ b/drivers/regulator/tps65217-regulator.c @@ -179,7 +179,8 @@ static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC1", TPS65217_DCDC_1, "dcdc1", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC1, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC1_EN, - NULL, tps65217_uv1_ranges, 2, TPS65217_REG_SEQ1, + NULL, tps65217_uv1_ranges, + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ1, TPS65217_SEQ1_DC1_SEQ_MASK), TPS65217_REGULATOR("DCDC2", TPS65217_DCDC_2, "dcdc2", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC2, @@ -190,7 +191,8 @@ static const struct regulator_desc regulators[] = { TPS65217_REGULATOR("DCDC3", TPS65217_DCDC_3, "dcdc3", tps65217_pmic_ops, 64, TPS65217_REG_DEFDCDC3, TPS65217_DEFDCDCX_DCDC_MASK, TPS65217_ENABLE_DC3_EN, - NULL, tps65217_uv1_ranges, 1, TPS65217_REG_SEQ2, + NULL, tps65217_uv1_ranges, + ARRAY_SIZE(tps65217_uv1_ranges), TPS65217_REG_SEQ2, TPS65217_SEQ2_DC3_SEQ_MASK), TPS65217_REGULATOR("LDO1", TPS65217_LDO_1, "ldo1", tps65217_pmic_ldo1_ops, 16, TPS65217_REG_DEFLDO1, diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 4864b9d742c0..716191046a70 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -452,7 +452,7 @@ static int twl6030smps_map_voltage(struct regulator_dev *rdev, int min_uV, vsel = 62; else if ((min_uV > 1800000) && (min_uV <= 1900000)) vsel = 61; - else if ((min_uV > 1350000) && (min_uV <= 1800000)) + else if ((min_uV > 1500000) && (min_uV <= 1800000)) vsel = 60; else if ((min_uV > 1350000) && (min_uV <= 1500000)) vsel = 59; diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c index 9a507e77eced..90b05c72186c 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -396,9 +396,6 @@ static int rproc_handle_vdev(struct rproc *rproc, struct fw_rsc_vdev *rsc, goto unwind_vring_allocations; } - /* track the rvdevs list reference */ - kref_get(&rvdev->refcount); - list_add_tail(&rvdev->node, &rproc->rvdevs); rproc_add_subdev(rproc, &rvdev->subdev, @@ -889,13 +886,15 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) /* * Create a copy of the resource table. When a virtio device starts * and calls vring_new_virtqueue() the address of the allocated vring - * will be stored in the table_ptr. Before the device is started, - * table_ptr will be copied into device memory. + * will be stored in the cached_table. Before the device is started, + * cached_table will be copied into device memory. */ - rproc->table_ptr = kmemdup(table, tablesz, GFP_KERNEL); - if (!rproc->table_ptr) + rproc->cached_table = kmemdup(table, tablesz, GFP_KERNEL); + if (!rproc->cached_table) goto clean_up; + rproc->table_ptr = rproc->cached_table; + /* reset max_notifyid */ rproc->max_notifyid = -1; @@ -914,16 +913,18 @@ static int rproc_fw_boot(struct rproc *rproc, const struct firmware *fw) } /* - * The starting device has been given the rproc->table_ptr as the + * The starting device has been given the rproc->cached_table as the * resource table. The address of the vring along with the other - * allocated resources (carveouts etc) is stored in table_ptr. + * allocated resources (carveouts etc) is stored in cached_table. * In order to pass this information to the remote device we must copy * this information to device memory. We also update the table_ptr so * that any subsequent changes will be applied to the loaded version. */ loaded_table = rproc_find_loaded_rsc_table(rproc, fw); - if (loaded_table) - memcpy(loaded_table, rproc->table_ptr, tablesz); + if (loaded_table) { + memcpy(loaded_table, rproc->cached_table, tablesz); + rproc->table_ptr = loaded_table; + } /* power up the remote processor */ ret = rproc->ops->start(rproc); @@ -951,7 +952,8 @@ stop_rproc: clean_up_resources: rproc_resource_cleanup(rproc); clean_up: - kfree(rproc->table_ptr); + kfree(rproc->cached_table); + rproc->cached_table = NULL; rproc->table_ptr = NULL; rproc_disable_iommu(rproc); @@ -1185,7 +1187,8 @@ void rproc_shutdown(struct rproc *rproc) rproc_disable_iommu(rproc); /* Free the copy of the resource table */ - kfree(rproc->table_ptr); + kfree(rproc->cached_table); + rproc->cached_table = NULL; rproc->table_ptr = NULL; /* if in crash state, unlock crash handler */ diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 10368ed8fd13..b6f5f1e1826c 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -163,7 +163,7 @@ int reset_control_reset(struct reset_control *rstc) } ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); - if (rstc->shared && !ret) + if (rstc->shared && ret) atomic_dec(&rstc->triggered_count); return ret; diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c index a79cb5a9e5f2..1cfb775e8e82 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -453,8 +453,8 @@ int rpmsg_register_device(struct rpmsg_device *rpdev) struct device *dev = &rpdev->dev; int ret; - dev_set_name(&rpdev->dev, "%s:%s", - dev_name(dev->parent), rpdev->id.name); + dev_set_name(&rpdev->dev, "%s.%s.%d.%d", dev_name(dev->parent), + rpdev->id.name, rpdev->src, rpdev->dst); rpdev->dev.bus = &rpmsg_bus; rpdev->dev.release = rpmsg_release_device; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index c93c5a8fba32..5dc673dc9487 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1551,12 +1551,15 @@ config RTC_DRV_MPC5121 will be called rtc-mpc5121. config RTC_DRV_JZ4740 - bool "Ingenic JZ4740 SoC" + tristate "Ingenic JZ4740 SoC" depends on MACH_INGENIC || COMPILE_TEST help If you say yes here you get support for the Ingenic JZ47xx SoCs RTC controllers. + This driver can also be buillt as a module. If so, the module + will be called rtc-jz4740. + config RTC_DRV_LPC24XX tristate "NXP RTC for LPC178x/18xx/408x/43xx" depends on ARCH_LPC18XX || COMPILE_TEST diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 72918c1ba092..64989afffa3d 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -17,6 +17,7 @@ #include <linux/clk.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reboot.h> @@ -294,7 +295,7 @@ static void jz4740_rtc_power_off(void) JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks); jz4740_rtc_poweroff(dev_for_power_off); - machine_halt(); + kernel_halt(); } static const struct of_device_id jz4740_rtc_of_match[] = { @@ -302,6 +303,7 @@ static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, {}, }; +MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match); static int jz4740_rtc_probe(struct platform_device *pdev) { @@ -429,6 +431,7 @@ static const struct platform_device_id jz4740_rtc_ids[] = { { "jz4780-rtc", ID_JZ4780 }, {} }; +MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids); static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, @@ -440,4 +443,9 @@ static struct platform_driver jz4740_rtc_driver = { .id_table = jz4740_rtc_ids, }; -builtin_platform_driver(jz4740_rtc_driver); +module_platform_driver(jz4740_rtc_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n"); +MODULE_ALIAS("platform:jz4740-rtc"); diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index 9f16ea6964ec..152de6817875 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -300,13 +300,6 @@ static void scm_blk_request(struct request_queue *rq) struct request *req; while ((req = blk_peek_request(rq))) { - if (req->cmd_type != REQ_TYPE_FS) { - blk_start_request(req); - blk_dump_rq_flags(req, KMSG_COMPONENT " bad request"); - __blk_end_request_all(req, -EIO); - continue; - } - if (!scm_permit_request(bdev, req)) goto out; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 75f820ca17b7..27ff38f839fc 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1583,7 +1583,7 @@ out: int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) { struct zfcp_qdio *qdio = wka_port->adapter->qdio; - struct zfcp_fsf_req *req = NULL; + struct zfcp_fsf_req *req; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -1612,7 +1612,7 @@ int zfcp_fsf_open_wka_port(struct zfcp_fc_wka_port *wka_port) zfcp_fsf_req_free(req); out: spin_unlock_irq(&qdio->req_q_lock); - if (req && !IS_ERR(req)) + if (!retval) zfcp_dbf_rec_run_wka("fsowp_1", wka_port, req->req_id); return retval; } @@ -1638,7 +1638,7 @@ static void zfcp_fsf_close_wka_port_handler(struct zfcp_fsf_req *req) int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) { struct zfcp_qdio *qdio = wka_port->adapter->qdio; - struct zfcp_fsf_req *req = NULL; + struct zfcp_fsf_req *req; int retval = -EIO; spin_lock_irq(&qdio->req_q_lock); @@ -1667,7 +1667,7 @@ int zfcp_fsf_close_wka_port(struct zfcp_fc_wka_port *wka_port) zfcp_fsf_req_free(req); out: spin_unlock_irq(&qdio->req_q_lock); - if (req && !IS_ERR(req)) + if (!retval) zfcp_dbf_rec_run_wka("fscwp_1", wka_port, req->req_id); return retval; } diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c index 639ed4e6afd1..070c4da95f48 100644 --- a/drivers/s390/virtio/virtio_ccw.c +++ b/drivers/s390/virtio/virtio_ccw.c @@ -145,6 +145,7 @@ static struct airq_info *airq_areas[MAX_AIRQ_AREAS]; #define CCW_CMD_WRITE_CONF 0x21 #define CCW_CMD_WRITE_STATUS 0x31 #define CCW_CMD_READ_VQ_CONF 0x32 +#define CCW_CMD_READ_STATUS 0x72 #define CCW_CMD_SET_IND_ADAPTER 0x73 #define CCW_CMD_SET_VIRTIO_REV 0x83 @@ -160,6 +161,7 @@ static struct airq_info *airq_areas[MAX_AIRQ_AREAS]; #define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000 #define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000 #define VIRTIO_CCW_DOING_SET_VIRTIO_REV 0x10000000 +#define VIRTIO_CCW_DOING_READ_STATUS 0x20000000 #define VIRTIO_CCW_INTPARM_MASK 0xffff0000 static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev) @@ -452,7 +454,7 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw) * This may happen on device detach. */ if (ret && (ret != -ENODEV)) - dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d", + dev_warn(&vq->vdev->dev, "Error %d while deleting queue %d\n", ret, index); vring_del_virtqueue(vq); @@ -892,6 +894,28 @@ out_free: static u8 virtio_ccw_get_status(struct virtio_device *vdev) { struct virtio_ccw_device *vcdev = to_vc_device(vdev); + u8 old_status = *vcdev->status; + struct ccw1 *ccw; + + if (vcdev->revision < 1) + return *vcdev->status; + + ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL); + if (!ccw) + return old_status; + + ccw->cmd_code = CCW_CMD_READ_STATUS; + ccw->flags = 0; + ccw->count = sizeof(*vcdev->status); + ccw->cda = (__u32)(unsigned long)vcdev->status; + ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_STATUS); +/* + * If the channel program failed (should only happen if the device + * was hotunplugged, and then we clean up via the machine check + * handler anyway), vcdev->status was not overwritten and we just + * return the old status, which is fine. +*/ + kfree(ccw); return *vcdev->status; } @@ -920,7 +944,7 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status) kfree(ccw); } -static struct virtio_config_ops virtio_ccw_config_ops = { +static const struct virtio_config_ops virtio_ccw_config_ops = { .get_features = virtio_ccw_get_features, .finalize_features = virtio_ccw_finalize_features, .get = virtio_ccw_get_config, @@ -987,6 +1011,7 @@ static void virtio_ccw_check_activity(struct virtio_ccw_device *vcdev, case VIRTIO_CCW_DOING_READ_CONFIG: case VIRTIO_CCW_DOING_WRITE_CONFIG: case VIRTIO_CCW_DOING_WRITE_STATUS: + case VIRTIO_CCW_DOING_READ_STATUS: case VIRTIO_CCW_DOING_SET_VQ: case VIRTIO_CCW_DOING_SET_IND: case VIRTIO_CCW_DOING_SET_CONF_IND: diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index a4f6b0d95515..d4023bf1e739 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -18,6 +18,7 @@ config SCSI depends on BLOCK select SCSI_DMA if HAS_DMA select SG_POOL + select BLK_SCSI_REQUEST ---help--- If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or any other SCSI device under Linux, say Y and make sure that you know diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index d0c77246d13d..40bfc57b6849 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -51,9 +51,13 @@ struct aac_common aac_config = { static inline int aac_is_msix_mode(struct aac_dev *dev) { - u32 status; + u32 status = 0; - status = src_readl(dev, MUnit.OMR); + if (dev->pdev->device == PMC_DEVICE_S6 || + dev->pdev->device == PMC_DEVICE_S7 || + dev->pdev->device == PMC_DEVICE_S8) { + status = src_readl(dev, MUnit.OMR); + } return (status & AAC_INT_MODE_MSIX); } diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index d9e15210b110..5caf5f3ff642 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -64,9 +64,9 @@ int max_rport_logins = BFA_FCS_MAX_RPORT_LOGINS; u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size; u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2; -#define BFAD_FW_FILE_CB "cbfw-3.2.3.0.bin" -#define BFAD_FW_FILE_CT "ctfw-3.2.3.0.bin" -#define BFAD_FW_FILE_CT2 "ct2fw-3.2.3.0.bin" +#define BFAD_FW_FILE_CB "cbfw-3.2.5.1.bin" +#define BFAD_FW_FILE_CT "ctfw-3.2.5.1.bin" +#define BFAD_FW_FILE_CT2 "ct2fw-3.2.5.1.bin" static u32 *bfad_load_fwimg(struct pci_dev *pdev); static void bfad_free_fwimg(void); diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index a9a00169ad91..b2e8c0dfc79c 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -3363,7 +3363,7 @@ bfad_im_bsg_els_ct_request(struct bsg_job *job) struct bfad_fcxp *drv_fcxp; struct bfa_fcs_lport_s *fcs_port; struct bfa_fcs_rport_s *fcs_rport; - struct fc_bsg_request *bsg_request = bsg_request; + struct fc_bsg_request *bsg_request = job->request; struct fc_bsg_reply *bsg_reply = job->reply; uint32_t command_type = bsg_request->msgcode; unsigned long flags; diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h index f9e862093a25..cfcfff48e8e1 100644 --- a/drivers/scsi/bfa/bfad_drv.h +++ b/drivers/scsi/bfa/bfad_drv.h @@ -58,7 +58,7 @@ #ifdef BFA_DRIVER_VERSION #define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION #else -#define BFAD_DRIVER_VERSION "3.2.25.0" +#define BFAD_DRIVER_VERSION "3.2.25.1" #endif #define BFAD_PROTO_NAME FCPI_NAME diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index f501095f91ac..898461b146cc 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -74,7 +74,7 @@ static void bnx2fc_cmd_timeout(struct work_struct *work) &io_req->req_flags)) { /* Handle internally generated ABTS timeout */ BNX2FC_IO_DBG(io_req, "ABTS timed out refcnt = %d\n", - io_req->refcount.refcount.counter); + kref_read(&io_req->refcount)); if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags))) { /* @@ -1141,7 +1141,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) return SUCCESS; } BNX2FC_IO_DBG(io_req, "eh_abort - refcnt = %d\n", - io_req->refcount.refcount.counter); + kref_read(&io_req->refcount)); /* Hold IO request across abort processing */ kref_get(&io_req->refcount); @@ -1299,7 +1299,7 @@ void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, { BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl " "refcnt = %d, cmd_type = %d\n", - io_req->refcount.refcount.counter, io_req->cmd_type); + kref_read(&io_req->refcount), io_req->cmd_type); bnx2fc_scsi_done(io_req, DID_ERROR); kref_put(&io_req->refcount, bnx2fc_cmd_release); if (io_req->wait_for_comp) @@ -1318,7 +1318,7 @@ void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, BNX2FC_IO_DBG(io_req, "Entered process_abts_compl xid = 0x%x" "refcnt = %d, cmd_type = %d\n", io_req->xid, - io_req->refcount.refcount.counter, io_req->cmd_type); + kref_read(&io_req->refcount), io_req->cmd_type); if (test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, &io_req->req_flags)) { diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 95ba99044c3e..18e0ea83d361 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -301,7 +301,7 @@ static inline void __cxgbi_sock_put(const char *fn, struct cxgbi_sock *csk) { log_debug(1 << CXGBI_DBG_SOCK, "%s, put csk 0x%p, ref %u-1.\n", - fn, csk, atomic_read(&csk->refcnt.refcount)); + fn, csk, kref_read(&csk->refcnt)); kref_put(&csk->refcnt, cxgbi_sock_free); } #define cxgbi_sock_put(csk) __cxgbi_sock_put(__func__, csk) @@ -310,7 +310,7 @@ static inline void __cxgbi_sock_get(const char *fn, struct cxgbi_sock *csk) { log_debug(1 << CXGBI_DBG_SOCK, "%s, get csk 0x%p, ref %u+1.\n", - fn, csk, atomic_read(&csk->refcnt.refcount)); + fn, csk, kref_read(&csk->refcnt)); kref_get(&csk->refcnt); } #define cxgbi_sock_get(csk) __cxgbi_sock_get(__func__, csk) diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 5b80746980b8..4a7679f6c73d 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -88,12 +88,6 @@ struct clariion_dh_data { */ unsigned char buffer[CLARIION_BUFFER_SIZE]; /* - * SCSI sense buffer for commands -- assumes serial issuance - * and completion sequence of all commands for same multipath. - */ - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - unsigned int senselen; - /* * LUN state */ int lun_state; @@ -116,44 +110,38 @@ struct clariion_dh_data { /* * Parse MODE_SELECT cmd reply. */ -static int trespass_endio(struct scsi_device *sdev, char *sense) +static int trespass_endio(struct scsi_device *sdev, + struct scsi_sense_hdr *sshdr) { int err = SCSI_DH_IO; - struct scsi_sense_hdr sshdr; - - if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { - sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " - "0x%2x, 0x%2x while sending CLARiiON trespass " - "command.\n", CLARIION_NAME, sshdr.sense_key, - sshdr.asc, sshdr.ascq); - if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && - (sshdr.ascq == 0x00)) { - /* - * Array based copy in progress -- do not send - * mode_select or copy will be aborted mid-stream. - */ - sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " - "progress while sending CLARiiON trespass " - "command.\n", CLARIION_NAME); - err = SCSI_DH_DEV_TEMP_BUSY; - } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && - (sshdr.ascq == 0x03)) { - /* - * LUN Not Ready - Manual Intervention Required - * indicates in-progress ucode upgrade (NDU). - */ - sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " - "ucode upgrade NDU operation while sending " - "CLARiiON trespass command.\n", CLARIION_NAME); - err = SCSI_DH_DEV_TEMP_BUSY; - } else - err = SCSI_DH_DEV_FAILED; - } else { - sdev_printk(KERN_INFO, sdev, - "%s: failed to send MODE SELECT, no sense available\n", - CLARIION_NAME); - } + sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " + "0x%2x, 0x%2x while sending CLARiiON trespass " + "command.\n", CLARIION_NAME, sshdr->sense_key, + sshdr->asc, sshdr->ascq); + + if (sshdr->sense_key == 0x05 && sshdr->asc == 0x04 && + sshdr->ascq == 0x00) { + /* + * Array based copy in progress -- do not send + * mode_select or copy will be aborted mid-stream. + */ + sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " + "progress while sending CLARiiON trespass " + "command.\n", CLARIION_NAME); + err = SCSI_DH_DEV_TEMP_BUSY; + } else if (sshdr->sense_key == 0x02 && sshdr->asc == 0x04 && + sshdr->ascq == 0x03) { + /* + * LUN Not Ready - Manual Intervention Required + * indicates in-progress ucode upgrade (NDU). + */ + sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " + "ucode upgrade NDU operation while sending " + "CLARiiON trespass command.\n", CLARIION_NAME); + err = SCSI_DH_DEV_TEMP_BUSY; + } else + err = SCSI_DH_DEV_FAILED; return err; } @@ -257,103 +245,15 @@ out: return sp_model; } -/* - * Get block request for REQ_BLOCK_PC command issued to path. Currently - * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. - * - * Uses data and sense buffers in hardware handler context structure and - * assumes serial servicing of commands, both issuance and completion. - */ -static struct request *get_req(struct scsi_device *sdev, int cmd, - unsigned char *buffer) -{ - struct request *rq; - int len = 0; - - rq = blk_get_request(sdev->request_queue, - (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO); - if (IS_ERR(rq)) { - sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); - return NULL; - } - - blk_rq_set_block_pc(rq); - rq->cmd_len = COMMAND_SIZE(cmd); - rq->cmd[0] = cmd; - - switch (cmd) { - case MODE_SELECT: - len = sizeof(short_trespass); - rq->cmd[1] = 0x10; - rq->cmd[4] = len; - break; - case MODE_SELECT_10: - len = sizeof(long_trespass); - rq->cmd[1] = 0x10; - rq->cmd[8] = len; - break; - case INQUIRY: - len = CLARIION_BUFFER_SIZE; - rq->cmd[4] = len; - memset(buffer, 0, len); - break; - default: - BUG_ON(1); - break; - } - - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - rq->timeout = CLARIION_TIMEOUT; - rq->retries = CLARIION_RETRIES; - - if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) { - blk_put_request(rq); - return NULL; - } - - return rq; -} - -static int send_inquiry_cmd(struct scsi_device *sdev, int page, - struct clariion_dh_data *csdev) -{ - struct request *rq = get_req(sdev, INQUIRY, csdev->buffer); - int err; - - if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; - - rq->sense = csdev->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = csdev->senselen = 0; - - rq->cmd[0] = INQUIRY; - if (page != 0) { - rq->cmd[1] = 1; - rq->cmd[2] = page; - } - err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: failed to send %s INQUIRY: %x\n", - CLARIION_NAME, page?"EVPD":"standard", - rq->errors); - csdev->senselen = rq->sense_len; - err = SCSI_DH_IO; - } - - blk_put_request(rq); - - return err; -} - static int send_trespass_cmd(struct scsi_device *sdev, struct clariion_dh_data *csdev) { - struct request *rq; unsigned char *page22; - int err, len, cmd; + unsigned char cdb[COMMAND_SIZE(MODE_SELECT)]; + int err, res = SCSI_DH_OK, len; + struct scsi_sense_hdr sshdr; + u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; if (csdev->flags & CLARIION_SHORT_TRESPASS) { page22 = short_trespass; @@ -361,40 +261,37 @@ static int send_trespass_cmd(struct scsi_device *sdev, /* Set Honor Reservations bit */ page22[6] |= 0x80; len = sizeof(short_trespass); - cmd = MODE_SELECT; + cdb[0] = MODE_SELECT; + cdb[1] = 0x10; + cdb[4] = len; } else { page22 = long_trespass; if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) /* Set Honor Reservations bit */ page22[10] |= 0x80; len = sizeof(long_trespass); - cmd = MODE_SELECT_10; + cdb[0] = MODE_SELECT_10; + cdb[8] = len; } BUG_ON((len > CLARIION_BUFFER_SIZE)); memcpy(csdev->buffer, page22, len); - rq = get_req(sdev, cmd, csdev->buffer); - if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; - - rq->sense = csdev->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = csdev->senselen = 0; - - err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); - if (err == -EIO) { - if (rq->sense_len) { - err = trespass_endio(sdev, csdev->sense); - } else { + err = scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE, + csdev->buffer, len, &sshdr, + CLARIION_TIMEOUT * HZ, CLARIION_RETRIES, + NULL, req_flags, 0); + if (err) { + if (scsi_sense_valid(&sshdr)) + res = trespass_endio(sdev, &sshdr); + else { sdev_printk(KERN_INFO, sdev, "%s: failed to send MODE SELECT: %x\n", - CLARIION_NAME, rq->errors); + CLARIION_NAME, err); + res = SCSI_DH_IO; } } - blk_put_request(rq); - - return err; + return res; } static int clariion_check_sense(struct scsi_device *sdev, @@ -464,21 +361,7 @@ static int clariion_std_inquiry(struct scsi_device *sdev, int err; char *sp_model; - err = send_inquiry_cmd(sdev, 0, csdev); - if (err != SCSI_DH_OK && csdev->senselen) { - struct scsi_sense_hdr sshdr; - - if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, - &sshdr)) { - sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " - "%02x/%02x/%02x\n", CLARIION_NAME, - sshdr.sense_key, sshdr.asc, sshdr.ascq); - } - err = SCSI_DH_IO; - goto out; - } - - sp_model = parse_sp_model(sdev, csdev->buffer); + sp_model = parse_sp_model(sdev, sdev->inquiry); if (!sp_model) { err = SCSI_DH_DEV_UNSUPP; goto out; @@ -500,30 +383,12 @@ out: static int clariion_send_inquiry(struct scsi_device *sdev, struct clariion_dh_data *csdev) { - int err, retry = CLARIION_RETRIES; - -retry: - err = send_inquiry_cmd(sdev, 0xC0, csdev); - if (err != SCSI_DH_OK && csdev->senselen) { - struct scsi_sense_hdr sshdr; - - err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, - &sshdr); - if (!err) - return SCSI_DH_IO; - - err = clariion_check_sense(sdev, &sshdr); - if (retry > 0 && err == ADD_TO_MLQUEUE) { - retry--; - goto retry; - } - sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " - "%02x/%02x/%02x\n", CLARIION_NAME, - sshdr.sense_key, sshdr.asc, sshdr.ascq); - err = SCSI_DH_IO; - } else { + int err = SCSI_DH_IO; + + if (!scsi_get_vpd_page(sdev, 0xC0, csdev->buffer, + CLARIION_BUFFER_SIZE)) err = parse_sp_info_reply(sdev, csdev); - } + return err; } diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 308e87195dc1..be43c940636d 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -38,13 +38,10 @@ #define HP_SW_PATH_PASSIVE 1 struct hp_sw_dh_data { - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; int path_state; int retries; int retry_cnt; struct scsi_device *sdev; - activate_complete callback_fn; - void *callback_data; }; static int hp_sw_start_stop(struct hp_sw_dh_data *); @@ -56,43 +53,34 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *); * * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path */ -static int tur_done(struct scsi_device *sdev, unsigned char *sense) +static int tur_done(struct scsi_device *sdev, struct hp_sw_dh_data *h, + struct scsi_sense_hdr *sshdr) { - struct scsi_sense_hdr sshdr; - int ret; + int ret = SCSI_DH_IO; - ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); - if (!ret) { - sdev_printk(KERN_WARNING, sdev, - "%s: sending tur failed, no sense available\n", - HP_SW_NAME); - ret = SCSI_DH_IO; - goto done; - } - switch (sshdr.sense_key) { + switch (sshdr->sense_key) { case UNIT_ATTENTION: ret = SCSI_DH_IMM_RETRY; break; case NOT_READY: - if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { + if (sshdr->asc == 0x04 && sshdr->ascq == 2) { /* * LUN not ready - Initialization command required * * This is the passive path */ - ret = SCSI_DH_DEV_OFFLINED; + h->path_state = HP_SW_PATH_PASSIVE; + ret = SCSI_DH_OK; break; } /* Fallthrough */ default: sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed, sense %x/%x/%x\n", - HP_SW_NAME, sshdr.sense_key, sshdr.asc, - sshdr.ascq); + HP_SW_NAME, sshdr->sense_key, sshdr->asc, + sshdr->ascq); break; } - -done: return ret; } @@ -105,131 +93,36 @@ done: */ static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) { - struct request *req; - int ret; + unsigned char cmd[6] = { TEST_UNIT_READY }; + struct scsi_sense_hdr sshdr; + int ret = SCSI_DH_OK, res; + u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; retry: - req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); - if (IS_ERR(req)) - return SCSI_DH_RES_TEMP_UNAVAIL; - - blk_rq_set_block_pc(req); - req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); - req->cmd[0] = TEST_UNIT_READY; - req->timeout = HP_SW_TIMEOUT; - req->sense = h->sense; - memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - req->sense_len = 0; - - ret = blk_execute_rq(req->q, NULL, req, 1); - if (ret == -EIO) { - if (req->sense_len > 0) { - ret = tur_done(sdev, h->sense); - } else { + res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, + HP_SW_TIMEOUT, HP_SW_RETRIES, + NULL, req_flags, 0); + if (res) { + if (scsi_sense_valid(&sshdr)) + ret = tur_done(sdev, h, &sshdr); + else { sdev_printk(KERN_WARNING, sdev, "%s: sending tur failed with %x\n", - HP_SW_NAME, req->errors); + HP_SW_NAME, res); ret = SCSI_DH_IO; } } else { h->path_state = HP_SW_PATH_ACTIVE; ret = SCSI_DH_OK; } - if (ret == SCSI_DH_IMM_RETRY) { - blk_put_request(req); + if (ret == SCSI_DH_IMM_RETRY) goto retry; - } - if (ret == SCSI_DH_DEV_OFFLINED) { - h->path_state = HP_SW_PATH_PASSIVE; - ret = SCSI_DH_OK; - } - - blk_put_request(req); return ret; } /* - * start_done - Handle START STOP UNIT return status - * @sdev: sdev the command has been sent to - * @errors: blk error code - */ -static int start_done(struct scsi_device *sdev, unsigned char *sense) -{ - struct scsi_sense_hdr sshdr; - int rc; - - rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); - if (!rc) { - sdev_printk(KERN_WARNING, sdev, - "%s: sending start_stop_unit failed, " - "no sense available\n", - HP_SW_NAME); - return SCSI_DH_IO; - } - switch (sshdr.sense_key) { - case NOT_READY: - if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { - /* - * LUN not ready - manual intervention required - * - * Switch-over in progress, retry. - */ - rc = SCSI_DH_RETRY; - break; - } - /* fall through */ - default: - sdev_printk(KERN_WARNING, sdev, - "%s: sending start_stop_unit failed, sense %x/%x/%x\n", - HP_SW_NAME, sshdr.sense_key, sshdr.asc, - sshdr.ascq); - rc = SCSI_DH_IO; - } - - return rc; -} - -static void start_stop_endio(struct request *req, int error) -{ - struct hp_sw_dh_data *h = req->end_io_data; - unsigned err = SCSI_DH_OK; - - if (error || host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { - sdev_printk(KERN_WARNING, h->sdev, - "%s: sending start_stop_unit failed with %x\n", - HP_SW_NAME, req->errors); - err = SCSI_DH_IO; - goto done; - } - - if (req->sense_len > 0) { - err = start_done(h->sdev, h->sense); - if (err == SCSI_DH_RETRY) { - err = SCSI_DH_IO; - if (--h->retry_cnt) { - blk_put_request(req); - err = hp_sw_start_stop(h); - if (err == SCSI_DH_OK) - return; - } - } - } -done: - req->end_io_data = NULL; - __blk_put_request(req->q, req); - if (h->callback_fn) { - h->callback_fn(h->callback_data, err); - h->callback_fn = h->callback_data = NULL; - } - return; - -} - -/* * hp_sw_start_stop - Send START STOP UNIT command * @sdev: sdev command should be sent to * @@ -237,26 +130,48 @@ done: */ static int hp_sw_start_stop(struct hp_sw_dh_data *h) { - struct request *req; - - req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); - if (IS_ERR(req)) - return SCSI_DH_RES_TEMP_UNAVAIL; - - blk_rq_set_block_pc(req); - req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - req->cmd_len = COMMAND_SIZE(START_STOP); - req->cmd[0] = START_STOP; - req->cmd[4] = 1; /* Start spin cycle */ - req->timeout = HP_SW_TIMEOUT; - req->sense = h->sense; - memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - req->sense_len = 0; - req->end_io_data = h; + unsigned char cmd[6] = { START_STOP, 0, 0, 0, 1, 0 }; + struct scsi_sense_hdr sshdr; + struct scsi_device *sdev = h->sdev; + int res, rc = SCSI_DH_OK; + int retry_cnt = HP_SW_RETRIES; + u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; - blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio); - return SCSI_DH_OK; +retry: + res = scsi_execute_req_flags(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, + HP_SW_TIMEOUT, HP_SW_RETRIES, + NULL, req_flags, 0); + if (res) { + if (!scsi_sense_valid(&sshdr)) { + sdev_printk(KERN_WARNING, sdev, + "%s: sending start_stop_unit failed, " + "no sense available\n", HP_SW_NAME); + return SCSI_DH_IO; + } + switch (sshdr.sense_key) { + case NOT_READY: + if (sshdr.asc == 0x04 && sshdr.ascq == 3) { + /* + * LUN not ready - manual intervention required + * + * Switch-over in progress, retry. + */ + if (--retry_cnt) + goto retry; + rc = SCSI_DH_RETRY; + break; + } + /* fall through */ + default: + sdev_printk(KERN_WARNING, sdev, + "%s: sending start_stop_unit failed, " + "sense %x/%x/%x\n", HP_SW_NAME, + sshdr.sense_key, sshdr.asc, sshdr.ascq); + rc = SCSI_DH_IO; + } + } + return rc; } static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) @@ -290,15 +205,8 @@ static int hp_sw_activate(struct scsi_device *sdev, ret = hp_sw_tur(sdev, h); - if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { - h->retry_cnt = h->retries; - h->callback_fn = fn; - h->callback_data = data; + if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) ret = hp_sw_start_stop(h); - if (ret == SCSI_DH_OK) - return 0; - h->callback_fn = h->callback_data = NULL; - } if (fn) fn(data, ret); diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index 00d9c326158e..b64eaae8533d 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -205,7 +205,6 @@ struct rdac_dh_data { #define RDAC_NON_PREFERRED 1 char preferred; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; union { struct c2_inquiry c2; struct c4_inquiry c4; @@ -262,40 +261,12 @@ do { \ sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \ } while (0); -static struct request *get_rdac_req(struct scsi_device *sdev, - void *buffer, unsigned buflen, int rw) +static unsigned int rdac_failover_get(struct rdac_controller *ctlr, + struct list_head *list, + unsigned char *cdb) { - struct request *rq; - struct request_queue *q = sdev->request_queue; - - rq = blk_get_request(q, rw, GFP_NOIO); - - if (IS_ERR(rq)) { - sdev_printk(KERN_INFO, sdev, - "get_rdac_req: blk_get_request failed.\n"); - return NULL; - } - blk_rq_set_block_pc(rq); - - if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { - blk_put_request(rq); - sdev_printk(KERN_INFO, sdev, - "get_rdac_req: blk_rq_map_kern failed.\n"); - return NULL; - } - - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - rq->retries = RDAC_RETRIES; - rq->timeout = RDAC_TIMEOUT; - - return rq; -} - -static struct request *rdac_failover_get(struct scsi_device *sdev, - struct rdac_dh_data *h, struct list_head *list) -{ - struct request *rq; + struct scsi_device *sdev = ctlr->ms_sdev; + struct rdac_dh_data *h = sdev->handler_data; struct rdac_mode_common *common; unsigned data_size; struct rdac_queue_data *qdata; @@ -332,27 +303,17 @@ static struct request *rdac_failover_get(struct scsi_device *sdev, lun_table[qdata->h->lun] = 0x81; } - /* get request for block layer packet command */ - rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE); - if (!rq) - return NULL; - /* Prepare the command. */ if (h->ctlr->use_ms10) { - rq->cmd[0] = MODE_SELECT_10; - rq->cmd[7] = data_size >> 8; - rq->cmd[8] = data_size & 0xff; + cdb[0] = MODE_SELECT_10; + cdb[7] = data_size >> 8; + cdb[8] = data_size & 0xff; } else { - rq->cmd[0] = MODE_SELECT; - rq->cmd[4] = data_size; + cdb[0] = MODE_SELECT; + cdb[4] = data_size; } - rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; - return rq; + return data_size; } static void release_controller(struct kref *kref) @@ -400,46 +361,14 @@ static struct rdac_controller *get_controller(int index, char *array_name, return ctlr; } -static int submit_inquiry(struct scsi_device *sdev, int page_code, - unsigned int len, struct rdac_dh_data *h) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - int err = SCSI_DH_RES_TEMP_UNAVAIL; - - rq = get_rdac_req(sdev, &h->inq, len, READ); - if (!rq) - goto done; - - /* Prepare the command. */ - rq->cmd[0] = INQUIRY; - rq->cmd[1] = 1; - rq->cmd[2] = page_code; - rq->cmd[4] = len; - rq->cmd_len = COMMAND_SIZE(INQUIRY); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; - - err = blk_execute_rq(q, NULL, rq, 1); - if (err == -EIO) - err = SCSI_DH_IO; - - blk_put_request(rq); -done: - return err; -} - static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h, char *array_name, u8 *array_id) { - int err, i; - struct c8_inquiry *inqp; + int err = SCSI_DH_IO, i; + struct c8_inquiry *inqp = &h->inq.c8; - err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c8; + if (!scsi_get_vpd_page(sdev, 0xC8, (unsigned char *)inqp, + sizeof(struct c8_inquiry))) { if (inqp->page_code != 0xc8) return SCSI_DH_NOSYS; if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' || @@ -453,20 +382,20 @@ static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h, *(array_name+ARRAY_LABEL_LEN-1) = '\0'; memset(array_id, 0, UNIQUE_ID_LEN); memcpy(array_id, inqp->array_unique_id, inqp->array_uniq_id_len); + err = SCSI_DH_OK; } return err; } static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) { - int err, access_state; + int err = SCSI_DH_IO, access_state; struct rdac_dh_data *tmp; - struct c9_inquiry *inqp; + struct c9_inquiry *inqp = &h->inq.c9; h->state = RDAC_STATE_ACTIVE; - err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c9; + if (!scsi_get_vpd_page(sdev, 0xC9, (unsigned char *)inqp, + sizeof(struct c9_inquiry))) { /* detect the operating mode */ if ((inqp->avte_cvp >> 5) & 0x1) h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */ @@ -501,6 +430,7 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) tmp->sdev->access_state = access_state; } rcu_read_unlock(); + err = SCSI_DH_OK; } return err; @@ -509,12 +439,11 @@ static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) static int initialize_controller(struct scsi_device *sdev, struct rdac_dh_data *h, char *array_name, u8 *array_id) { - int err, index; - struct c4_inquiry *inqp; + int err = SCSI_DH_IO, index; + struct c4_inquiry *inqp = &h->inq.c4; - err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c4; + if (!scsi_get_vpd_page(sdev, 0xC4, (unsigned char *)inqp, + sizeof(struct c4_inquiry))) { /* get the controller index */ if (inqp->slot_id[1] == 0x31) index = 0; @@ -530,18 +459,18 @@ static int initialize_controller(struct scsi_device *sdev, h->sdev = sdev; } spin_unlock(&list_lock); + err = SCSI_DH_OK; } return err; } static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) { - int err; - struct c2_inquiry *inqp; + int err = SCSI_DH_IO; + struct c2_inquiry *inqp = &h->inq.c2; - err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c2; + if (!scsi_get_vpd_page(sdev, 0xC2, (unsigned char *)inqp, + sizeof(struct c2_inquiry))) { /* * If more than MODE6_MAX_LUN luns are supported, use * mode select 10 @@ -550,36 +479,35 @@ static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) h->ctlr->use_ms10 = 1; else h->ctlr->use_ms10 = 0; + err = SCSI_DH_OK; } return err; } static int mode_select_handle_sense(struct scsi_device *sdev, - unsigned char *sensebuf) + struct scsi_sense_hdr *sense_hdr) { - struct scsi_sense_hdr sense_hdr; - int err = SCSI_DH_IO, ret; + int err = SCSI_DH_IO; struct rdac_dh_data *h = sdev->handler_data; - ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); - if (!ret) + if (!scsi_sense_valid(sense_hdr)) goto done; - switch (sense_hdr.sense_key) { + switch (sense_hdr->sense_key) { case NO_SENSE: case ABORTED_COMMAND: case UNIT_ATTENTION: err = SCSI_DH_RETRY; break; case NOT_READY: - if (sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x01) + if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) /* LUN Not Ready and is in the Process of Becoming * Ready */ err = SCSI_DH_RETRY; break; case ILLEGAL_REQUEST: - if (sense_hdr.asc == 0x91 && sense_hdr.ascq == 0x36) + if (sense_hdr->asc == 0x91 && sense_hdr->ascq == 0x36) /* * Command Lock contention */ @@ -592,7 +520,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " "MODE_SELECT returned with sense %02x/%02x/%02x", (char *) h->ctlr->array_name, h->ctlr->index, - sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); + sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq); done: return err; @@ -602,13 +530,16 @@ static void send_mode_select(struct work_struct *work) { struct rdac_controller *ctlr = container_of(work, struct rdac_controller, ms_work); - struct request *rq; struct scsi_device *sdev = ctlr->ms_sdev; struct rdac_dh_data *h = sdev->handler_data; - struct request_queue *q = sdev->request_queue; - int err, retry_cnt = RDAC_RETRY_COUNT; + int err = SCSI_DH_OK, retry_cnt = RDAC_RETRY_COUNT; struct rdac_queue_data *tmp, *qdata; LIST_HEAD(list); + unsigned char cdb[COMMAND_SIZE(MODE_SELECT_10)]; + struct scsi_sense_hdr sshdr; + unsigned int data_size; + u64 req_flags = REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | + REQ_FAILFAST_DRIVER; spin_lock(&ctlr->ms_lock); list_splice_init(&ctlr->ms_head, &list); @@ -616,21 +547,19 @@ static void send_mode_select(struct work_struct *work) ctlr->ms_sdev = NULL; spin_unlock(&ctlr->ms_lock); -retry: - err = SCSI_DH_RES_TEMP_UNAVAIL; - rq = rdac_failover_get(sdev, h, &list); - if (!rq) - goto done; + retry: + data_size = rdac_failover_get(ctlr, &list, cdb); RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " "%s MODE_SELECT command", (char *) h->ctlr->array_name, h->ctlr->index, (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); - err = blk_execute_rq(q, NULL, rq, 1); - blk_put_request(rq); - if (err != SCSI_DH_OK) { - err = mode_select_handle_sense(sdev, h->sense); + if (scsi_execute_req_flags(sdev, cdb, DMA_TO_DEVICE, + &h->ctlr->mode_select, data_size, &sshdr, + RDAC_TIMEOUT * HZ, + RDAC_RETRIES, NULL, req_flags, 0)) { + err = mode_select_handle_sense(sdev, &sshdr); if (err == SCSI_DH_RETRY && retry_cnt--) goto retry; if (err == SCSI_DH_IMM_RETRY) @@ -643,7 +572,6 @@ retry: (char *) h->ctlr->array_name, h->ctlr->index); } -done: list_for_each_entry_safe(qdata, tmp, &list, entry) { list_del(&qdata->entry); if (err == SCSI_DH_OK) diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 9ddc9200e0a4..9e4b7709043e 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -248,6 +248,7 @@ struct fnic { struct completion *remove_wait; /* device remove thread blocks */ atomic_t in_flight; /* io counter */ + bool internal_reset_inprogress; u32 _reserved; /* fill hole */ unsigned long state_flags; /* protected by host lock */ enum fnic_state state; diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 2544a37ece0a..adb3d5871e74 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -2581,6 +2581,19 @@ int fnic_host_reset(struct scsi_cmnd *sc) unsigned long wait_host_tmo; struct Scsi_Host *shost = sc->device->host; struct fc_lport *lp = shost_priv(shost); + struct fnic *fnic = lport_priv(lp); + unsigned long flags; + + spin_lock_irqsave(&fnic->fnic_lock, flags); + if (fnic->internal_reset_inprogress == 0) { + fnic->internal_reset_inprogress = 1; + } else { + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + "host reset in progress skipping another host reset\n"); + return SUCCESS; + } + spin_unlock_irqrestore(&fnic->fnic_lock, flags); /* * If fnic_reset is successful, wait for fabric login to complete @@ -2601,6 +2614,9 @@ int fnic_host_reset(struct scsi_cmnd *sc) } } + spin_lock_irqsave(&fnic->fnic_lock, flags); + fnic->internal_reset_inprogress = 0; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); return ret; } diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 258a3f9a2519..831a1c8b9f89 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -213,6 +213,10 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, goto fail; } + error = scsi_init_sense_cache(shost); + if (error) + goto fail; + if (shost_use_blk_mq(shost)) { error = scsi_mq_setup_tags(shost); if (error) @@ -226,19 +230,6 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, } } - /* - * Note that we allocate the freelist even for the MQ case for now, - * as we need a command set aside for scsi_reset_provider. Having - * the full host freelist and one command available for that is a - * little heavy-handed, but avoids introducing a special allocator - * just for this. Eventually the structure of scsi_reset_provider - * will need a major overhaul. - */ - error = scsi_setup_command_freelist(shost); - if (error) - goto out_destroy_tags; - - if (!shost->shost_gendev.parent) shost->shost_gendev.parent = dev ? dev : &platform_bus; if (!dma_dev) @@ -258,7 +249,7 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, error = device_add(&shost->shost_gendev); if (error) - goto out_destroy_freelist; + goto out_disable_runtime_pm; scsi_host_set_state(shost, SHOST_RUNNING); get_device(shost->shost_gendev.parent); @@ -308,13 +299,11 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, device_del(&shost->shost_dev); out_del_gendev: device_del(&shost->shost_gendev); - out_destroy_freelist: + out_disable_runtime_pm: device_disable_async_suspend(&shost->shost_gendev); pm_runtime_disable(&shost->shost_gendev); pm_runtime_set_suspended(&shost->shost_gendev); pm_runtime_put_noidle(&shost->shost_gendev); - scsi_destroy_command_freelist(shost); - out_destroy_tags: if (shost_use_blk_mq(shost)) scsi_mq_destroy_tags(shost); fail: @@ -355,7 +344,6 @@ static void scsi_host_dev_release(struct device *dev) kfree(dev_name(&shost->shost_dev)); } - scsi_destroy_command_freelist(shost); if (shost_use_blk_mq(shost)) { if (shost->tag_set.tags) scsi_mq_destroy_tags(shost); diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 4323ddcf9718..524a0c755ed7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -5539,8 +5539,8 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd) * Retries always go down the normal I/O path. */ if (likely(cmd->retries == 0 && - cmd->request->cmd_type == REQ_TYPE_FS && - h->acciopath_status)) { + !blk_rq_is_passthrough(cmd->request) && + h->acciopath_status)) { rc = hpsa_ioaccel_submit(h, c, cmd, scsi3addr); if (rc == 0) return 0; diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 3d3768aaab4f..0f807798c624 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -46,6 +46,7 @@ #define INITIAL_SRP_LIMIT 800 #define DEFAULT_MAX_SECTORS 256 +#define MAX_TXU 1024 * 1024 static uint max_vdma_size = MAX_H_COPY_RDMA; @@ -1391,7 +1392,7 @@ static long ibmvscsis_adapter_info(struct scsi_info *vscsi, } info = dma_alloc_coherent(&vscsi->dma_dev->dev, sizeof(*info), &token, - GFP_KERNEL); + GFP_ATOMIC); if (!info) { dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n", iue->target); @@ -1443,7 +1444,7 @@ static long ibmvscsis_adapter_info(struct scsi_info *vscsi, info->mad_version = cpu_to_be32(MAD_VERSION_1); info->os_type = cpu_to_be32(LINUX); memset(&info->port_max_txu[0], 0, sizeof(info->port_max_txu)); - info->port_max_txu[0] = cpu_to_be32(128 * PAGE_SIZE); + info->port_max_txu[0] = cpu_to_be32(MAX_TXU); dma_wmb(); rc = h_copy_rdma(sizeof(*info), vscsi->dds.window[LOCAL].liobn, @@ -1509,7 +1510,7 @@ static int ibmvscsis_cap_mad(struct scsi_info *vscsi, struct iu_entry *iue) } cap = dma_alloc_coherent(&vscsi->dma_dev->dev, olen, &token, - GFP_KERNEL); + GFP_ATOMIC); if (!cap) { dev_err(&vscsi->dev, "bad dma_alloc_coherent %p\n", iue->target); @@ -3585,7 +3586,7 @@ static int ibmvscsis_write_pending(struct se_cmd *se_cmd) 1, 1); if (rc) { pr_err("srp_transfer_data() failed: %d\n", rc); - return -EAGAIN; + return -EIO; } /* * We now tell TCM to add this WRITE CDB directly into the TCM storage @@ -3815,6 +3816,7 @@ static struct configfs_attribute *ibmvscsis_tpg_attrs[] = { static const struct target_core_fabric_ops ibmvscsis_ops = { .module = THIS_MODULE, .name = "ibmvscsis", + .max_data_sg_nents = MAX_TXU / PAGE_SIZE, .get_fabric_name = ibmvscsis_get_fabric_name, .tpg_get_wwn = ibmvscsis_get_fabric_wwn, .tpg_get_tag = ibmvscsis_get_tag, diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 919736a74ffa..aa76f36abe03 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -2095,7 +2095,7 @@ int fc_lport_bsg_request(struct bsg_job *job) bsg_reply->reply_payload_rcv_len = 0; if (rsp) - rsp->resid_len = job->reply_payload.payload_len; + scsi_req(rsp)->resid_len = job->reply_payload.payload_len; mutex_lock(&lport->lp_mutex); diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 022bb6e10d98..570b2cb2da43 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2174,12 +2174,12 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, bio_data(rsp->bio), blk_rq_bytes(rsp)); if (ret > 0) { /* positive number is the untransferred residual */ - rsp->resid_len = ret; - req->resid_len = 0; + scsi_req(rsp)->resid_len = ret; + scsi_req(req)->resid_len = 0; ret = 0; } else if (ret == 0) { - rsp->resid_len = 0; - req->resid_len = 0; + scsi_req(rsp)->resid_len = 0; + scsi_req(req)->resid_len = 0; } return ret; diff --git a/drivers/scsi/libsas/sas_host_smp.c b/drivers/scsi/libsas/sas_host_smp.c index d24792575169..45cbbc44f4d7 100644 --- a/drivers/scsi/libsas/sas_host_smp.c +++ b/drivers/scsi/libsas/sas_host_smp.c @@ -274,15 +274,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, switch (req_data[1]) { case SMP_REPORT_GENERAL: - req->resid_len -= 8; - rsp->resid_len -= 32; + scsi_req(req)->resid_len -= 8; + scsi_req(rsp)->resid_len -= 32; resp_data[2] = SMP_RESP_FUNC_ACC; resp_data[9] = sas_ha->num_phys; break; case SMP_REPORT_MANUF_INFO: - req->resid_len -= 8; - rsp->resid_len -= 64; + scsi_req(req)->resid_len -= 8; + scsi_req(rsp)->resid_len -= 64; resp_data[2] = SMP_RESP_FUNC_ACC; memcpy(resp_data + 12, shost->hostt->name, SAS_EXPANDER_VENDOR_ID_LEN); @@ -295,13 +295,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_DISCOVER: - req->resid_len -= 16; - if ((int)req->resid_len < 0) { - req->resid_len = 0; + scsi_req(req)->resid_len -= 16; + if ((int)scsi_req(req)->resid_len < 0) { + scsi_req(req)->resid_len = 0; error = -EINVAL; goto out; } - rsp->resid_len -= 56; + scsi_req(rsp)->resid_len -= 56; sas_host_smp_discover(sas_ha, resp_data, req_data[9]); break; @@ -311,13 +311,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_REPORT_PHY_SATA: - req->resid_len -= 16; - if ((int)req->resid_len < 0) { - req->resid_len = 0; + scsi_req(req)->resid_len -= 16; + if ((int)scsi_req(req)->resid_len < 0) { + scsi_req(req)->resid_len = 0; error = -EINVAL; goto out; } - rsp->resid_len -= 60; + scsi_req(rsp)->resid_len -= 60; sas_report_phy_sata(sas_ha, resp_data, req_data[9]); break; @@ -331,15 +331,15 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, int to_write = req_data[4]; if (blk_rq_bytes(req) < base_frame_size + to_write * 4 || - req->resid_len < base_frame_size + to_write * 4) { + scsi_req(req)->resid_len < base_frame_size + to_write * 4) { resp_data[2] = SMP_RESP_INV_FRM_LEN; break; } to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2], req_data[3], to_write, &req_data[8]); - req->resid_len -= base_frame_size + to_write * 4; - rsp->resid_len -= 8; + scsi_req(req)->resid_len -= base_frame_size + to_write * 4; + scsi_req(rsp)->resid_len -= 8; break; } @@ -348,13 +348,13 @@ int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, break; case SMP_PHY_CONTROL: - req->resid_len -= 44; - if ((int)req->resid_len < 0) { - req->resid_len = 0; + scsi_req(req)->resid_len -= 44; + if ((int)scsi_req(req)->resid_len < 0) { + scsi_req(req)->resid_len = 0; error = -EINVAL; goto out; } - rsp->resid_len -= 8; + scsi_req(rsp)->resid_len -= 8; sas_phy_control(sas_ha, req_data[9], req_data[10], req_data[32] >> 4, req_data[33] >> 4, resp_data); diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index a63542bac153..caa7a7b0ec53 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -607,7 +607,7 @@ lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) len += snprintf(buf+len, size-len, "usgmap:%x ", ndlp->nlp_usg_map); len += snprintf(buf+len, size-len, "refcnt:%x", - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); len += snprintf(buf+len, size-len, "\n"); } spin_unlock_irq(shost->host_lock); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index ede14f1810d2..3a1f1a2a2b55 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -3593,12 +3593,14 @@ lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) } else { buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; lpfc_els_free_data(phba, buf_ptr1); + elsiocb->context2 = NULL; } } if (elsiocb->context3) { buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; lpfc_els_free_bpl(phba, buf_ptr); + elsiocb->context3 = NULL; } lpfc_sli_release_iocbq(phba, elsiocb); return 0; @@ -3691,7 +3693,7 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, "0006 rpi%x DID:%x flg:%x %d map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); if (NLP_CHK_NODE_ACT(ndlp)) { lpfc_nlp_put(ndlp); diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index ed223937798a..82047070cdc9 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3440,7 +3440,7 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0002 rpi:%x DID:%x flg:%x %d map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; @@ -3861,7 +3861,7 @@ out: lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0003 rpi:%x DID:%x flg:%x %d map%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); if (vport->port_state < LPFC_VPORT_READY) { @@ -4238,7 +4238,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "0277 lpfc_enable_node: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); return NULL; } /* The ndlp should not already be in active mode */ @@ -4248,7 +4248,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "0278 lpfc_enable_node: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); return NULL; } @@ -4272,7 +4272,7 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "0008 rpi:%x DID:%x flg:%x refcnt:%d " "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); } @@ -4546,7 +4546,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == LPFC_SLI_INTF_IF_TYPE_2) && - (atomic_read(&ndlp->kref.refcount) > 0)) { + (kref_read(&ndlp->kref) > 0)) { mbox->context1 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; @@ -4695,14 +4695,14 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "0280 lpfc_cleanup_node: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); lpfc_dequeue_node(vport, ndlp); } else { lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, "0281 lpfc_cleanup_node: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); lpfc_disable_node(vport, ndlp); } @@ -4791,7 +4791,7 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, "0005 rpi:%x DID:%x flg:%x %d map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { @@ -5557,7 +5557,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, "0004 rpi:%x DID:%x flg:%x %d map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); /* * Start issuing Fabric-Device Management Interface (FDMI) command to @@ -5728,7 +5728,7 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "0007 rpi:%x DID:%x flg:%x refcnt:%d " "map:%x %p\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount), + kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); ndlp->active_rrqs_xri_bitmap = @@ -5767,7 +5767,7 @@ lpfc_nlp_release(struct kref *kref) "0279 lpfc_nlp_release: ndlp:x%p did %x " "usgmap:x%x refcnt:%d rpi:%x\n", (void *)ndlp, ndlp->nlp_DID, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount), ndlp->nlp_rpi); + kref_read(&ndlp->kref), ndlp->nlp_rpi); /* remove ndlp from action. */ lpfc_nlp_remove(ndlp->vport, ndlp); @@ -5804,7 +5804,7 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node get: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); /* The check of ndlp usage to prevent incrementing the * ndlp reference count that is in the process of being * released. @@ -5817,7 +5817,7 @@ lpfc_nlp_get(struct lpfc_nodelist *ndlp) "0276 lpfc_nlp_get: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); return NULL; } else kref_get(&ndlp->kref); @@ -5844,7 +5844,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node put: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); phba = ndlp->phba; spin_lock_irqsave(&phba->ndlp_lock, flags); /* Check the ndlp memory free acknowledge flag to avoid the @@ -5857,7 +5857,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) "0274 lpfc_nlp_put: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); return 1; } /* Check the ndlp inactivate log flag to avoid the possible @@ -5870,7 +5870,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) "0275 lpfc_nlp_put: ndlp:x%p " "usgmap:x%x refcnt:%d\n", (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); + kref_read(&ndlp->kref)); return 1; } /* For last put, mark the ndlp usage flags to make sure no @@ -5878,7 +5878,7 @@ lpfc_nlp_put(struct lpfc_nodelist *ndlp) * in between the process when the final kref_put has been * invoked on this ndlp. */ - if (atomic_read(&ndlp->kref.refcount) == 1) { + if (kref_read(&ndlp->kref) == 1) { /* Indicate ndlp is put to inactive state. */ NLP_SET_IACT_REQ(ndlp); /* Acknowledge ndlp memory free has been seen. */ @@ -5906,8 +5906,8 @@ lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, "node not used: did:x%x flg:x%x refcnt:x%x", ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); - if (atomic_read(&ndlp->kref.refcount) == 1) + kref_read(&ndlp->kref)); + if (kref_read(&ndlp->kref) == 1) if (lpfc_nlp_put(ndlp)) return 1; return 0; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 4776fd85514f..64717c171b15 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -2660,8 +2660,7 @@ lpfc_cleanup(struct lpfc_vport *vport) "usgmap:x%x refcnt:%d\n", ndlp->nlp_DID, (void *)ndlp, ndlp->nlp_usg_map, - atomic_read( - &ndlp->kref.refcount)); + kref_read(&ndlp->kref)); } break; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3a8470d55af5..d977a472f89f 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -5956,18 +5956,25 @@ lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) free_vfi_bmask: kfree(phba->sli4_hba.vfi_bmask); + phba->sli4_hba.vfi_bmask = NULL; free_xri_ids: kfree(phba->sli4_hba.xri_ids); + phba->sli4_hba.xri_ids = NULL; free_xri_bmask: kfree(phba->sli4_hba.xri_bmask); + phba->sli4_hba.xri_bmask = NULL; free_vpi_ids: kfree(phba->vpi_ids); + phba->vpi_ids = NULL; free_vpi_bmask: kfree(phba->vpi_bmask); + phba->vpi_bmask = NULL; free_rpi_ids: kfree(phba->sli4_hba.rpi_ids); + phba->sli4_hba.rpi_ids = NULL; free_rpi_bmask: kfree(phba->sli4_hba.rpi_bmask); + phba->sli4_hba.rpi_bmask = NULL; err_exit: return rc; } diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index b2f3e24f6bc0..4ab634fc27df 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -393,6 +393,7 @@ struct MPT3SAS_TARGET { * @eedp_enable: eedp support enable bit * @eedp_type: 0(type_1), 1(type_2), 2(type_3) * @eedp_block_length: block size + * @ata_command_pending: SATL passthrough outstanding for device */ struct MPT3SAS_DEVICE { struct MPT3SAS_TARGET *sas_target; @@ -404,6 +405,17 @@ struct MPT3SAS_DEVICE { u8 ignore_delay_remove; /* Iopriority Command Handling */ u8 ncq_prio_enable; + /* + * Bug workaround for SATL handling: the mpt2/3sas firmware + * doesn't return BUSY or TASK_SET_FULL for subsequent + * commands while a SATL pass through is in operation as the + * spec requires, it simply does nothing with them until the + * pass through completes, causing them possibly to timeout if + * the passthrough is a long executing command (like format or + * secure erase). This variable allows us to do the right + * thing while a SATL command is pending. + */ + unsigned long ata_command_pending; }; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index b8cd0a1050d1..46e866c36c8a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -51,6 +51,7 @@ #include <linux/workqueue.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/pci-aspm.h> #include <linux/interrupt.h> #include <linux/aer.h> #include <linux/raid_class.h> @@ -3918,9 +3919,18 @@ _scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc, } } -static inline bool ata_12_16_cmd(struct scsi_cmnd *scmd) +static int _scsih_set_satl_pending(struct scsi_cmnd *scmd, bool pending) { - return (scmd->cmnd[0] == ATA_12 || scmd->cmnd[0] == ATA_16); + struct MPT3SAS_DEVICE *priv = scmd->device->hostdata; + + if (scmd->cmnd[0] != ATA_12 && scmd->cmnd[0] != ATA_16) + return 0; + + if (pending) + return test_and_set_bit(0, &priv->ata_command_pending); + + clear_bit(0, &priv->ata_command_pending); + return 0; } /** @@ -3944,9 +3954,7 @@ _scsih_flush_running_cmds(struct MPT3SAS_ADAPTER *ioc) if (!scmd) continue; count++; - if (ata_12_16_cmd(scmd)) - scsi_internal_device_unblock(scmd->device, - SDEV_RUNNING); + _scsih_set_satl_pending(scmd, false); mpt3sas_base_free_smid(ioc, smid); scsi_dma_unmap(scmd); if (ioc->pci_error_recovery) @@ -4082,13 +4090,6 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) if (ioc->logging_level & MPT_DEBUG_SCSI) scsi_print_command(scmd); - /* - * Lock the device for any subsequent command until command is - * done. - */ - if (ata_12_16_cmd(scmd)) - scsi_internal_device_block(scmd->device); - sas_device_priv_data = scmd->device->hostdata; if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { scmd->result = DID_NO_CONNECT << 16; @@ -4102,6 +4103,19 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) return 0; } + /* + * Bug work around for firmware SATL handling. The loop + * is based on atomic operations and ensures consistency + * since we're lockless at this point + */ + do { + if (test_bit(0, &sas_device_priv_data->ata_command_pending)) { + scmd->result = SAM_STAT_BUSY; + scmd->scsi_done(scmd); + return 0; + } + } while (_scsih_set_satl_pending(scmd, true)); + sas_target_priv_data = sas_device_priv_data->sas_target; /* invalid device handle */ @@ -4663,6 +4677,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) struct MPT3SAS_DEVICE *sas_device_priv_data; u32 response_code = 0; unsigned long flags; + unsigned int sector_sz; mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply); @@ -4675,8 +4690,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) if (scmd == NULL) return 1; - if (ata_12_16_cmd(scmd)) - scsi_internal_device_unblock(scmd->device, SDEV_RUNNING); + _scsih_set_satl_pending(scmd, false); mpi_request = mpt3sas_base_get_msg_frame(ioc, smid); @@ -4728,6 +4742,20 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) } xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); + + /* In case of bogus fw or device, we could end up having + * unaligned partial completion. We can force alignment here, + * then scsi-ml does not need to handle this misbehavior. + */ + sector_sz = scmd->device->sector_size; + if (unlikely(!blk_rq_is_passthrough(scmd->request) && sector_sz && + xfer_cnt % sector_sz)) { + sdev_printk(KERN_INFO, scmd->device, + "unaligned partial completion avoided (xfer_cnt=%u, sector_sz=%u)\n", + xfer_cnt, sector_sz); + xfer_cnt = round_down(xfer_cnt, sector_sz); + } + scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) log_info = le32_to_cpu(mpi_reply->IOCLogInfo); @@ -8768,6 +8796,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) switch (hba_mpi_version) { case MPI2_VERSION: + pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | + PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); /* Use mpt2sas driver host template for SAS 2.0 HBA's */ shost = scsi_host_alloc(&mpt2sas_driver_template, sizeof(struct MPT3SAS_ADAPTER)); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 7f1d5785bc30..e7a7a704a315 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -2057,10 +2057,10 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ioc->name, __func__, le16_to_cpu(mpi_reply->ResponseDataLength))); - memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); - req->sense_len = sizeof(*mpi_reply); - req->resid_len = 0; - rsp->resid_len -= + memcpy(scsi_req(req)->sense, mpi_reply, sizeof(*mpi_reply)); + scsi_req(req)->sense_len = sizeof(*mpi_reply); + scsi_req(req)->resid_len = 0; + scsi_req(rsp)->resid_len -= le16_to_cpu(mpi_reply->ResponseDataLength); /* check if the resp needs to be copied from the allocated diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index ef99f62831fb..30b905080c61 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -48,6 +48,7 @@ #include <scsi/osd_sense.h> #include <scsi/scsi_device.h> +#include <scsi/scsi_request.h> #include "osd_debug.h" @@ -477,11 +478,13 @@ static void _set_error_resid(struct osd_request *or, struct request *req, { or->async_error = error; or->req_errors = req->errors ? : error; - or->sense_len = req->sense_len; + or->sense_len = scsi_req(req)->sense_len; + if (or->sense_len) + memcpy(or->sense, scsi_req(req)->sense, or->sense_len); if (or->out.req) - or->out.residual = or->out.req->resid_len; + or->out.residual = scsi_req(or->out.req)->resid_len; if (or->in.req) - or->in.residual = or->in.req->resid_len; + or->in.residual = scsi_req(or->in.req)->resid_len; } int osd_execute_request(struct osd_request *or) @@ -1562,10 +1565,11 @@ static struct request *_make_request(struct request_queue *q, bool has_write, struct bio *bio = oii->bio; int ret; - req = blk_get_request(q, has_write ? WRITE : READ, flags); + req = blk_get_request(q, has_write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, + flags); if (IS_ERR(req)) return req; - blk_rq_set_block_pc(req); + scsi_req_init(req); for_each_bio(bio) { struct bio *bounce_bio = bio; @@ -1599,8 +1603,6 @@ static int _init_blk_request(struct osd_request *or, req->timeout = or->timeout; req->retries = or->retries; - req->sense = or->sense; - req->sense_len = 0; if (has_out) { or->out.req = req; @@ -1612,7 +1614,7 @@ static int _init_blk_request(struct osd_request *or, ret = PTR_ERR(req); goto out; } - blk_rq_set_block_pc(req); + scsi_req_init(req); or->in.req = or->request->next_rq = req; } } else if (has_in) @@ -1699,8 +1701,8 @@ int osd_finalize_request(struct osd_request *or, osd_sec_sign_cdb(&or->cdb, cap_key); - or->request->cmd = or->cdb.buff; - or->request->cmd_len = _osd_req_cdb_len(or); + scsi_req(or->request)->cmd = or->cdb.buff; + scsi_req(or->request)->cmd_len = _osd_req_cdb_len(or); return 0; } diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index e8196c55b633..451de6c5e3c9 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -322,6 +322,7 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) /* Wakeup from interrupt */ static void osst_end_async(struct request *req, int update) { + struct scsi_request *rq = scsi_req(req); struct osst_request *SRpnt = req->end_io_data; struct osst_tape *STp = SRpnt->stp; struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; @@ -330,6 +331,8 @@ static void osst_end_async(struct request *req, int update) #if DEBUG STp->write_pending = 0; #endif + if (rq->sense_len) + memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE); if (SRpnt->waiting) complete(SRpnt->waiting); @@ -357,17 +360,20 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, int use_sg, int timeout, int retries) { struct request *req; + struct scsi_request *rq; struct page **pages = NULL; struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; int err = 0; int write = (data_direction == DMA_TO_DEVICE); - req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); + req = blk_get_request(SRpnt->stp->device->request_queue, + write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(req)) return DRIVER_ERROR << 24; - blk_rq_set_block_pc(req); + rq = scsi_req(req); + scsi_req_init(req); req->rq_flags |= RQF_QUIET; SRpnt->bio = NULL; @@ -404,11 +410,9 @@ static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, goto free_req; } - req->cmd_len = cmd_len; - memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = SRpnt->sense; - req->sense_len = 0; + rq->cmd_len = cmd_len; + memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ + memcpy(rq->cmd, cmd, rq->cmd_len); req->timeout = timeout; req->retries = retries; req->end_io_data = SRpnt; diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig index 23ca8a274586..21331453db7b 100644 --- a/drivers/scsi/qedi/Kconfig +++ b/drivers/scsi/qedi/Kconfig @@ -1,6 +1,6 @@ config QEDI tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support" - depends on PCI && SCSI + depends on PCI && SCSI && UIO depends on QED select SCSI_ISCSI_ATTRS select QED_LL2 diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 47eb4d545d13..f201f4099620 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -243,12 +243,15 @@ qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj, struct qla_hw_data *ha = vha->hw; ssize_t rval = 0; + mutex_lock(&ha->optrom_mutex); + if (ha->optrom_state != QLA_SREADING) - return 0; + goto out; - mutex_lock(&ha->optrom_mutex); rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer, ha->optrom_region_size); + +out: mutex_unlock(&ha->optrom_mutex); return rval; @@ -263,14 +266,19 @@ qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; - if (ha->optrom_state != QLA_SWRITING) + mutex_lock(&ha->optrom_mutex); + + if (ha->optrom_state != QLA_SWRITING) { + mutex_unlock(&ha->optrom_mutex); return -EINVAL; - if (off > ha->optrom_region_size) + } + if (off > ha->optrom_region_size) { + mutex_unlock(&ha->optrom_mutex); return -ERANGE; + } if (off + count > ha->optrom_region_size) count = ha->optrom_region_size - off; - mutex_lock(&ha->optrom_mutex); memcpy(&ha->optrom_buffer[off], buf, count); mutex_unlock(&ha->optrom_mutex); @@ -753,7 +761,6 @@ qla2x00_issue_logo(struct file *filp, struct kobject *kobj, struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, struct device, kobj))); int type; - int rval = 0; port_id_t did; type = simple_strtol(buf, NULL, 10); @@ -767,7 +774,7 @@ qla2x00_issue_logo(struct file *filp, struct kobject *kobj, ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type); - rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did); + qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did); return count; } diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 1bf8061ff803..40ca75bbcb9d 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -921,7 +921,7 @@ qla2x00_process_loopback(struct bsg_job *bsg_job) bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(response) + sizeof(uint8_t); - fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + + fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) + sizeof(struct fc_bsg_reply); memcpy(fw_sts_ptr, response, sizeof(response)); fw_sts_ptr += sizeof(response); diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ef699b66b685..2f14adfab018 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1556,7 +1556,8 @@ typedef struct { struct atio { uint8_t entry_type; /* Entry type. */ uint8_t entry_count; /* Entry count. */ - uint8_t data[58]; + __le16 attr_n_length; + uint8_t data[56]; uint32_t signature; #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ }; @@ -2732,7 +2733,7 @@ struct isp_operations { #define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) #define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) -#define QLA_MSIX_DEFAULT 0x00 +#define QLA_BASE_VECTORS 2 /* default + RSP */ #define QLA_MSIX_RSP_Q 0x01 #define QLA_ATIO_VECTOR 0x02 #define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03 @@ -2754,7 +2755,6 @@ struct qla_msix_entry { uint16_t entry; char name[30]; void *handle; - struct irq_affinity_notify irq_notify; int cpuid; }; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 632d5f30386a..7b6317c8c2e9 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1191,7 +1191,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) /* Wait for soft-reset to complete. */ RD_REG_DWORD(®->ctrl_status); - for (cnt = 0; cnt < 6000000; cnt++) { + for (cnt = 0; cnt < 60; cnt++) { barrier(); if ((RD_REG_DWORD(®->ctrl_status) & CSRX_ISP_SOFT_RESET) == 0) @@ -1234,7 +1234,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) RD_REG_DWORD(®->hccr); RD_REG_WORD(®->mailbox0); - for (cnt = 6000000; RD_REG_WORD(®->mailbox0) != 0 && + for (cnt = 60; RD_REG_WORD(®->mailbox0) != 0 && rval == QLA_SUCCESS; cnt--) { barrier(); if (cnt) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b9c113e47346..edc2264db45b 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -19,10 +19,6 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, sts_entry_t *); -static void qla_irq_affinity_notify(struct irq_affinity_notify *, - const cpumask_t *); -static void qla_irq_affinity_release(struct kref *); - /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. @@ -1472,7 +1468,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, type, sp->handle, comp_status, fw_status[1], fw_status[2], le16_to_cpu(((struct els_sts_entry_24xx *) pkt)->total_byte_count)); - fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); } else { @@ -1486,7 +1483,8 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, pkt)->error_subcode_2)); res = DID_ERROR << 16; bsg_reply->reply_payload_rcv_len = 0; - fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + fw_sts_ptr = ((uint8_t*)scsi_req(bsg_job->req)->sense) + + sizeof(struct fc_bsg_reply); memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); } ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056, @@ -2496,6 +2494,10 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) if (pkt->entry_status & RF_BUSY) res = DID_BUS_BUSY << 16; + if (pkt->entry_type == NOTIFY_ACK_TYPE && + pkt->handle == QLA_TGT_SKIP_HANDLE) + return; + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { sp->done(ha, sp, res); @@ -2572,14 +2574,6 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (!vha->flags.online) return; - if (rsp->msix && rsp->msix->cpuid != smp_processor_id()) { - /* if kernel does not notify qla of IRQ's CPU change, - * then set it here. - */ - rsp->msix->cpuid = smp_processor_id(); - ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid; - } - while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) { pkt = (struct sts_entry_24xx *)rsp->ring_ptr; @@ -3018,13 +3012,20 @@ static const struct qla_init_msix_entry qla82xx_msix_entries[] = { static int qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) { -#define MIN_MSIX_COUNT 2 int i, ret; struct qla_msix_entry *qentry; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); + struct irq_affinity desc = { + .pre_vectors = QLA_BASE_VECTORS, + }; + + if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) + desc.pre_vectors++; + + ret = pci_alloc_irq_vectors_affinity(ha->pdev, QLA_BASE_VECTORS, + ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, + &desc); - ret = pci_alloc_irq_vectors(ha->pdev, MIN_MSIX_COUNT, ha->msix_count, - PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); if (ret < 0) { ql_log(ql_log_fatal, vha, 0x00c7, "MSI-X: Failed to enable support, " @@ -3069,13 +3070,10 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) qentry->have_irq = 0; qentry->in_use = 0; qentry->handle = NULL; - qentry->irq_notify.notify = qla_irq_affinity_notify; - qentry->irq_notify.release = qla_irq_affinity_release; - qentry->cpuid = -1; } /* Enable MSI-X vectors for the base queue */ - for (i = 0; i < (QLA_MSIX_RSP_Q + 1); i++) { + for (i = 0; i < QLA_BASE_VECTORS; i++) { qentry = &ha->msix_entries[i]; qentry->handle = rsp; rsp->msix = qentry; @@ -3093,18 +3091,6 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) goto msix_register_fail; qentry->have_irq = 1; qentry->in_use = 1; - - /* Register for CPU affinity notification. */ - irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify); - - /* Schedule work (ie. trigger a notification) to read cpu - * mask for this specific irq. - * kref_get is required because - * irq_affinity_notify() will do - * kref_put(). - */ - kref_get(&qentry->irq_notify.kref); - schedule_work(&qentry->irq_notify.work); } /* @@ -3258,7 +3244,7 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) * from a probe failure context. */ if (!ha->rsp_q_map || !ha->rsp_q_map[0]) - return; + goto free_irqs; rsp = ha->rsp_q_map[0]; if (ha->flags.msix_enabled) { @@ -3278,6 +3264,7 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) free_irq(pci_irq_vector(ha->pdev, 0), rsp); } +free_irqs: pci_free_irq_vectors(ha->pdev); } @@ -3301,49 +3288,3 @@ int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, msix->handle = qpair; return ret; } - - -/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */ -static void qla_irq_affinity_notify(struct irq_affinity_notify *notify, - const cpumask_t *mask) -{ - struct qla_msix_entry *e = - container_of(notify, struct qla_msix_entry, irq_notify); - struct qla_hw_data *ha; - struct scsi_qla_host *base_vha; - struct rsp_que *rsp = e->handle; - - /* user is recommended to set mask to just 1 cpu */ - e->cpuid = cpumask_first(mask); - - ha = rsp->hw; - base_vha = pci_get_drvdata(ha->pdev); - - ql_dbg(ql_dbg_init, base_vha, 0xffff, - "%s: host %ld : vector %d cpu %d \n", __func__, - base_vha->host_no, e->vector, e->cpuid); - - if (e->have_irq) { - if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && - (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) { - ha->tgt.rspq_vector_cpuid = e->cpuid; - ql_dbg(ql_dbg_init, base_vha, 0xffff, - "%s: host%ld: rspq vector %d cpu %d runtime change\n", - __func__, base_vha->host_no, e->vector, e->cpuid); - } - } -} - -static void qla_irq_affinity_release(struct kref *ref) -{ - struct irq_affinity_notify *notify = - container_of(ref, struct irq_affinity_notify, kref); - struct qla_msix_entry *e = - container_of(notify, struct qla_msix_entry, irq_notify); - struct rsp_que *rsp = e->handle; - struct scsi_qla_host *base_vha = pci_get_drvdata(rsp->hw->pdev); - - ql_dbg(ql_dbg_init, base_vha, 0xffff, - "%s: host%ld: vector %d cpu %d\n", __func__, - base_vha->host_no, e->vector, e->cpuid); -} diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 2819ceb96041..67f64db390b0 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -10,7 +10,7 @@ #include <linux/delay.h> #include <linux/gfp.h> -struct rom_cmd { +static struct rom_cmd { uint16_t cmd; } rom_cmds[] = { { MBC_LOAD_RAM }, @@ -101,12 +101,12 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) return QLA_FUNCTION_TIMEOUT; } - /* if PCI error, then avoid mbx processing.*/ - if (test_bit(PCI_ERR, &base_vha->dpc_flags)) { + /* if PCI error, then avoid mbx processing.*/ + if (test_bit(PCI_ERR, &base_vha->dpc_flags)) { ql_log(ql_log_warn, vha, 0x1191, "PCI error, exiting.\n"); return QLA_FUNCTION_TIMEOUT; - } + } reg = ha->iobase; io_lock_on = base_vha->flags.init_done; @@ -323,20 +323,33 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) } } else { - uint16_t mb0; - uint32_t ictrl; + uint16_t mb[8]; + uint32_t ictrl, host_status, hccr; uint16_t w; if (IS_FWI2_CAPABLE(ha)) { - mb0 = RD_REG_WORD(®->isp24.mailbox0); + mb[0] = RD_REG_WORD(®->isp24.mailbox0); + mb[1] = RD_REG_WORD(®->isp24.mailbox1); + mb[2] = RD_REG_WORD(®->isp24.mailbox2); + mb[3] = RD_REG_WORD(®->isp24.mailbox3); + mb[7] = RD_REG_WORD(®->isp24.mailbox7); ictrl = RD_REG_DWORD(®->isp24.ictrl); + host_status = RD_REG_DWORD(®->isp24.host_status); + hccr = RD_REG_DWORD(®->isp24.hccr); + + ql_log(ql_log_warn, vha, 0x1119, + "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx " + "mb[0-3]=[0x%x 0x%x 0x%x 0x%x] mb7 0x%x host_status 0x%x hccr 0x%x\n", + command, ictrl, jiffies, mb[0], mb[1], mb[2], mb[3], + mb[7], host_status, hccr); + } else { - mb0 = RD_MAILBOX_REG(ha, ®->isp, 0); + mb[0] = RD_MAILBOX_REG(ha, ®->isp, 0); ictrl = RD_REG_WORD(®->isp.ictrl); + ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119, + "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx " + "mb[0]=0x%x\n", command, ictrl, jiffies, mb[0]); } - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119, - "MBX Command timeout for cmd %x, iocontrol=%x jiffies=%lx " - "mb[0]=0x%x\n", command, ictrl, jiffies, mb0); ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019); /* Capture FW dump only, if PCI device active */ @@ -684,7 +697,6 @@ qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; struct qla_hw_data *ha = vha->hw; - int configured_count; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x111a, "Entered %s.\n", __func__); @@ -707,7 +719,6 @@ qla_set_exlogin_mem_cfg(scsi_qla_host_t *vha, dma_addr_t phys_addr) /*EMPTY*/ ql_dbg(ql_dbg_mbx, vha, 0x111b, "Failed=%x.\n", rval); } else { - configured_count = mcp->mb[11]; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x118c, "Done %s.\n", __func__); } diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 02f1de18bc2b..96c33e292eba 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -2244,7 +2244,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req, memcpy(fstatus.reserved_3, pkt->reserved_2, 20 * sizeof(uint8_t)); - fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + + fw_sts_ptr = ((uint8_t *)scsi_req(bsg_job->req)->sense) + sizeof(struct fc_bsg_reply); memcpy(fw_sts_ptr, (uint8_t *)&fstatus, diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 54380b434b30..0a1723cc08cf 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -42,6 +42,11 @@ static int qla82xx_crb_table_initialized; (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \ QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20) +const int MD_MIU_TEST_AGT_RDDATA[] = { + 0x410000A8, 0x410000AC, + 0x410000B8, 0x410000BC +}; + static void qla82xx_crb_addr_transform_setup(void) { qla82xx_crb_addr_transform(XDMA); diff --git a/drivers/scsi/qla2xxx/qla_nx.h b/drivers/scsi/qla2xxx/qla_nx.h index 6201dce3553b..77624eac95a4 100644 --- a/drivers/scsi/qla2xxx/qla_nx.h +++ b/drivers/scsi/qla2xxx/qla_nx.h @@ -1176,8 +1176,7 @@ struct qla82xx_md_entry_queue { #define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 #define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 -static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, - 0x410000B8, 0x410000BC }; +extern const int MD_MIU_TEST_AGT_RDDATA[4]; #define CRB_NIU_XG_PAUSE_CTL_P0 0x1 #define CRB_NIU_XG_PAUSE_CTL_P1 0x8 diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 007192d7bad8..dc1ec9b61027 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -15,6 +15,23 @@ #define TIMEOUT_100_MS 100 +static const uint32_t qla8044_reg_tbl[] = { + QLA8044_PEG_HALT_STATUS1, + QLA8044_PEG_HALT_STATUS2, + QLA8044_PEG_ALIVE_COUNTER, + QLA8044_CRB_DRV_ACTIVE, + QLA8044_CRB_DEV_STATE, + QLA8044_CRB_DRV_STATE, + QLA8044_CRB_DRV_SCRATCH, + QLA8044_CRB_DEV_PART_INFO1, + QLA8044_CRB_IDC_VER_MAJOR, + QLA8044_FW_VER_MAJOR, + QLA8044_FW_VER_MINOR, + QLA8044_FW_VER_SUB, + QLA8044_CMDPEG_STATE, + QLA8044_ASIC_TEMP, +}; + /* 8044 Flash Read/Write functions */ uint32_t qla8044_rd_reg(struct qla_hw_data *ha, ulong addr) diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h index 02fe3c4cdf55..83c1b7e17c80 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.h +++ b/drivers/scsi/qla2xxx/qla_nx2.h @@ -535,23 +535,6 @@ enum qla_regs { #define CRB_CMDPEG_CHECK_RETRY_COUNT 60 #define CRB_CMDPEG_CHECK_DELAY 500 -static const uint32_t qla8044_reg_tbl[] = { - QLA8044_PEG_HALT_STATUS1, - QLA8044_PEG_HALT_STATUS2, - QLA8044_PEG_ALIVE_COUNTER, - QLA8044_CRB_DRV_ACTIVE, - QLA8044_CRB_DEV_STATE, - QLA8044_CRB_DRV_STATE, - QLA8044_CRB_DRV_SCRATCH, - QLA8044_CRB_DEV_PART_INFO1, - QLA8044_CRB_IDC_VER_MAJOR, - QLA8044_FW_VER_MAJOR, - QLA8044_FW_VER_MINOR, - QLA8044_FW_VER_SUB, - QLA8044_CMDPEG_STATE, - QLA8044_ASIC_TEMP, -}; - /* MiniDump Structures */ /* Driver_code is for driver to write some info about the entry diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index c5a9d6c295a0..d01c90c7dd04 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -467,7 +467,7 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) continue; rsp = ha->rsp_q_map[cnt]; - clear_bit(cnt, ha->req_qid_map); + clear_bit(cnt, ha->rsp_qid_map); ha->rsp_q_map[cnt] = NULL; spin_unlock_irqrestore(&ha->hardware_lock, flags); qla2x00_free_rsp_que(ha, rsp); @@ -1617,7 +1617,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) /* Don't abort commands in adapter during EEH * recovery as it's not accessible/responding. */ - if (!ha->flags.eeh_busy) { + if (GET_CMD_SP(sp) && !ha->flags.eeh_busy) { /* Get a reference to the sp and drop the lock. * The reference ensures this sp->done() call * - and not the call in qla2xxx_eh_abort() - @@ -3663,7 +3663,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, sizeof(struct ct6_dsd), 0, SLAB_HWCACHE_ALIGN, NULL); if (!ctx_cachep) - goto fail_free_gid_list; + goto fail_free_srb_mempool; } ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ, ctx_cachep); @@ -3816,7 +3816,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, ha->loop_id_map = kzalloc(BITS_TO_LONGS(LOOPID_MAP_SIZE) * sizeof(long), GFP_KERNEL); if (!ha->loop_id_map) - goto fail_async_pd; + goto fail_loop_id_map; else { qla2x00_set_reserved_loop_ids(ha); ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0123, @@ -3825,6 +3825,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, return 0; +fail_loop_id_map: + dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); fail_async_pd: dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); fail_ex_init_cb: @@ -3852,6 +3854,10 @@ fail_free_ms_iocb: dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); ha->ms_iocb = NULL; ha->ms_iocb_dma = 0; + + if (ha->sns_cmd) + dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), + ha->sns_cmd, ha->sns_cmd_dma); fail_dma_pool: if (IS_QLA82XX(ha) || ql2xenabledif) { dma_pool_destroy(ha->fcp_cmnd_dma_pool); @@ -3869,10 +3875,12 @@ fail_free_nvram: kfree(ha->nvram); ha->nvram = NULL; fail_free_ctx_mempool: - mempool_destroy(ha->ctx_mempool); + if (ha->ctx_mempool) + mempool_destroy(ha->ctx_mempool); ha->ctx_mempool = NULL; fail_free_srb_mempool: - mempool_destroy(ha->srb_mempool); + if (ha->srb_mempool) + mempool_destroy(ha->srb_mempool); ha->srb_mempool = NULL; fail_free_gid_list: dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index bff9689f5ca9..e4fda84b959e 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -668,11 +668,9 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) { struct qla_hw_data *ha = vha->hw; struct qla_tgt_sess *sess = NULL; - uint32_t unpacked_lun, lun = 0; uint16_t loop_id; int res = 0; struct imm_ntfy_from_isp *n = (struct imm_ntfy_from_isp *)iocb; - struct atio_from_isp *a = (struct atio_from_isp *)iocb; unsigned long flags; loop_id = le16_to_cpu(n->u.isp24.nport_handle); @@ -725,11 +723,7 @@ static int qlt_reset(struct scsi_qla_host *vha, void *iocb, int mcmd) "loop_id %d)\n", vha->host_no, sess, sess->port_name, mcmd, loop_id); - lun = a->u.isp24.fcp_cmnd.lun; - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - return qlt_issue_task_mgmt(sess, unpacked_lun, mcmd, - iocb, QLA24XX_MGMT_SEND_NACK); + return qlt_issue_task_mgmt(sess, 0, mcmd, iocb, QLA24XX_MGMT_SEND_NACK); } /* ha->tgt.sess_lock supposed to be held on entry */ @@ -3067,7 +3061,7 @@ static int __qlt_send_term_imm_notif(struct scsi_qla_host *vha, pkt->entry_type = NOTIFY_ACK_TYPE; pkt->entry_count = 1; - pkt->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; + pkt->handle = QLA_TGT_SKIP_HANDLE; nack = (struct nack_to_isp *)pkt; nack->ox_id = ntfy->ox_id; @@ -3110,6 +3104,9 @@ static void qlt_send_term_imm_notif(struct scsi_qla_host *vha, #if 0 /* Todo */ if (rc == -ENOMEM) qlt_alloc_qfull_cmd(vha, imm, 0, 0); +#else + if (rc) { + } #endif goto done; } @@ -6457,12 +6454,29 @@ qlt_24xx_process_atio_queue(struct scsi_qla_host *vha, uint8_t ha_locked) if (!vha->flags.online) return; - while (ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) { + while ((ha->tgt.atio_ring_ptr->signature != ATIO_PROCESSED) || + fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr)) { pkt = (struct atio_from_isp *)ha->tgt.atio_ring_ptr; cnt = pkt->u.raw.entry_count; - qlt_24xx_atio_pkt_all_vps(vha, (struct atio_from_isp *)pkt, - ha_locked); + if (unlikely(fcpcmd_is_corrupted(ha->tgt.atio_ring_ptr))) { + /* + * This packet is corrupted. The header + payload + * can not be trusted. There is no point in passing + * it further up. + */ + ql_log(ql_log_warn, vha, 0xffff, + "corrupted fcp frame SID[%3phN] OXID[%04x] EXCG[%x] %64phN\n", + pkt->u.isp24.fcp_hdr.s_id, + be16_to_cpu(pkt->u.isp24.fcp_hdr.ox_id), + le32_to_cpu(pkt->u.isp24.exchange_addr), pkt); + + adjust_corrupted_atio(pkt); + qlt_send_term_exchange(vha, NULL, pkt, ha_locked, 0); + } else { + qlt_24xx_atio_pkt_all_vps(vha, + (struct atio_from_isp *)pkt, ha_locked); + } for (i = 0; i < cnt; i++) { ha->tgt.atio_ring_index++; @@ -6545,6 +6559,13 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) /* Disable Full Login after LIP */ nv->host_p &= cpu_to_le32(~BIT_10); + + /* + * clear BIT 15 explicitly as we have seen at least + * a couple of instances where this was set and this + * was causing the firmware to not be initialized. + */ + nv->firmware_options_1 &= cpu_to_le32(~BIT_15); /* Enable target PRLI control */ nv->firmware_options_2 |= cpu_to_le32(BIT_14); } else { @@ -6560,9 +6581,6 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) return; } - /* out-of-order frames reassembly */ - nv->firmware_options_3 |= BIT_6|BIT_9; - if (ha->tgt.enable_class_2) { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = @@ -6629,11 +6647,17 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) /* Disable ini mode, if requested */ if (!qla_ini_mode_enabled(vha)) nv->firmware_options_1 |= cpu_to_le32(BIT_5); - /* Disable Full Login after LIP */ nv->firmware_options_1 &= cpu_to_le32(~BIT_13); /* Enable initial LIP */ nv->firmware_options_1 &= cpu_to_le32(~BIT_9); + /* + * clear BIT 15 explicitly as we have seen at + * least a couple of instances where this was set + * and this was causing the firmware to not be + * initialized. + */ + nv->firmware_options_1 &= cpu_to_le32(~BIT_15); if (ql2xtgt_tape_enable) /* Enable FC tape support */ nv->firmware_options_2 |= cpu_to_le32(BIT_12); @@ -6658,9 +6682,6 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) return; } - /* out-of-order frames reassembly */ - nv->firmware_options_3 |= BIT_6|BIT_9; - if (ha->tgt.enable_class_2) { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index f26c5f60eedd..0824a8164a24 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -427,13 +427,33 @@ struct atio_from_isp { struct { uint8_t entry_type; /* Entry type. */ uint8_t entry_count; /* Entry count. */ - uint8_t data[58]; + __le16 attr_n_length; +#define FCP_CMD_LENGTH_MASK 0x0fff +#define FCP_CMD_LENGTH_MIN 0x38 + uint8_t data[56]; uint32_t signature; #define ATIO_PROCESSED 0xDEADDEAD /* Signature */ } raw; } u; } __packed; +static inline int fcpcmd_is_corrupted(struct atio *atio) +{ + if (atio->entry_type == ATIO_TYPE7 && + (le16_to_cpu(atio->attr_n_length & FCP_CMD_LENGTH_MASK) < + FCP_CMD_LENGTH_MIN)) + return 1; + else + return 0; +} + +/* adjust corrupted atio so we won't trip over the same entry again. */ +static inline void adjust_corrupted_atio(struct atio_from_isp *atio) +{ + atio->u.raw.attr_n_length = cpu_to_le16(FCP_CMD_LENGTH_MIN); + atio->u.isp24.fcp_cmnd.add_cdb_len = 0; +} + #define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */ /* diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 36935c9ed669..8a58ef3adab4 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -433,6 +433,18 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, count++; } } + } else if (QLA_TGT_MODE_ENABLED() && + ent->t263.queue_type == T263_QUEUE_TYPE_ATIO) { + struct qla_hw_data *ha = vha->hw; + struct atio *atr = ha->tgt.atio_ring; + + if (atr || !buf) { + length = ha->tgt.atio_q_length; + qla27xx_insert16(0, buf, len); + qla27xx_insert16(length, buf, len); + qla27xx_insertbuf(atr, length * sizeof(*atr), buf, len); + count++; + } } else { ql_dbg(ql_dbg_misc, vha, 0xd026, "%s: unknown queue %x\n", __func__, ent->t263.queue_type); @@ -676,6 +688,18 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, count++; } } + } else if (QLA_TGT_MODE_ENABLED() && + ent->t274.queue_type == T274_QUEUE_TYPE_ATIO_SHAD) { + struct qla_hw_data *ha = vha->hw; + struct atio *atr = ha->tgt.atio_ring_ptr; + + if (atr || !buf) { + qla27xx_insert16(0, buf, len); + qla27xx_insert16(1, buf, len); + qla27xx_insert32(ha->tgt.atio_q_in ? + readl(ha->tgt.atio_q_in) : 0, buf, len); + count++; + } } else { ql_dbg(ql_dbg_misc, vha, 0xd02f, "%s: unknown queue %x\n", __func__, ent->t274.queue_type); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 6643f6fc7795..3084983c1287 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -371,7 +371,7 @@ static int tcm_qla2xxx_write_pending(struct se_cmd *se_cmd) */ pr_debug("write_pending aborted cmd[%p] refcount %d " "transport_state %x, t_state %x, se_cmd_flags %x\n", - cmd,cmd->se_cmd.cmd_kref.refcount.counter, + cmd, kref_read(&cmd->se_cmd.cmd_kref), cmd->se_cmd.transport_state, cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); @@ -584,7 +584,7 @@ static int tcm_qla2xxx_queue_data_in(struct se_cmd *se_cmd) */ pr_debug("queue_data_in aborted cmd[%p] refcount %d " "transport_state %x, t_state %x, se_cmd_flags %x\n", - cmd,cmd->se_cmd.cmd_kref.refcount.counter, + cmd, kref_read(&cmd->se_cmd.cmd_kref), cmd->se_cmd.transport_state, cmd->se_cmd.t_state, cmd->se_cmd.se_cmd_flags); @@ -1800,7 +1800,7 @@ static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item, { return sprintf(page, "TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on " - UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, + UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname, utsname()->machine); } @@ -1906,7 +1906,7 @@ static int tcm_qla2xxx_register_configfs(void) int ret; pr_debug("TCM QLOGIC QLA2XXX fabric module %s on %s/%s on " - UTS_RELEASE"\n", TCM_QLA2XXX_VERSION, utsname()->sysname, + UTS_RELEASE"\n", QLA2XXX_VERSION, utsname()->sysname, utsname()->machine); ret = target_register_template(&tcm_qla2xxx_ops); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 37e026a4823d..cf8430be183b 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -1,7 +1,6 @@ #include <target/target_core_base.h> #include <linux/btree.h> -#define TCM_QLA2XXX_VERSION "v0.1" /* length of ASCII WWPNs including pad */ #define TCM_QLA2XXX_NAMELEN 32 /* diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 75455d4dab68..7bfbcfa7af40 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -98,176 +98,6 @@ EXPORT_SYMBOL(scsi_sd_probe_domain); ASYNC_DOMAIN_EXCLUSIVE(scsi_sd_pm_domain); EXPORT_SYMBOL(scsi_sd_pm_domain); -struct scsi_host_cmd_pool { - struct kmem_cache *cmd_slab; - struct kmem_cache *sense_slab; - unsigned int users; - char *cmd_name; - char *sense_name; - unsigned int slab_flags; - gfp_t gfp_mask; -}; - -static struct scsi_host_cmd_pool scsi_cmd_pool = { - .cmd_name = "scsi_cmd_cache", - .sense_name = "scsi_sense_cache", - .slab_flags = SLAB_HWCACHE_ALIGN, -}; - -static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { - .cmd_name = "scsi_cmd_cache(DMA)", - .sense_name = "scsi_sense_cache(DMA)", - .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA, - .gfp_mask = __GFP_DMA, -}; - -static DEFINE_MUTEX(host_cmd_pool_mutex); - -/** - * scsi_host_free_command - internal function to release a command - * @shost: host to free the command for - * @cmd: command to release - * - * the command must previously have been allocated by - * scsi_host_alloc_command. - */ -static void -scsi_host_free_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) -{ - struct scsi_host_cmd_pool *pool = shost->cmd_pool; - - if (cmd->prot_sdb) - kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); - kmem_cache_free(pool->sense_slab, cmd->sense_buffer); - kmem_cache_free(pool->cmd_slab, cmd); -} - -/** - * scsi_host_alloc_command - internal function to allocate command - * @shost: SCSI host whose pool to allocate from - * @gfp_mask: mask for the allocation - * - * Returns a fully allocated command with sense buffer and protection - * data buffer (where applicable) or NULL on failure - */ -static struct scsi_cmnd * -scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask) -{ - struct scsi_host_cmd_pool *pool = shost->cmd_pool; - struct scsi_cmnd *cmd; - - cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask); - if (!cmd) - goto fail; - - cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab, - gfp_mask | pool->gfp_mask); - if (!cmd->sense_buffer) - goto fail_free_cmd; - - if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) { - cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask); - if (!cmd->prot_sdb) - goto fail_free_sense; - } - - return cmd; - -fail_free_sense: - kmem_cache_free(pool->sense_slab, cmd->sense_buffer); -fail_free_cmd: - kmem_cache_free(pool->cmd_slab, cmd); -fail: - return NULL; -} - -/** - * __scsi_get_command - Allocate a struct scsi_cmnd - * @shost: host to transmit command - * @gfp_mask: allocation mask - * - * Description: allocate a struct scsi_cmd from host's slab, recycling from the - * host's free_list if necessary. - */ -static struct scsi_cmnd * -__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask); - - if (unlikely(!cmd)) { - unsigned long flags; - - spin_lock_irqsave(&shost->free_list_lock, flags); - if (likely(!list_empty(&shost->free_list))) { - cmd = list_entry(shost->free_list.next, - struct scsi_cmnd, list); - list_del_init(&cmd->list); - } - spin_unlock_irqrestore(&shost->free_list_lock, flags); - - if (cmd) { - void *buf, *prot; - - buf = cmd->sense_buffer; - prot = cmd->prot_sdb; - - memset(cmd, 0, sizeof(*cmd)); - - cmd->sense_buffer = buf; - cmd->prot_sdb = prot; - } - } - - return cmd; -} - -/** - * scsi_get_command - Allocate and setup a scsi command block - * @dev: parent scsi device - * @gfp_mask: allocator flags - * - * Returns: The allocated scsi command structure. - */ -struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd = __scsi_get_command(dev->host, gfp_mask); - unsigned long flags; - - if (unlikely(cmd == NULL)) - return NULL; - - cmd->device = dev; - INIT_LIST_HEAD(&cmd->list); - INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler); - spin_lock_irqsave(&dev->list_lock, flags); - list_add_tail(&cmd->list, &dev->cmd_list); - spin_unlock_irqrestore(&dev->list_lock, flags); - cmd->jiffies_at_alloc = jiffies; - return cmd; -} - -/** - * __scsi_put_command - Free a struct scsi_cmnd - * @shost: dev->host - * @cmd: Command to free - */ -static void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) -{ - unsigned long flags; - - if (unlikely(list_empty(&shost->free_list))) { - spin_lock_irqsave(&shost->free_list_lock, flags); - if (list_empty(&shost->free_list)) { - list_add(&cmd->list, &shost->free_list); - cmd = NULL; - } - spin_unlock_irqrestore(&shost->free_list_lock, flags); - } - - if (likely(cmd != NULL)) - scsi_host_free_command(shost, cmd); -} - /** * scsi_put_command - Free a scsi command block * @cmd: command block to free @@ -287,188 +117,6 @@ void scsi_put_command(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&cmd->device->list_lock, flags); BUG_ON(delayed_work_pending(&cmd->abort_work)); - - __scsi_put_command(cmd->device->host, cmd); -} - -static struct scsi_host_cmd_pool * -scsi_find_host_cmd_pool(struct Scsi_Host *shost) -{ - if (shost->hostt->cmd_size) - return shost->hostt->cmd_pool; - if (shost->unchecked_isa_dma) - return &scsi_cmd_dma_pool; - return &scsi_cmd_pool; -} - -static void -scsi_free_host_cmd_pool(struct scsi_host_cmd_pool *pool) -{ - kfree(pool->sense_name); - kfree(pool->cmd_name); - kfree(pool); -} - -static struct scsi_host_cmd_pool * -scsi_alloc_host_cmd_pool(struct Scsi_Host *shost) -{ - struct scsi_host_template *hostt = shost->hostt; - struct scsi_host_cmd_pool *pool; - - pool = kzalloc(sizeof(*pool), GFP_KERNEL); - if (!pool) - return NULL; - - pool->cmd_name = kasprintf(GFP_KERNEL, "%s_cmd", hostt->proc_name); - pool->sense_name = kasprintf(GFP_KERNEL, "%s_sense", hostt->proc_name); - if (!pool->cmd_name || !pool->sense_name) { - scsi_free_host_cmd_pool(pool); - return NULL; - } - - pool->slab_flags = SLAB_HWCACHE_ALIGN; - if (shost->unchecked_isa_dma) { - pool->slab_flags |= SLAB_CACHE_DMA; - pool->gfp_mask = __GFP_DMA; - } - - if (hostt->cmd_size) - hostt->cmd_pool = pool; - - return pool; -} - -static struct scsi_host_cmd_pool * -scsi_get_host_cmd_pool(struct Scsi_Host *shost) -{ - struct scsi_host_template *hostt = shost->hostt; - struct scsi_host_cmd_pool *retval = NULL, *pool; - size_t cmd_size = sizeof(struct scsi_cmnd) + hostt->cmd_size; - - /* - * Select a command slab for this host and create it if not - * yet existent. - */ - mutex_lock(&host_cmd_pool_mutex); - pool = scsi_find_host_cmd_pool(shost); - if (!pool) { - pool = scsi_alloc_host_cmd_pool(shost); - if (!pool) - goto out; - } - - if (!pool->users) { - pool->cmd_slab = kmem_cache_create(pool->cmd_name, cmd_size, 0, - pool->slab_flags, NULL); - if (!pool->cmd_slab) - goto out_free_pool; - - pool->sense_slab = kmem_cache_create(pool->sense_name, - SCSI_SENSE_BUFFERSIZE, 0, - pool->slab_flags, NULL); - if (!pool->sense_slab) - goto out_free_slab; - } - - pool->users++; - retval = pool; -out: - mutex_unlock(&host_cmd_pool_mutex); - return retval; - -out_free_slab: - kmem_cache_destroy(pool->cmd_slab); -out_free_pool: - if (hostt->cmd_size) { - scsi_free_host_cmd_pool(pool); - hostt->cmd_pool = NULL; - } - goto out; -} - -static void scsi_put_host_cmd_pool(struct Scsi_Host *shost) -{ - struct scsi_host_template *hostt = shost->hostt; - struct scsi_host_cmd_pool *pool; - - mutex_lock(&host_cmd_pool_mutex); - pool = scsi_find_host_cmd_pool(shost); - - /* - * This may happen if a driver has a mismatched get and put - * of the command pool; the driver should be implicated in - * the stack trace - */ - BUG_ON(pool->users == 0); - - if (!--pool->users) { - kmem_cache_destroy(pool->cmd_slab); - kmem_cache_destroy(pool->sense_slab); - if (hostt->cmd_size) { - scsi_free_host_cmd_pool(pool); - hostt->cmd_pool = NULL; - } - } - mutex_unlock(&host_cmd_pool_mutex); -} - -/** - * scsi_setup_command_freelist - Setup the command freelist for a scsi host. - * @shost: host to allocate the freelist for. - * - * Description: The command freelist protects against system-wide out of memory - * deadlock by preallocating one SCSI command structure for each host, so the - * system can always write to a swap file on a device associated with that host. - * - * Returns: Nothing. - */ -int scsi_setup_command_freelist(struct Scsi_Host *shost) -{ - const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; - struct scsi_cmnd *cmd; - - spin_lock_init(&shost->free_list_lock); - INIT_LIST_HEAD(&shost->free_list); - - shost->cmd_pool = scsi_get_host_cmd_pool(shost); - if (!shost->cmd_pool) - return -ENOMEM; - - /* - * Get one backup command for this host. - */ - cmd = scsi_host_alloc_command(shost, gfp_mask); - if (!cmd) { - scsi_put_host_cmd_pool(shost); - shost->cmd_pool = NULL; - return -ENOMEM; - } - list_add(&cmd->list, &shost->free_list); - return 0; -} - -/** - * scsi_destroy_command_freelist - Release the command freelist for a scsi host. - * @shost: host whose freelist is going to be destroyed - */ -void scsi_destroy_command_freelist(struct Scsi_Host *shost) -{ - /* - * If cmd_pool is NULL the free list was not initialized, so - * do not attempt to release resources. - */ - if (!shost->cmd_pool) - return; - - while (!list_empty(&shost->free_list)) { - struct scsi_cmnd *cmd; - - cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); - list_del_init(&cmd->list); - scsi_host_free_command(shost, cmd); - } - shost->cmd_pool = NULL; - scsi_put_host_cmd_pool(shost); } #ifdef CONFIG_SCSI_LOGGING @@ -590,7 +238,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) "(result %x)\n", cmd->result)); good_bytes = scsi_bufflen(cmd); - if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + if (!blk_rq_is_passthrough(cmd->request)) { int old_good_bytes = good_bytes; drv = scsi_cmd_to_driver(cmd); if (drv->done) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 9d7bfbb02389..f2cafae150bc 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1104,7 +1104,7 @@ static int scsi_request_sense(struct scsi_cmnd *scmd) static int scsi_eh_action(struct scsi_cmnd *scmd, int rtn) { - if (scmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { + if (!blk_rq_is_passthrough(scmd->request)) { struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); if (sdrv->eh_action) rtn = sdrv->eh_action(scmd, rtn); @@ -1744,7 +1744,7 @@ check_type: * the check condition was retryable. */ if (scmd->request->cmd_flags & REQ_FAILFAST_DEV || - scmd->request->cmd_type == REQ_TYPE_BLOCK_PC) + blk_rq_is_passthrough(scmd->request)) return 1; else return 0; @@ -1966,25 +1966,25 @@ static void eh_lock_door_done(struct request *req, int uptodate) static void scsi_eh_lock_door(struct scsi_device *sdev) { struct request *req; + struct scsi_request *rq; /* * blk_get_request with GFP_KERNEL (__GFP_RECLAIM) sleeps until a * request becomes available */ - req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); + req = blk_get_request(sdev->request_queue, REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(req)) return; + rq = scsi_req(req); + scsi_req_init(req); - blk_rq_set_block_pc(req); - - req->cmd[0] = ALLOW_MEDIUM_REMOVAL; - req->cmd[1] = 0; - req->cmd[2] = 0; - req->cmd[3] = 0; - req->cmd[4] = SCSI_REMOVAL_PREVENT; - req->cmd[5] = 0; - - req->cmd_len = COMMAND_SIZE(req->cmd[0]); + rq->cmd[0] = ALLOW_MEDIUM_REMOVAL; + rq->cmd[1] = 0; + rq->cmd[2] = 0; + rq->cmd[3] = 0; + rq->cmd[4] = SCSI_REMOVAL_PREVENT; + rq->cmd[5] = 0; + rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); req->rq_flags |= RQF_QUIET; req->timeout = 10 * HZ; @@ -2329,7 +2329,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) { struct scsi_cmnd *scmd; struct Scsi_Host *shost = dev->host; - struct request req; + struct request *rq; unsigned long flags; int error = 0, rtn, val; @@ -2344,14 +2344,16 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) return -EIO; error = -EIO; - scmd = scsi_get_command(dev, GFP_KERNEL); - if (!scmd) + rq = kzalloc(sizeof(struct request) + sizeof(struct scsi_cmnd) + + shost->hostt->cmd_size, GFP_KERNEL); + if (!rq) goto out_put_autopm_host; + blk_rq_init(NULL, rq); - blk_rq_init(NULL, &req); - scmd->request = &req; - - scmd->cmnd = req.cmd; + scmd = (struct scsi_cmnd *)(rq + 1); + scsi_init_command(dev, scmd); + scmd->request = rq; + scmd->cmnd = scsi_req(rq)->cmd; scmd->scsi_done = scsi_reset_provider_done_command; memset(&scmd->sdb, 0, sizeof(scmd->sdb)); @@ -2411,6 +2413,7 @@ scsi_ioctl_reset(struct scsi_device *dev, int __user *arg) scsi_run_host_queues(shost); scsi_put_command(scmd); + kfree(rq); out_put_autopm_host: scsi_autopm_put_host(shost); diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c35b6de4ca64..912fbc3b4543 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -37,8 +37,59 @@ #include "scsi_priv.h" #include "scsi_logging.h" +static struct kmem_cache *scsi_sdb_cache; +static struct kmem_cache *scsi_sense_cache; +static struct kmem_cache *scsi_sense_isadma_cache; +static DEFINE_MUTEX(scsi_sense_cache_mutex); -struct kmem_cache *scsi_sdb_cache; +static inline struct kmem_cache * +scsi_select_sense_cache(struct Scsi_Host *shost) +{ + return shost->unchecked_isa_dma ? + scsi_sense_isadma_cache : scsi_sense_cache; +} + +static void scsi_free_sense_buffer(struct Scsi_Host *shost, + unsigned char *sense_buffer) +{ + kmem_cache_free(scsi_select_sense_cache(shost), sense_buffer); +} + +static unsigned char *scsi_alloc_sense_buffer(struct Scsi_Host *shost, + gfp_t gfp_mask, int numa_node) +{ + return kmem_cache_alloc_node(scsi_select_sense_cache(shost), gfp_mask, + numa_node); +} + +int scsi_init_sense_cache(struct Scsi_Host *shost) +{ + struct kmem_cache *cache; + int ret = 0; + + cache = scsi_select_sense_cache(shost); + if (cache) + return 0; + + mutex_lock(&scsi_sense_cache_mutex); + if (shost->unchecked_isa_dma) { + scsi_sense_isadma_cache = + kmem_cache_create("scsi_sense_cache(DMA)", + SCSI_SENSE_BUFFERSIZE, 0, + SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, NULL); + if (!scsi_sense_isadma_cache) + ret = -ENOMEM; + } else { + scsi_sense_cache = + kmem_cache_create("scsi_sense_cache", + SCSI_SENSE_BUFFERSIZE, 0, SLAB_HWCACHE_ALIGN, NULL); + if (!scsi_sense_cache) + ret = -ENOMEM; + } + + mutex_unlock(&scsi_sense_cache_mutex); + return ret; +} /* * When to reinvoke queueing after a resource shortage. It's 3 msecs to @@ -168,22 +219,23 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req_flags_t rq_flags, int *resid) { struct request *req; - int write = (data_direction == DMA_TO_DEVICE); + struct scsi_request *rq; int ret = DRIVER_ERROR << 24; - req = blk_get_request(sdev->request_queue, write, __GFP_RECLAIM); + req = blk_get_request(sdev->request_queue, + data_direction == DMA_TO_DEVICE ? + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, __GFP_RECLAIM); if (IS_ERR(req)) return ret; - blk_rq_set_block_pc(req); + rq = scsi_req(req); + scsi_req_init(req); if (bufflen && blk_rq_map_kern(sdev->request_queue, req, buffer, bufflen, __GFP_RECLAIM)) goto out; - req->cmd_len = COMMAND_SIZE(cmd[0]); - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = sense; - req->sense_len = 0; + rq->cmd_len = COMMAND_SIZE(cmd[0]); + memcpy(rq->cmd, cmd, rq->cmd_len); req->retries = retries; req->timeout = timeout; req->cmd_flags |= flags; @@ -200,11 +252,13 @@ static int __scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, * is invalid. Prevent the garbage from being misinterpreted * and prevent security leaks by zeroing out the excess data. */ - if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen)) - memset(buffer + (bufflen - req->resid_len), 0, req->resid_len); + if (unlikely(rq->resid_len > 0 && rq->resid_len <= bufflen)) + memset(buffer + (bufflen - rq->resid_len), 0, rq->resid_len); if (resid) - *resid = req->resid_len; + *resid = rq->resid_len; + if (sense && rq->sense_len) + memcpy(sense, rq->sense, SCSI_SENSE_BUFFERSIZE); ret = req->errors; out: blk_put_request(req); @@ -529,7 +583,7 @@ void scsi_run_host_queues(struct Scsi_Host *shost) static void scsi_uninit_cmd(struct scsi_cmnd *cmd) { - if (cmd->request->cmd_type == REQ_TYPE_FS) { + if (!blk_rq_is_passthrough(cmd->request)) { struct scsi_driver *drv = scsi_cmd_to_driver(cmd); if (drv->uninit_command) @@ -645,14 +699,13 @@ static bool scsi_end_request(struct request *req, int error, if (bidi_bytes) scsi_release_bidi_buffers(cmd); + scsi_release_buffers(cmd); + scsi_put_command(cmd); spin_lock_irqsave(q->queue_lock, flags); blk_finish_request(req, error); spin_unlock_irqrestore(q->queue_lock, flags); - scsi_release_buffers(cmd); - - scsi_put_command(cmd); scsi_run_queue(q); } @@ -754,18 +807,15 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) sense_deferred = scsi_sense_is_deferred(&sshdr); } - if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ + if (blk_rq_is_passthrough(req)) { if (result) { - if (sense_valid && req->sense) { + if (sense_valid) { /* * SG_IO wants current and deferred errors */ - int len = 8 + cmd->sense_buffer[7]; - - if (len > SCSI_SENSE_BUFFERSIZE) - len = SCSI_SENSE_BUFFERSIZE; - memcpy(req->sense, cmd->sense_buffer, len); - req->sense_len = len; + scsi_req(req)->sense_len = + min(8 + cmd->sense_buffer[7], + SCSI_SENSE_BUFFERSIZE); } if (!sense_deferred) error = __scsi_error_from_host_byte(cmd, result); @@ -775,14 +825,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) */ req->errors = cmd->result; - req->resid_len = scsi_get_resid(cmd); + scsi_req(req)->resid_len = scsi_get_resid(cmd); if (scsi_bidi_cmnd(cmd)) { /* * Bidi commands Must be complete as a whole, * both sides at once. */ - req->next_rq->resid_len = scsi_in(cmd)->resid; + scsi_req(req->next_rq)->resid_len = scsi_in(cmd)->resid; if (scsi_end_request(req, 0, blk_rq_bytes(req), blk_rq_bytes(req->next_rq))) BUG(); @@ -790,15 +840,14 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) } } else if (blk_rq_bytes(req) == 0 && result && !sense_deferred) { /* - * Certain non BLOCK_PC requests are commands that don't - * actually transfer anything (FLUSH), so cannot use + * Flush commands do not transfers any data, and thus cannot use * good_bytes != blk_rq_bytes(req) as the signal for an error. * This sets the error explicitly for the problem case. */ error = __scsi_error_from_host_byte(cmd, result); } - /* no bidi support for !REQ_TYPE_BLOCK_PC yet */ + /* no bidi support for !blk_rq_is_passthrough yet */ BUG_ON(blk_bidi_rq(req)); /* @@ -810,8 +859,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) blk_rq_sectors(req), good_bytes)); /* - * Recovered errors need reporting, but they're always treated - * as success, so fiddle the result code here. For BLOCK_PC + * Recovered errors need reporting, but they're always treated as + * success, so fiddle the result code here. For passthrough requests * we already took a copy of the original into rq->errors which * is what gets returned to the user */ @@ -825,7 +874,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) else if (!(req->rq_flags & RQF_QUIET)) scsi_print_sense(cmd); result = 0; - /* BLOCK_PC may have set error */ + /* for passthrough error may be set */ error = 0; } @@ -1018,7 +1067,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb) count = blk_rq_map_sg(req->q, req, sdb->table.sgl); BUG_ON(count > sdb->table.nents); sdb->table.nents = count; - sdb->length = blk_rq_bytes(req); + sdb->length = blk_rq_payload_bytes(req); return BLKPREP_OK; } @@ -1040,7 +1089,8 @@ int scsi_init_io(struct scsi_cmnd *cmd) bool is_mq = (rq->mq_ctx != NULL); int error; - BUG_ON(!blk_rq_nr_phys_segments(rq)); + if (WARN_ON_ONCE(!blk_rq_nr_phys_segments(rq))) + return -EINVAL; error = scsi_init_sgtable(rq, &cmd->sdb); if (error) @@ -1109,42 +1159,33 @@ err_exit: } EXPORT_SYMBOL(scsi_init_io); -static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, - struct request *req) +void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) { - struct scsi_cmnd *cmd; - - if (!req->special) { - /* Bail if we can't get a reference to the device */ - if (!get_device(&sdev->sdev_gendev)) - return NULL; - - cmd = scsi_get_command(sdev, GFP_ATOMIC); - if (unlikely(!cmd)) { - put_device(&sdev->sdev_gendev); - return NULL; - } - req->special = cmd; - } else { - cmd = req->special; - } + void *buf = cmd->sense_buffer; + void *prot = cmd->prot_sdb; + unsigned long flags; - /* pull a tag out of the request if we have one */ - cmd->tag = req->tag; - cmd->request = req; + /* zero out the cmd, except for the embedded scsi_request */ + memset((char *)cmd + sizeof(cmd->req), 0, + sizeof(*cmd) - sizeof(cmd->req)); - cmd->cmnd = req->cmd; - cmd->prot_op = SCSI_PROT_NORMAL; + cmd->device = dev; + cmd->sense_buffer = buf; + cmd->prot_sdb = prot; + INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler); + cmd->jiffies_at_alloc = jiffies; - return cmd; + spin_lock_irqsave(&dev->list_lock, flags); + list_add_tail(&cmd->list, &dev->cmd_list); + spin_unlock_irqrestore(&dev->list_lock, flags); } -static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) +static int scsi_setup_scsi_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd = req->special; /* - * BLOCK_PC requests may transfer data, in which case they must + * Passthrough requests may transfer data, in which case they must * a bio attached to them. Or they might contain a SCSI command * that does not transfer data, in which case they may optionally * submit a request without an attached bio. @@ -1159,14 +1200,15 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) memset(&cmd->sdb, 0, sizeof(cmd->sdb)); } - cmd->cmd_len = req->cmd_len; + cmd->cmd_len = scsi_req(req)->cmd_len; + cmd->cmnd = scsi_req(req)->cmd; cmd->transfersize = blk_rq_bytes(req); cmd->allowed = req->retries; return BLKPREP_OK; } /* - * Setup a REQ_TYPE_FS command. These are simple request from filesystems + * Setup a normal block command. These are simple request from filesystems * that still need to be translated to SCSI CDBs from the ULD. */ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) @@ -1179,6 +1221,7 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) return ret; } + cmd->cmnd = scsi_req(req)->cmd = scsi_req(req)->__cmd; memset(cmd->cmnd, 0, BLK_MAX_CDB); return scsi_cmd_to_driver(cmd)->init_command(cmd); } @@ -1194,14 +1237,10 @@ static int scsi_setup_cmnd(struct scsi_device *sdev, struct request *req) else cmd->sc_data_direction = DMA_FROM_DEVICE; - switch (req->cmd_type) { - case REQ_TYPE_FS: + if (blk_rq_is_scsi(req)) + return scsi_setup_scsi_cmnd(sdev, req); + else return scsi_setup_fs_cmnd(sdev, req); - case REQ_TYPE_BLOCK_PC: - return scsi_setup_blk_pc_cmnd(sdev, req); - default: - return BLKPREP_KILL; - } } static int @@ -1297,19 +1336,28 @@ scsi_prep_return(struct request_queue *q, struct request *req, int ret) static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; - struct scsi_cmnd *cmd; + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(req); int ret; ret = scsi_prep_state_check(sdev, req); if (ret != BLKPREP_OK) goto out; - cmd = scsi_get_cmd_from_req(sdev, req); - if (unlikely(!cmd)) { - ret = BLKPREP_DEFER; - goto out; + if (!req->special) { + /* Bail if we can't get a reference to the device */ + if (unlikely(!get_device(&sdev->sdev_gendev))) { + ret = BLKPREP_DEFER; + goto out; + } + + scsi_init_command(sdev, cmd); + req->special = cmd; } + cmd->tag = req->tag; + cmd->request = req; + cmd->prot_op = SCSI_PROT_NORMAL; + ret = scsi_setup_cmnd(sdev, req); out: return scsi_prep_return(q, req, ret); @@ -1826,7 +1874,9 @@ static int scsi_mq_prep_fn(struct request *req) unsigned char *sense_buf = cmd->sense_buffer; struct scatterlist *sg; - memset(cmd, 0, sizeof(struct scsi_cmnd)); + /* zero out the cmd, except for the embedded scsi_request */ + memset((char *)cmd + sizeof(cmd->req), 0, + sizeof(*cmd) - sizeof(cmd->req)); req->special = cmd; @@ -1836,7 +1886,6 @@ static int scsi_mq_prep_fn(struct request *req) cmd->tag = req->tag; - cmd->cmnd = req->cmd; cmd->prot_op = SCSI_PROT_NORMAL; INIT_LIST_HEAD(&cmd->list); @@ -1911,7 +1960,6 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx, if (!scsi_host_queue_ready(q, shost, sdev)) goto out_dec_target_busy; - if (!(req->rq_flags & RQF_DONTPREP)) { ret = prep_to_mq(scsi_mq_prep_fn(req)); if (ret != BLK_MQ_RQ_QUEUE_OK) @@ -1981,21 +2029,24 @@ static int scsi_init_request(void *data, struct request *rq, unsigned int hctx_idx, unsigned int request_idx, unsigned int numa_node) { + struct Scsi_Host *shost = data; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); - cmd->sense_buffer = kzalloc_node(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL, - numa_node); + cmd->sense_buffer = + scsi_alloc_sense_buffer(shost, GFP_KERNEL, numa_node); if (!cmd->sense_buffer) return -ENOMEM; + cmd->req.sense = cmd->sense_buffer; return 0; } static void scsi_exit_request(void *data, struct request *rq, unsigned int hctx_idx, unsigned int request_idx) { + struct Scsi_Host *shost = data; struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); - kfree(cmd->sense_buffer); + scsi_free_sense_buffer(shost, cmd->sense_buffer); } static int scsi_map_queues(struct blk_mq_tag_set *set) @@ -2028,7 +2079,7 @@ static u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) return bounce_limit; } -static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) +void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) { struct device *dev = shost->dma_dev; @@ -2063,28 +2114,64 @@ static void __scsi_init_queue(struct Scsi_Host *shost, struct request_queue *q) */ blk_queue_dma_alignment(q, 0x03); } +EXPORT_SYMBOL_GPL(__scsi_init_queue); -struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, - request_fn_proc *request_fn) +static int scsi_init_rq(struct request_queue *q, struct request *rq, gfp_t gfp) { - struct request_queue *q; + struct Scsi_Host *shost = q->rq_alloc_data; + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); - q = blk_init_queue(request_fn, NULL); - if (!q) - return NULL; - __scsi_init_queue(shost, q); - return q; + memset(cmd, 0, sizeof(*cmd)); + + cmd->sense_buffer = scsi_alloc_sense_buffer(shost, gfp, NUMA_NO_NODE); + if (!cmd->sense_buffer) + goto fail; + cmd->req.sense = cmd->sense_buffer; + + if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) { + cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp); + if (!cmd->prot_sdb) + goto fail_free_sense; + } + + return 0; + +fail_free_sense: + scsi_free_sense_buffer(shost, cmd->sense_buffer); +fail: + return -ENOMEM; +} + +static void scsi_exit_rq(struct request_queue *q, struct request *rq) +{ + struct Scsi_Host *shost = q->rq_alloc_data; + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + + if (cmd->prot_sdb) + kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); + scsi_free_sense_buffer(shost, cmd->sense_buffer); } -EXPORT_SYMBOL(__scsi_alloc_queue); struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) { + struct Scsi_Host *shost = sdev->host; struct request_queue *q; - q = __scsi_alloc_queue(sdev->host, scsi_request_fn); + q = blk_alloc_queue_node(GFP_KERNEL, NUMA_NO_NODE); if (!q) return NULL; + q->cmd_size = sizeof(struct scsi_cmnd) + shost->hostt->cmd_size; + q->rq_alloc_data = shost; + q->request_fn = scsi_request_fn; + q->init_rq_fn = scsi_init_rq; + q->exit_rq_fn = scsi_exit_rq; + + if (blk_init_allocated_queue(q) < 0) { + blk_cleanup_queue(q); + return NULL; + } + __scsi_init_queue(shost, q); blk_queue_prep_rq(q, scsi_prep_fn); blk_queue_unprep_rq(q, scsi_unprep_fn); blk_queue_softirq_done(q, scsi_softirq_done); @@ -2208,6 +2295,8 @@ int __init scsi_init_queue(void) void scsi_exit_queue(void) { + kmem_cache_destroy(scsi_sense_cache); + kmem_cache_destroy(scsi_sense_isadma_cache); kmem_cache_destroy(scsi_sdb_cache); } @@ -2893,7 +2982,7 @@ scsi_internal_device_block(struct scsi_device *sdev) * request queue. */ if (q->mq_ops) { - blk_mq_stop_hw_queues(q); + blk_mq_quiesce_queue(q); } else { spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index 193636a59adf..99bfc985e190 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -30,8 +30,8 @@ extern void scsi_exit_hosts(void); /* scsi.c */ extern bool scsi_use_blk_mq; -extern int scsi_setup_command_freelist(struct Scsi_Host *shost); -extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); +int scsi_init_sense_cache(struct Scsi_Host *shost); +void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd); #ifdef CONFIG_SCSI_LOGGING void scsi_log_send(struct scsi_cmnd *cmd); void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); @@ -96,7 +96,6 @@ extern void scsi_exit_queue(void); extern void scsi_evt_thread(struct work_struct *work); struct request_queue; struct request; -extern struct kmem_cache *scsi_sdb_cache; /* scsi_proc.c */ #ifdef CONFIG_SCSI_PROC_FS diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 1be339420b02..2d753c93e07a 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -3747,7 +3747,6 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) struct device *dev = &shost->shost_gendev; struct fc_internal *i = to_fc_internal(shost->transportt); struct request_queue *q; - int err; char bsg_name[20]; fc_host->rqst_q = NULL; @@ -3758,23 +3757,14 @@ fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) snprintf(bsg_name, sizeof(bsg_name), "fc_host%d", shost->host_no); - q = __scsi_alloc_queue(shost, bsg_request_fn); - if (!q) { - dev_err(dev, - "fc_host%d: bsg interface failed to initialize - no request queue\n", - shost->host_no); - return -ENOMEM; - } - - err = bsg_setup_queue(dev, q, bsg_name, fc_bsg_dispatch, - i->f->dd_bsg_size); - if (err) { + q = bsg_setup_queue(dev, bsg_name, fc_bsg_dispatch, i->f->dd_bsg_size); + if (IS_ERR(q)) { dev_err(dev, "fc_host%d: bsg interface failed to initialize - setup queue\n", shost->host_no); - blk_cleanup_queue(q); - return err; + return PTR_ERR(q); } + __scsi_init_queue(shost, q); blk_queue_rq_timed_out(q, fc_bsg_job_timeout); blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT); fc_host->rqst_q = q; @@ -3806,26 +3796,18 @@ fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) struct device *dev = &rport->dev; struct fc_internal *i = to_fc_internal(shost->transportt); struct request_queue *q; - int err; rport->rqst_q = NULL; if (!i->f->bsg_request) return -ENOTSUPP; - q = __scsi_alloc_queue(shost, bsg_request_fn); - if (!q) { - dev_err(dev, "bsg interface failed to initialize - no request queue\n"); - return -ENOMEM; - } - - err = bsg_setup_queue(dev, q, NULL, fc_bsg_dispatch, i->f->dd_bsg_size); - if (err) { + q = bsg_setup_queue(dev, NULL, fc_bsg_dispatch, i->f->dd_bsg_size); + if (IS_ERR(q)) { dev_err(dev, "failed to setup bsg queue\n"); - blk_cleanup_queue(q); - return err; + return PTR_ERR(q); } - + __scsi_init_queue(shost, q); blk_queue_prep_rq(q, fc_bsg_rport_prep); blk_queue_rq_timed_out(q, fc_bsg_job_timeout); blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 42bca619f854..568c9f26a561 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c @@ -1537,24 +1537,18 @@ iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost) struct iscsi_internal *i = to_iscsi_internal(shost->transportt); struct request_queue *q; char bsg_name[20]; - int ret; if (!i->iscsi_transport->bsg_request) return -ENOTSUPP; snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no); - - q = __scsi_alloc_queue(shost, bsg_request_fn); - if (!q) - return -ENOMEM; - - ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0); - if (ret) { + q = bsg_setup_queue(dev, bsg_name, iscsi_bsg_host_dispatch, 0); + if (IS_ERR(q)) { shost_printk(KERN_ERR, shost, "bsg interface failed to " "initialize - no request queue\n"); - blk_cleanup_queue(q); - return ret; + return PTR_ERR(q); } + __scsi_init_queue(shost, q); ihost->bsg_q = q; return 0; diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 60b651bfaa01..126a5ee00987 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -33,6 +33,7 @@ #include <linux/bsg.h> #include <scsi/scsi.h> +#include <scsi/scsi_request.h> #include <scsi/scsi_device.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> @@ -177,6 +178,10 @@ static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, while ((req = blk_fetch_request(q)) != NULL) { spin_unlock_irq(q->queue_lock); + scsi_req(req)->resid_len = blk_rq_bytes(req); + if (req->next_rq) + scsi_req(req->next_rq)->resid_len = + blk_rq_bytes(req->next_rq); handler = to_sas_internal(shost->transportt)->f->smp_handler; ret = handler(shost, rphy, req); req->errors = ret; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 52105d8bce5b..cb6e68dd6df0 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -781,7 +781,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd) rq->special_vec.bv_len = len; rq->rq_flags |= RQF_SPECIAL_PAYLOAD; - rq->resid_len = len; + scsi_req(rq)->resid_len = len; ret = scsi_init_io(cmd); out: @@ -871,11 +871,11 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd) cmd->allowed = SD_MAX_RETRIES; /* - * For WRITE_SAME the data transferred in the DATA IN buffer is + * For WRITE SAME the data transferred via the DATA OUT buffer is * different from the amount of data actually written to the target. * - * We set up __data_len to the amount of data transferred from the - * DATA IN buffer so that blk_rq_map_sg set up the proper S/G list + * We set up __data_len to the amount of data transferred via the + * DATA OUT buffer so that blk_rq_map_sg sets up the proper S/G list * to transfer a single sector of data first, but then reset it to * the amount of data to be written right after so that the I/O path * knows how much to actually write. @@ -1179,7 +1179,7 @@ static void sd_uninit_command(struct scsi_cmnd *SCpnt) if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) __free_page(rq->special_vec.bv_page); - if (SCpnt->cmnd != rq->cmd) { + if (SCpnt->cmnd != scsi_req(rq)->cmd) { mempool_free(SCpnt->cmnd, sd_cdb_pool); SCpnt->cmnd = NULL; SCpnt->cmd_len = 0; @@ -1750,9 +1750,6 @@ static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd); unsigned int good_bytes; - if (scmd->request->cmd_type != REQ_TYPE_FS) - return 0; - info_valid = scsi_get_sense_info_fld(scmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, &bad_lba); @@ -2600,7 +2597,8 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) if (sdp->broken_fua) { sd_first_printk(KERN_NOTICE, sdkp, "Disabling FUA\n"); sdkp->DPOFUA = 0; - } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { + } else if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw && + !sdkp->device->use_16_for_rw) { sd_first_printk(KERN_NOTICE, sdkp, "Uses READ/WRITE(6), disabling FUA\n"); sdkp->DPOFUA = 0; @@ -2783,13 +2781,21 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, q); } - sdkp->zoned = (buffer[8] >> 4) & 3; - if (sdkp->zoned == 1) - q->limits.zoned = BLK_ZONED_HA; - else if (sdkp->device->type == TYPE_ZBC) + if (sdkp->device->type == TYPE_ZBC) { + /* Host-managed */ q->limits.zoned = BLK_ZONED_HM; - else - q->limits.zoned = BLK_ZONED_NONE; + } else { + sdkp->zoned = (buffer[8] >> 4) & 3; + if (sdkp->zoned == 1) + /* Host-aware */ + q->limits.zoned = BLK_ZONED_HA; + else + /* + * Treat drive-managed devices as + * regular block devices. + */ + q->limits.zoned = BLK_ZONED_NONE; + } if (blk_queue_is_zoned(q) && sdkp->first_scan) sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n", q->limits.zoned == BLK_ZONED_HM ? "managed" : "aware"); @@ -3073,6 +3079,23 @@ static void sd_probe_async(void *data, async_cookie_t cookie) put_device(&sdkp->dev); } +struct sd_devt { + int idx; + struct disk_devt disk_devt; +}; + +void sd_devt_release(struct disk_devt *disk_devt) +{ + struct sd_devt *sd_devt = container_of(disk_devt, struct sd_devt, + disk_devt); + + spin_lock(&sd_index_lock); + ida_remove(&sd_index_ida, sd_devt->idx); + spin_unlock(&sd_index_lock); + + kfree(sd_devt); +} + /** * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once @@ -3094,6 +3117,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie) static int sd_probe(struct device *dev) { struct scsi_device *sdp = to_scsi_device(dev); + struct sd_devt *sd_devt; struct scsi_disk *sdkp; struct gendisk *gd; int index; @@ -3119,9 +3143,13 @@ static int sd_probe(struct device *dev) if (!sdkp) goto out; + sd_devt = kzalloc(sizeof(*sd_devt), GFP_KERNEL); + if (!sd_devt) + goto out_free; + gd = alloc_disk(SD_MINORS); if (!gd) - goto out_free; + goto out_free_devt; do { if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) @@ -3137,6 +3165,11 @@ static int sd_probe(struct device *dev) goto out_put; } + atomic_set(&sd_devt->disk_devt.count, 1); + sd_devt->disk_devt.release = sd_devt_release; + sd_devt->idx = index; + gd->disk_devt = &sd_devt->disk_devt; + error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); if (error) { sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n"); @@ -3176,13 +3209,14 @@ static int sd_probe(struct device *dev) return 0; out_free_index: - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, index); - spin_unlock(&sd_index_lock); + put_disk_devt(&sd_devt->disk_devt); + sd_devt = NULL; out_put: put_disk(gd); out_free: kfree(sdkp); + out_free_devt: + kfree(sd_devt); out: scsi_autopm_put_device(sdp); return error; @@ -3241,10 +3275,7 @@ static void scsi_disk_release(struct device *dev) struct scsi_disk *sdkp = to_scsi_disk(dev); struct gendisk *disk = sdkp->disk; - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, sdkp->index); - spin_unlock(&sd_index_lock); - + put_disk_devt(disk->disk_devt); disk->private_data = NULL; put_disk(disk); put_device(&sdkp->device->sdev_gendev); diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 8c9a35c91705..50adabbb5808 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -587,7 +587,7 @@ static void ses_match_to_enclosure(struct enclosure_device *edev, ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); - if (scsi_is_sas_rphy(&sdev->sdev_gendev)) + if (scsi_is_sas_rphy(sdev->sdev_target->dev.parent)) efd.addr = sas_get_address(sdev); if (efd.addr) { diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index dbe5b4b95df0..e831e01f9fa6 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -781,9 +781,7 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, } if (atomic_read(&sdp->detaching)) { if (srp->bio) { - if (srp->rq->cmd != srp->rq->__cmd) - kfree(srp->rq->cmd); - + scsi_req_free_cmd(scsi_req(srp->rq)); blk_end_request_all(srp->rq, -EIO); srp->rq = NULL; } @@ -1279,6 +1277,7 @@ static void sg_rq_end_io(struct request *rq, int uptodate) { struct sg_request *srp = rq->end_io_data; + struct scsi_request *req = scsi_req(rq); Sg_device *sdp; Sg_fd *sfp; unsigned long iflags; @@ -1297,9 +1296,9 @@ sg_rq_end_io(struct request *rq, int uptodate) if (unlikely(atomic_read(&sdp->detaching))) pr_info("%s: device detaching\n", __func__); - sense = rq->sense; + sense = req->sense; result = rq->errors; - resid = rq->resid_len; + resid = req->resid_len; SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sdp, "sg_cmd_done: pack_id=%d, res=0x%x\n", @@ -1333,6 +1332,10 @@ sg_rq_end_io(struct request *rq, int uptodate) sdp->device->changed = 1; } } + + if (req->sense_len) + memcpy(srp->sense_b, req->sense, SCSI_SENSE_BUFFERSIZE); + /* Rely on write phase to clean out srp status values, so no "else" */ /* @@ -1342,8 +1345,7 @@ sg_rq_end_io(struct request *rq, int uptodate) * blk_rq_unmap_user() can be called from user context. */ srp->rq = NULL; - if (rq->cmd != rq->__cmd) - kfree(rq->cmd); + scsi_req_free_cmd(scsi_req(rq)); __blk_put_request(rq->q, rq); write_lock_irqsave(&sfp->rq_list_lock, iflags); @@ -1658,6 +1660,7 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) { int res; struct request *rq; + struct scsi_request *req; Sg_fd *sfp = srp->parentfp; sg_io_hdr_t *hp = &srp->header; int dxfer_len = (int) hp->dxfer_len; @@ -1695,22 +1698,23 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) * With scsi-mq disabled, blk_get_request() with GFP_KERNEL usually * does not sleep except under memory pressure. */ - rq = blk_get_request(q, rw, GFP_KERNEL); + rq = blk_get_request(q, hp->dxfer_direction == SG_DXFER_TO_DEV ? + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(rq)) { kfree(long_cmdp); return PTR_ERR(rq); } + req = scsi_req(rq); - blk_rq_set_block_pc(rq); + scsi_req_init(rq); if (hp->cmd_len > BLK_MAX_CDB) - rq->cmd = long_cmdp; - memcpy(rq->cmd, cmd, hp->cmd_len); - rq->cmd_len = hp->cmd_len; + req->cmd = long_cmdp; + memcpy(req->cmd, cmd, hp->cmd_len); + req->cmd_len = hp->cmd_len; srp->rq = rq; rq->end_io_data = srp; - rq->sense = srp->sense_b; rq->retries = SG_DEFAULT_RETRIES; if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) @@ -1753,6 +1757,10 @@ sg_start_req(Sg_request *srp, unsigned char *cmd) return res; iov_iter_truncate(&i, hp->dxfer_len); + if (!iov_iter_count(&i)) { + kfree(iov); + return -EINVAL; + } res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC); kfree(iov); @@ -1786,8 +1794,7 @@ sg_finish_rem_req(Sg_request *srp) ret = blk_rq_unmap_user(srp->bio); if (srp->rq) { - if (srp->rq->cmd != srp->rq->__cmd) - kfree(srp->rq->cmd); + scsi_req_free_cmd(scsi_req(srp->rq)); blk_put_request(srp->rq); } diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 8702d9cf8040..11c0dfb3dfa3 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -4499,7 +4499,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, if (pqi_is_logical_device(device)) { raid_bypassed = false; if (device->offload_enabled && - scmd->request->cmd_type == REQ_TYPE_FS) { + !blk_rq_is_passthrough(scmd->request)) { rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); if (rc == 0 || diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c index 396b32dca074..7cf70aaec0ba 100644 --- a/drivers/scsi/snic/snic_main.c +++ b/drivers/scsi/snic/snic_main.c @@ -591,6 +591,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!pool) { SNIC_HOST_ERR(shost, "dflt sgl pool creation failed\n"); + ret = -ENOMEM; goto err_free_res; } @@ -601,6 +602,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!pool) { SNIC_HOST_ERR(shost, "max sgl pool creation failed\n"); + ret = -ENOMEM; goto err_free_dflt_sgl_pool; } @@ -611,6 +613,7 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!pool) { SNIC_HOST_ERR(shost, "snic tmreq info pool creation failed.\n"); + ret = -ENOMEM; goto err_free_max_sgl_pool; } diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 94352e4df831..0b29b9329b1c 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -117,7 +117,7 @@ static unsigned int sr_check_events(struct cdrom_device_info *cdi, unsigned int clearing, int slot); static int sr_packet(struct cdrom_device_info *, struct packet_command *); -static struct cdrom_device_ops sr_dops = { +static const struct cdrom_device_ops sr_dops = { .open = sr_open, .release = sr_release, .drive_status = sr_drive_status, @@ -437,14 +437,17 @@ static int sr_init_command(struct scsi_cmnd *SCpnt) goto out; } - if (rq_data_dir(rq) == WRITE) { + switch (req_op(rq)) { + case REQ_OP_WRITE: if (!cd->writeable) goto out; SCpnt->cmnd[0] = WRITE_10; cd->cdi.media_written = 1; - } else if (rq_data_dir(rq) == READ) { + break; + case REQ_OP_READ: SCpnt->cmnd[0] = READ_10; - } else { + break; + default: blk_dump_rq_flags(rq, "Unknown sr command"); goto out; } diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 5f35b863e1a7..81212d4bd9bf 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -475,7 +475,7 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req) ktime_t now; now = ktime_get(); - if (req->cmd[0] == WRITE_6) { + if (scsi_req(req)->cmd[0] == WRITE_6) { now = ktime_sub(now, STp->stats->write_time); atomic64_add(ktime_to_ns(now), &STp->stats->tot_write_time); atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time); @@ -489,7 +489,7 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req) } else atomic64_add(atomic_read(&STp->stats->last_write_size), &STp->stats->write_byte_cnt); - } else if (req->cmd[0] == READ_6) { + } else if (scsi_req(req)->cmd[0] == READ_6) { now = ktime_sub(now, STp->stats->read_time); atomic64_add(ktime_to_ns(now), &STp->stats->tot_read_time); atomic64_add(ktime_to_ns(now), &STp->stats->tot_io_time); @@ -514,15 +514,18 @@ static void st_do_stats(struct scsi_tape *STp, struct request *req) static void st_scsi_execute_end(struct request *req, int uptodate) { struct st_request *SRpnt = req->end_io_data; + struct scsi_request *rq = scsi_req(req); struct scsi_tape *STp = SRpnt->stp; struct bio *tmp; STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; - STp->buffer->cmdstat.residual = req->resid_len; + STp->buffer->cmdstat.residual = rq->resid_len; st_do_stats(STp, req); tmp = SRpnt->bio; + if (rq->sense_len) + memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE); if (SRpnt->waiting) complete(SRpnt->waiting); @@ -535,17 +538,18 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, int timeout, int retries) { struct request *req; + struct scsi_request *rq; struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; int err = 0; - int write = (data_direction == DMA_TO_DEVICE); struct scsi_tape *STp = SRpnt->stp; - req = blk_get_request(SRpnt->stp->device->request_queue, write, - GFP_KERNEL); + req = blk_get_request(SRpnt->stp->device->request_queue, + data_direction == DMA_TO_DEVICE ? + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(req)) return DRIVER_ERROR << 24; - - blk_rq_set_block_pc(req); + rq = scsi_req(req); + scsi_req_init(req); req->rq_flags |= RQF_QUIET; mdata->null_mapped = 1; @@ -571,11 +575,9 @@ static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, } SRpnt->bio = req->bio; - req->cmd_len = COMMAND_SIZE(cmd[0]); - memset(req->cmd, 0, BLK_MAX_CDB); - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = SRpnt->sense; - req->sense_len = 0; + rq->cmd_len = COMMAND_SIZE(cmd[0]); + memset(rq->cmd, 0, BLK_MAX_CDB); + memcpy(rq->cmd, cmd, rq->cmd_len); req->timeout = timeout; req->retries = retries; req->end_io_data = SRpnt; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 14cebaf10371..e64b0c542f95 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -335,7 +335,7 @@ static int sun3scsi_dma_xfer_len(struct NCR5380_hostdata *hostdata, { int wanted_len = cmd->SCp.this_residual; - if (wanted_len < DMA_MIN_SIZE || cmd->request->cmd_type != REQ_TYPE_FS) + if (wanted_len < DMA_MIN_SIZE || blk_rq_is_passthrough(cmd->request)) return 0; return wanted_len; diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c index ec91bd07f00a..c680d7641311 100644 --- a/drivers/scsi/virtio_scsi.c +++ b/drivers/scsi/virtio_scsi.c @@ -534,7 +534,9 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, { struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); struct virtio_scsi_cmd *cmd = scsi_cmd_priv(sc); + unsigned long flags; int req_size; + int ret; BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); @@ -562,8 +564,15 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi, req_size = sizeof(cmd->req.cmd); } - if (virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)) != 0) + ret = virtscsi_kick_cmd(req_vq, cmd, req_size, sizeof(cmd->resp.cmd)); + if (ret == -EIO) { + cmd->resp.cmd.response = VIRTIO_SCSI_S_BAD_TARGET; + spin_lock_irqsave(&req_vq->vq_lock, flags); + virtscsi_complete_cmd(vscsi, cmd); + spin_unlock_irqrestore(&req_vq->vq_lock, flags); + } else if (ret != 0) { return SCSI_MLQUEUE_HOST_BUSY; + } return 0; } diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 8823cc81ae45..5bb376009d98 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -459,6 +459,7 @@ static int wkup_m3_ipc_probe(struct platform_device *pdev) if (IS_ERR(task)) { dev_err(dev, "can't create rproc_boot thread\n"); + ret = PTR_ERR(task); goto err_put_rproc; } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ec4aa252d6e8..25ae7f2e44b5 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -162,7 +162,8 @@ config SPI_BCM63XX_HSSPI config SPI_BCM_QSPI tristate "Broadcom BSPI and MSPI controller support" - depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST + depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || \ + BMIPS_GENERIC || COMPILE_TEST default ARCH_BCM_IPROC help Enables support for the Broadcom SPI flash and MSPI controller. @@ -263,7 +264,7 @@ config SPI_EP93XX mode. config SPI_FALCON - tristate "Falcon SPI controller support" + bool "Falcon SPI controller support" depends on SOC_FALCON help The external bus unit (EBU) found on the FALC-ON SoC has SPI @@ -378,6 +379,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select REGMAP_MMIO + depends on HAS_DMA depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST help This enables support for the Freescale DSPI controller in master @@ -415,6 +417,14 @@ config SPI_NUC900 help SPI driver for Nuvoton NUC900 series ARM SoCs +config SPI_LANTIQ_SSC + tristate "Lantiq SSC SPI controller" + depends on LANTIQ || COMPILE_TEST + help + This driver supports the Lantiq SSC SPI controller in master + mode. This controller is found on Intel (former Lantiq) SoCs like + the Danube, Falcon, xRX200, xRX300. + config SPI_OC_TINY tristate "OpenCores tiny SPI" depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 7a6b64662c82..b375a7a89216 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o obj-$(CONFIG_SPI_GPIO) += spi-gpio.o obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o obj-$(CONFIG_SPI_IMX) += spi-imx.o +obj-$(CONFIG_SPI_LANTIQ_SSC) += spi-lantiq-ssc.o obj-$(CONFIG_SPI_JCORE) += spi-jcore.o obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o obj-$(CONFIG_SPI_LP8841_RTC) += spi-lp8841-rtc.o diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c index e89da0af45d2..6c7d7a460689 100644 --- a/drivers/spi/spi-armada-3700.c +++ b/drivers/spi/spi-armada-3700.c @@ -170,12 +170,12 @@ static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi, val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1); switch (pin_mode) { - case 1: + case SPI_NBITS_SINGLE: break; - case 2: + case SPI_NBITS_DUAL: val |= A3700_SPI_DATA_PIN0; break; - case 4: + case SPI_NBITS_QUAD: val |= A3700_SPI_DATA_PIN1; break; default: @@ -340,8 +340,7 @@ static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id) spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause); /* Wake up the transfer */ - if (a3700_spi->wait_mask & cause) - complete(&a3700_spi->done); + complete(&a3700_spi->done); return IRQ_HANDLED; } @@ -421,7 +420,7 @@ static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi, } static void a3700_spi_transfer_setup(struct spi_device *spi, - struct spi_transfer *xfer) + struct spi_transfer *xfer) { struct a3700_spi *a3700_spi; unsigned int byte_len; @@ -562,6 +561,7 @@ static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi) val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG); if (a3700_spi->buf_len >= 4) { u32 data = le32_to_cpu(val); + memcpy(a3700_spi->rx_buf, &data, 4); a3700_spi->buf_len -= 4; @@ -800,7 +800,7 @@ static int a3700_spi_probe(struct platform_device *pdev) struct spi_master *master; struct a3700_spi *spi; u32 num_cs = 0; - int ret = 0; + int irq, ret = 0; master = spi_alloc_master(dev, sizeof(*spi)); if (!master) { @@ -825,7 +825,7 @@ static int a3700_spi_probe(struct platform_device *pdev) master->unprepare_message = a3700_spi_unprepare_message; master->set_cs = a3700_spi_set_cs; master->flags = SPI_MASTER_HALF_DUPLEX; - master->mode_bits |= (SPI_RX_DUAL | SPI_RX_DUAL | + master->mode_bits |= (SPI_RX_DUAL | SPI_TX_DUAL | SPI_RX_QUAD | SPI_TX_QUAD); platform_set_drvdata(pdev, master); @@ -846,12 +846,13 @@ static int a3700_spi_probe(struct platform_device *pdev) goto error; } - spi->irq = platform_get_irq(pdev, 0); - if (spi->irq < 0) { - dev_err(dev, "could not get irq: %d\n", spi->irq); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "could not get irq: %d\n", irq); ret = -ENXIO; goto error; } + spi->irq = irq; init_completion(&spi->done); @@ -900,7 +901,6 @@ static int a3700_spi_remove(struct platform_device *pdev) struct a3700_spi *spi = spi_master_get_devdata(master); clk_unprepare(spi->clk); - spi_master_put(master); return 0; } @@ -908,7 +908,6 @@ static int a3700_spi_remove(struct platform_device *pdev) static struct platform_driver a3700_spi_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(a3700_spi_dt_ids), }, .probe = a3700_spi_probe, diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index f369174fbd88..b89cee11f418 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -78,14 +78,16 @@ static void ath79_spi_chipselect(struct spi_device *spi, int is_active) ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { /* SPI is normally active-low */ - gpio_set_value(spi->cs_gpio, cs_high); + gpio_set_value_cansleep(spi->cs_gpio, cs_high); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (cs_high) - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; else - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -118,11 +120,8 @@ static int ath79_spi_setup_cs(struct spi_device *spi) struct ath79_spi *sp = ath79_spidev_to_sp(spi); int status; - if (spi->chip_select && !gpio_is_valid(spi->cs_gpio)) - return -EINVAL; - status = 0; - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { unsigned long flags; flags = GPIOF_DIR_OUT; @@ -134,10 +133,12 @@ static int ath79_spi_setup_cs(struct spi_device *spi) status = gpio_request_one(spi->cs_gpio, flags, dev_name(&spi->dev)); } else { + u32 cs_bit = AR71XX_SPI_IOC_CS(spi->chip_select); + if (spi->mode & SPI_CS_HIGH) - sp->ioc_base &= ~AR71XX_SPI_IOC_CS0; + sp->ioc_base &= ~cs_bit; else - sp->ioc_base |= AR71XX_SPI_IOC_CS0; + sp->ioc_base |= cs_bit; ath79_spi_wr(sp, AR71XX_SPI_REG_IOC, sp->ioc_base); } @@ -147,7 +148,7 @@ static int ath79_spi_setup_cs(struct spi_device *spi) static void ath79_spi_cleanup_cs(struct spi_device *spi) { - if (spi->chip_select) { + if (gpio_is_valid(spi->cs_gpio)) { gpio_free(spi->cs_gpio); } } diff --git a/drivers/spi/spi-axi-spi-engine.c b/drivers/spi/spi-axi-spi-engine.c index 319225d7e761..6ab4c7700228 100644 --- a/drivers/spi/spi-axi-spi-engine.c +++ b/drivers/spi/spi-axi-spi-engine.c @@ -494,7 +494,8 @@ static int spi_engine_probe(struct platform_device *pdev) SPI_ENGINE_VERSION_MAJOR(version), SPI_ENGINE_VERSION_MINOR(version), SPI_ENGINE_VERSION_PATCH(version)); - return -ENODEV; + ret = -ENODEV; + goto err_put_master; } spi_engine->clk = devm_clk_get(&pdev->dev, "s_axi_aclk"); diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c index 14f9dea3173f..b19722ba908c 100644 --- a/drivers/spi/spi-bcm-qspi.c +++ b/drivers/spi/spi-bcm-qspi.c @@ -89,7 +89,7 @@ #define BSPI_BPP_MODE_SELECT_MASK BIT(8) #define BSPI_BPP_ADDR_SELECT_MASK BIT(16) -#define BSPI_READ_LENGTH 256 +#define BSPI_READ_LENGTH 512 /* MSPI register offsets */ #define MSPI_SPCR0_LSB 0x000 @@ -192,9 +192,11 @@ struct bcm_qspi_dev_id { void *dev; }; + struct qspi_trans { struct spi_transfer *trans; int byte; + bool mspi_last_trans; }; struct bcm_qspi { @@ -371,7 +373,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, /* default mode, does not need flex_cmd */ flex_mode = 0; else - command = SPINOR_OP_READ4_FAST; + command = SPINOR_OP_READ_FAST_4B; break; case SPI_NBITS_DUAL: bpc = 0x00000001; @@ -384,7 +386,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, } else { command = SPINOR_OP_READ_1_1_2; if (spans_4byte) - command = SPINOR_OP_READ4_1_1_2; + command = SPINOR_OP_READ_1_1_2_4B; } break; case SPI_NBITS_QUAD: @@ -399,7 +401,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi, int width, } else { command = SPINOR_OP_READ_1_1_4; if (spans_4byte) - command = SPINOR_OP_READ4_1_1_4; + command = SPINOR_OP_READ_1_1_4_4B; } break; default: @@ -616,6 +618,16 @@ static int bcm_qspi_setup(struct spi_device *spi) return 0; } +static bool bcm_qspi_mspi_transfer_is_last(struct bcm_qspi *qspi, + struct qspi_trans *qt) +{ + if (qt->mspi_last_trans && + spi_transfer_is_last(qspi->master, qt->trans)) + return true; + else + return false; +} + static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, struct qspi_trans *qt, int flags) { @@ -629,7 +641,6 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, if (qt->byte >= qt->trans->len) { /* we're at the end of the spi_transfer */ - /* in TX mode, need to pause for a delay or CS change */ if (qt->trans->delay_usecs && (flags & TRANS_STATUS_BREAK_DELAY)) @@ -641,7 +652,7 @@ static int update_qspi_trans_byte_count(struct bcm_qspi *qspi, goto done; dev_dbg(&qspi->pdev->dev, "advance msg exit\n"); - if (spi_transfer_is_last(qspi->master, qt->trans)) + if (bcm_qspi_mspi_transfer_is_last(qspi, qt)) ret = TRANS_STATUS_BREAK_EOM; else ret = TRANS_STATUS_BREAK_NO_BYTES; @@ -813,7 +824,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, struct spi_flash_read_message *msg) { struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); - u32 addr = 0, len, len_words; + u32 addr = 0, len, rdlen, len_words; int ret = 0; unsigned long timeo = msecs_to_jiffies(100); struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc; @@ -826,7 +837,7 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0); /* - * when using flex mode mode we need to send + * when using flex mode we need to send * the upper address byte to bspi */ if (bcm_qspi_bspi_ver_three(qspi) == false) { @@ -840,48 +851,127 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi, else addr = msg->from & 0x00ffffff; - /* set BSPI RAF buffer max read length */ - len = msg->len; - if (len > BSPI_READ_LENGTH) - len = BSPI_READ_LENGTH; - if (bcm_qspi_bspi_ver_three(qspi) == true) addr = (addr + 0xc00000) & 0xffffff; - reinit_completion(&qspi->bspi_done); - bcm_qspi_enable_bspi(qspi); - len_words = (len + 3) >> 2; - qspi->bspi_rf_msg = msg; - qspi->bspi_rf_msg_status = 0; + /* + * read into the entire buffer by breaking the reads + * into RAF buffer read lengths + */ + len = msg->len; qspi->bspi_rf_msg_idx = 0; - qspi->bspi_rf_msg_len = len; - dev_dbg(&qspi->pdev->dev, "bspi xfr addr 0x%x len 0x%x", addr, len); - bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); - bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); - bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); + do { + if (len > BSPI_READ_LENGTH) + rdlen = BSPI_READ_LENGTH; + else + rdlen = len; + + reinit_completion(&qspi->bspi_done); + bcm_qspi_enable_bspi(qspi); + len_words = (rdlen + 3) >> 2; + qspi->bspi_rf_msg = msg; + qspi->bspi_rf_msg_status = 0; + qspi->bspi_rf_msg_len = rdlen; + dev_dbg(&qspi->pdev->dev, + "bspi xfr addr 0x%x len 0x%x", addr, rdlen); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_NUM_WORDS, len_words); + bcm_qspi_write(qspi, BSPI, BSPI_RAF_WATERMARK, 0); + if (qspi->soc_intc) { + /* + * clear soc MSPI and BSPI interrupts and enable + * BSPI interrupts. + */ + soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); + soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); + } - if (qspi->soc_intc) { - /* - * clear soc MSPI and BSPI interrupts and enable - * BSPI interrupts. - */ - soc_intc->bcm_qspi_int_ack(soc_intc, MSPI_BSPI_DONE); - soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE, true); + /* Must flush previous writes before starting BSPI operation */ + mb(); + bcm_qspi_bspi_lr_start(qspi); + if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) { + dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n"); + ret = -ETIMEDOUT; + break; + } + + /* set msg return length */ + msg->retlen += rdlen; + addr += rdlen; + len -= rdlen; + } while (len); + + return ret; +} + +static int bcm_qspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *trans) +{ + struct bcm_qspi *qspi = spi_master_get_devdata(master); + int slots; + unsigned long timeo = msecs_to_jiffies(100); + + bcm_qspi_chip_select(qspi, spi->chip_select); + qspi->trans_pos.trans = trans; + qspi->trans_pos.byte = 0; + + while (qspi->trans_pos.byte < trans->len) { + reinit_completion(&qspi->mspi_done); + + slots = write_to_hw(qspi, spi); + if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) { + dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n"); + return -ETIMEDOUT; + } + + read_from_hw(qspi, slots); } - /* Must flush previous writes before starting BSPI operation */ - mb(); + return 0; +} - bcm_qspi_bspi_lr_start(qspi); - if (!wait_for_completion_timeout(&qspi->bspi_done, timeo)) { - dev_err(&qspi->pdev->dev, "timeout waiting for BSPI\n"); - ret = -ETIMEDOUT; - } else { - /* set the return length for the caller */ - msg->retlen = len; +static int bcm_qspi_mspi_flash_read(struct spi_device *spi, + struct spi_flash_read_message *msg) +{ + struct bcm_qspi *qspi = spi_master_get_devdata(spi->master); + struct spi_transfer t[2]; + u8 cmd[6]; + int ret; + + memset(cmd, 0, sizeof(cmd)); + memset(t, 0, sizeof(t)); + + /* tx */ + /* opcode is in cmd[0] */ + cmd[0] = msg->read_opcode; + cmd[1] = msg->from >> (msg->addr_width * 8 - 8); + cmd[2] = msg->from >> (msg->addr_width * 8 - 16); + cmd[3] = msg->from >> (msg->addr_width * 8 - 24); + cmd[4] = msg->from >> (msg->addr_width * 8 - 32); + t[0].tx_buf = cmd; + t[0].len = msg->addr_width + msg->dummy_bytes + 1; + t[0].bits_per_word = spi->bits_per_word; + t[0].tx_nbits = msg->opcode_nbits; + /* lets mspi know that this is not last transfer */ + qspi->trans_pos.mspi_last_trans = false; + ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]); + + /* rx */ + qspi->trans_pos.mspi_last_trans = true; + if (!ret) { + /* rx */ + t[1].rx_buf = msg->buf; + t[1].len = msg->len; + t[1].rx_nbits = msg->data_nbits; + t[1].bits_per_word = spi->bits_per_word; + ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]); } + if (!ret) + msg->retlen = msg->len; + return ret; } @@ -918,8 +1008,7 @@ static int bcm_qspi_flash_read(struct spi_device *spi, mspi_read = true; if (mspi_read) - /* this will make the m25p80 read to fallback to mspi read */ - return -EAGAIN; + return bcm_qspi_mspi_flash_read(spi, msg); io_width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE; addrlen = msg->addr_width; @@ -931,33 +1020,6 @@ static int bcm_qspi_flash_read(struct spi_device *spi, return ret; } -static int bcm_qspi_transfer_one(struct spi_master *master, - struct spi_device *spi, - struct spi_transfer *trans) -{ - struct bcm_qspi *qspi = spi_master_get_devdata(master); - int slots; - unsigned long timeo = msecs_to_jiffies(100); - - bcm_qspi_chip_select(qspi, spi->chip_select); - qspi->trans_pos.trans = trans; - qspi->trans_pos.byte = 0; - - while (qspi->trans_pos.byte < trans->len) { - reinit_completion(&qspi->mspi_done); - - slots = write_to_hw(qspi, spi); - if (!wait_for_completion_timeout(&qspi->mspi_done, timeo)) { - dev_err(&qspi->pdev->dev, "timeout waiting for MSPI\n"); - return -ETIMEDOUT; - } - - read_from_hw(qspi, slots); - } - - return 0; -} - static void bcm_qspi_cleanup(struct spi_device *spi) { struct bcm_qspi_parms *xp = spi_get_ctldata(spi); @@ -1187,6 +1249,7 @@ int bcm_qspi_probe(struct platform_device *pdev, qspi->pdev = pdev; qspi->trans_pos.trans = NULL; qspi->trans_pos.byte = 0; + qspi->trans_pos.mspi_last_trans = true; qspi->master = master; master->bus_num = -1; @@ -1345,7 +1408,6 @@ int bcm_qspi_remove(struct platform_device *pdev) { struct bcm_qspi *qspi = platform_get_drvdata(pdev); - platform_set_drvdata(pdev, NULL); bcm_qspi_hw_uninit(qspi); clk_disable_unprepare(qspi->clk); kfree(qspi->dev_ids); diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c index afb51699dbb5..6e409eabe1c9 100644 --- a/drivers/spi/spi-bcm53xx.c +++ b/drivers/spi/spi-bcm53xx.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2014-2016 RafaÅ‚ MiÅ‚ecki <rafal@milecki.pl> + * + * 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. + */ + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> @@ -275,10 +283,6 @@ static int bcm53xxspi_flash_read(struct spi_device *spi, * BCMA **************************************************/ -static struct spi_board_info bcm53xx_info = { - .modalias = "bcm53xxspiflash", -}; - static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = { BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS), {}, @@ -311,6 +315,7 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) b53spi->bspi = true; bcm53xxspi_disable_bspi(b53spi); + master->dev.of_node = dev->of_node; master->transfer_one = bcm53xxspi_transfer_one; if (b53spi->mmio_base) master->spi_flash_read = bcm53xxspi_flash_read; @@ -324,9 +329,6 @@ static int bcm53xxspi_bcma_probe(struct bcma_device *core) return err; } - /* Broadcom SoCs (at least with the CC rev 42) use SPI for flash only */ - spi_new_device(master, &bcm53xx_info); - return 0; } @@ -361,4 +363,4 @@ module_exit(bcm53xxspi_module_exit); MODULE_DESCRIPTION("Broadcom BCM53xx SPI Controller driver"); MODULE_AUTHOR("RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index d36c11b73a35..02fb96797ac8 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -646,7 +646,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) buf = t->rx_buf; t->rx_dma = dma_map_single(&spi->dev, buf, t->len, DMA_FROM_DEVICE); - if (!t->rx_dma) { + if (dma_mapping_error(&spi->dev, !t->rx_dma)) { ret = -EFAULT; goto err_rx_map; } @@ -660,7 +660,7 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t) buf = (void *)t->tx_buf; t->tx_dma = dma_map_single(&spi->dev, buf, t->len, DMA_TO_DEVICE); - if (!t->tx_dma) { + if (dma_mapping_error(&spi->dev, t->tx_dma)) { ret = -EFAULT; goto err_tx_map; } diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c index e31971f91475..837cb8d0bac6 100644 --- a/drivers/spi/spi-dw-mid.c +++ b/drivers/spi/spi-dw-mid.c @@ -274,11 +274,11 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer) static void mid_spi_dma_stop(struct dw_spi *dws) { if (test_bit(TX_BUSY, &dws->dma_chan_busy)) { - dmaengine_terminate_all(dws->txchan); + dmaengine_terminate_sync(dws->txchan); clear_bit(TX_BUSY, &dws->dma_chan_busy); } if (test_bit(RX_BUSY, &dws->dma_chan_busy)) { - dmaengine_terminate_all(dws->rxchan); + dmaengine_terminate_sync(dws->rxchan); clear_bit(RX_BUSY, &dws->dma_chan_busy); } } diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index b715a26a9148..b217c22ff72f 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -107,7 +107,10 @@ static const struct file_operations dw_spi_regs_ops = { static int dw_spi_debugfs_init(struct dw_spi *dws) { - dws->debugfs = debugfs_create_dir("dw_spi", NULL); + char name[32]; + + snprintf(name, 32, "dw_spi%d", dws->master->bus_num); + dws->debugfs = debugfs_create_dir(name, NULL); if (!dws->debugfs) return -ENOMEM; @@ -483,9 +486,9 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); - snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); - ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dws->name, master); + ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), + master); if (ret < 0) { dev_err(dev, "can not get IRQ\n"); goto err_free_master; diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h index c21ca02f8ec5..da5eab62df34 100644 --- a/drivers/spi/spi-dw.h +++ b/drivers/spi/spi-dw.h @@ -101,7 +101,6 @@ struct dw_spi_dma_ops { struct dw_spi { struct spi_master *master; enum dw_ssi_type type; - char name[16]; void __iomem *regs; unsigned long paddr; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 17a6387e20b5..b5d766064b7b 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -28,6 +28,7 @@ #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/scatterlist.h> +#include <linux/gpio.h> #include <linux/spi/spi.h> #include <linux/platform_data/dma-ep93xx.h> @@ -107,16 +108,6 @@ struct ep93xx_spi { void *zeropage; }; -/** - * struct ep93xx_spi_chip - SPI device hardware settings - * @spi: back pointer to the SPI device - * @ops: private chip operations - */ -struct ep93xx_spi_chip { - const struct spi_device *spi; - struct ep93xx_spi_chip_ops *ops; -}; - /* converts bits per word to CR0.DSS value */ #define bits_per_word_to_dss(bpw) ((bpw) - 1) @@ -229,104 +220,36 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, return -EINVAL; } -static void ep93xx_spi_cs_control(struct spi_device *spi, bool control) -{ - struct ep93xx_spi_chip *chip = spi_get_ctldata(spi); - int value = (spi->mode & SPI_CS_HIGH) ? control : !control; - - if (chip->ops && chip->ops->cs_control) - chip->ops->cs_control(spi, value); -} - -/** - * ep93xx_spi_setup() - setup an SPI device - * @spi: SPI device to setup - * - * This function sets up SPI device mode, speed etc. Can be called multiple - * times for a single device. Returns %0 in case of success, negative error in - * case of failure. When this function returns success, the device is - * deselected. - */ -static int ep93xx_spi_setup(struct spi_device *spi) +static void ep93xx_spi_cs_control(struct spi_device *spi, bool enable) { - struct ep93xx_spi *espi = spi_master_get_devdata(spi->master); - struct ep93xx_spi_chip *chip; + if (spi->mode & SPI_CS_HIGH) + enable = !enable; - chip = spi_get_ctldata(spi); - if (!chip) { - dev_dbg(&espi->pdev->dev, "initial setup for %s\n", - spi->modalias); - - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) - return -ENOMEM; - - chip->spi = spi; - chip->ops = spi->controller_data; - - if (chip->ops && chip->ops->setup) { - int ret = chip->ops->setup(spi); - - if (ret) { - kfree(chip); - return ret; - } - } - - spi_set_ctldata(spi, chip); - } - - ep93xx_spi_cs_control(spi, false); - return 0; + if (gpio_is_valid(spi->cs_gpio)) + gpio_set_value(spi->cs_gpio, !enable); } -/** - * ep93xx_spi_cleanup() - cleans up master controller specific state - * @spi: SPI device to cleanup - * - * This function releases master controller specific state for given @spi - * device. - */ -static void ep93xx_spi_cleanup(struct spi_device *spi) -{ - struct ep93xx_spi_chip *chip; - - chip = spi_get_ctldata(spi); - if (chip) { - if (chip->ops && chip->ops->cleanup) - chip->ops->cleanup(spi); - spi_set_ctldata(spi, NULL); - kfree(chip); - } -} - -/** - * ep93xx_spi_chip_setup() - configures hardware according to given @chip - * @espi: ep93xx SPI controller struct - * @chip: chip specific settings - * @speed_hz: transfer speed - * @bits_per_word: transfer bits_per_word - */ static int ep93xx_spi_chip_setup(const struct ep93xx_spi *espi, - const struct ep93xx_spi_chip *chip, - u32 speed_hz, u8 bits_per_word) + struct spi_device *spi, + struct spi_transfer *xfer) { - u8 dss = bits_per_word_to_dss(bits_per_word); + u8 dss = bits_per_word_to_dss(xfer->bits_per_word); u8 div_cpsr = 0; u8 div_scr = 0; u16 cr0; int err; - err = ep93xx_spi_calc_divisors(espi, speed_hz, &div_cpsr, &div_scr); + err = ep93xx_spi_calc_divisors(espi, xfer->speed_hz, + &div_cpsr, &div_scr); if (err) return err; cr0 = div_scr << SSPCR0_SCR_SHIFT; - cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT; + cr0 |= (spi->mode & (SPI_CPHA | SPI_CPOL)) << SSPCR0_MODE_SHIFT; cr0 |= dss; dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n", - chip->spi->mode, div_cpsr, div_scr, dss); + spi->mode, div_cpsr, div_scr, dss); dev_dbg(&espi->pdev->dev, "setup: cr0 %#x\n", cr0); ep93xx_spi_write_u8(espi, SSPCPSR, div_cpsr); @@ -603,12 +526,11 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi, struct spi_message *msg, struct spi_transfer *t) { - struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi); int err; msg->state = t; - err = ep93xx_spi_chip_setup(espi, chip, t->speed_hz, t->bits_per_word); + err = ep93xx_spi_chip_setup(espi, msg->spi, t); if (err) { dev_err(&espi->pdev->dev, "failed to setup chip for transfer\n"); @@ -863,8 +785,13 @@ static int ep93xx_spi_probe(struct platform_device *pdev) struct resource *res; int irq; int error; + int i; info = dev_get_platdata(&pdev->dev); + if (!info) { + dev_err(&pdev->dev, "missing platform data\n"); + return -EINVAL; + } irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -882,14 +809,36 @@ static int ep93xx_spi_probe(struct platform_device *pdev) if (!master) return -ENOMEM; - master->setup = ep93xx_spi_setup; master->transfer_one_message = ep93xx_spi_transfer_one_message; - master->cleanup = ep93xx_spi_cleanup; master->bus_num = pdev->id; - master->num_chipselect = info->num_chipselect; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); + master->num_chipselect = info->num_chipselect; + master->cs_gpios = devm_kzalloc(&master->dev, + sizeof(int) * master->num_chipselect, + GFP_KERNEL); + if (!master->cs_gpios) { + error = -ENOMEM; + goto fail_release_master; + } + + for (i = 0; i < master->num_chipselect; i++) { + master->cs_gpios[i] = info->chipselect[i]; + + if (!gpio_is_valid(master->cs_gpios[i])) + continue; + + error = devm_gpio_request_one(&pdev->dev, master->cs_gpios[i], + GPIOF_OUT_INIT_HIGH, + "ep93xx-spi"); + if (error) { + dev_err(&pdev->dev, "could not request cs gpio %d\n", + master->cs_gpios[i]); + goto fail_release_master; + } + } + platform_set_drvdata(pdev, master); espi = spi_master_get_devdata(master); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index 52551f6d0c7d..cb3c73007ca1 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -366,7 +366,7 @@ static int fsl_lpspi_transfer_one_msg(struct spi_master *master, struct spi_transfer *xfer; bool is_first_xfer = true; u32 temp; - int ret; + int ret = 0; msg->status = 0; msg->actual_length = 0; @@ -512,9 +512,9 @@ static int fsl_lpspi_remove(struct platform_device *pdev) static struct platform_driver fsl_lpspi_driver = { .driver = { - .name = DRIVER_NAME, - .of_match_table = fsl_lpspi_dt_ids, - }, + .name = DRIVER_NAME, + .of_match_table = fsl_lpspi_dt_ids, + }, .probe = fsl_lpspi_probe, .remove = fsl_lpspi_remove, }; diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 8b290d9d7935..0fc3452652ae 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -267,10 +267,9 @@ static int fsl_spi_setup_transfer(struct spi_device *spi, if ((mpc8xxx_spi->spibrg / hz) > 64) { cs->hw_mode |= SPMODE_DIV16; pm = (mpc8xxx_spi->spibrg - 1) / (hz * 64) + 1; - - WARN_ONCE(pm > 16, "%s: Requested speed is too low: %d Hz. " - "Will use %d Hz instead.\n", dev_name(&spi->dev), - hz, mpc8xxx_spi->spibrg / 1024); + WARN_ONCE(pm > 16, + "%s: Requested speed is too low: %d Hz. Will use %d Hz instead.\n", + dev_name(&spi->dev), hz, mpc8xxx_spi->spibrg / 1024); if (pm > 16) pm = 16; } else { @@ -727,12 +726,13 @@ static int of_fsl_spi_get_chipselects(struct device *dev) return 0; } - pinfo->gpios = kmalloc(ngpios * sizeof(*pinfo->gpios), GFP_KERNEL); + pinfo->gpios = kmalloc_array(ngpios, sizeof(*pinfo->gpios), + GFP_KERNEL); if (!pinfo->gpios) return -ENOMEM; memset(pinfo->gpios, -1, ngpios * sizeof(*pinfo->gpios)); - pinfo->alow_flags = kzalloc(ngpios * sizeof(*pinfo->alow_flags), + pinfo->alow_flags = kcalloc(ngpios, sizeof(*pinfo->alow_flags), GFP_KERNEL); if (!pinfo->alow_flags) { ret = -ENOMEM; @@ -762,8 +762,9 @@ static int of_fsl_spi_get_chipselects(struct device *dev) ret = gpio_direction_output(pinfo->gpios[i], pinfo->alow_flags[i]); if (ret) { - dev_err(dev, "can't set output direction for gpio " - "#%d: %d\n", i, ret); + dev_err(dev, + "can't set output direction for gpio #%d: %d\n", + i, ret); goto err_loop; } } diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index 32ced64a5bb9..9a7c62f471dc 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -211,7 +211,7 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *transfer) { struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - unsigned int bpw; + unsigned int bpw, i; if (!master->dma_rx) return false; @@ -228,12 +228,16 @@ static bool spi_imx_can_dma(struct spi_master *master, struct spi_device *spi, if (bpw != 1 && bpw != 2 && bpw != 4) return false; - if (transfer->len < spi_imx->wml * bpw) - return false; + for (i = spi_imx_get_fifosize(spi_imx) / 2; i > 0; i--) { + if (!(transfer->len % (i * bpw))) + break; + } - if (transfer->len % (spi_imx->wml * bpw)) + if (i == 0) return false; + spi_imx->wml = i; + return true; } @@ -837,10 +841,6 @@ static int spi_imx_dma_configure(struct spi_master *master, struct dma_slave_config rx = {}, tx = {}; struct spi_imx_data *spi_imx = spi_master_get_devdata(master); - if (bytes_per_word == spi_imx->bytes_per_word) - /* Same as last time */ - return 0; - switch (bytes_per_word) { case 4: buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES; diff --git a/drivers/spi/spi-lantiq-ssc.c b/drivers/spi/spi-lantiq-ssc.c new file mode 100644 index 000000000000..8a626f7fccea --- /dev/null +++ b/drivers/spi/spi-lantiq-ssc.c @@ -0,0 +1,983 @@ +/* + * Copyright (C) 2011-2015 Daniel Schwierzeck <daniel.schwierzeck@gmail.com> + * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de> + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/completion.h> +#include <linux/spinlock.h> +#include <linux/err.h> +#include <linux/gpio.h> +#include <linux/pm_runtime.h> +#include <linux/spi/spi.h> + +#ifdef CONFIG_LANTIQ +#include <lantiq_soc.h> +#endif + +#define SPI_RX_IRQ_NAME "spi_rx" +#define SPI_TX_IRQ_NAME "spi_tx" +#define SPI_ERR_IRQ_NAME "spi_err" +#define SPI_FRM_IRQ_NAME "spi_frm" + +#define SPI_CLC 0x00 +#define SPI_PISEL 0x04 +#define SPI_ID 0x08 +#define SPI_CON 0x10 +#define SPI_STAT 0x14 +#define SPI_WHBSTATE 0x18 +#define SPI_TB 0x20 +#define SPI_RB 0x24 +#define SPI_RXFCON 0x30 +#define SPI_TXFCON 0x34 +#define SPI_FSTAT 0x38 +#define SPI_BRT 0x40 +#define SPI_BRSTAT 0x44 +#define SPI_SFCON 0x60 +#define SPI_SFSTAT 0x64 +#define SPI_GPOCON 0x70 +#define SPI_GPOSTAT 0x74 +#define SPI_FPGO 0x78 +#define SPI_RXREQ 0x80 +#define SPI_RXCNT 0x84 +#define SPI_DMACON 0xec +#define SPI_IRNEN 0xf4 +#define SPI_IRNICR 0xf8 +#define SPI_IRNCR 0xfc + +#define SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */ +#define SPI_CLC_SMC_M (0xFF << SPI_CLC_SMC_S) +#define SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */ +#define SPI_CLC_RMC_M (0xFF << SPI_CLC_RMC_S) +#define SPI_CLC_DISS BIT(1) /* Disable status bit */ +#define SPI_CLC_DISR BIT(0) /* Disable request bit */ + +#define SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */ +#define SPI_ID_TXFS_M (0x3F << SPI_ID_TXFS_S) +#define SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */ +#define SPI_ID_RXFS_M (0x3F << SPI_ID_RXFS_S) +#define SPI_ID_MOD_S 8 /* Module ID */ +#define SPI_ID_MOD_M (0xff << SPI_ID_MOD_S) +#define SPI_ID_CFG_S 5 /* DMA interface support */ +#define SPI_ID_CFG_M (1 << SPI_ID_CFG_S) +#define SPI_ID_REV_M 0x1F /* Hardware revision number */ + +#define SPI_CON_BM_S 16 /* Data width selection */ +#define SPI_CON_BM_M (0x1F << SPI_CON_BM_S) +#define SPI_CON_EM BIT(24) /* Echo mode */ +#define SPI_CON_IDLE BIT(23) /* Idle bit value */ +#define SPI_CON_ENBV BIT(22) /* Enable byte valid control */ +#define SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ +#define SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ +#define SPI_CON_AEN BIT(10) /* Abort error enable */ +#define SPI_CON_REN BIT(9) /* Receive overflow error enable */ +#define SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ +#define SPI_CON_LB BIT(7) /* Loopback control */ +#define SPI_CON_PO BIT(6) /* Clock polarity control */ +#define SPI_CON_PH BIT(5) /* Clock phase control */ +#define SPI_CON_HB BIT(4) /* Heading control */ +#define SPI_CON_RXOFF BIT(1) /* Switch receiver off */ +#define SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ + +#define SPI_STAT_RXBV_S 28 +#define SPI_STAT_RXBV_M (0x7 << SPI_STAT_RXBV_S) +#define SPI_STAT_BSY BIT(13) /* Busy flag */ +#define SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ +#define SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ +#define SPI_STAT_AE BIT(10) /* Abort error flag */ +#define SPI_STAT_RE BIT(9) /* Receive error flag */ +#define SPI_STAT_TE BIT(8) /* Transmit error flag */ +#define SPI_STAT_ME BIT(7) /* Mode error flag */ +#define SPI_STAT_MS BIT(1) /* Master/slave select bit */ +#define SPI_STAT_EN BIT(0) /* Enable bit */ +#define SPI_STAT_ERRORS (SPI_STAT_ME | SPI_STAT_TE | SPI_STAT_RE | \ + SPI_STAT_AE | SPI_STAT_TUE | SPI_STAT_RUE) + +#define SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ +#define SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ +#define SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ +#define SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ +#define SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ +#define SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ +#define SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ +#define SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ +#define SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ +#define SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ +#define SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ +#define SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ +#define SPI_WHBSTATE_SETMS BIT(3) /* Set master select bit */ +#define SPI_WHBSTATE_CLRMS BIT(2) /* Clear master select bit */ +#define SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ +#define SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ +#define SPI_WHBSTATE_CLR_ERRORS (SPI_WHBSTATE_CLRRUE | SPI_WHBSTATE_CLRME | \ + SPI_WHBSTATE_CLRTE | SPI_WHBSTATE_CLRRE | \ + SPI_WHBSTATE_CLRAE | SPI_WHBSTATE_CLRTUE) + +#define SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */ +#define SPI_RXFCON_RXFITL_M (0x3F << SPI_RXFCON_RXFITL_S) +#define SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ +#define SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ + +#define SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */ +#define SPI_TXFCON_TXFITL_M (0x3F << SPI_TXFCON_TXFITL_S) +#define SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ +#define SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ + +#define SPI_FSTAT_RXFFL_S 0 +#define SPI_FSTAT_RXFFL_M (0x3f << SPI_FSTAT_RXFFL_S) +#define SPI_FSTAT_TXFFL_S 8 +#define SPI_FSTAT_TXFFL_M (0x3f << SPI_FSTAT_TXFFL_S) + +#define SPI_GPOCON_ISCSBN_S 8 +#define SPI_GPOCON_INVOUTN_S 0 + +#define SPI_FGPO_SETOUTN_S 8 +#define SPI_FGPO_CLROUTN_S 0 + +#define SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ +#define SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ + +#define SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ +#define SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ +#define SPI_IRNEN_E BIT(2) /* Error end interrupt request */ +#define SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */ +#define SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */ +#define SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */ +#define SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */ +#define SPI_IRNEN_ALL 0x1F + +struct lantiq_ssc_hwcfg { + unsigned int irnen_r; + unsigned int irnen_t; +}; + +struct lantiq_ssc_spi { + struct spi_master *master; + struct device *dev; + void __iomem *regbase; + struct clk *spi_clk; + struct clk *fpi_clk; + const struct lantiq_ssc_hwcfg *hwcfg; + + spinlock_t lock; + struct workqueue_struct *wq; + struct work_struct work; + + const u8 *tx; + u8 *rx; + unsigned int tx_todo; + unsigned int rx_todo; + unsigned int bits_per_word; + unsigned int speed_hz; + unsigned int tx_fifo_size; + unsigned int rx_fifo_size; + unsigned int base_cs; +}; + +static u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg) +{ + return __raw_readl(spi->regbase + reg); +} + +static void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val, + u32 reg) +{ + __raw_writel(val, spi->regbase + reg); +} + +static void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr, + u32 set, u32 reg) +{ + u32 val = __raw_readl(spi->regbase + reg); + + val &= ~clr; + val |= set; + __raw_writel(val, spi->regbase + reg); +} + +static unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi) +{ + u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + + return (fstat & SPI_FSTAT_TXFFL_M) >> SPI_FSTAT_TXFFL_S; +} + +static unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi) +{ + u32 fstat = lantiq_ssc_readl(spi, SPI_FSTAT); + + return fstat & SPI_FSTAT_RXFFL_M; +} + +static unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) +{ + return spi->tx_fifo_size - tx_fifo_level(spi); +} + +static void rx_fifo_reset(const struct lantiq_ssc_spi *spi) +{ + u32 val = spi->rx_fifo_size << SPI_RXFCON_RXFITL_S; + + val |= SPI_RXFCON_RXFEN | SPI_RXFCON_RXFLU; + lantiq_ssc_writel(spi, val, SPI_RXFCON); +} + +static void tx_fifo_reset(const struct lantiq_ssc_spi *spi) +{ + u32 val = 1 << SPI_TXFCON_TXFITL_S; + + val |= SPI_TXFCON_TXFEN | SPI_TXFCON_TXFLU; + lantiq_ssc_writel(spi, val, SPI_TXFCON); +} + +static void rx_fifo_flush(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_maskl(spi, 0, SPI_RXFCON_RXFLU, SPI_RXFCON); +} + +static void tx_fifo_flush(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_maskl(spi, 0, SPI_TXFCON_TXFLU, SPI_TXFCON); +} + +static void hw_enter_config_mode(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_writel(spi, SPI_WHBSTATE_CLREN, SPI_WHBSTATE); +} + +static void hw_enter_active_mode(const struct lantiq_ssc_spi *spi) +{ + lantiq_ssc_writel(spi, SPI_WHBSTATE_SETEN, SPI_WHBSTATE); +} + +static void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi, + unsigned int max_speed_hz) +{ + u32 spi_clk, brt; + + /* + * SPI module clock is derived from FPI bus clock dependent on + * divider value in CLC.RMS which is always set to 1. + * + * f_SPI + * baudrate = -------------- + * 2 * (BR + 1) + */ + spi_clk = clk_get_rate(spi->fpi_clk) / 2; + + if (max_speed_hz > spi_clk) + brt = 0; + else + brt = spi_clk / max_speed_hz - 1; + + if (brt > 0xFFFF) + brt = 0xFFFF; + + dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n", + spi_clk, max_speed_hz, brt); + + lantiq_ssc_writel(spi, brt, SPI_BRT); +} + +static void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi, + unsigned int bits_per_word) +{ + u32 bm; + + /* CON.BM value = bits_per_word - 1 */ + bm = (bits_per_word - 1) << SPI_CON_BM_S; + + lantiq_ssc_maskl(spi, SPI_CON_BM_M, bm, SPI_CON); +} + +static void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi, + unsigned int mode) +{ + u32 con_set = 0, con_clr = 0; + + /* + * SPI mode mapping in CON register: + * Mode CPOL CPHA CON.PO CON.PH + * 0 0 0 0 1 + * 1 0 1 0 0 + * 2 1 0 1 1 + * 3 1 1 1 0 + */ + if (mode & SPI_CPHA) + con_clr |= SPI_CON_PH; + else + con_set |= SPI_CON_PH; + + if (mode & SPI_CPOL) + con_set |= SPI_CON_PO | SPI_CON_IDLE; + else + con_clr |= SPI_CON_PO | SPI_CON_IDLE; + + /* Set heading control */ + if (mode & SPI_LSB_FIRST) + con_clr |= SPI_CON_HB; + else + con_set |= SPI_CON_HB; + + /* Set loopback mode */ + if (mode & SPI_LOOP) + con_set |= SPI_CON_LB; + else + con_clr |= SPI_CON_LB; + + lantiq_ssc_maskl(spi, con_clr, con_set, SPI_CON); +} + +static void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi) +{ + const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; + + /* + * Set clock divider for run mode to 1 to + * run at same frequency as FPI bus + */ + lantiq_ssc_writel(spi, 1 << SPI_CLC_RMC_S, SPI_CLC); + + /* Put controller into config mode */ + hw_enter_config_mode(spi); + + /* Clear error flags */ + lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE); + + /* Enable error checking, disable TX/RX */ + lantiq_ssc_writel(spi, SPI_CON_RUEN | SPI_CON_AEN | SPI_CON_TEN | + SPI_CON_REN | SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON); + + /* Setup default SPI mode */ + hw_setup_bits_per_word(spi, spi->bits_per_word); + hw_setup_clock_mode(spi, SPI_MODE_0); + + /* Enable master mode and clear error flags */ + lantiq_ssc_writel(spi, SPI_WHBSTATE_SETMS | SPI_WHBSTATE_CLR_ERRORS, + SPI_WHBSTATE); + + /* Reset GPIO/CS registers */ + lantiq_ssc_writel(spi, 0, SPI_GPOCON); + lantiq_ssc_writel(spi, 0xFF00, SPI_FPGO); + + /* Enable and flush FIFOs */ + rx_fifo_reset(spi); + tx_fifo_reset(spi); + + /* Enable interrupts */ + lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | SPI_IRNEN_E, + SPI_IRNEN); +} + +static int lantiq_ssc_setup(struct spi_device *spidev) +{ + struct spi_master *master = spidev->master; + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + unsigned int cs = spidev->chip_select; + u32 gpocon; + + /* GPIOs are used for CS */ + if (gpio_is_valid(spidev->cs_gpio)) + return 0; + + dev_dbg(spi->dev, "using internal chipselect %u\n", cs); + + if (cs < spi->base_cs) { + dev_err(spi->dev, + "chipselect %i too small (min %i)\n", cs, spi->base_cs); + return -EINVAL; + } + + /* set GPO pin to CS mode */ + gpocon = 1 << ((cs - spi->base_cs) + SPI_GPOCON_ISCSBN_S); + + /* invert GPO pin */ + if (spidev->mode & SPI_CS_HIGH) + gpocon |= 1 << (cs - spi->base_cs); + + lantiq_ssc_maskl(spi, 0, gpocon, SPI_GPOCON); + + return 0; +} + +static int lantiq_ssc_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + hw_enter_config_mode(spi); + hw_setup_clock_mode(spi, message->spi->mode); + hw_enter_active_mode(spi); + + return 0; +} + +static void hw_setup_transfer(struct lantiq_ssc_spi *spi, + struct spi_device *spidev, struct spi_transfer *t) +{ + unsigned int speed_hz = t->speed_hz; + unsigned int bits_per_word = t->bits_per_word; + u32 con; + + if (bits_per_word != spi->bits_per_word || + speed_hz != spi->speed_hz) { + hw_enter_config_mode(spi); + hw_setup_speed_hz(spi, speed_hz); + hw_setup_bits_per_word(spi, bits_per_word); + hw_enter_active_mode(spi); + + spi->speed_hz = speed_hz; + spi->bits_per_word = bits_per_word; + } + + /* Configure transmitter and receiver */ + con = lantiq_ssc_readl(spi, SPI_CON); + if (t->tx_buf) + con &= ~SPI_CON_TXOFF; + else + con |= SPI_CON_TXOFF; + + if (t->rx_buf) + con &= ~SPI_CON_RXOFF; + else + con |= SPI_CON_RXOFF; + + lantiq_ssc_writel(spi, con, SPI_CON); +} + +static int lantiq_ssc_unprepare_message(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + flush_workqueue(spi->wq); + + /* Disable transmitter and receiver while idle */ + lantiq_ssc_maskl(spi, 0, SPI_CON_TXOFF | SPI_CON_RXOFF, SPI_CON); + + return 0; +} + +static void tx_fifo_write(struct lantiq_ssc_spi *spi) +{ + const u8 *tx8; + const u16 *tx16; + const u32 *tx32; + u32 data; + unsigned int tx_free = tx_fifo_free(spi); + + while (spi->tx_todo && tx_free) { + switch (spi->bits_per_word) { + case 2 ... 8: + tx8 = spi->tx; + data = *tx8; + spi->tx_todo--; + spi->tx++; + break; + case 16: + tx16 = (u16 *) spi->tx; + data = *tx16; + spi->tx_todo -= 2; + spi->tx += 2; + break; + case 32: + tx32 = (u32 *) spi->tx; + data = *tx32; + spi->tx_todo -= 4; + spi->tx += 4; + break; + default: + WARN_ON(1); + data = 0; + break; + } + + lantiq_ssc_writel(spi, data, SPI_TB); + tx_free--; + } +} + +static void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi) +{ + u8 *rx8; + u16 *rx16; + u32 *rx32; + u32 data; + unsigned int rx_fill = rx_fifo_level(spi); + + while (rx_fill) { + data = lantiq_ssc_readl(spi, SPI_RB); + + switch (spi->bits_per_word) { + case 2 ... 8: + rx8 = spi->rx; + *rx8 = data; + spi->rx_todo--; + spi->rx++; + break; + case 16: + rx16 = (u16 *) spi->rx; + *rx16 = data; + spi->rx_todo -= 2; + spi->rx += 2; + break; + case 32: + rx32 = (u32 *) spi->rx; + *rx32 = data; + spi->rx_todo -= 4; + spi->rx += 4; + break; + default: + WARN_ON(1); + break; + } + + rx_fill--; + } +} + +static void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi) +{ + u32 data, *rx32; + u8 *rx8; + unsigned int rxbv, shift; + unsigned int rx_fill = rx_fifo_level(spi); + + /* + * In RX-only mode the bits per word value is ignored by HW. A value + * of 32 is used instead. Thus all 4 bytes per FIFO must be read. + * If remaining RX bytes are less than 4, the FIFO must be read + * differently. The amount of received and valid bytes is indicated + * by STAT.RXBV register value. + */ + while (rx_fill) { + if (spi->rx_todo < 4) { + rxbv = (lantiq_ssc_readl(spi, SPI_STAT) & + SPI_STAT_RXBV_M) >> SPI_STAT_RXBV_S; + data = lantiq_ssc_readl(spi, SPI_RB); + + shift = (rxbv - 1) * 8; + rx8 = spi->rx; + + while (rxbv) { + *rx8++ = (data >> shift) & 0xFF; + rxbv--; + shift -= 8; + spi->rx_todo--; + spi->rx++; + } + } else { + data = lantiq_ssc_readl(spi, SPI_RB); + rx32 = (u32 *) spi->rx; + + *rx32++ = data; + spi->rx_todo -= 4; + spi->rx += 4; + } + rx_fill--; + } +} + +static void rx_request(struct lantiq_ssc_spi *spi) +{ + unsigned int rxreq, rxreq_max; + + /* + * To avoid receive overflows at high clocks it is better to request + * only the amount of bytes that fits into all FIFOs. This value + * depends on the FIFO size implemented in hardware. + */ + rxreq = spi->rx_todo; + rxreq_max = spi->rx_fifo_size * 4; + if (rxreq > rxreq_max) + rxreq = rxreq_max; + + lantiq_ssc_writel(spi, rxreq, SPI_RXREQ); +} + +static irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) +{ + struct lantiq_ssc_spi *spi = data; + + if (spi->tx) { + if (spi->rx && spi->rx_todo) + rx_fifo_read_full_duplex(spi); + + if (spi->tx_todo) + tx_fifo_write(spi); + else if (!tx_fifo_level(spi)) + goto completed; + } else if (spi->rx) { + if (spi->rx_todo) { + rx_fifo_read_half_duplex(spi); + + if (spi->rx_todo) + rx_request(spi); + else + goto completed; + } else { + goto completed; + } + } + + return IRQ_HANDLED; + +completed: + queue_work(spi->wq, &spi->work); + + return IRQ_HANDLED; +} + +static irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data) +{ + struct lantiq_ssc_spi *spi = data; + u32 stat = lantiq_ssc_readl(spi, SPI_STAT); + + if (!(stat & SPI_STAT_ERRORS)) + return IRQ_NONE; + + if (stat & SPI_STAT_RUE) + dev_err(spi->dev, "receive underflow error\n"); + if (stat & SPI_STAT_TUE) + dev_err(spi->dev, "transmit underflow error\n"); + if (stat & SPI_STAT_AE) + dev_err(spi->dev, "abort error\n"); + if (stat & SPI_STAT_RE) + dev_err(spi->dev, "receive overflow error\n"); + if (stat & SPI_STAT_TE) + dev_err(spi->dev, "transmit overflow error\n"); + if (stat & SPI_STAT_ME) + dev_err(spi->dev, "mode error\n"); + + /* Clear error flags */ + lantiq_ssc_maskl(spi, 0, SPI_WHBSTATE_CLR_ERRORS, SPI_WHBSTATE); + + /* set bad status so it can be retried */ + if (spi->master->cur_msg) + spi->master->cur_msg->status = -EIO; + queue_work(spi->wq, &spi->work); + + return IRQ_HANDLED; +} + +static int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev, + struct spi_transfer *t) +{ + unsigned long flags; + + spin_lock_irqsave(&spi->lock, flags); + + spi->tx = t->tx_buf; + spi->rx = t->rx_buf; + + if (t->tx_buf) { + spi->tx_todo = t->len; + + /* initially fill TX FIFO */ + tx_fifo_write(spi); + } + + if (spi->rx) { + spi->rx_todo = t->len; + + /* start shift clock in RX-only mode */ + if (!spi->tx) + rx_request(spi); + } + + spin_unlock_irqrestore(&spi->lock, flags); + + return t->len; +} + +/* + * The driver only gets an interrupt when the FIFO is empty, but there + * is an additional shift register from which the data is written to + * the wire. We get the last interrupt when the controller starts to + * write the last word to the wire, not when it is finished. Do busy + * waiting till it finishes. + */ +static void lantiq_ssc_bussy_work(struct work_struct *work) +{ + struct lantiq_ssc_spi *spi; + unsigned long long timeout = 8LL * 1000LL; + unsigned long end; + + spi = container_of(work, typeof(*spi), work); + + do_div(timeout, spi->speed_hz); + timeout += timeout + 100; /* some tolerance */ + + end = jiffies + msecs_to_jiffies(timeout); + do { + u32 stat = lantiq_ssc_readl(spi, SPI_STAT); + + if (!(stat & SPI_STAT_BSY)) { + spi_finalize_current_transfer(spi->master); + return; + } + + cond_resched(); + } while (!time_after_eq(jiffies, end)); + + if (spi->master->cur_msg) + spi->master->cur_msg->status = -EIO; + spi_finalize_current_transfer(spi->master); +} + +static void lantiq_ssc_handle_err(struct spi_master *master, + struct spi_message *message) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + /* flush FIFOs on timeout */ + rx_fifo_flush(spi); + tx_fifo_flush(spi); +} + +static void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(spidev->master); + unsigned int cs = spidev->chip_select; + u32 fgpo; + + if (!!(spidev->mode & SPI_CS_HIGH) == enable) + fgpo = (1 << (cs - spi->base_cs)); + else + fgpo = (1 << (cs - spi->base_cs + SPI_FGPO_SETOUTN_S)); + + lantiq_ssc_writel(spi, fgpo, SPI_FPGO); +} + +static int lantiq_ssc_transfer_one(struct spi_master *master, + struct spi_device *spidev, + struct spi_transfer *t) +{ + struct lantiq_ssc_spi *spi = spi_master_get_devdata(master); + + hw_setup_transfer(spi, spidev, t); + + return transfer_start(spi, spidev, t); +} + +static const struct lantiq_ssc_hwcfg lantiq_ssc_xway = { + .irnen_r = SPI_IRNEN_R_XWAY, + .irnen_t = SPI_IRNEN_T_XWAY, +}; + +static const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = { + .irnen_r = SPI_IRNEN_R_XRX, + .irnen_t = SPI_IRNEN_T_XRX, +}; + +static const struct of_device_id lantiq_ssc_match[] = { + { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, }, + { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, }, + { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, }, + {}, +}; +MODULE_DEVICE_TABLE(of, lantiq_ssc_match); + +static int lantiq_ssc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_master *master; + struct resource *res; + struct lantiq_ssc_spi *spi; + const struct lantiq_ssc_hwcfg *hwcfg; + const struct of_device_id *match; + int err, rx_irq, tx_irq, err_irq; + u32 id, supports_dma, revision; + unsigned int num_cs; + + match = of_match_device(lantiq_ssc_match, dev); + if (!match) { + dev_err(dev, "no device match\n"); + return -EINVAL; + } + hwcfg = match->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get resources\n"); + return -ENXIO; + } + + rx_irq = platform_get_irq_byname(pdev, SPI_RX_IRQ_NAME); + if (rx_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_RX_IRQ_NAME); + return -ENXIO; + } + + tx_irq = platform_get_irq_byname(pdev, SPI_TX_IRQ_NAME); + if (tx_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_TX_IRQ_NAME); + return -ENXIO; + } + + err_irq = platform_get_irq_byname(pdev, SPI_ERR_IRQ_NAME); + if (err_irq < 0) { + dev_err(dev, "failed to get %s\n", SPI_ERR_IRQ_NAME); + return -ENXIO; + } + + master = spi_alloc_master(dev, sizeof(struct lantiq_ssc_spi)); + if (!master) + return -ENOMEM; + + spi = spi_master_get_devdata(master); + spi->master = master; + spi->dev = dev; + spi->hwcfg = hwcfg; + platform_set_drvdata(pdev, spi); + + spi->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(spi->regbase)) { + err = PTR_ERR(spi->regbase); + goto err_master_put; + } + + err = devm_request_irq(dev, rx_irq, lantiq_ssc_xmit_interrupt, + 0, SPI_RX_IRQ_NAME, spi); + if (err) + goto err_master_put; + + err = devm_request_irq(dev, tx_irq, lantiq_ssc_xmit_interrupt, + 0, SPI_TX_IRQ_NAME, spi); + if (err) + goto err_master_put; + + err = devm_request_irq(dev, err_irq, lantiq_ssc_err_interrupt, + 0, SPI_ERR_IRQ_NAME, spi); + if (err) + goto err_master_put; + + spi->spi_clk = devm_clk_get(dev, "gate"); + if (IS_ERR(spi->spi_clk)) { + err = PTR_ERR(spi->spi_clk); + goto err_master_put; + } + err = clk_prepare_enable(spi->spi_clk); + if (err) + goto err_master_put; + + /* + * Use the old clk_get_fpi() function on Lantiq platform, till it + * supports common clk. + */ +#if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK) + spi->fpi_clk = clk_get_fpi(); +#else + spi->fpi_clk = clk_get(dev, "freq"); +#endif + if (IS_ERR(spi->fpi_clk)) { + err = PTR_ERR(spi->fpi_clk); + goto err_clk_disable; + } + + num_cs = 8; + of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); + + spi->base_cs = 1; + of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs); + + spin_lock_init(&spi->lock); + spi->bits_per_word = 8; + spi->speed_hz = 0; + + master->dev.of_node = pdev->dev.of_node; + master->num_chipselect = num_cs; + master->setup = lantiq_ssc_setup; + master->set_cs = lantiq_ssc_set_cs; + master->handle_err = lantiq_ssc_handle_err; + master->prepare_message = lantiq_ssc_prepare_message; + master->unprepare_message = lantiq_ssc_unprepare_message; + master->transfer_one = lantiq_ssc_transfer_one; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH | + SPI_LOOP; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) | + SPI_BPW_MASK(16) | SPI_BPW_MASK(32); + + spi->wq = alloc_ordered_workqueue(dev_name(dev), 0); + if (!spi->wq) { + err = -ENOMEM; + goto err_clk_put; + } + INIT_WORK(&spi->work, lantiq_ssc_bussy_work); + + id = lantiq_ssc_readl(spi, SPI_ID); + spi->tx_fifo_size = (id & SPI_ID_TXFS_M) >> SPI_ID_TXFS_S; + spi->rx_fifo_size = (id & SPI_ID_RXFS_M) >> SPI_ID_RXFS_S; + supports_dma = (id & SPI_ID_CFG_M) >> SPI_ID_CFG_S; + revision = id & SPI_ID_REV_M; + + lantiq_ssc_hw_init(spi); + + dev_info(dev, + "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n", + revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma); + + err = devm_spi_register_master(dev, master); + if (err) { + dev_err(dev, "failed to register spi_master\n"); + goto err_wq_destroy; + } + + return 0; + +err_wq_destroy: + destroy_workqueue(spi->wq); +err_clk_put: + clk_put(spi->fpi_clk); +err_clk_disable: + clk_disable_unprepare(spi->spi_clk); +err_master_put: + spi_master_put(master); + + return err; +} + +static int lantiq_ssc_remove(struct platform_device *pdev) +{ + struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev); + + lantiq_ssc_writel(spi, 0, SPI_IRNEN); + lantiq_ssc_writel(spi, 0, SPI_CLC); + rx_fifo_flush(spi); + tx_fifo_flush(spi); + hw_enter_config_mode(spi); + + destroy_workqueue(spi->wq); + clk_disable_unprepare(spi->spi_clk); + clk_put(spi->fpi_clk); + + return 0; +} + +static struct platform_driver lantiq_ssc_driver = { + .probe = lantiq_ssc_probe, + .remove = lantiq_ssc_remove, + .driver = { + .name = "spi-lantiq-ssc", + .owner = THIS_MODULE, + .of_match_table = lantiq_ssc_match, + }, +}; +module_platform_driver(lantiq_ssc_driver); + +MODULE_DESCRIPTION("Lantiq SSC SPI controller driver"); +MODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@gmail.com>"); +MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:spi-lantiq-ssc"); diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index c36002110c30..e8b59ce4dc3a 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -437,8 +437,9 @@ static int mpc52xx_spi_probe(struct platform_device *op) ms->gpio_cs_count = of_gpio_count(op->dev.of_node); if (ms->gpio_cs_count > 0) { master->num_chipselect = ms->gpio_cs_count; - ms->gpio_cs = kmalloc(ms->gpio_cs_count * sizeof(unsigned int), - GFP_KERNEL); + ms->gpio_cs = kmalloc_array(ms->gpio_cs_count, + sizeof(*ms->gpio_cs), + GFP_KERNEL); if (!ms->gpio_cs) { rc = -ENOMEM; goto err_alloc_gpio; @@ -448,8 +449,7 @@ static int mpc52xx_spi_probe(struct platform_device *op) gpio_cs = of_get_gpio(op->dev.of_node, i); if (gpio_cs < 0) { dev_err(&op->dev, - "could not parse the gpio field " - "in oftree\n"); + "could not parse the gpio field in oftree\n"); rc = -ENODEV; goto err_gpio; } @@ -457,8 +457,8 @@ static int mpc52xx_spi_probe(struct platform_device *op) rc = gpio_request(gpio_cs, dev_name(&op->dev)); if (rc) { dev_err(&op->dev, - "can't request spi cs gpio #%d " - "on gpio line %d\n", i, gpio_cs); + "can't request spi cs gpio #%d on gpio line %d\n", + i, gpio_cs); goto err_gpio; } diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 899d7a8f0889..278867a31950 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -73,7 +73,7 @@ #define MTK_SPI_IDLE 0 #define MTK_SPI_PAUSED 1 -#define MTK_SPI_MAX_FIFO_SIZE 32 +#define MTK_SPI_MAX_FIFO_SIZE 32U #define MTK_SPI_PACKET_SIZE 1024 struct mtk_spi_compatible { @@ -333,7 +333,7 @@ static int mtk_spi_fifo_transfer(struct spi_master *master, struct mtk_spi *mdata = spi_master_get_devdata(master); mdata->cur_transfer = xfer; - mdata->xfer_len = xfer->len; + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, xfer->len); mtk_spi_prepare_transfer(master, xfer); mtk_spi_setup_packet(master); @@ -410,7 +410,10 @@ static bool mtk_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { - return xfer->len > MTK_SPI_MAX_FIFO_SIZE; + /* Buffers for DMA transactions must be 4-byte aligned */ + return (xfer->len > MTK_SPI_MAX_FIFO_SIZE && + (unsigned long)xfer->tx_buf % 4 == 0 && + (unsigned long)xfer->rx_buf % 4 == 0); } static int mtk_spi_setup(struct spi_device *spi) @@ -451,7 +454,33 @@ static irqreturn_t mtk_spi_interrupt(int irq, void *dev_id) ®_val, remainder); } } - spi_finalize_current_transfer(master); + + trans->len -= mdata->xfer_len; + if (!trans->len) { + spi_finalize_current_transfer(master); + return IRQ_HANDLED; + } + + if (trans->tx_buf) + trans->tx_buf += mdata->xfer_len; + if (trans->rx_buf) + trans->rx_buf += mdata->xfer_len; + + mdata->xfer_len = min(MTK_SPI_MAX_FIFO_SIZE, trans->len); + mtk_spi_setup_packet(master); + + cnt = trans->len / 4; + iowrite32_rep(mdata->base + SPI_TX_DATA_REG, trans->tx_buf, cnt); + + remainder = trans->len % 4; + if (remainder > 0) { + reg_val = 0; + memcpy(®_val, trans->tx_buf + (cnt * 4), remainder); + writel(reg_val, mdata->base + SPI_TX_DATA_REG); + } + + mtk_spi_enable_transfer(master); + return IRQ_HANDLED; } diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index dd3d0a218d8b..967d94844b30 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -411,7 +411,7 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) if (num_gpios > 0) { int i; - hw->gpios = kzalloc(sizeof(int) * num_gpios, GFP_KERNEL); + hw->gpios = kcalloc(num_gpios, sizeof(*hw->gpios), GFP_KERNEL); if (!hw->gpios) { ret = -ENOMEM; goto free_master; @@ -428,8 +428,9 @@ static int spi_ppc4xx_of_probe(struct platform_device *op) /* Real CS - set the initial state. */ ret = gpio_request(gpio, np->name); if (ret < 0) { - dev_err(dev, "can't request gpio " - "#%d: %d\n", i, ret); + dev_err(dev, + "can't request gpio #%d: %d\n", + i, ret); goto free_gpios; } diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c index 58d2d48e16a5..869f188b02eb 100644 --- a/drivers/spi/spi-pxa2xx-pci.c +++ b/drivers/spi/spi-pxa2xx-pci.c @@ -41,6 +41,13 @@ struct pxa_spi_info { static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; +static struct dw_dma_slave mrfld3_tx_param = { .dst_id = 15 }; +static struct dw_dma_slave mrfld3_rx_param = { .src_id = 14 }; +static struct dw_dma_slave mrfld5_tx_param = { .dst_id = 13 }; +static struct dw_dma_slave mrfld5_rx_param = { .src_id = 12 }; +static struct dw_dma_slave mrfld6_tx_param = { .dst_id = 11 }; +static struct dw_dma_slave mrfld6_rx_param = { .src_id = 10 }; + static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 }; static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 }; static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 }; @@ -93,22 +100,39 @@ static int lpss_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) static int mrfld_spi_setup(struct pci_dev *dev, struct pxa_spi_info *c) { + struct pci_dev *dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); + struct dw_dma_slave *tx, *rx; + switch (PCI_FUNC(dev->devfn)) { case 0: c->port_id = 3; c->num_chipselect = 1; + c->tx_param = &mrfld3_tx_param; + c->rx_param = &mrfld3_rx_param; break; case 1: c->port_id = 5; c->num_chipselect = 4; + c->tx_param = &mrfld5_tx_param; + c->rx_param = &mrfld5_rx_param; break; case 2: c->port_id = 6; c->num_chipselect = 1; + c->tx_param = &mrfld6_tx_param; + c->rx_param = &mrfld6_rx_param; break; default: return -ENODEV; } + + tx = c->tx_param; + tx->dma_dev = &dma_dev->dev; + + rx = c->rx_param; + rx->dma_dev = &dma_dev->dev; + + c->dma_filter = lpss_dma_filter; return 0; } @@ -203,10 +227,16 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev, ssp = &spi_pdata.ssp; ssp->phys_base = pci_resource_start(dev, 0); ssp->mmio_base = pcim_iomap_table(dev)[0]; - ssp->irq = dev->irq; ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn; ssp->type = c->type; + pci_set_master(dev); + + ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + ssp->irq = pci_irq_vector(dev, 0); + snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL, 0, c->max_clk_rate); diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index dd7b5b47291d..47b65d7c4072 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -732,6 +732,20 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) return IRQ_HANDLED; } +static void handle_bad_msg(struct driver_data *drv_data) +{ + pxa2xx_spi_write(drv_data, SSCR0, + pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE); + pxa2xx_spi_write(drv_data, SSCR1, + pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1); + if (!pxa25x_ssp_comp(drv_data)) + pxa2xx_spi_write(drv_data, SSTO, 0); + write_SSSR_CS(drv_data, drv_data->clear_sr); + + dev_err(&drv_data->pdev->dev, + "bad message state in interrupt handler\n"); +} + static irqreturn_t ssp_int(int irq, void *dev_id) { struct driver_data *drv_data = dev_id; @@ -771,21 +785,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id) if (!(status & mask)) return IRQ_NONE; - if (!drv_data->master->cur_msg) { - - pxa2xx_spi_write(drv_data, SSCR0, - pxa2xx_spi_read(drv_data, SSCR0) - & ~SSCR0_SSE); - pxa2xx_spi_write(drv_data, SSCR1, - pxa2xx_spi_read(drv_data, SSCR1) - & ~drv_data->int_cr1); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); - write_SSSR_CS(drv_data, drv_data->clear_sr); - - dev_err(&drv_data->pdev->dev, - "bad message state in interrupt handler\n"); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg & ~drv_data->int_cr1); + pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); + if (!drv_data->master->cur_msg) { + handle_bad_msg(drv_data); /* Never fail */ return IRQ_HANDLED; } @@ -1458,6 +1462,10 @@ static const struct pci_device_id pxa2xx_spi_pci_compound_match[] = { { PCI_VDEVICE(INTEL, 0x1ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x1ac4), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x1ac6), LPSS_BXT_SSP }, + /* GLK */ + { PCI_VDEVICE(INTEL, 0x31c2), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x31c4), LPSS_BXT_SSP }, + { PCI_VDEVICE(INTEL, 0x31c6), LPSS_BXT_SSP }, /* APL */ { PCI_VDEVICE(INTEL, 0x5ac2), LPSS_BXT_SSP }, { PCI_VDEVICE(INTEL, 0x5ac4), LPSS_BXT_SSP }, @@ -1690,6 +1698,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev) pxa2xx_spi_write(drv_data, SSCR1, tmp); tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8); pxa2xx_spi_write(drv_data, SSCR0, tmp); + break; default: tmp = SSCR1_RxTresh(RX_THRESH_DFLT) | SSCR1_TxTresh(TX_THRESH_DFLT); diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c index 0f89c2169c24..acf31f36b898 100644 --- a/drivers/spi/spi-rockchip.c +++ b/drivers/spi/spi-rockchip.c @@ -17,6 +17,7 @@ #include <linux/dmaengine.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> #include <linux/pm_runtime.h> @@ -843,6 +844,8 @@ static int rockchip_spi_suspend(struct device *dev) clk_disable_unprepare(rs->apb_pclk); } + pinctrl_pm_select_sleep_state(dev); + return ret; } @@ -852,6 +855,8 @@ static int rockchip_spi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct rockchip_spi *rs = spi_master_get_devdata(master); + pinctrl_pm_select_default_state(dev); + if (!pm_runtime_suspended(dev)) { ret = clk_prepare_enable(rs->apb_pclk); if (ret < 0) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 9daf50031737..2a10b3f94ff7 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -808,7 +808,7 @@ static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) for (i = 0; i < len; i++) rspi_write_data(rspi, *tx++); } else { - ret = rspi_pio_transfer(rspi, tx, NULL, n); + ret = rspi_pio_transfer(rspi, tx, NULL, len); if (ret < 0) return ret; } @@ -845,10 +845,9 @@ static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) for (i = 0; i < len; i++) *rx++ = rspi_read_data(rspi); } else { - ret = rspi_pio_transfer(rspi, NULL, rx, n); + ret = rspi_pio_transfer(rspi, NULL, rx, len); if (ret < 0) return ret; - *rx++ = ret; } n -= len; } @@ -1227,10 +1226,8 @@ static int rspi_probe(struct platform_device *pdev) const struct spi_ops *ops; master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); - if (master == NULL) { - dev_err(&pdev->dev, "spi_alloc_master error.\n"); + if (master == NULL) return -ENOMEM; - } of_id = of_match_device(rspi_of_match, &pdev->dev); if (of_id) { diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 28dfdce4beae..b392cca8fa4f 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -341,43 +341,16 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - struct device *dev = &sdd->pdev->dev; if (is_polling(sdd)) return 0; - /* Acquire DMA channels */ - sdd->rx_dma.ch = dma_request_slave_channel(dev, "rx"); - if (!sdd->rx_dma.ch) { - dev_err(dev, "Failed to get RX DMA channel\n"); - return -EBUSY; - } spi->dma_rx = sdd->rx_dma.ch; - - sdd->tx_dma.ch = dma_request_slave_channel(dev, "tx"); - if (!sdd->tx_dma.ch) { - dev_err(dev, "Failed to get TX DMA channel\n"); - dma_release_channel(sdd->rx_dma.ch); - return -EBUSY; - } spi->dma_tx = sdd->tx_dma.ch; return 0; } -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - dma_release_channel(sdd->rx_dma.ch); - dma_release_channel(sdd->tx_dma.ch); - } - - return 0; -} - static bool s3c64xx_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -996,7 +969,7 @@ static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) sci->num_cs = temp; } - sci->no_cs = of_property_read_bool(dev->of_node, "broken-cs"); + sci->no_cs = of_property_read_bool(dev->of_node, "no-cs-readback"); return sci; } @@ -1094,7 +1067,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | @@ -1161,6 +1133,24 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) } } + if (!is_polling(sdd)) { + /* Acquire DMA channels */ + sdd->rx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "rx"); + if (IS_ERR(sdd->rx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get RX DMA channel\n"); + ret = PTR_ERR(sdd->rx_dma.ch); + goto err_disable_io_clk; + } + sdd->tx_dma.ch = dma_request_slave_channel_reason(&pdev->dev, + "tx"); + if (IS_ERR(sdd->tx_dma.ch)) { + dev_err(&pdev->dev, "Failed to get TX DMA channel\n"); + ret = PTR_ERR(sdd->tx_dma.ch); + goto err_release_rx_dma; + } + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); @@ -1206,6 +1196,12 @@ err_pm_put: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + if (!is_polling(sdd)) + dma_release_channel(sdd->tx_dma.ch); +err_release_rx_dma: + if (!is_polling(sdd)) + dma_release_channel(sdd->rx_dma.ch); +err_disable_io_clk: clk_disable_unprepare(sdd->ioclk); err_disable_src_clk: clk_disable_unprepare(sdd->src_clk); @@ -1226,6 +1222,11 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) writel(0, sdd->regs + S3C64XX_SPI_INT_EN); + if (!is_polling(sdd)) { + dma_release_channel(sdd->rx_dma.ch); + dma_release_channel(sdd->tx_dma.ch); + } + clk_disable_unprepare(sdd->ioclk); clk_disable_unprepare(sdd->src_clk); diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 0012ad02e569..2ce15ca97782 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -973,14 +973,16 @@ static const struct sh_msiof_chipdata r8a779x_data = { }; static const struct of_device_id sh_msiof_match[] = { - { .compatible = "renesas,sh-msiof", .data = &sh_data }, { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7792", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7793", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7794", .data = &r8a779x_data }, + { .compatible = "renesas,rcar-gen2-msiof", .data = &r8a779x_data }, { .compatible = "renesas,msiof-r8a7796", .data = &r8a779x_data }, + { .compatible = "renesas,rcar-gen3-msiof", .data = &r8a779x_data }, + { .compatible = "renesas,sh-msiof", .data = &sh_data }, /* Deprecated */ {}, }; MODULE_DEVICE_TABLE(of, sh_msiof_match); @@ -1162,10 +1164,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) int ret; master = spi_alloc_master(&pdev->dev, sizeof(struct sh_msiof_spi_priv)); - if (master == NULL) { - dev_err(&pdev->dev, "failed to allocate spi master\n"); + if (master == NULL) return -ENOMEM; - } p = spi_master_get_devdata(master); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index ec6fb09e2e17..ad76a44fee6f 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -652,7 +652,8 @@ static int ti_qspi_probe(struct platform_device *pdev) r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&pdev->dev, "missing platform data\n"); - return -ENODEV; + ret = -ENODEV; + goto free_master; } } @@ -669,7 +670,8 @@ static int ti_qspi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); - return irq; + ret = irq; + goto free_master; } mutex_init(&qspi->list_lock); @@ -685,15 +687,17 @@ static int ti_qspi_probe(struct platform_device *pdev) qspi->ctrl_base = syscon_regmap_lookup_by_phandle(np, "syscon-chipselects"); - if (IS_ERR(qspi->ctrl_base)) - return PTR_ERR(qspi->ctrl_base); + if (IS_ERR(qspi->ctrl_base)) { + ret = PTR_ERR(qspi->ctrl_base); + goto free_master; + } ret = of_property_read_u32_index(np, "syscon-chipselects", 1, &qspi->ctrl_reg); if (ret) { dev_err(&pdev->dev, "couldn't get ctrl_mod reg index\n"); - return ret; + goto free_master; } } @@ -714,9 +718,10 @@ static int ti_qspi_probe(struct platform_device *pdev) dma_cap_set(DMA_MEMCPY, mask); qspi->rx_chan = dma_request_chan_by_mask(&mask); - if (!qspi->rx_chan) { + if (IS_ERR(qspi->rx_chan)) { dev_err(qspi->dev, "No Rx DMA available, trying mmap mode\n"); + qspi->rx_chan = NULL; ret = 0; goto no_dma; } @@ -742,6 +747,7 @@ no_dma: if (!ret) return 0; + pm_runtime_disable(&pdev->dev); free_master: spi_master_put(master); return ret; diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index fcb991034c3d..97d137591b18 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -591,7 +591,6 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) if (!data->pkt_rx_buff) { /* flush queue and set status of all transfers to -ENOMEM */ - dev_err(&data->master->dev, "%s :kzalloc failed\n", __func__); list_for_each_entry_safe(pmsg, tmp, data->queue.next, queue) { pmsg->status = -ENOMEM; @@ -622,8 +621,9 @@ static void pch_spi_set_tx(struct pch_spi_data *data, int *bpw) if (n_writes > PCH_MAX_FIFO_DEPTH) n_writes = PCH_MAX_FIFO_DEPTH; - dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " - "0x2 to SSNXCR\n", __func__); + dev_dbg(&data->master->dev, + "\n%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", + __func__); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); for (j = 0; j < n_writes; j++) @@ -915,7 +915,6 @@ static void pch_spi_release_dma(struct pch_spi_data *data) dma_release_channel(dma->chan_rx); dma->chan_rx = NULL; } - return; } static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) @@ -1008,7 +1007,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) spin_unlock_irqrestore(&data->lock, flags); /* RX */ - dma->sg_rx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + dma->sg_rx_p = kcalloc(num, sizeof(*dma->sg_rx_p), GFP_ATOMIC); sg_init_table(dma->sg_rx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_rx_p; @@ -1068,7 +1067,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) head = 0; } - dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); + dma->sg_tx_p = kcalloc(num, sizeof(*dma->sg_tx_p), GFP_ATOMIC); sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */ sg = dma->sg_tx_p; @@ -1181,14 +1180,16 @@ static void pch_spi_process_messages(struct work_struct *pwork) data->cur_trans = list_entry(data->current_msg->transfers.next, struct spi_transfer, transfer_list); - dev_dbg(&data->master->dev, "%s " - ":Getting 1st transfer message\n", __func__); + dev_dbg(&data->master->dev, + "%s :Getting 1st transfer message\n", + __func__); } else { data->cur_trans = list_entry(data->cur_trans->transfer_list.next, struct spi_transfer, transfer_list); - dev_dbg(&data->master->dev, "%s " - ":Getting next transfer message\n", __func__); + dev_dbg(&data->master->dev, + "%s :Getting next transfer message\n", + __func__); } spin_unlock(&data->lock); @@ -1233,9 +1234,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) /* check for delay */ if (data->cur_trans->delay_usecs) { - dev_dbg(&data->master->dev, "%s:" - "delay in usec=%d\n", __func__, - data->cur_trans->delay_usecs); + dev_dbg(&data->master->dev, "%s:delay in usec=%d\n", + __func__, data->cur_trans->delay_usecs); udelay(data->cur_trans->delay_usecs); } @@ -1292,7 +1292,6 @@ static void pch_free_dma_buf(struct pch_spi_board_data *board_dat, if (dma->rx_buf_dma) dma_free_coherent(&board_dat->pdev->dev, PCH_BUF_SIZE, dma->rx_buf_virt, dma->rx_buf_dma); - return; } static void pch_alloc_dma_buf(struct pch_spi_board_data *board_dat, @@ -1541,11 +1540,11 @@ static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) int i; struct pch_pd_dev_save *pd_dev_save; - pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL); + pd_dev_save = kzalloc(sizeof(*pd_dev_save), GFP_KERNEL); if (!pd_dev_save) return -ENOMEM; - board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); + board_dat = kzalloc(sizeof(*board_dat), GFP_KERNEL); if (!board_dat) { retval = -ENOMEM; goto err_no_mem; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 656dd3e3220c..44222ef9471e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -621,8 +621,10 @@ void spi_unregister_device(struct spi_device *spi) if (!spi) return; - if (spi->dev.of_node) + if (spi->dev.of_node) { of_node_clear_flag(spi->dev.of_node, OF_POPULATED); + of_node_put(spi->dev.of_node); + } if (ACPI_COMPANION(&spi->dev)) acpi_device_clear_enumerated(ACPI_COMPANION(&spi->dev)); device_unregister(&spi->dev); @@ -672,7 +674,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n) if (!n) return -EINVAL; - bi = kzalloc(n * sizeof(*bi), GFP_KERNEL); + bi = kcalloc(n, sizeof(*bi), GFP_KERNEL); if (!bi) return -ENOMEM; @@ -805,12 +807,12 @@ static int __spi_map_msg(struct spi_master *master, struct spi_message *msg) if (master->dma_tx) tx_dev = master->dma_tx->device->dev; else - tx_dev = &master->dev; + tx_dev = master->dev.parent; if (master->dma_rx) rx_dev = master->dma_rx->device->dev; else - rx_dev = &master->dev; + rx_dev = master->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) @@ -852,12 +854,12 @@ static int __spi_unmap_msg(struct spi_master *master, struct spi_message *msg) if (master->dma_tx) tx_dev = master->dma_tx->device->dev; else - tx_dev = &master->dev; + tx_dev = master->dev.parent; if (master->dma_rx) rx_dev = master->dma_rx->device->dev; else - rx_dev = &master->dev; + rx_dev = master->dev.parent; list_for_each_entry(xfer, &msg->transfers, transfer_list) { if (!master->can_dma(master, msg->spi, xfer)) @@ -1502,37 +1504,18 @@ err_init_queue: /*-------------------------------------------------------------------------*/ #if defined(CONFIG_OF) -static struct spi_device * -of_register_spi_device(struct spi_master *master, struct device_node *nc) +static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi, + struct device_node *nc) { - struct spi_device *spi; - int rc; u32 value; - - /* Alloc an spi_device */ - spi = spi_alloc_device(master); - if (!spi) { - dev_err(&master->dev, "spi_device alloc error for %s\n", - nc->full_name); - rc = -ENOMEM; - goto err_out; - } - - /* Select device driver */ - rc = of_modalias_node(nc, spi->modalias, - sizeof(spi->modalias)); - if (rc < 0) { - dev_err(&master->dev, "cannot find modalias for %s\n", - nc->full_name); - goto err_out; - } + int rc; /* Device address */ rc = of_property_read_u32(nc, "reg", &value); if (rc) { dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->chip_select = value; @@ -1590,10 +1573,41 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) if (rc) { dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n", nc->full_name, rc); - goto err_out; + return rc; } spi->max_speed_hz = value; + return 0; +} + +static struct spi_device * +of_register_spi_device(struct spi_master *master, struct device_node *nc) +{ + struct spi_device *spi; + int rc; + + /* Alloc an spi_device */ + spi = spi_alloc_device(master); + if (!spi) { + dev_err(&master->dev, "spi_device alloc error for %s\n", + nc->full_name); + rc = -ENOMEM; + goto err_out; + } + + /* Select device driver */ + rc = of_modalias_node(nc, spi->modalias, + sizeof(spi->modalias)); + if (rc < 0) { + dev_err(&master->dev, "cannot find modalias for %s\n", + nc->full_name); + goto err_out; + } + + rc = of_spi_parse_dt(master, spi, nc); + if (rc) + goto err_out; + /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; @@ -1603,11 +1617,13 @@ of_register_spi_device(struct spi_master *master, struct device_node *nc) if (rc) { dev_err(&master->dev, "spi_device register error %s\n", nc->full_name); - goto err_out; + goto err_of_node_put; } return spi; +err_of_node_put: + of_node_put(nc); err_out: spi_dev_put(spi); return ERR_PTR(rc); @@ -1722,13 +1738,15 @@ static acpi_status acpi_register_spi_device(struct spi_master *master, return AE_OK; } + acpi_set_modalias(adev, acpi_device_hid(adev), spi->modalias, + sizeof(spi->modalias)); + if (spi->irq < 0) spi->irq = acpi_dev_gpio_irq_get(adev, 0); acpi_device_set_enumerated(adev); adev->power.flags.ignore_parent = true; - strlcpy(spi->modalias, acpi_device_hid(adev), sizeof(spi->modalias)); if (spi_add_device(spi)) { adev->power.flags.ignore_parent = false; dev_err(&master->dev, "failed to add SPI device %s from ACPI\n", diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index b653451843c8..937c2d5d7ec3 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1300,7 +1300,7 @@ static int ion_debug_heap_show(struct seq_file *s, void *unused) seq_printf(s, "%16s %16u %16zu %d %d\n", buffer->task_comm, buffer->pid, buffer->size, buffer->kmap_cnt, - atomic_read(&buffer->ref.refcount)); + kref_read(&buffer->ref)); total_orphaned_size += buffer->size; } } diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c index c7d7682b1412..1e1df89b5018 100644 --- a/drivers/staging/comedi/comedi_buf.c +++ b/drivers/staging/comedi/comedi_buf.c @@ -188,7 +188,7 @@ bool comedi_buf_is_mmapped(struct comedi_subdevice *s) { struct comedi_buf_map *bm = s->async->buf_map; - return bm && (atomic_read(&bm->refcount.refcount) > 1); + return bm && (kref_read(&bm->refcount) > 1); } int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, diff --git a/drivers/staging/greybus/timesync_platform.c b/drivers/staging/greybus/timesync_platform.c index 113f3d6c4b3a..27f75b17679b 100644 --- a/drivers/staging/greybus/timesync_platform.c +++ b/drivers/staging/greybus/timesync_platform.c @@ -45,12 +45,18 @@ u32 gb_timesync_platform_get_clock_rate(void) int gb_timesync_platform_lock_bus(struct gb_timesync_svc *pdata) { + if (!arche_platform_change_state_cb) + return 0; + return arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_TIME_SYNC, pdata); } void gb_timesync_platform_unlock_bus(void) { + if (!arche_platform_change_state_cb) + return; + arche_platform_change_state_cb(ARCHE_PLATFORM_STATE_ACTIVE, NULL); } diff --git a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c index 39a72e3f0c18..7035356e56b3 100644 --- a/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c +++ b/drivers/staging/lustre/lnet/libcfs/linux/linux-debug.c @@ -107,7 +107,7 @@ void __noreturn lbug_with_loc(struct libcfs_debug_msg_data *msgdata) libcfs_debug_dumplog(); if (libcfs_panic_on_lbug) panic("LBUG"); - set_task_state(current, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); while (1) schedule(); } diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c index ee01f20d8b11..9afa6bec3e6f 100644 --- a/drivers/staging/lustre/lustre/llite/llite_mmap.c +++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c @@ -390,15 +390,13 @@ static int ll_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) result = VM_FAULT_LOCKED; break; case -ENODATA: + case -EAGAIN: case -EFAULT: result = VM_FAULT_NOPAGE; break; case -ENOMEM: result = VM_FAULT_OOM; break; - case -EAGAIN: - result = VM_FAULT_RETRY; - break; default: result = VM_FAULT_SIGBUS; break; diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 8130dfe89745..4971aa54756a 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -770,6 +770,7 @@ static int cvm_oct_probe(struct platform_device *pdev) /* Initialize the device private structure. */ struct octeon_ethernet *priv = netdev_priv(dev); + SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &cvm_oct_pow_netdev_ops; priv->imode = CVMX_HELPER_INTERFACE_MODE_DISABLED; priv->port = CVMX_PIP_NUM_INPUT_PORTS; @@ -816,6 +817,7 @@ static int cvm_oct_probe(struct platform_device *pdev) } /* Initialize the device private structure. */ + SET_NETDEV_DEV(dev, &pdev->dev); priv = netdev_priv(dev); priv->netdev = dev; priv->of_node = cvm_oct_node_for_port(pip, interface, diff --git a/drivers/target/Kconfig b/drivers/target/Kconfig index 257361280510..e2bc99980f75 100644 --- a/drivers/target/Kconfig +++ b/drivers/target/Kconfig @@ -4,6 +4,7 @@ menuconfig TARGET_CORE depends on SCSI && BLOCK select CONFIGFS_FS select CRC_T10DIF + select BLK_SCSI_REQUEST # only for scsi_command_size_tbl.. default n help Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 1ebd13ef7bd3..26929c44d703 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -352,7 +352,15 @@ int core_enable_device_list_for_node( kfree(new); return -EINVAL; } - BUG_ON(orig->se_lun_acl != NULL); + if (orig->se_lun_acl != NULL) { + pr_warn_ratelimited("Detected existing explicit" + " se_lun_acl->se_lun_group reference for %s" + " mapped_lun: %llu, failing\n", + nacl->initiatorname, mapped_lun); + mutex_unlock(&nacl->lun_entry_mutex); + kfree(new); + return -EINVAL; + } rcu_assign_pointer(new->se_lun, lun); rcu_assign_pointer(new->se_lun_acl, lun_acl); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index d761025144f9..e18051185846 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -788,7 +788,7 @@ static struct t10_pr_registration *__core_scsi3_alloc_registration( * __core_scsi3_add_registration() */ dest_lun = rcu_dereference_check(deve_tmp->se_lun, - atomic_read(&deve_tmp->pr_kref.refcount) != 0); + kref_read(&deve_tmp->pr_kref) != 0); pr_reg_atp = __core_scsi3_do_alloc_registration(dev, nacl_tmp, dest_lun, deve_tmp, @@ -1463,7 +1463,7 @@ static int core_scsi3_lunacl_depend_item(struct se_dev_entry *se_deve) * For nacl->dynamic_node_acl=1 */ lun_acl = rcu_dereference_check(se_deve->se_lun_acl, - atomic_read(&se_deve->pr_kref.refcount) != 0); + kref_read(&se_deve->pr_kref) != 0); if (!lun_acl) return 0; @@ -1478,7 +1478,7 @@ static void core_scsi3_lunacl_undepend_item(struct se_dev_entry *se_deve) * For nacl->dynamic_node_acl=1 */ lun_acl = rcu_dereference_check(se_deve->se_lun_acl, - atomic_read(&se_deve->pr_kref.refcount) != 0); + kref_read(&se_deve->pr_kref) != 0); if (!lun_acl) { kref_put(&se_deve->pr_kref, target_pr_kref_release); return; @@ -1759,7 +1759,7 @@ core_scsi3_decode_spec_i_port( * 2nd loop which will never fail. */ dest_lun = rcu_dereference_check(dest_se_deve->se_lun, - atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + kref_read(&dest_se_deve->pr_kref) != 0); dest_pr_reg = __core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_lun, dest_se_deve, @@ -3466,7 +3466,7 @@ after_iport_check: iport_ptr); if (!dest_pr_reg) { struct se_lun *dest_lun = rcu_dereference_check(dest_se_deve->se_lun, - atomic_read(&dest_se_deve->pr_kref.refcount) != 0); + kref_read(&dest_se_deve->pr_kref) != 0); spin_unlock(&dev->dev_reservation_lock); if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 04d7aa7390d0..a8f8e53f2f57 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -1005,7 +1005,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) scsi_command_size(cmd->t_task_cdb)); req = blk_get_request(pdv->pdv_sd->request_queue, - (cmd->data_direction == DMA_TO_DEVICE), + cmd->data_direction == DMA_TO_DEVICE ? + REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, GFP_KERNEL); if (IS_ERR(req)) { pr_err("PSCSI: blk_get_request() failed\n"); @@ -1013,7 +1014,7 @@ pscsi_execute_cmd(struct se_cmd *cmd) goto fail; } - blk_rq_set_block_pc(req); + scsi_req_init(req); if (sgl) { ret = pscsi_map_sg(cmd, sgl, sgl_nents, req); @@ -1023,10 +1024,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) req->end_io = pscsi_req_done; req->end_io_data = cmd; - req->cmd_len = scsi_command_size(pt->pscsi_cdb); - req->cmd = &pt->pscsi_cdb[0]; - req->sense = &pt->pscsi_sense[0]; - req->sense_len = 0; + scsi_req(req)->cmd_len = scsi_command_size(pt->pscsi_cdb); + scsi_req(req)->cmd = &pt->pscsi_cdb[0]; if (pdv->pdv_sd->type == TYPE_DISK) req->timeout = PS_TIMEOUT_DISK; else @@ -1075,7 +1074,7 @@ static void pscsi_req_done(struct request *req, int uptodate) struct pscsi_plugin_task *pt = cmd->priv; pt->pscsi_result = req->errors; - pt->pscsi_resid = req->resid_len; + pt->pscsi_resid = scsi_req(req)->resid_len; cmd->scsi_status = status_byte(pt->pscsi_result) << 1; if (cmd->scsi_status) { @@ -1096,6 +1095,7 @@ static void pscsi_req_done(struct request *req, int uptodate) break; } + memcpy(pt->pscsi_sense, scsi_req(req)->sense, TRANSPORT_SENSE_BUFFER); __blk_put_request(req->q, req); kfree(pt); } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 4879e70e2eef..df7b6e95c019 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -451,6 +451,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, int *post_ret) { struct se_device *dev = cmd->se_dev; + sense_reason_t ret = TCM_NO_SENSE; /* * Only set SCF_COMPARE_AND_WRITE_POST to force a response fall-through @@ -458,9 +459,12 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, * sent to the backend driver. */ spin_lock_irq(&cmd->t_state_lock); - if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) { + if (cmd->transport_state & CMD_T_SENT) { cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; *post_ret = 1; + + if (cmd->scsi_status == SAM_STAT_CHECK_CONDITION) + ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } spin_unlock_irq(&cmd->t_state_lock); @@ -470,7 +474,7 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success, */ up(&dev->caw_sem); - return TCM_NO_SENSE; + return ret; } static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success, diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7dfefd66df93..437591bc7c08 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -457,8 +457,20 @@ static void target_complete_nacl(struct kref *kref) { struct se_node_acl *nacl = container_of(kref, struct se_node_acl, acl_kref); + struct se_portal_group *se_tpg = nacl->se_tpg; - complete(&nacl->acl_free_comp); + if (!nacl->dynamic_stop) { + complete(&nacl->acl_free_comp); + return; + } + + mutex_lock(&se_tpg->acl_node_mutex); + list_del(&nacl->acl_list); + mutex_unlock(&se_tpg->acl_node_mutex); + + core_tpg_wait_for_nacl_pr_ref(nacl); + core_free_device_list_for_node(nacl, se_tpg); + kfree(nacl); } void target_put_nacl(struct se_node_acl *nacl) @@ -499,12 +511,39 @@ EXPORT_SYMBOL(transport_deregister_session_configfs); void transport_free_session(struct se_session *se_sess) { struct se_node_acl *se_nacl = se_sess->se_node_acl; + /* * Drop the se_node_acl->nacl_kref obtained from within * core_tpg_get_initiator_node_acl(). */ if (se_nacl) { + struct se_portal_group *se_tpg = se_nacl->se_tpg; + const struct target_core_fabric_ops *se_tfo = se_tpg->se_tpg_tfo; + unsigned long flags; + se_sess->se_node_acl = NULL; + + /* + * Also determine if we need to drop the extra ->cmd_kref if + * it had been previously dynamically generated, and + * the endpoint is not caching dynamic ACLs. + */ + mutex_lock(&se_tpg->acl_node_mutex); + if (se_nacl->dynamic_node_acl && + !se_tfo->tpg_check_demo_mode_cache(se_tpg)) { + spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); + if (list_empty(&se_nacl->acl_sess_list)) + se_nacl->dynamic_stop = true; + spin_unlock_irqrestore(&se_nacl->nacl_sess_lock, flags); + + if (se_nacl->dynamic_stop) + list_del(&se_nacl->acl_list); + } + mutex_unlock(&se_tpg->acl_node_mutex); + + if (se_nacl->dynamic_stop) + target_put_nacl(se_nacl); + target_put_nacl(se_nacl); } if (se_sess->sess_cmd_map) { @@ -518,16 +557,12 @@ EXPORT_SYMBOL(transport_free_session); void transport_deregister_session(struct se_session *se_sess) { struct se_portal_group *se_tpg = se_sess->se_tpg; - const struct target_core_fabric_ops *se_tfo; - struct se_node_acl *se_nacl; unsigned long flags; - bool drop_nacl = false; if (!se_tpg) { transport_free_session(se_sess); return; } - se_tfo = se_tpg->se_tpg_tfo; spin_lock_irqsave(&se_tpg->session_lock, flags); list_del(&se_sess->sess_list); @@ -535,33 +570,15 @@ void transport_deregister_session(struct se_session *se_sess) se_sess->fabric_sess_ptr = NULL; spin_unlock_irqrestore(&se_tpg->session_lock, flags); - /* - * Determine if we need to do extra work for this initiator node's - * struct se_node_acl if it had been previously dynamically generated. - */ - se_nacl = se_sess->se_node_acl; - - mutex_lock(&se_tpg->acl_node_mutex); - if (se_nacl && se_nacl->dynamic_node_acl) { - if (!se_tfo->tpg_check_demo_mode_cache(se_tpg)) { - list_del(&se_nacl->acl_list); - drop_nacl = true; - } - } - mutex_unlock(&se_tpg->acl_node_mutex); - - if (drop_nacl) { - core_tpg_wait_for_nacl_pr_ref(se_nacl); - core_free_device_list_for_node(se_nacl, se_tpg); - se_sess->se_node_acl = NULL; - kfree(se_nacl); - } pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->get_fabric_name()); /* * If last kref is dropping now for an explicit NodeACL, awake sleeping * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group * removal context from within transport_free_session() code. + * + * For dynamic ACL, target_put_nacl() uses target_complete_nacl() + * to release all remaining generate_node_acl=1 created ACL resources. */ transport_free_session(se_sess); @@ -1693,6 +1710,10 @@ void transport_generic_request_failure(struct se_cmd *cmd, case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: case TCM_COPY_TARGET_DEVICE_NOT_REACHABLE: + case TCM_TOO_MANY_TARGET_DESCS: + case TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE: + case TCM_TOO_MANY_SEGMENT_DESCS: + case TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE: break; case TCM_OUT_OF_RESOURCES: sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; @@ -2808,6 +2829,26 @@ static const struct sense_info sense_info_table[] = { .key = ILLEGAL_REQUEST, .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */ }, + [TCM_TOO_MANY_TARGET_DESCS] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, + .ascq = 0x06, /* TOO MANY TARGET DESCRIPTORS */ + }, + [TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, + .ascq = 0x07, /* UNSUPPORTED TARGET DESCRIPTOR TYPE CODE */ + }, + [TCM_TOO_MANY_SEGMENT_DESCS] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, + .ascq = 0x08, /* TOO MANY SEGMENT DESCRIPTORS */ + }, + [TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, + .ascq = 0x09, /* UNSUPPORTED SEGMENT DESCRIPTOR TYPE CODE */ + }, [TCM_PARAMETER_LIST_LENGTH_ERROR] = { .key = ILLEGAL_REQUEST, .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */ @@ -3086,7 +3127,6 @@ static void target_tmr_work(struct work_struct *work) spin_unlock_irqrestore(&cmd->t_state_lock, flags); goto check_stop; } - cmd->t_state = TRANSPORT_ISTATE_PROCESSING; spin_unlock_irqrestore(&cmd->t_state_lock, flags); cmd->se_tfo->queue_tm_rsp(cmd); @@ -3099,11 +3139,25 @@ int transport_generic_handle_tmr( struct se_cmd *cmd) { unsigned long flags; + bool aborted = false; spin_lock_irqsave(&cmd->t_state_lock, flags); - cmd->transport_state |= CMD_T_ACTIVE; + if (cmd->transport_state & CMD_T_ABORTED) { + aborted = true; + } else { + cmd->t_state = TRANSPORT_ISTATE_PROCESSING; + cmd->transport_state |= CMD_T_ACTIVE; + } spin_unlock_irqrestore(&cmd->t_state_lock, flags); + if (aborted) { + pr_warn_ratelimited("handle_tmr caught CMD_T_ABORTED TMR %d" + "ref_tag: %llu tag: %llu\n", cmd->se_tmr_req->function, + cmd->se_tmr_req->ref_task_tag, cmd->tag); + transport_cmd_check_stop_to_fabric(cmd); + return 0; + } + INIT_WORK(&cmd->work, target_tmr_work); queue_work(cmd->se_dev->tmr_wq, &cmd->work); return 0; diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 37d5caebffa6..cac5a20a4de0 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -53,18 +53,13 @@ static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) return 0; } -static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, - bool src) +static int target_xcopy_locate_se_dev_e4(const unsigned char *dev_wwn, + struct se_device **found_dev) { struct se_device *se_dev; - unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; + unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; int rc; - if (src) - dev_wwn = &xop->dst_tid_wwn[0]; - else - dev_wwn = &xop->src_tid_wwn[0]; - mutex_lock(&g_device_mutex); list_for_each_entry(se_dev, &g_device_list, g_dev_node) { @@ -78,15 +73,8 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op if (rc != 0) continue; - if (src) { - xop->dst_dev = se_dev; - pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" - " se_dev\n", xop->dst_dev); - } else { - xop->src_dev = se_dev; - pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located" - " se_dev\n", xop->src_dev); - } + *found_dev = se_dev; + pr_debug("XCOPY 0xe4: located se_dev: %p\n", se_dev); rc = target_depend_item(&se_dev->dev_group.cg_item); if (rc != 0) { @@ -110,7 +98,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op } static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, - unsigned char *p, bool src) + unsigned char *p, unsigned short cscd_index) { unsigned char *desc = p; unsigned short ript; @@ -155,7 +143,13 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op return -EINVAL; } - if (src) { + if (cscd_index != xop->stdi && cscd_index != xop->dtdi) { + pr_debug("XCOPY 0xe4: ignoring CSCD entry %d - neither src nor " + "dest\n", cscd_index); + return 0; + } + + if (cscd_index == xop->stdi) { memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); /* * Determine if the source designator matches the local device @@ -167,10 +161,15 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" " received xop\n", xop->src_dev); } - } else { + } + + if (cscd_index == xop->dtdi) { memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); /* - * Determine if the destination designator matches the local device + * Determine if the destination designator matches the local + * device. If @cscd_index corresponds to both source (stdi) and + * destination (dtdi), or dtdi comes after stdi, then + * XCOL_DEST_RECV_OP wins. */ if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0], XCOPY_NAA_IEEE_REGEX_LEN)) { @@ -190,20 +189,23 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, { struct se_device *local_dev = se_cmd->se_dev; unsigned char *desc = p; - int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0; + int offset = tdll % XCOPY_TARGET_DESC_LEN, rc; + unsigned short cscd_index = 0; unsigned short start = 0; - bool src = true; *sense_ret = TCM_INVALID_PARAMETER_LIST; if (offset != 0) { pr_err("XCOPY target descriptor list length is not" " multiple of %d\n", XCOPY_TARGET_DESC_LEN); + *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE; return -EINVAL; } - if (tdll > 64) { + if (tdll > RCR_OP_MAX_TARGET_DESC_COUNT * XCOPY_TARGET_DESC_LEN) { pr_err("XCOPY target descriptor supports a maximum" " two src/dest descriptors, tdll: %hu too large..\n", tdll); + /* spc4r37 6.4.3.4 CSCD DESCRIPTOR LIST LENGTH field */ + *sense_ret = TCM_TOO_MANY_TARGET_DESCS; return -EINVAL; } /* @@ -215,37 +217,43 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, while (start < tdll) { /* - * Check target descriptor identification with 0xE4 type with - * use VPD 0x83 WWPN matching .. + * Check target descriptor identification with 0xE4 type, and + * compare the current index with the CSCD descriptor IDs in + * the segment descriptor. Use VPD 0x83 WWPN matching .. */ switch (desc[0]) { case 0xe4: rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, - &desc[0], src); + &desc[0], cscd_index); if (rc != 0) goto out; - /* - * Assume target descriptors are in source -> destination order.. - */ - if (src) - src = false; - else - src = true; start += XCOPY_TARGET_DESC_LEN; desc += XCOPY_TARGET_DESC_LEN; - ret++; + cscd_index++; break; default: pr_err("XCOPY unsupported descriptor type code:" " 0x%02x\n", desc[0]); + *sense_ret = TCM_UNSUPPORTED_TARGET_DESC_TYPE_CODE; goto out; } } - if (xop->op_origin == XCOL_SOURCE_RECV_OP) - rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); - else - rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); + switch (xop->op_origin) { + case XCOL_SOURCE_RECV_OP: + rc = target_xcopy_locate_se_dev_e4(xop->dst_tid_wwn, + &xop->dst_dev); + break; + case XCOL_DEST_RECV_OP: + rc = target_xcopy_locate_se_dev_e4(xop->src_tid_wwn, + &xop->src_dev); + break; + default: + pr_err("XCOPY CSCD descriptor IDs not found in CSCD list - " + "stdi: %hu dtdi: %hu\n", xop->stdi, xop->dtdi); + rc = -EINVAL; + break; + } /* * If a matching IEEE NAA 0x83 descriptor for the requested device * is not located on this node, return COPY_ABORTED with ASQ/ASQC @@ -262,7 +270,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n", xop->dst_dev, &xop->dst_tid_wwn[0]); - return ret; + return cscd_index; out: return -EINVAL; @@ -284,6 +292,14 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op xop->stdi = get_unaligned_be16(&desc[4]); xop->dtdi = get_unaligned_be16(&desc[6]); + + if (xop->stdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX || + xop->dtdi > XCOPY_CSCD_DESC_ID_LIST_OFF_MAX) { + pr_err("XCOPY segment desc 0x02: unsupported CSCD ID > 0x%x; stdi: %hu dtdi: %hu\n", + XCOPY_CSCD_DESC_ID_LIST_OFF_MAX, xop->stdi, xop->dtdi); + return -EINVAL; + } + pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n", desc_len, xop->stdi, xop->dtdi, dc); @@ -306,15 +322,25 @@ static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, struct xcopy_op *xop, unsigned char *p, - unsigned int sdll) + unsigned int sdll, sense_reason_t *sense_ret) { unsigned char *desc = p; unsigned int start = 0; int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0; + *sense_ret = TCM_INVALID_PARAMETER_LIST; + if (offset != 0) { pr_err("XCOPY segment descriptor list length is not" " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN); + *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE; + return -EINVAL; + } + if (sdll > RCR_OP_MAX_SG_DESC_COUNT * XCOPY_SEGMENT_DESC_LEN) { + pr_err("XCOPY supports %u segment descriptor(s), sdll: %u too" + " large..\n", RCR_OP_MAX_SG_DESC_COUNT, sdll); + /* spc4r37 6.4.3.5 SEGMENT DESCRIPTOR LIST LENGTH field */ + *sense_ret = TCM_TOO_MANY_SEGMENT_DESCS; return -EINVAL; } @@ -335,6 +361,7 @@ static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, default: pr_err("XCOPY unsupported segment descriptor" "type: 0x%02x\n", desc[0]); + *sense_ret = TCM_UNSUPPORTED_SEGMENT_DESC_TYPE_CODE; goto out; } } @@ -837,7 +864,7 @@ out: " CHECK_CONDITION -> sending response\n", rc); ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; } - target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); + target_complete_cmd(ec_cmd, ec_cmd->scsi_status); } sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) @@ -861,6 +888,16 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) return TCM_UNSUPPORTED_SCSI_OPCODE; } + if (se_cmd->data_length == 0) { + target_complete_cmd(se_cmd, SAM_STAT_GOOD); + return TCM_NO_SENSE; + } + if (se_cmd->data_length < XCOPY_HDR_LEN) { + pr_err("XCOPY parameter truncation: length %u < hdr_len %u\n", + se_cmd->data_length, XCOPY_HDR_LEN); + return TCM_PARAMETER_LIST_LENGTH_ERROR; + } + xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); if (!xop) { pr_err("Unable to allocate xcopy_op\n"); @@ -883,6 +920,12 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) */ tdll = get_unaligned_be16(&p[2]); sdll = get_unaligned_be32(&p[8]); + if (tdll + sdll > RCR_OP_MAX_DESC_LIST_LEN) { + pr_err("XCOPY descriptor list length %u exceeds maximum %u\n", + tdll + sdll, RCR_OP_MAX_DESC_LIST_LEN); + ret = TCM_PARAMETER_LIST_LENGTH_ERROR; + goto out; + } inline_dl = get_unaligned_be32(&p[12]); if (inline_dl != 0) { @@ -890,10 +933,32 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) goto out; } + if (se_cmd->data_length < (XCOPY_HDR_LEN + tdll + sdll + inline_dl)) { + pr_err("XCOPY parameter truncation: data length %u too small " + "for tdll: %hu sdll: %u inline_dl: %u\n", + se_cmd->data_length, tdll, sdll, inline_dl); + ret = TCM_PARAMETER_LIST_LENGTH_ERROR; + goto out; + } + pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x" " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, tdll, sdll, inline_dl); + /* + * skip over the target descriptors until segment descriptors + * have been passed - CSCD ids are needed to determine src and dest. + */ + seg_desc = &p[16] + tdll; + + rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, + sdll, &ret); + if (rc <= 0) + goto out; + + pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, + rc * XCOPY_SEGMENT_DESC_LEN); + rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll, &ret); if (rc <= 0) goto out; @@ -911,18 +976,8 @@ sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, rc * XCOPY_TARGET_DESC_LEN); - seg_desc = &p[16]; - seg_desc += (rc * XCOPY_TARGET_DESC_LEN); - - rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll); - if (rc <= 0) { - xcopy_pt_undepend_remotedev(xop); - goto out; - } transport_kunmap_data_sg(se_cmd); - pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, - rc * XCOPY_SEGMENT_DESC_LEN); INIT_WORK(&xop->xop_work, target_xcopy_do_work); queue_work(xcopy_wq, &xop->xop_work); return TCM_NO_SENSE; diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h index 4d3d4dd060f2..7c0b105cbe1b 100644 --- a/drivers/target/target_core_xcopy.h +++ b/drivers/target/target_core_xcopy.h @@ -1,10 +1,17 @@ #include <target/target_core_base.h> +#define XCOPY_HDR_LEN 16 #define XCOPY_TARGET_DESC_LEN 32 #define XCOPY_SEGMENT_DESC_LEN 28 #define XCOPY_NAA_IEEE_REGEX_LEN 16 #define XCOPY_MAX_SECTORS 1024 +/* + * SPC4r37 6.4.6.1 + * Table 150 — CSCD descriptor ID values + */ +#define XCOPY_CSCD_DESC_ID_LIST_OFF_MAX 0x07FF + enum xcopy_origin_list { XCOL_SOURCE_RECV_OP = 0x01, XCOL_DEST_RECV_OP = 0x02, diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index fd5c3de79470..c91979c1463d 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c @@ -454,7 +454,7 @@ static void ft_sess_free(struct kref *kref) void ft_sess_put(struct ft_sess *sess) { - int sess_held = atomic_read(&sess->kref.refcount); + int sess_held = kref_read(&sess->kref); BUG_ON(!sess_held); kref_put(&sess->kref, ft_sess_free); diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 9ce0e9eef923..85fdbf762fa0 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -297,8 +297,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, if (!power_table) return -ENOMEM; - rcu_read_lock(); - for (freq = 0, i = 0; opp = dev_pm_opp_find_freq_ceil(dev, &freq), !IS_ERR(opp); freq++, i++) { @@ -306,13 +304,13 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, u64 power; if (i >= num_opps) { - rcu_read_unlock(); ret = -EAGAIN; goto free_power_table; } freq_mhz = freq / 1000000; voltage_mv = dev_pm_opp_get_voltage(opp) / 1000; + dev_pm_opp_put(opp); /* * Do the multiplication with MHz and millivolt so as @@ -328,8 +326,6 @@ static int build_dyn_power_table(struct cpufreq_cooling_device *cpufreq_device, power_table[i].power = power; } - rcu_read_unlock(); - if (i != num_opps) { ret = PTR_ERR(opp); goto free_power_table; @@ -433,13 +429,10 @@ static int get_static_power(struct cpufreq_cooling_device *cpufreq_device, return 0; } - rcu_read_lock(); - opp = dev_pm_opp_find_freq_exact(cpufreq_device->cpu_dev, freq_hz, true); voltage = dev_pm_opp_get_voltage(opp); - - rcu_read_unlock(); + dev_pm_opp_put(opp); if (voltage == 0) { dev_warn_ratelimited(cpufreq_device->cpu_dev, diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c index 5a737fd5f1aa..ba7a5cd994dc 100644 --- a/drivers/thermal/devfreq_cooling.c +++ b/drivers/thermal/devfreq_cooling.c @@ -113,15 +113,15 @@ static int partition_enable_opps(struct devfreq_cooling_device *dfc, unsigned int freq = dfc->freq_table[i]; bool want_enable = i >= cdev_state ? true : false; - rcu_read_lock(); opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable); - rcu_read_unlock(); if (PTR_ERR(opp) == -ERANGE) continue; else if (IS_ERR(opp)) return PTR_ERR(opp); + dev_pm_opp_put(opp); + if (want_enable) ret = dev_pm_opp_enable(dev, freq); else @@ -221,15 +221,12 @@ get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq) if (!dfc->power_ops->get_static_power) return 0; - rcu_read_lock(); - opp = dev_pm_opp_find_freq_exact(dev, freq, true); if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE)) opp = dev_pm_opp_find_freq_exact(dev, freq, false); voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ - - rcu_read_unlock(); + dev_pm_opp_put(opp); if (voltage == 0) { dev_warn_ratelimited(dev, @@ -412,18 +409,14 @@ static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc) unsigned long power_dyn, voltage; struct dev_pm_opp *opp; - rcu_read_lock(); - opp = dev_pm_opp_find_freq_floor(dev, &freq); if (IS_ERR(opp)) { - rcu_read_unlock(); ret = PTR_ERR(opp); goto free_tables; } voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */ - - rcu_read_unlock(); + dev_pm_opp_put(opp); if (dfc->power_ops) { power_dyn = get_dynamic_power(dfc, freq, voltage); diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index b811b0fb61b1..4c7796512453 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -118,12 +118,12 @@ struct rockchip_tsadc_chip { void (*control)(void __iomem *reg, bool on); /* Per-sensor methods */ - int (*get_temp)(struct chip_tsadc_table table, + int (*get_temp)(const struct chip_tsadc_table *table, int chn, void __iomem *reg, int *temp); - void (*set_alarm_temp)(struct chip_tsadc_table table, - int chn, void __iomem *reg, int temp); - void (*set_tshut_temp)(struct chip_tsadc_table table, - int chn, void __iomem *reg, int temp); + int (*set_alarm_temp)(const struct chip_tsadc_table *table, + int chn, void __iomem *reg, int temp); + int (*set_tshut_temp)(const struct chip_tsadc_table *table, + int chn, void __iomem *reg, int temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); /* Per-table methods */ @@ -317,6 +317,7 @@ static const struct tsadc_table rk3288_code_table[] = { {3452, 115000}, {3437, 120000}, {3421, 125000}, + {0, 125000}, }; static const struct tsadc_table rk3368_code_table[] = { @@ -397,59 +398,80 @@ static const struct tsadc_table rk3399_code_table[] = { {TSADCV3_DATA_MASK, 125000}, }; -static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, +static u32 rk_tsadcv2_temp_to_code(const struct chip_tsadc_table *table, int temp) { int high, low, mid; - u32 error = 0; + unsigned long num; + unsigned int denom; + u32 error = table->data_mask; low = 0; - high = table.length - 1; + high = (table->length - 1) - 1; /* ignore the last check for table */ mid = (high + low) / 2; /* Return mask code data when the temp is over table range */ - if (temp < table.id[low].temp || temp > table.id[high].temp) { - error = table.data_mask; + if (temp < table->id[low].temp || temp > table->id[high].temp) goto exit; - } while (low <= high) { - if (temp == table.id[mid].temp) - return table.id[mid].code; - else if (temp < table.id[mid].temp) + if (temp == table->id[mid].temp) + return table->id[mid].code; + else if (temp < table->id[mid].temp) high = mid - 1; else low = mid + 1; mid = (low + high) / 2; } + /* + * The conversion code granularity provided by the table. Let's + * assume that the relationship between temperature and + * analog value between 2 table entries is linear and interpolate + * to produce less granular result. + */ + num = abs(table->id[mid + 1].code - table->id[mid].code); + num *= temp - table->id[mid].temp; + denom = table->id[mid + 1].temp - table->id[mid].temp; + + switch (table->mode) { + case ADC_DECREMENT: + return table->id[mid].code - (num / denom); + case ADC_INCREMENT: + return table->id[mid].code + (num / denom); + default: + pr_err("%s: unknown table mode: %d\n", __func__, table->mode); + return error; + } + exit: - pr_err("Invalid the conversion, error=%d\n", error); + pr_err("%s: invalid temperature, temp=%d error=%d\n", + __func__, temp, error); return error; } -static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, - int *temp) +static int rk_tsadcv2_code_to_temp(const struct chip_tsadc_table *table, + u32 code, int *temp) { unsigned int low = 1; - unsigned int high = table.length - 1; + unsigned int high = table->length - 1; unsigned int mid = (low + high) / 2; unsigned int num; unsigned long denom; - WARN_ON(table.length < 2); + WARN_ON(table->length < 2); - switch (table.mode) { + switch (table->mode) { case ADC_DECREMENT: - code &= table.data_mask; - if (code < table.id[high].code) + code &= table->data_mask; + if (code <= table->id[high].code) return -EAGAIN; /* Incorrect reading */ while (low <= high) { - if (code >= table.id[mid].code && - code < table.id[mid - 1].code) + if (code >= table->id[mid].code && + code < table->id[mid - 1].code) break; - else if (code < table.id[mid].code) + else if (code < table->id[mid].code) low = mid + 1; else high = mid - 1; @@ -458,15 +480,15 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, } break; case ADC_INCREMENT: - code &= table.data_mask; - if (code < table.id[low].code) + code &= table->data_mask; + if (code < table->id[low].code) return -EAGAIN; /* Incorrect reading */ while (low <= high) { - if (code <= table.id[mid].code && - code > table.id[mid - 1].code) + if (code <= table->id[mid].code && + code > table->id[mid - 1].code) break; - else if (code > table.id[mid].code) + else if (code > table->id[mid].code) low = mid + 1; else high = mid - 1; @@ -475,7 +497,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, } break; default: - pr_err("Invalid the conversion table\n"); + pr_err("%s: unknown table mode: %d\n", __func__, table->mode); + return -EINVAL; } /* @@ -484,10 +507,10 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, * temperature between 2 table entries is linear and interpolate * to produce less granular result. */ - num = table.id[mid].temp - table.id[mid - 1].temp; - num *= abs(table.id[mid - 1].code - code); - denom = abs(table.id[mid - 1].code - table.id[mid].code); - *temp = table.id[mid - 1].temp + (num / denom); + num = table->id[mid].temp - table->id[mid - 1].temp; + num *= abs(table->id[mid - 1].code - code); + denom = abs(table->id[mid - 1].code - table->id[mid].code); + *temp = table->id[mid - 1].temp + (num / denom); return 0; } @@ -638,7 +661,7 @@ static void rk_tsadcv3_control(void __iomem *regs, bool enable) writel_relaxed(val, regs + TSADCV2_AUTO_CON); } -static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, +static int rk_tsadcv2_get_temp(const struct chip_tsadc_table *table, int chn, void __iomem *regs, int *temp) { u32 val; @@ -648,39 +671,57 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, return rk_tsadcv2_code_to_temp(table, val, temp); } -static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table, - int chn, void __iomem *regs, int temp) +static int rk_tsadcv2_alarm_temp(const struct chip_tsadc_table *table, + int chn, void __iomem *regs, int temp) { - u32 alarm_value, int_en; + u32 alarm_value; + u32 int_en, int_clr; + + /* + * In some cases, some sensors didn't need the trip points, the + * set_trips will pass {-INT_MAX, INT_MAX} to trigger tsadc alarm + * in the end, ignore this case and disable the high temperature + * interrupt. + */ + if (temp == INT_MAX) { + int_clr = readl_relaxed(regs + TSADCV2_INT_EN); + int_clr &= ~TSADCV2_INT_SRC_EN(chn); + writel_relaxed(int_clr, regs + TSADCV2_INT_EN); + return 0; + } /* Make sure the value is valid */ alarm_value = rk_tsadcv2_temp_to_code(table, temp); - if (alarm_value == table.data_mask) - return; + if (alarm_value == table->data_mask) + return -ERANGE; - writel_relaxed(alarm_value & table.data_mask, + writel_relaxed(alarm_value & table->data_mask, regs + TSADCV2_COMP_INT(chn)); int_en = readl_relaxed(regs + TSADCV2_INT_EN); int_en |= TSADCV2_INT_SRC_EN(chn); writel_relaxed(int_en, regs + TSADCV2_INT_EN); + + return 0; } -static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, - int chn, void __iomem *regs, int temp) +static int rk_tsadcv2_tshut_temp(const struct chip_tsadc_table *table, + int chn, void __iomem *regs, int temp) { u32 tshut_value, val; /* Make sure the value is valid */ tshut_value = rk_tsadcv2_temp_to_code(table, temp); - if (tshut_value == table.data_mask) - return; + if (tshut_value == table->data_mask) + return -ERANGE; writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); /* TSHUT will be valid */ val = readl_relaxed(regs + TSADCV2_AUTO_CON); writel_relaxed(val | TSADCV2_AUTO_SRC_EN(chn), regs + TSADCV2_AUTO_CON); + + return 0; } static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, @@ -883,10 +924,8 @@ static int rockchip_thermal_set_trips(void *_sensor, int low, int high) dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n", __func__, sensor->id, low, high); - tsadc->set_alarm_temp(tsadc->table, - sensor->id, thermal->regs, high); - - return 0; + return tsadc->set_alarm_temp(&tsadc->table, + sensor->id, thermal->regs, high); } static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) @@ -896,7 +935,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip; int retval; - retval = tsadc->get_temp(tsadc->table, + retval = tsadc->get_temp(&tsadc->table, sensor->id, thermal->regs, out_temp); dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n", sensor->id, *out_temp, retval); @@ -982,8 +1021,12 @@ rockchip_thermal_register_sensor(struct platform_device *pdev, int error; tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); - tsadc->set_tshut_temp(tsadc->table, id, thermal->regs, + + error = tsadc->set_tshut_temp(&tsadc->table, id, thermal->regs, thermal->tshut_temp); + if (error) + dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n", + __func__, thermal->tshut_temp, error); sensor->thermal = thermal; sensor->id = id; @@ -1196,9 +1239,13 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) thermal->chip->set_tshut_mode(id, thermal->regs, thermal->tshut_mode); - thermal->chip->set_tshut_temp(thermal->chip->table, + + error = thermal->chip->set_tshut_temp(&thermal->chip->table, id, thermal->regs, thermal->tshut_temp); + if (error) + dev_err(&pdev->dev, "%s: invalid tshut=%d, error=%d\n", + __func__, thermal->tshut_temp, error); } thermal->chip->control(thermal->regs, true); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 641faab6e24b..655591316a88 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -799,6 +799,11 @@ static void thermal_release(struct device *dev) if (!strncmp(dev_name(dev), "thermal_zone", sizeof("thermal_zone") - 1)) { tz = to_thermal_zone(dev); + kfree(tz->trip_type_attrs); + kfree(tz->trip_temp_attrs); + kfree(tz->trip_hyst_attrs); + kfree(tz->trips_attribute_group.attrs); + kfree(tz->device.groups); kfree(tz); } else if (!strncmp(dev_name(dev), "cooling_device", sizeof("cooling_device") - 1)) { @@ -1305,10 +1310,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) thermal_zone_device_set_polling(tz, 0); - kfree(tz->trip_type_attrs); - kfree(tz->trip_temp_attrs); - kfree(tz->trip_hyst_attrs); - kfree(tz->trips_attribute_group.attrs); thermal_set_governor(tz, NULL); thermal_remove_hwmon_sysfs(tz); @@ -1316,7 +1317,6 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) idr_destroy(&tz->idr); mutex_destroy(&tz->lock); device_unregister(&tz->device); - kfree(tz->device.groups); } EXPORT_SYMBOL_GPL(thermal_zone_device_unregister); diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 61569a765d9e..76e03a7de9cc 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -675,7 +675,7 @@ static struct console univ8250_console = { .device = uart_console_device, .setup = univ8250_console_setup, .match = univ8250_console_match, - .flags = CON_PRINTBUFFER | CON_ANYTIME | CON_CONSDEV, + .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg, }; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index aa0166b6d450..116436b7fa52 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -5642,17 +5642,15 @@ static pci_ers_result_t serial8250_io_slot_reset(struct pci_dev *dev) static void serial8250_io_resume(struct pci_dev *dev) { struct serial_private *priv = pci_get_drvdata(dev); - const struct pciserial_board *board; + struct serial_private *new; if (!priv) return; - board = priv->board; - kfree(priv); - priv = pciserial_init_ports(dev, board); - - if (!IS_ERR(priv)) { - pci_set_drvdata(dev, priv); + new = pciserial_init_ports(dev, priv->board); + if (!IS_ERR(new)) { + pci_set_drvdata(dev, new); + kfree(priv); } } diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fe4399b41df6..c13fec451d03 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1413,7 +1413,7 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) * Enable previously disabled RX interrupts. */ if (!(p->port.rs485.flags & SER_RS485_RX_DURING_TX)) { - serial8250_clear_fifos(p); + serial8250_clear_and_reinit_fifos(p); p->ier |= UART_IER_RLSI | UART_IER_RDI; serial_port_out(&p->port, UART_IER, p->ier); diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 168b10cad47b..fabbe76203bb 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -481,6 +481,14 @@ static void atmel_stop_tx(struct uart_port *port) /* disable PDC transmit */ atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } + + /* + * Disable the transmitter. + * This is mandatory when DMA is used, otherwise the DMA buffer + * is fully transmitted. + */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS); + /* Disable interrupts */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); @@ -513,6 +521,9 @@ static void atmel_start_tx(struct uart_port *port) /* Enable interrupts */ atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); + + /* re-enable the transmitter */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN); } /* @@ -798,6 +809,11 @@ static void atmel_complete_tx_dma(void *arg) */ if (!uart_circ_empty(xmit)) atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); + else if ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { + /* DMA done, stop TX, start RX for RS485 */ + atmel_start_rx(port); + } spin_unlock_irqrestore(&port->lock, flags); } @@ -900,12 +916,6 @@ static void atmel_tx_dma(struct uart_port *port) desc->callback = atmel_complete_tx_dma; desc->callback_param = atmel_port; atmel_port->cookie_tx = dmaengine_submit(desc); - - } else { - if (port->rs485.flags & SER_RS485_ENABLED) { - /* DMA done, stop TX, start RX for RS485 */ - atmel_start_rx(port); - } } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index 52bbd27e93ae..701c085bb19b 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -946,8 +946,8 @@ static const struct input_device_id sysrq_ids[] = { { .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, - .evbit = { BIT_MASK(EV_KEY) }, - .keybit = { BIT_MASK(KEY_LEFTALT) }, + .evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) }, + .keybit = { [BIT_WORD(KEY_LEFTALT)] = BIT_MASK(KEY_LEFTALT) }, }, { }, }; diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 1bf8ed13f827..9229de43e19d 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -200,7 +200,6 @@ static struct ld_semaphore __sched * down_read_failed(struct ld_semaphore *sem, long count, long timeout) { struct ldsem_waiter waiter; - struct task_struct *tsk = current; long adjust = -LDSEM_ACTIVE_BIAS + LDSEM_WAIT_BIAS; /* set up my own style of waitqueue */ @@ -221,8 +220,8 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) list_add_tail(&waiter.list, &sem->read_wait); sem->wait_readers++; - waiter.task = tsk; - get_task_struct(tsk); + waiter.task = current; + get_task_struct(current); /* if there are no active locks, wake the new lock owner(s) */ if ((count & LDSEM_ACTIVE_MASK) == 0) @@ -232,7 +231,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) /* wait to be given the lock */ for (;;) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); if (!waiter.task) break; @@ -241,7 +240,7 @@ down_read_failed(struct ld_semaphore *sem, long count, long timeout) timeout = schedule_timeout(timeout); } - __set_task_state(tsk, TASK_RUNNING); + __set_current_state(TASK_RUNNING); if (!timeout) { /* lock timed out but check if this task was just @@ -268,7 +267,6 @@ static struct ld_semaphore __sched * down_write_failed(struct ld_semaphore *sem, long count, long timeout) { struct ldsem_waiter waiter; - struct task_struct *tsk = current; long adjust = -LDSEM_ACTIVE_BIAS; int locked = 0; @@ -289,16 +287,16 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) list_add_tail(&waiter.list, &sem->write_wait); - waiter.task = tsk; + waiter.task = current; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); for (;;) { if (!timeout) break; raw_spin_unlock_irq(&sem->wait_lock); timeout = schedule_timeout(timeout); raw_spin_lock_irq(&sem->wait_lock); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); + set_current_state(TASK_UNINTERRUPTIBLE); locked = writer_trylock(sem); if (locked) break; @@ -309,7 +307,7 @@ down_write_failed(struct ld_semaphore *sem, long count, long timeout) list_del(&waiter.list); raw_spin_unlock_irq(&sem->wait_lock); - __set_task_state(tsk, TASK_RUNNING); + __set_current_state(TASK_RUNNING); /* lock wait may have timed out */ if (!locked) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 0aa9e7d697a5..25dbd8c7aec7 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -239,6 +239,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, if (ifp->desc.bNumEndpoints >= num_ep) goto skip_to_next_endpoint_or_interface_descriptor; + /* Check for duplicate endpoint addresses */ + for (i = 0; i < ifp->desc.bNumEndpoints; ++i) { + if (ifp->endpoint[i].desc.bEndpointAddress == + d->bEndpointAddress) { + dev_warn(ddev, "config %d interface %d altsetting %d has a duplicate endpoint with address 0x%X, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; + } + } + endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; ++ifp->desc.bNumEndpoints; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 1fa5c0f29c64..a56c75e09786 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -103,8 +103,7 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem); static void hub_release(struct kref *kref); static int usb_reset_and_verify_device(struct usb_device *udev); -static void hub_usb3_port_prepare_disable(struct usb_hub *hub, - struct usb_port *port_dev); +static int hub_port_disable(struct usb_hub *hub, int port1, int set_state); static inline char *portspeed(struct usb_hub *hub, int portstatus) { @@ -903,34 +902,6 @@ static int hub_set_port_link_state(struct usb_hub *hub, int port1, } /* - * USB-3 does not have a similar link state as USB-2 that will avoid negotiating - * a connection with a plugged-in cable but will signal the host when the cable - * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices - */ -static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) -{ - struct usb_port *port_dev = hub->ports[port1 - 1]; - struct usb_device *hdev = hub->hdev; - int ret = 0; - - if (!hub->error) { - if (hub_is_superspeed(hub->hdev)) { - hub_usb3_port_prepare_disable(hub, port_dev); - ret = hub_set_port_link_state(hub, port_dev->portnum, - USB_SS_PORT_LS_U3); - } else { - ret = usb_clear_port_feature(hdev, port1, - USB_PORT_FEAT_ENABLE); - } - } - if (port_dev->child && set_state) - usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED); - if (ret && ret != -ENODEV) - dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret); - return ret; -} - -/* * Disable a port and mark a logical connect-change event, so that some * time later hub_wq will disconnect() any existing usb_device on the port * and will re-enumerate if there actually is a device attached. @@ -4162,6 +4133,34 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port, #endif /* CONFIG_PM */ +/* + * USB-3 does not have a similar link state as USB-2 that will avoid negotiating + * a connection with a plugged-in cable but will signal the host when the cable + * is unplugged. Disable remote wake and set link state to U3 for USB-3 devices + */ +static int hub_port_disable(struct usb_hub *hub, int port1, int set_state) +{ + struct usb_port *port_dev = hub->ports[port1 - 1]; + struct usb_device *hdev = hub->hdev; + int ret = 0; + + if (!hub->error) { + if (hub_is_superspeed(hub->hdev)) { + hub_usb3_port_prepare_disable(hub, port_dev); + ret = hub_set_port_link_state(hub, port_dev->portnum, + USB_SS_PORT_LS_U3); + } else { + ret = usb_clear_port_feature(hdev, port1, + USB_PORT_FEAT_ENABLE); + } + } + if (port_dev->child && set_state) + usb_set_device_state(port_dev->child, USB_STATE_NOTATTACHED); + if (ret && ret != -ENODEV) + dev_err(&port_dev->dev, "cannot disable (err = %d)\n", ret); + return ret; +} + /* USB 2.0 spec, 7.1.7.3 / fig 7-29: * diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index d2e50a27140c..24f9f98968a5 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -37,6 +37,10 @@ static const struct usb_device_id usb_quirk_list[] = { /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, + /* WORLDE easy key (easykey.25) MIDI controller */ + { USB_DEVICE(0x0218, 0x0401), .driver_info = + USB_QUIRK_CONFIG_INTF_STRINGS }, + /* HP 5300/5370C scanner */ { USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 }, diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 9548d3e03453..302b8f5f7d27 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -513,8 +513,8 @@ struct dwc2_core_params { /* Gadget parameters */ bool g_dma; bool g_dma_desc; - u16 g_rx_fifo_size; - u16 g_np_tx_fifo_size; + u32 g_rx_fifo_size; + u32 g_np_tx_fifo_size; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; }; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index b95930f20d90..77c5fcf3a5bf 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -3169,7 +3169,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, /* keep other bits untouched (so e.g. forced modes are not lost) */ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | - GUSBCFG_HNPCAP); + GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && (hsotg->params.speed == DWC2_SPEED_PARAM_FULL || @@ -3749,11 +3749,11 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, __func__, epctrl, epctrl_reg); /* Allocate DMA descriptor chain for non-ctrl endpoints */ - if (using_desc_dma(hsotg)) { - hs_ep->desc_list = dma_alloc_coherent(hsotg->dev, + if (using_desc_dma(hsotg) && !hs_ep->desc_list) { + hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * sizeof(struct dwc2_dma_desc), - &hs_ep->desc_list_dma, GFP_KERNEL); + &hs_ep->desc_list_dma, GFP_ATOMIC); if (!hs_ep->desc_list) { ret = -ENOMEM; goto error2; @@ -3872,7 +3872,7 @@ error1: error2: if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { - dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * + dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * sizeof(struct dwc2_dma_desc), hs_ep->desc_list, hs_ep->desc_list_dma); hs_ep->desc_list = NULL; @@ -3902,14 +3902,6 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep) return -EINVAL; } - /* Remove DMA memory allocated for non-control Endpoints */ - if (using_desc_dma(hsotg)) { - dma_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * - sizeof(struct dwc2_dma_desc), - hs_ep->desc_list, hs_ep->desc_list_dma); - hs_ep->desc_list = NULL; - } - epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); spin_lock_irqsave(&hsotg->lock, flags); @@ -4131,7 +4123,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) /* keep other bits untouched (so e.g. forced modes are not lost) */ usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | - GUSBCFG_HNPCAP); + GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); /* set the PLL on, remove the HNP/SRP and set the PHY */ trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 911c3b36ac06..46d0ad5105e4 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4367,6 +4367,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) if (!HCD_HW_ACCESSIBLE(hcd)) goto unlock; + if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) + goto unlock; + if (!hsotg->params.hibernation) goto skip_power_saving; @@ -4489,8 +4492,8 @@ static void dwc2_dump_urb_info(struct usb_hcd *hcd, struct urb *urb, { #ifdef VERBOSE_DEBUG struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); - char *pipetype; - char *speed; + char *pipetype = NULL; + char *speed = NULL; dev_vdbg(hsotg->dev, "%s, urb %p\n", fn_name, urb); dev_vdbg(hsotg->dev, " Device address: %d\n", diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index a786256535b6..bcd1e19b4076 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -247,8 +247,6 @@ MODULE_DEVICE_TABLE(of, dwc2_of_match_table); static void dwc2_get_device_property(struct dwc2_hsotg *hsotg, char *property, u8 size, u64 *value) { - u8 val8; - u16 val16; u32 val32; switch (size) { @@ -256,17 +254,7 @@ static void dwc2_get_device_property(struct dwc2_hsotg *hsotg, *value = device_property_read_bool(hsotg->dev, property); break; case 1: - if (device_property_read_u8(hsotg->dev, property, &val8)) - return; - - *value = val8; - break; case 2: - if (device_property_read_u16(hsotg->dev, property, &val16)) - return; - - *value = val16; - break; case 4: if (device_property_read_u32(hsotg->dev, property, &val32)) return; @@ -397,16 +385,16 @@ static void dwc2_set_param(struct dwc2_hsotg *hsotg, void *param, } /** - * dwc2_set_param_u16() - Set a u16 parameter + * dwc2_set_param_u32() - Set a u32 parameter * * See dwc2_set_param(). */ -static void dwc2_set_param_u16(struct dwc2_hsotg *hsotg, u16 *param, +static void dwc2_set_param_u32(struct dwc2_hsotg *hsotg, u32 *param, bool lookup, char *property, u16 legacy, u16 def, u16 min, u16 max) { dwc2_set_param(hsotg, param, lookup, property, - legacy, def, min, max, 2); + legacy, def, min, max, 4); } /** @@ -1100,13 +1088,13 @@ static void dwc2_set_gadget_dma(struct dwc2_hsotg *hsotg) /* Buffer DMA */ dwc2_set_param_bool(hsotg, &p->g_dma, false, "gadget-dma", - true, false, + dma_capable, false, dma_capable); /* DMA Descriptor */ dwc2_set_param_bool(hsotg, &p->g_dma_desc, false, "gadget-dma-desc", - p->g_dma, false, + !!hw->dma_desc_enable, false, !!hw->dma_desc_enable); } @@ -1130,8 +1118,14 @@ static void dwc2_set_parameters(struct dwc2_hsotg *hsotg, dwc2_set_param_bool(hsotg, &p->host_dma, false, "host-dma", - true, false, + dma_capable, false, dma_capable); + dwc2_set_param_host_rx_fifo_size(hsotg, + params->host_rx_fifo_size); + dwc2_set_param_host_nperio_tx_fifo_size(hsotg, + params->host_nperio_tx_fifo_size); + dwc2_set_param_host_perio_tx_fifo_size(hsotg, + params->host_perio_tx_fifo_size); } dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable); dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable); @@ -1140,12 +1134,6 @@ static void dwc2_set_parameters(struct dwc2_hsotg *hsotg, params->host_support_fs_ls_low_power); dwc2_set_param_enable_dynamic_fifo(hsotg, params->enable_dynamic_fifo); - dwc2_set_param_host_rx_fifo_size(hsotg, - params->host_rx_fifo_size); - dwc2_set_param_host_nperio_tx_fifo_size(hsotg, - params->host_nperio_tx_fifo_size); - dwc2_set_param_host_perio_tx_fifo_size(hsotg, - params->host_perio_tx_fifo_size); dwc2_set_param_max_transfer_size(hsotg, params->max_transfer_size); dwc2_set_param_max_packet_count(hsotg, @@ -1190,12 +1178,12 @@ static void dwc2_set_parameters(struct dwc2_hsotg *hsotg, * auto-detect if the hardware does not support the * default. */ - dwc2_set_param_u16(hsotg, &p->g_rx_fifo_size, + dwc2_set_param_u32(hsotg, &p->g_rx_fifo_size, true, "g-rx-fifo-size", 2048, hw->rx_fifo_size, 16, hw->rx_fifo_size); - dwc2_set_param_u16(hsotg, &p->g_np_tx_fifo_size, + dwc2_set_param_u32(hsotg, &p->g_np_tx_fifo_size, true, "g-np-tx-fifo-size", 1024, hw->dev_nperio_tx_fifo_size, 16, hw->dev_nperio_tx_fifo_size); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index de5a8570be04..14b760209680 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -45,9 +45,7 @@ #define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_SCRATCHBUF_SIZE 4096 /* each buffer is assumed to be 4KiB */ -#define DWC3_EVENT_SIZE 4 /* bytes */ -#define DWC3_EVENT_MAX_NUM 64 /* 2 events/endpoint */ -#define DWC3_EVENT_BUFFERS_SIZE (DWC3_EVENT_SIZE * DWC3_EVENT_MAX_NUM) +#define DWC3_EVENT_BUFFERS_SIZE 4096 #define DWC3_EVENT_TYPE_MASK 0xfe #define DWC3_EVENT_TYPE_DEV 0 @@ -311,9 +309,8 @@ #define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */ #define DWC3_DCFG_SUPERSPEED (4 << 0) #define DWC3_DCFG_HIGHSPEED (0 << 0) -#define DWC3_DCFG_FULLSPEED2 (1 << 0) +#define DWC3_DCFG_FULLSPEED (1 << 0) #define DWC3_DCFG_LOWSPEED (2 << 0) -#define DWC3_DCFG_FULLSPEED1 (3 << 0) #define DWC3_DCFG_NUMP_SHIFT 17 #define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f) @@ -405,9 +402,8 @@ #define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */ #define DWC3_DSTS_SUPERSPEED (4 << 0) #define DWC3_DSTS_HIGHSPEED (0 << 0) -#define DWC3_DSTS_FULLSPEED2 (1 << 0) +#define DWC3_DSTS_FULLSPEED (1 << 0) #define DWC3_DSTS_LOWSPEED (2 << 0) -#define DWC3_DSTS_FULLSPEED1 (3 << 0) /* Device Generic Command Register */ #define DWC3_DGCMD_SET_LMP 0x01 diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index e27899bb5706..e956306d9b0f 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -138,7 +138,8 @@ static int dwc3_exynos_probe(struct platform_device *pdev) exynos->axius_clk = devm_clk_get(dev, "usbdrd30_axius_clk"); if (IS_ERR(exynos->axius_clk)) { dev_err(dev, "no AXI UpScaler clk specified\n"); - return -ENODEV; + ret = -ENODEV; + goto axius_clk_err; } clk_prepare_enable(exynos->axius_clk); } else { @@ -196,6 +197,7 @@ err3: regulator_disable(exynos->vdd33); err2: clk_disable_unprepare(exynos->axius_clk); +axius_clk_err: clk_disable_unprepare(exynos->susp_clk); clk_disable_unprepare(exynos->clk); return ret; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index 29e80cc9b634..eb1b9cb3f9d1 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/irq.h> #include <linux/interrupt.h> #include <linux/platform_device.h> #include <linux/platform_data/dwc3-omap.h> @@ -510,7 +511,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) /* check the DMA Status */ reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); - + irq_set_status_flags(omap->irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(dev, omap->irq, dwc3_omap_interrupt, dwc3_omap_interrupt_thread, IRQF_SHARED, "dwc3-omap", omap); @@ -531,7 +532,7 @@ static int dwc3_omap_probe(struct platform_device *pdev) } dwc3_omap_enable_irqs(omap); - + enable_irq(omap->irq); return 0; err2: @@ -552,6 +553,7 @@ static int dwc3_omap_remove(struct platform_device *pdev) extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); dwc3_omap_disable_irqs(omap); + disable_irq(omap->irq); of_platform_depopulate(omap->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 2b73339f286b..cce0a220b6b0 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -38,6 +38,7 @@ #define PCI_DEVICE_ID_INTEL_BXT_M 0x1aaa #define PCI_DEVICE_ID_INTEL_APL 0x5aaa #define PCI_DEVICE_ID_INTEL_KBP 0xa2b0 +#define PCI_DEVICE_ID_INTEL_GLK 0x31aa #define PCI_INTEL_BXT_DSM_UUID "732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511" #define PCI_INTEL_BXT_FUNC_PMU_PWR 4 @@ -73,16 +74,6 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) { struct platform_device *dwc3 = dwc->dwc3; struct pci_dev *pdev = dwc->pci; - int ret; - - struct property_entry sysdev_property[] = { - PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), - { }, - }; - - ret = platform_device_add_properties(dwc3, sysdev_property); - if (ret) - return ret; if (pdev->vendor == PCI_VENDOR_ID_AMD && pdev->device == PCI_DEVICE_ID_AMD_NL_USB) { @@ -105,6 +96,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"), PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"), PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), { }, }; @@ -115,7 +107,8 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) int ret; struct property_entry properties[] = { - PROPERTY_ENTRY_STRING("dr-mode", "peripheral"), + PROPERTY_ENTRY_STRING("dr_mode", "peripheral"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), { } }; @@ -167,6 +160,7 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc) PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"), PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"), PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), { }, }; @@ -274,6 +268,7 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 4878d187c7d4..9bb1f8526f3e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -39,18 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); -static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, - u32 len, u32 type, bool chain) +static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum, + dma_addr_t buf_dma, u32 len, u32 type, bool chain) { - struct dwc3_gadget_ep_cmd_params params; struct dwc3_trb *trb; struct dwc3_ep *dep; - int ret; - dep = dwc->eps[epnum]; - if (dep->flags & DWC3_EP_BUSY) - return 0; trb = &dwc->ep0_trb[dep->trb_enqueue]; @@ -71,15 +66,23 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma, trb->ctrl |= (DWC3_TRB_CTRL_IOC | DWC3_TRB_CTRL_LST); - if (chain) + trace_dwc3_prepare_trb(dep, trb); +} + +static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum) +{ + struct dwc3_gadget_ep_cmd_params params; + struct dwc3_ep *dep; + int ret; + + dep = dwc->eps[epnum]; + if (dep->flags & DWC3_EP_BUSY) return 0; memset(¶ms, 0, sizeof(params)); params.param0 = upper_32_bits(dwc->ep0_trb_addr); params.param1 = lower_32_bits(dwc->ep0_trb_addr); - trace_dwc3_prepare_trb(dep, trb); - ret = dwc3_send_gadget_ep_cmd(dep, DWC3_DEPCMD_STARTTRANSFER, ¶ms); if (ret < 0) return ret; @@ -280,8 +283,9 @@ void dwc3_ep0_out_start(struct dwc3 *dwc) complete(&dwc->ep0_in_setup); - ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8, + dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8, DWC3_TRBCTL_CONTROL_SETUP, false); + ret = dwc3_ep0_start_trans(dwc, 0); WARN_ON(ret < 0); } @@ -912,9 +916,9 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, dwc->ep0_next_event = DWC3_EP0_COMPLETE; - ret = dwc3_ep0_start_trans(dwc, epnum, - dwc->ctrl_req_addr, 0, - DWC3_TRBCTL_CONTROL_DATA, false); + dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr, + 0, DWC3_TRBCTL_CONTROL_DATA, false); + ret = dwc3_ep0_start_trans(dwc, epnum); WARN_ON(ret < 0); } } @@ -993,9 +997,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, req->direction = !!dep->number; if (req->request.length == 0) { - ret = dwc3_ep0_start_trans(dwc, dep->number, + dwc3_ep0_prepare_one_trb(dwc, dep->number, dwc->ctrl_req_addr, 0, DWC3_TRBCTL_CONTROL_DATA, false); + ret = dwc3_ep0_start_trans(dwc, dep->number); } else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) && (dep->number == 0)) { u32 transfer_size = 0; @@ -1011,7 +1016,7 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, if (req->request.length > DWC3_EP0_BOUNCE_SIZE) { transfer_size = ALIGN(req->request.length - maxpacket, maxpacket); - ret = dwc3_ep0_start_trans(dwc, dep->number, + dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma, transfer_size, DWC3_TRBCTL_CONTROL_DATA, @@ -1023,18 +1028,20 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, dwc->ep0_bounced = true; - ret = dwc3_ep0_start_trans(dwc, dep->number, + dwc3_ep0_prepare_one_trb(dwc, dep->number, dwc->ep0_bounce_addr, transfer_size, DWC3_TRBCTL_CONTROL_DATA, false); + ret = dwc3_ep0_start_trans(dwc, dep->number); } else { ret = usb_gadget_map_request_by_dev(dwc->sysdev, &req->request, dep->number); if (ret) return; - ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma, + dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma, req->request.length, DWC3_TRBCTL_CONTROL_DATA, false); + ret = dwc3_ep0_start_trans(dwc, dep->number); } WARN_ON(ret < 0); @@ -1048,8 +1055,9 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3 : DWC3_TRBCTL_CONTROL_STATUS2; - return dwc3_ep0_start_trans(dwc, dep->number, + dwc3_ep0_prepare_one_trb(dwc, dep->number, dwc->ctrl_req_addr, 0, type, false); + return dwc3_ep0_start_trans(dwc, dep->number); } static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index efddaf5d11d1..204c754cc647 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -180,11 +180,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, if (req->request.status == -EINPROGRESS) req->request.status = status; - if (dwc->ep0_bounced && dep->number == 0) + if (dwc->ep0_bounced && dep->number <= 1) dwc->ep0_bounced = false; - else - usb_gadget_unmap_request_by_dev(dwc->sysdev, - &req->request, req->direction); + + usb_gadget_unmap_request_by_dev(dwc->sysdev, + &req->request, req->direction); trace_dwc3_gadget_giveback(req); @@ -1720,7 +1720,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) reg |= DWC3_DCFG_LOWSPEED; break; case USB_SPEED_FULL: - reg |= DWC3_DCFG_FULLSPEED1; + reg |= DWC3_DCFG_FULLSPEED; break; case USB_SPEED_HIGH: reg |= DWC3_DCFG_HIGHSPEED; @@ -2232,9 +2232,14 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dep = dwc->eps[epnum]; - if (!(dep->flags & DWC3_EP_ENABLED) && - !(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) - return; + if (!(dep->flags & DWC3_EP_ENABLED)) { + if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING)) + return; + + /* Handle only EPCMDCMPLT when EP disabled */ + if (event->endpoint_event != DWC3_DEPEVT_EPCMDCMPLT) + return; + } if (epnum == 0 || epnum == 1) { dwc3_ep0_interrupt(dwc, event); @@ -2531,8 +2536,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) dwc->gadget.ep0->maxpacket = 64; dwc->gadget.speed = USB_SPEED_HIGH; break; - case DWC3_DSTS_FULLSPEED2: - case DWC3_DSTS_FULLSPEED1: + case DWC3_DSTS_FULLSPEED: dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64); dwc->gadget.ep0->maxpacket = 64; dwc->gadget.speed = USB_SPEED_FULL; diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 41ab61f9b6e0..49d685ad0da9 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -1694,9 +1694,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) value = min(w_length, (u16) 1); break; - /* function drivers must handle get/set altsetting; if there's - * no get() method, we know only altsetting zero works. - */ + /* function drivers must handle get/set altsetting */ case USB_REQ_SET_INTERFACE: if (ctrl->bRequestType != USB_RECIP_INTERFACE) goto unknown; @@ -1705,7 +1703,13 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) f = cdev->config->interface[intf]; if (!f) break; - if (w_value && !f->set_alt) + + /* + * If there's no get_alt() method, we know only altsetting zero + * works. There is no need to check if set_alt() is not NULL + * as we check this in usb_add_function(). + */ + if (w_value && !f->get_alt) break; value = f->set_alt(f, w_index, w_value); if (value == USB_GADGET_DELAYED_STATUS) { @@ -2143,7 +2147,7 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, cdev->os_desc_req->buf = kmalloc(4096, GFP_KERNEL); if (!cdev->os_desc_req->buf) { ret = -ENOMEM; - kfree(cdev->os_desc_req); + usb_ep_free_request(ep0, cdev->os_desc_req); goto end; } cdev->os_desc_req->context = cdev; diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index aab3fc1dbb94..e6a17455adac 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1806,7 +1806,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) unsigned long flags; spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { + while (count--) { /* pending requests get nuked */ if (likely(ep->ep)) usb_ep_disable(ep->ep); @@ -1817,7 +1817,7 @@ static void ffs_func_eps_disable(struct ffs_function *func) __ffs_epfile_read_buffer_free(epfile); ++epfile; } - } while (--count); + } spin_unlock_irqrestore(&func->ffs->eps_lock, flags); } @@ -1831,7 +1831,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) int ret = 0; spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { + while(count--) { struct usb_endpoint_descriptor *ds; int desc_idx; @@ -1867,7 +1867,7 @@ static int ffs_func_eps_enable(struct ffs_function *func) ++ep; ++epfile; - } while (--count); + } spin_unlock_irqrestore(&func->ffs->eps_lock, flags); return ret; @@ -2091,8 +2091,8 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, case FFS_STRING: /* - * Strings are indexed from 1 (0 is magic ;) reserved - * for languages list or some such) + * Strings are indexed from 1 (0 is reserved + * for languages list) */ if (*valuep > helper->ffs->strings_count) helper->ffs->strings_count = *valuep; @@ -2252,7 +2252,7 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, if (len < sizeof(*d) || d->bFirstInterfaceNumber >= ffs->interfaces_count || - !d->Reserved1) + d->Reserved1) return -EINVAL; for (i = 0; i < ARRAY_SIZE(d->Reserved2); ++i) if (d->Reserved2[i]) @@ -2269,6 +2269,8 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, if (len < sizeof(*d) || h->interface >= ffs->interfaces_count) return -EINVAL; length = le32_to_cpu(d->dwSize); + if (len < length) + return -EINVAL; type = le32_to_cpu(d->dwPropertyDataType); if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) { @@ -2277,6 +2279,11 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, return -EINVAL; } pnl = le16_to_cpu(d->wPropertyNameLength); + if (length < 14 + pnl) { + pr_vdebug("invalid os descriptor length: %d pnl:%d (descriptor %d)\n", + length, pnl, type); + return -EINVAL; + } pdl = le32_to_cpu(*(u32 *)((u8 *)data + 10 + pnl)); if (length != 14 + pnl + pdl) { pr_vdebug("invalid os descriptor length: %d pnl:%d pdl:%d (descriptor %d)\n", @@ -2363,6 +2370,9 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, } } if (flags & (1 << i)) { + if (len < 4) { + goto error; + } os_descs_count = get_unaligned_le32(data); data += 4; len -= 4; @@ -2435,7 +2445,8 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, ENTER(); - if (unlikely(get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || + if (unlikely(len < 16 || + get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len)) goto error; str_count = get_unaligned_le32(data + 8); @@ -3448,12 +3459,12 @@ static void ffs_func_unbind(struct usb_configuration *c, /* cleanup after autoconfig */ spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { + while (count--) { if (ep->ep && ep->req) usb_ep_free_request(ep->ep, ep->req); ep->req = NULL; ++ep; - } while (--count); + } spin_unlock_irqrestore(&func->ffs->eps_lock, flags); kfree(func->eps); func->eps = NULL; @@ -3666,6 +3677,7 @@ static void ffs_closed(struct ffs_data *ffs) { struct ffs_dev *ffs_obj; struct f_fs_opts *opts; + struct config_item *ci; ENTER(); ffs_dev_lock(); @@ -3686,11 +3698,14 @@ static void ffs_closed(struct ffs_data *ffs) goto done; if (opts->no_configfs || !opts->func_inst.group.cg_item.ci_parent - || !atomic_read(&opts->func_inst.group.cg_item.ci_kref.refcount)) + || !kref_read(&opts->func_inst.group.cg_item.ci_kref)) goto done; - unregister_gadget_item(ffs_obj->opts-> - func_inst.group.cg_item.ci_parent->ci_parent); + ci = opts->func_inst.group.cg_item.ci_parent->ci_parent; + ffs_dev_unlock(); + + unregister_gadget_item(ci); + return; done: ffs_dev_unlock(); } diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 3151d2a0fe59..5f8139b8e601 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -593,7 +593,7 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) } status = usb_ep_enable(hidg->out_ep); if (status < 0) { - ERROR(cdev, "Enable IN endpoint FAILED!\n"); + ERROR(cdev, "Enable OUT endpoint FAILED!\n"); goto fail; } hidg->out_ep->driver_data = hidg; diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index e8f4102d19df..6bde4396927c 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -1126,7 +1126,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* data and/or status stage for control request */ } else if (dev->state == STATE_DEV_SETUP) { - /* IN DATA+STATUS caller makes len <= wLength */ + len = min_t(size_t, len, dev->setup_wLength); if (dev->setup_in) { retval = setup_req (dev->gadget->ep0, dev->req, len); if (retval == 0) { @@ -1734,10 +1734,12 @@ static struct usb_gadget_driver gadgetfs_driver = { * such as configuration notifications. */ -static int is_valid_config (struct usb_config_descriptor *config) +static int is_valid_config(struct usb_config_descriptor *config, + unsigned int total) { return config->bDescriptorType == USB_DT_CONFIG && config->bLength == USB_DT_CONFIG_SIZE + && total >= USB_DT_CONFIG_SIZE && config->bConfigurationValue != 0 && (config->bmAttributes & USB_CONFIG_ATT_ONE) != 0 && (config->bmAttributes & USB_CONFIG_ATT_WAKEUP) == 0; @@ -1762,7 +1764,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) } spin_unlock_irq(&dev->lock); - if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) + if ((len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4)) || + (len > PAGE_SIZE * 4)) return -EINVAL; /* we might need to change message format someday */ @@ -1786,7 +1789,8 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* full or low speed config */ dev->config = (void *) kbuf; total = le16_to_cpu(dev->config->wTotalLength); - if (!is_valid_config (dev->config) || total >= length) + if (!is_valid_config(dev->config, total) || + total > length - USB_DT_DEVICE_SIZE) goto fail; kbuf += total; length -= total; @@ -1795,10 +1799,13 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) if (kbuf [1] == USB_DT_CONFIG) { dev->hs_config = (void *) kbuf; total = le16_to_cpu(dev->hs_config->wTotalLength); - if (!is_valid_config (dev->hs_config) || total >= length) + if (!is_valid_config(dev->hs_config, total) || + total > length - USB_DT_DEVICE_SIZE) goto fail; kbuf += total; length -= total; + } else { + dev->hs_config = NULL; } /* could support multiple configs, using another encoding! */ @@ -1811,7 +1818,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) || dev->dev->bDescriptorType != USB_DT_DEVICE || dev->dev->bNumConfigurations != 1) goto fail; - dev->dev->bNumConfigurations = 1; dev->dev->bcdUSB = cpu_to_le16 (0x0200); /* triggers gadgetfs_bind(); then we can enumerate. */ diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index f3212db9bc37..12c7687216e6 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1978,7 +1978,8 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, dev_err(&pdev->dev, "of_probe: name error(%d)\n", ret); goto err; } - ep->ep.name = kasprintf(GFP_KERNEL, "ep%d", ep->index); + sprintf(ep->name, "ep%d", ep->index); + ep->ep.name = ep->name; ep->ep_regs = udc->regs + USBA_EPT_BASE(i); ep->dma_regs = udc->regs + USBA_DMA_BASE(i); diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index 3e1c9d589dfa..b03b2ebfc53a 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h @@ -280,6 +280,7 @@ struct usba_ep { void __iomem *ep_regs; void __iomem *dma_regs; void __iomem *fifo; + char name[8]; struct usb_ep ep; struct usba_udc *udc; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 9483489080f6..0402177f93cd 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1317,7 +1317,11 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver) if (!ret) break; } - if (!ret && !udc->driver) + if (ret) + ret = -ENODEV; + else if (udc->driver) + ret = -EBUSY; + else goto found; } else { list_for_each_entry(udc, &udc_list, list) { diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 02b14e91ae6c..c60abe3a68f9 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -330,7 +330,7 @@ static void nuke(struct dummy *dum, struct dummy_ep *ep) /* caller must hold lock */ static void stop_activity(struct dummy *dum) { - struct dummy_ep *ep; + int i; /* prevent any more requests */ dum->address = 0; @@ -338,8 +338,8 @@ static void stop_activity(struct dummy *dum) /* The timer is left running so that outstanding URBs can fail */ /* nuke any pending requests first, so driver i/o is quiesced */ - list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list) - nuke(dum, ep); + for (i = 0; i < DUMMY_ENDPOINTS; ++i) + nuke(dum, &dum->ep[i]); /* driver now does any non-usb quiescing necessary */ } diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index be9e63836881..414e3c376dbb 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -43,7 +43,6 @@ struct at91_usbh_data { struct gpio_desc *overcurrent_pin[AT91_MAX_USBH_PORTS]; u8 ports; /* number of ports on root hub */ u8 overcurrent_supported; - u8 vbus_pin_active_low[AT91_MAX_USBH_PORTS]; u8 overcurrent_status[AT91_MAX_USBH_PORTS]; u8 overcurrent_changed[AT91_MAX_USBH_PORTS]; }; @@ -266,8 +265,7 @@ static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int if (!valid_port(port)) return; - gpiod_set_value(pdata->vbus_pin[port], - pdata->vbus_pin_active_low[port] ^ enable); + gpiod_set_value(pdata->vbus_pin[port], enable); } static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) @@ -275,8 +273,7 @@ static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port) if (!valid_port(port)) return -EINVAL; - return gpiod_get_value(pdata->vbus_pin[port]) ^ - pdata->vbus_pin_active_low[port]; + return gpiod_get_value(pdata->vbus_pin[port]); } /* @@ -533,18 +530,17 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) pdata->ports = ports; at91_for_each_port(i) { - pdata->vbus_pin[i] = devm_gpiod_get_optional(&pdev->dev, - "atmel,vbus-gpio", - GPIOD_IN); + if (i >= pdata->ports) + break; + + pdata->vbus_pin[i] = + devm_gpiod_get_index_optional(&pdev->dev, "atmel,vbus", + i, GPIOD_OUT_HIGH); if (IS_ERR(pdata->vbus_pin[i])) { err = PTR_ERR(pdata->vbus_pin[i]); dev_err(&pdev->dev, "unable to claim gpio \"vbus\": %d\n", err); continue; } - - pdata->vbus_pin_active_low[i] = gpiod_get_value(pdata->vbus_pin[i]); - - ohci_at91_usb_set_power(pdata, i, 1); } at91_for_each_port(i) { @@ -552,8 +548,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev) break; pdata->overcurrent_pin[i] = - devm_gpiod_get_optional(&pdev->dev, - "atmel,oc-gpio", GPIOD_IN); + devm_gpiod_get_index_optional(&pdev->dev, "atmel,oc", + i, GPIOD_IN); if (IS_ERR(pdata->overcurrent_pin[i])) { err = PTR_ERR(pdata->overcurrent_pin[i]); dev_err(&pdev->dev, "unable to claim gpio \"overcurrent\": %d\n", err); diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 321de2e0161b..8414ed2a02de 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -979,6 +979,40 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) xhci->devs[slot_id] = NULL; } +/* + * Free a virt_device structure. + * If the virt_device added a tt_info (a hub) and has children pointing to + * that tt_info, then free the child first. Recursive. + * We can't rely on udev at this point to find child-parent relationships. + */ +void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_id) +{ + struct xhci_virt_device *vdev; + struct list_head *tt_list_head; + struct xhci_tt_bw_info *tt_info, *next; + int i; + + vdev = xhci->devs[slot_id]; + if (!vdev) + return; + + tt_list_head = &(xhci->rh_bw[vdev->real_port - 1].tts); + list_for_each_entry_safe(tt_info, next, tt_list_head, tt_list) { + /* is this a hub device that added a tt_info to the tts list */ + if (tt_info->slot_id == slot_id) { + /* are any devices using this tt_info? */ + for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + vdev = xhci->devs[i]; + if (vdev && (vdev->tt_info == tt_info)) + xhci_free_virt_devices_depth_first( + xhci, i); + } + } + } + /* we are now at a leaf device */ + xhci_free_virt_device(xhci, slot_id); +} + int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, struct usb_device *udev, gfp_t flags) { @@ -1795,7 +1829,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) int size; int i, j, num_ports; - del_timer_sync(&xhci->cmd_timer); + cancel_delayed_work_sync(&xhci->cmd_timer); /* Free the Event Ring Segment Table and the actual Event Ring */ size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); @@ -1828,8 +1862,8 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } } - for (i = 1; i < MAX_HC_SLOTS; ++i) - xhci_free_virt_device(xhci, i); + for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--) + xhci_free_virt_devices_depth_first(xhci, i); dma_pool_destroy(xhci->segment_pool); xhci->segment_pool = NULL; @@ -2342,9 +2376,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) INIT_LIST_HEAD(&xhci->cmd_list); - /* init command timeout timer */ - setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout, - (unsigned long)xhci); + /* init command timeout work */ + INIT_DELAYED_WORK(&xhci->cmd_timer, xhci_handle_command_timeout); + init_completion(&xhci->cmd_ring_stop_completion); page_size = readl(&xhci->op_regs->page_size); xhci_dbg_trace(xhci, trace_xhci_dbg_init, diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 1094ebd2838f..bac961cd24ad 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -579,8 +579,10 @@ static int xhci_mtk_probe(struct platform_device *pdev) goto disable_ldos; irq = platform_get_irq(pdev, 0); - if (irq < 0) + if (irq < 0) { + ret = irq; goto disable_clk; + } /* Initialize dma_mask and coherent_dma_mask to 32-bits */ ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index e96ae80d107e..954abfd5014d 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -165,7 +165,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_CHERRYVIEW_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI)) { + pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI)) { xhci->quirks |= XHCI_PME_STUCK_QUIRK; } if (pdev->vendor == PCI_VENDOR_ID_INTEL && diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index ddfab301e366..e5834dd9bcde 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -165,7 +165,7 @@ static int xhci_plat_probe(struct platform_device *pdev) return -ENODEV; /* Try to set 64-bit DMA first */ - if (WARN_ON(!pdev->dev.dma_mask)) + if (!pdev->dev.dma_mask) /* Platform did not initialize dma_mask */ ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bdf6b13d9b67..e32029a31ca4 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -279,23 +279,76 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) readl(&xhci->dba->doorbell[0]); } -static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) +static bool xhci_mod_cmd_timer(struct xhci_hcd *xhci, unsigned long delay) +{ + return mod_delayed_work(system_wq, &xhci->cmd_timer, delay); +} + +static struct xhci_command *xhci_next_queued_cmd(struct xhci_hcd *xhci) +{ + return list_first_entry_or_null(&xhci->cmd_list, struct xhci_command, + cmd_list); +} + +/* + * Turn all commands on command ring with status set to "aborted" to no-op trbs. + * If there are other commands waiting then restart the ring and kick the timer. + * This must be called with command ring stopped and xhci->lock held. + */ +static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, + struct xhci_command *cur_cmd) +{ + struct xhci_command *i_cmd; + u32 cycle_state; + + /* Turn all aborted commands in list to no-ops, then restart */ + list_for_each_entry(i_cmd, &xhci->cmd_list, cmd_list) { + + if (i_cmd->status != COMP_CMD_ABORT) + continue; + + i_cmd->status = COMP_CMD_STOP; + + xhci_dbg(xhci, "Turn aborted command %p to no-op\n", + i_cmd->command_trb); + /* get cycle state from the original cmd trb */ + cycle_state = le32_to_cpu( + i_cmd->command_trb->generic.field[3]) & TRB_CYCLE; + /* modify the command trb to no-op command */ + i_cmd->command_trb->generic.field[0] = 0; + i_cmd->command_trb->generic.field[1] = 0; + i_cmd->command_trb->generic.field[2] = 0; + i_cmd->command_trb->generic.field[3] = cpu_to_le32( + TRB_TYPE(TRB_CMD_NOOP) | cycle_state); + + /* + * caller waiting for completion is called when command + * completion event is received for these no-op commands + */ + } + + xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; + + /* ring command ring doorbell to restart the command ring */ + if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) && + !(xhci->xhc_state & XHCI_STATE_DYING)) { + xhci->current_cmd = cur_cmd; + xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); + xhci_ring_cmd_db(xhci); + } +} + +/* Must be called with xhci->lock held, releases and aquires lock back */ +static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) { u64 temp_64; int ret; xhci_dbg(xhci, "Abort command ring\n"); - temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); - xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; + reinit_completion(&xhci->cmd_ring_stop_completion); - /* - * Writing the CMD_RING_ABORT bit should cause a cmd completion event, - * however on some host hw the CMD_RING_RUNNING bit is correctly cleared - * but the completion event in never sent. Use the cmd timeout timer to - * handle those cases. Use twice the time to cover the bit polling retry - */ - mod_timer(&xhci->cmd_timer, jiffies + (2 * XHCI_CMD_DEFAULT_TIMEOUT)); + temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); @@ -315,17 +368,30 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) udelay(1000); ret = xhci_handshake(&xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 3 * 1000 * 1000); - if (ret == 0) - return 0; - - xhci_err(xhci, "Stopped the command ring failed, " - "maybe the host is dead\n"); - del_timer(&xhci->cmd_timer); - xhci->xhc_state |= XHCI_STATE_DYING; - xhci_halt(xhci); - return -ESHUTDOWN; + if (ret < 0) { + xhci_err(xhci, "Stopped the command ring failed, " + "maybe the host is dead\n"); + xhci->xhc_state |= XHCI_STATE_DYING; + xhci_halt(xhci); + return -ESHUTDOWN; + } + } + /* + * Writing the CMD_RING_ABORT bit should cause a cmd completion event, + * however on some host hw the CMD_RING_RUNNING bit is correctly cleared + * but the completion event in never sent. Wait 2 secs (arbitrary + * number) to handle those cases after negation of CMD_RING_RUNNING. + */ + spin_unlock_irqrestore(&xhci->lock, flags); + ret = wait_for_completion_timeout(&xhci->cmd_ring_stop_completion, + msecs_to_jiffies(2000)); + spin_lock_irqsave(&xhci->lock, flags); + if (!ret) { + xhci_dbg(xhci, "No stop event for abort, ring start fail?\n"); + xhci_cleanup_command_queue(xhci); + } else { + xhci_handle_stopped_cmd_ring(xhci, xhci_next_queued_cmd(xhci)); } - return 0; } @@ -847,17 +913,6 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); ep->stop_cmds_pending--; - if (xhci->xhc_state & XHCI_STATE_REMOVING) { - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } - if (xhci->xhc_state & XHCI_STATE_DYING) { - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Stop EP timer ran, but another timer marked " - "xHCI as DYING, exiting."); - spin_unlock_irqrestore(&xhci->lock, flags); - return; - } if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Stop EP timer ran, but no command pending, " @@ -1207,101 +1262,62 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci) xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT); } -/* - * Turn all commands on command ring with status set to "aborted" to no-op trbs. - * If there are other commands waiting then restart the ring and kick the timer. - * This must be called with command ring stopped and xhci->lock held. - */ -static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, - struct xhci_command *cur_cmd) -{ - struct xhci_command *i_cmd, *tmp_cmd; - u32 cycle_state; - - /* Turn all aborted commands in list to no-ops, then restart */ - list_for_each_entry_safe(i_cmd, tmp_cmd, &xhci->cmd_list, - cmd_list) { - - if (i_cmd->status != COMP_CMD_ABORT) - continue; - - i_cmd->status = COMP_CMD_STOP; - - xhci_dbg(xhci, "Turn aborted command %p to no-op\n", - i_cmd->command_trb); - /* get cycle state from the original cmd trb */ - cycle_state = le32_to_cpu( - i_cmd->command_trb->generic.field[3]) & TRB_CYCLE; - /* modify the command trb to no-op command */ - i_cmd->command_trb->generic.field[0] = 0; - i_cmd->command_trb->generic.field[1] = 0; - i_cmd->command_trb->generic.field[2] = 0; - i_cmd->command_trb->generic.field[3] = cpu_to_le32( - TRB_TYPE(TRB_CMD_NOOP) | cycle_state); - - /* - * caller waiting for completion is called when command - * completion event is received for these no-op commands - */ - } - - xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; - - /* ring command ring doorbell to restart the command ring */ - if ((xhci->cmd_ring->dequeue != xhci->cmd_ring->enqueue) && - !(xhci->xhc_state & XHCI_STATE_DYING)) { - xhci->current_cmd = cur_cmd; - mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); - xhci_ring_cmd_db(xhci); - } - return; -} - - -void xhci_handle_command_timeout(unsigned long data) +void xhci_handle_command_timeout(struct work_struct *work) { struct xhci_hcd *xhci; int ret; unsigned long flags; u64 hw_ring_state; - bool second_timeout = false; - xhci = (struct xhci_hcd *) data; - /* mark this command to be cancelled */ + xhci = container_of(to_delayed_work(work), struct xhci_hcd, cmd_timer); + spin_lock_irqsave(&xhci->lock, flags); - if (xhci->current_cmd) { - if (xhci->current_cmd->status == COMP_CMD_ABORT) - second_timeout = true; - xhci->current_cmd->status = COMP_CMD_ABORT; + + /* + * If timeout work is pending, or current_cmd is NULL, it means we + * raced with command completion. Command is handled so just return. + */ + if (!xhci->current_cmd || delayed_work_pending(&xhci->cmd_timer)) { + spin_unlock_irqrestore(&xhci->lock, flags); + return; } + /* mark this command to be cancelled */ + xhci->current_cmd->status = COMP_CMD_ABORT; /* Make sure command ring is running before aborting it */ hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); if ((xhci->cmd_ring_state & CMD_RING_STATE_RUNNING) && (hw_ring_state & CMD_RING_RUNNING)) { - spin_unlock_irqrestore(&xhci->lock, flags); + /* Prevent new doorbell, and start command abort */ + xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; xhci_dbg(xhci, "Command timeout\n"); - ret = xhci_abort_cmd_ring(xhci); + ret = xhci_abort_cmd_ring(xhci, flags); if (unlikely(ret == -ESHUTDOWN)) { xhci_err(xhci, "Abort command ring failed\n"); xhci_cleanup_command_queue(xhci); + spin_unlock_irqrestore(&xhci->lock, flags); usb_hc_died(xhci_to_hcd(xhci)->primary_hcd); xhci_dbg(xhci, "xHCI host controller is dead.\n"); + + return; } - return; + + goto time_out_completed; } - /* command ring failed to restart, or host removed. Bail out */ - if (second_timeout || xhci->xhc_state & XHCI_STATE_REMOVING) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "command timed out twice, ring start fail?\n"); + /* host removed. Bail out */ + if (xhci->xhc_state & XHCI_STATE_REMOVING) { + xhci_dbg(xhci, "host removed, ring start fail?\n"); xhci_cleanup_command_queue(xhci); - return; + + goto time_out_completed; } /* command timeout on stopped ring, ring can't be aborted */ xhci_dbg(xhci, "Command timeout on stopped ring\n"); xhci_handle_stopped_cmd_ring(xhci, xhci->current_cmd); + +time_out_completed: spin_unlock_irqrestore(&xhci->lock, flags); return; } @@ -1333,7 +1349,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list); - del_timer(&xhci->cmd_timer); + cancel_delayed_work(&xhci->cmd_timer); trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); @@ -1341,7 +1357,7 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, /* If CMD ring stopped we own the trbs between enqueue and dequeue */ if (cmd_comp_code == COMP_CMD_STOP) { - xhci_handle_stopped_cmd_ring(xhci, cmd); + complete_all(&xhci->cmd_ring_stop_completion); return; } @@ -1359,8 +1375,11 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, */ if (cmd_comp_code == COMP_CMD_ABORT) { xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; - if (cmd->status == COMP_CMD_ABORT) + if (cmd->status == COMP_CMD_ABORT) { + if (xhci->current_cmd == cmd) + xhci->current_cmd = NULL; goto event_handled; + } } cmd_type = TRB_FIELD_TO_TYPE(le32_to_cpu(cmd_trb->generic.field[3])); @@ -1421,7 +1440,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, if (cmd->cmd_list.next != &xhci->cmd_list) { xhci->current_cmd = list_entry(cmd->cmd_list.next, struct xhci_command, cmd_list); - mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); + xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); + } else if (xhci->current_cmd == cmd) { + xhci->current_cmd = NULL; } event_handled: @@ -1939,8 +1960,9 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, struct xhci_ep_ctx *ep_ctx; u32 trb_comp_code; u32 remaining, requested; - bool on_data_stage; + u32 trb_type; + trb_type = TRB_FIELD_TO_TYPE(le32_to_cpu(ep_trb->generic.field[3])); slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; ep_index = TRB_TO_EP_ID(le32_to_cpu(event->flags)) - 1; @@ -1950,14 +1972,11 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, requested = td->urb->transfer_buffer_length; remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); - /* not setup (dequeue), or status stage means we are at data stage */ - on_data_stage = (ep_trb != ep_ring->dequeue && ep_trb != td->last_trb); - switch (trb_comp_code) { case COMP_SUCCESS: - if (ep_trb != td->last_trb) { + if (trb_type != TRB_STATUS) { xhci_warn(xhci, "WARN: Success on ctrl %s TRB without IOC set?\n", - on_data_stage ? "data" : "setup"); + (trb_type == TRB_DATA) ? "data" : "setup"); *status = -ESHUTDOWN; break; } @@ -1967,15 +1986,25 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, *status = 0; break; case COMP_STOP_SHORT: - if (on_data_stage) + if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = remaining; else xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); goto finish_td; case COMP_STOP: - if (on_data_stage) + switch (trb_type) { + case TRB_SETUP: + td->urb->actual_length = 0; + goto finish_td; + case TRB_DATA: + case TRB_NORMAL: td->urb->actual_length = requested - remaining; - goto finish_td; + goto finish_td; + default: + xhci_warn(xhci, "WARN: unexpected TRB Type %d\n", + trb_type); + goto finish_td; + } case COMP_STOP_INVAL: goto finish_td; default: @@ -1987,7 +2016,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, /* else fall through */ case COMP_STALL: /* Did we transfer part of the data (middle) phase? */ - if (on_data_stage) + if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = requested - remaining; else if (!td->urb_length_set) td->urb->actual_length = 0; @@ -1995,14 +2024,15 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, } /* stopped at setup stage, no data transferred */ - if (ep_trb == ep_ring->dequeue) + if (trb_type == TRB_SETUP) goto finish_td; /* * if on data stage then update the actual_length of the URB and flag it * as set, so it won't be overwritten in the event for the last TRB. */ - if (on_data_stage) { + if (trb_type == TRB_DATA || + trb_type == TRB_NORMAL) { td->urb_length_set = true; td->urb->actual_length = requested - remaining; xhci_dbg(xhci, "Waiting for status stage event\n"); @@ -3790,9 +3820,9 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, /* if there are no other commands queued we start the timeout timer */ if (xhci->cmd_list.next == &cmd->cmd_list && - !timer_pending(&xhci->cmd_timer)) { + !delayed_work_pending(&xhci->cmd_timer)) { xhci->current_cmd = cmd; - mod_timer(&xhci->cmd_timer, jiffies + XHCI_CMD_DEFAULT_TIMEOUT); + xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); } queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 1cd56417cbec..9a0ec116654a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -1534,19 +1534,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci_urb_free_priv(urb_priv); return ret; } - if ((xhci->xhc_state & XHCI_STATE_DYING) || - (xhci->xhc_state & XHCI_STATE_HALTED)) { - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Ep 0x%x: URB %p to be canceled on " - "non-responsive xHCI host.", - urb->ep->desc.bEndpointAddress, urb); - /* Let the stop endpoint command watchdog timer (which set this - * state) finish cleaning up the endpoint TD lists. We must - * have caught it in the middle of dropping a lock and giving - * back an URB. - */ - goto done; - } ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index]; @@ -3787,8 +3774,10 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, mutex_lock(&xhci->mutex); - if (xhci->xhc_state) /* dying, removing or halted */ + if (xhci->xhc_state) { /* dying, removing or halted */ + ret = -ESHUTDOWN; goto out; + } if (!udev->slot_id) { xhci_dbg_trace(xhci, trace_xhci_dbg_address, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 8ccc11a974b8..2d7b6374b58d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1568,7 +1568,8 @@ struct xhci_hcd { #define CMD_RING_STATE_STOPPED (1 << 2) struct list_head cmd_list; unsigned int cmd_ring_reserved_trbs; - struct timer_list cmd_timer; + struct delayed_work cmd_timer; + struct completion cmd_ring_stop_completion; struct xhci_command *current_cmd; struct xhci_ring *event_ring; struct xhci_erst erst; @@ -1934,7 +1935,7 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, struct xhci_dequeue_state *deq_state); void xhci_stop_endpoint_command_watchdog(unsigned long arg); -void xhci_handle_command_timeout(unsigned long data); +void xhci_handle_command_timeout(struct work_struct *work); void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, unsigned int ep_index, unsigned int stream_id); diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c index 33ff49c4cea4..46847340b819 100644 --- a/drivers/usb/mon/mon_main.c +++ b/drivers/usb/mon/mon_main.c @@ -409,7 +409,7 @@ static void __exit mon_exit(void) printk(KERN_ERR TAG ": Outstanding opens (%d) on usb%d, leaking...\n", mbus->nreaders, mbus->u_bus->busnum); - atomic_set(&mbus->ref.refcount, 2); /* Force leak */ + kref_get(&mbus->ref); /* Force leak */ } mon_dissolve(mbus, mbus->u_bus); diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 310238c6b5cd..896798071817 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -469,6 +469,7 @@ static const struct musb_platform_ops bfin_ops = { .init = bfin_musb_init, .exit = bfin_musb_exit, + .fifo_offset = bfin_fifo_offset, .readb = bfin_readb, .writeb = bfin_writeb, .readw = bfin_readw, diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 9e226468a13e..772f15821242 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -594,11 +594,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, | MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies + msecs_to_jiffies(USB_RESUME_TIMEOUT); - musb->need_finish_resume = 1; - musb->xceiv->otg->state = OTG_STATE_A_HOST; musb->is_active = 1; musb_host_resume_root_hub(musb); + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(USB_RESUME_TIMEOUT)); break; case OTG_STATE_B_WAIT_ACON: musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL; @@ -1925,6 +1925,14 @@ static void musb_pm_runtime_check_session(struct musb *musb) static void musb_irq_work(struct work_struct *data) { struct musb *musb = container_of(data, struct musb, irq_work.work); + int error; + + error = pm_runtime_get_sync(musb->controller); + if (error < 0) { + dev_err(musb->controller, "Could not enable: %i\n", error); + + return; + } musb_pm_runtime_check_session(musb); @@ -1932,6 +1940,9 @@ static void musb_irq_work(struct work_struct *data) musb->xceiv_old_state = musb->xceiv->otg->state; sysfs_notify(&musb->controller->kobj, NULL, "mode"); } + + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); } static void musb_recover_from_babble(struct musb *musb) @@ -2050,6 +2061,7 @@ struct musb_pending_work { struct list_head node; }; +#ifdef CONFIG_PM /* * Called from musb_runtime_resume(), musb_resume(), and * musb_queue_resume_work(). Callers must take musb->lock. @@ -2077,6 +2089,7 @@ static int musb_run_resume_work(struct musb *musb) return error; } +#endif /* * Called to run work if device is active or else queue the work to happen @@ -2708,11 +2721,6 @@ static int musb_resume(struct device *dev) mask = MUSB_DEVCTL_BDEVICE | MUSB_DEVCTL_FSDEV | MUSB_DEVCTL_LSDEV; if ((devctl & mask) != (musb->context.devctl & mask)) musb->port1_status = 0; - if (musb->need_finish_resume) { - musb->need_finish_resume = 0; - schedule_delayed_work(&musb->finish_resume_work, - msecs_to_jiffies(USB_RESUME_TIMEOUT)); - } /* * The USB HUB code expects the device to be in RPM_ACTIVE once it came @@ -2764,12 +2772,6 @@ static int musb_runtime_resume(struct device *dev) musb_restore_context(musb); - if (musb->need_finish_resume) { - musb->need_finish_resume = 0; - schedule_delayed_work(&musb->finish_resume_work, - msecs_to_jiffies(USB_RESUME_TIMEOUT)); - } - spin_lock_irqsave(&musb->lock, flags); error = musb_run_resume_work(musb); if (error) diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index a611e2f67bdc..ce5a18c98c6d 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -216,6 +216,7 @@ struct musb_platform_ops { void (*pre_root_reset_end)(struct musb *musb); void (*post_root_reset_end)(struct musb *musb); int (*phy_callback)(enum musb_vbus_id_status status); + void (*clear_ep_rxintr)(struct musb *musb, int epnum); }; /* @@ -409,7 +410,6 @@ struct musb { /* is_suspended means USB B_PERIPHERAL suspend */ unsigned is_suspended:1; - unsigned need_finish_resume :1; /* may_wakeup means remote wakeup is enabled */ unsigned may_wakeup:1; @@ -626,6 +626,12 @@ static inline void musb_platform_post_root_reset_end(struct musb *musb) musb->ops->post_root_reset_end(musb); } +static inline void musb_platform_clear_ep_rxintr(struct musb *musb, int epnum) +{ + if (musb->ops->clear_ep_rxintr) + musb->ops->clear_ep_rxintr(musb, epnum); +} + /* * gets the "dr_mode" property from DT and converts it into musb_mode * if the property is not found or not recognized returns MUSB_OTG diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 4fef50e5c8c1..dd70c88419d2 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -114,6 +114,7 @@ static int musb_regdump_show(struct seq_file *s, void *unused) unsigned i; seq_printf(s, "MUSB (M)HDRC Register Dump\n"); + pm_runtime_get_sync(musb->controller); for (i = 0; i < ARRAY_SIZE(musb_regmap); i++) { switch (musb_regmap[i].size) { @@ -132,6 +133,8 @@ static int musb_regdump_show(struct seq_file *s, void *unused) } } + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return 0; } @@ -145,7 +148,10 @@ static int musb_test_mode_show(struct seq_file *s, void *unused) struct musb *musb = s->private; unsigned test; + pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); if (test & MUSB_TEST_FORCE_HOST) seq_printf(s, "force host\n"); @@ -194,11 +200,12 @@ static ssize_t musb_test_mode_write(struct file *file, u8 test; char buf[18]; + pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); if (test) { dev_err(musb->controller, "Error: test mode is already set. " "Please do USB Bus Reset to start a new test.\n"); - return count; + goto ret; } memset(buf, 0x00, sizeof(buf)); @@ -234,6 +241,9 @@ static ssize_t musb_test_mode_write(struct file *file, musb_writeb(musb->mregs, MUSB_TESTMODE, test); +ret: + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return count; } @@ -254,8 +264,13 @@ static int musb_softconnect_show(struct seq_file *s, void *unused) switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: case OTG_STATE_A_WAIT_BCON: + pm_runtime_get_sync(musb->controller); + reg = musb_readb(musb->mregs, MUSB_DEVCTL); connect = reg & MUSB_DEVCTL_SESSION ? 1 : 0; + + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); break; default: connect = -1; @@ -284,6 +299,7 @@ static ssize_t musb_softconnect_write(struct file *file, if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; + pm_runtime_get_sync(musb->controller); if (!strncmp(buf, "0", 1)) { switch (musb->xceiv->otg->state) { case OTG_STATE_A_HOST: @@ -314,6 +330,8 @@ static ssize_t musb_softconnect_write(struct file *file, } } + pm_runtime_mark_last_busy(musb->controller); + pm_runtime_put_autosuspend(musb->controller); return count; } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index feae1561b9ab..9f125e179acd 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -267,6 +267,17 @@ static void otg_timer(unsigned long _musb) pm_runtime_put_autosuspend(dev); } +void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) +{ + u32 epintr; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + const struct dsps_musb_wrapper *wrp = glue->wrp; + + /* musb->lock might already been held */ + epintr = (1 << epnum) << wrp->rxep_shift; + musb_writel(musb->ctrl_base, wrp->epintr_status, epintr); +} + static irqreturn_t dsps_interrupt(int irq, void *hci) { struct musb *musb = hci; @@ -622,6 +633,7 @@ static struct musb_platform_ops dsps_ops = { .set_mode = dsps_musb_set_mode, .recover = dsps_musb_recover, + .clear_ep_rxintr = dsps_musb_clear_ep_rxintr, }; static u64 musb_dmamask = DMA_BIT_MASK(32); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index f6cdbad00dac..ac3a4952abb4 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2374,12 +2374,11 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) int is_in = usb_pipein(urb->pipe); int status = 0; u16 csr; + struct dma_channel *dma = NULL; musb_ep_select(regs, hw_end); if (is_dma_capable()) { - struct dma_channel *dma; - dma = is_in ? ep->rx_channel : ep->tx_channel; if (dma) { status = ep->musb->dma_controller->channel_abort(dma); @@ -2395,10 +2394,9 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh) /* giveback saves bulk toggle */ csr = musb_h_flush_rxfifo(ep, 0); - /* REVISIT we still get an irq; should likely clear the - * endpoint's irq status here to avoid bogus irqs. - * clearing that status is platform-specific... - */ + /* clear the endpoint's irq status here to avoid bogus irqs */ + if (is_dma_capable() && dma) + musb_platform_clear_ep_rxintr(musb, ep->epnum); } else if (ep->epnum) { musb_h_tx_flush_fifo(ep); csr = musb_readw(epio, MUSB_TXCSR); diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h index f7b13fd25257..a3dcbd55e436 100644 --- a/drivers/usb/musb/musbhsdma.h +++ b/drivers/usb/musb/musbhsdma.h @@ -157,5 +157,5 @@ struct musb_dma_controller { void __iomem *base; u8 channel_count; u8 used_channels; - u8 irq; + int irq; }; diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 2597b83a8ae2..95aa5233726c 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -95,6 +95,7 @@ struct ch341_private { unsigned baud_rate; /* set baud rate */ u8 line_control; /* set line control value RTS/DTR */ u8 line_status; /* active status of modem control inputs */ + u8 lcr; }; static void ch341_set_termios(struct tty_struct *tty, @@ -112,6 +113,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request, r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, value, index, NULL, 0, DEFAULT_TIMEOUT); + if (r < 0) + dev_err(&dev->dev, "failed to send control message: %d\n", r); return r; } @@ -129,11 +132,24 @@ static int ch341_control_in(struct usb_device *dev, r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, value, index, buf, bufsize, DEFAULT_TIMEOUT); - return r; + if (r < bufsize) { + if (r >= 0) { + dev_err(&dev->dev, + "short control message received (%d < %u)\n", + r, bufsize); + r = -EIO; + } + + dev_err(&dev->dev, "failed to receive control message: %d\n", + r); + return r; + } + + return 0; } -static int ch341_init_set_baudrate(struct usb_device *dev, - struct ch341_private *priv, unsigned ctrl) +static int ch341_set_baudrate_lcr(struct usb_device *dev, + struct ch341_private *priv, u8 lcr) { short a; int r; @@ -156,9 +172,19 @@ static int ch341_init_set_baudrate(struct usb_device *dev, factor = 0x10000 - factor; a = (factor & 0xff00) | divisor; - /* 0x9c is "enable SFR_UART Control register and timer" */ - r = ch341_control_out(dev, CH341_REQ_SERIAL_INIT, - 0x9c | (ctrl << 8), a | 0x80); + /* + * CH341A buffers data until a full endpoint-size packet (32 bytes) + * has been received unless bit 7 is set. + */ + a |= BIT(7); + + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a); + if (r) + return r; + + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, lcr); + if (r) + return r; return r; } @@ -170,9 +196,9 @@ static int ch341_set_handshake(struct usb_device *dev, u8 control) static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) { + const unsigned int size = 2; char *buffer; int r; - const unsigned size = 8; unsigned long flags; buffer = kmalloc(size, GFP_KERNEL); @@ -183,14 +209,9 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - /* setup the private status if available */ - if (r == 2) { - r = 0; - spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; - spin_unlock_irqrestore(&priv->lock, flags); - } else - r = -EPROTO; + spin_lock_irqsave(&priv->lock, flags); + priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; + spin_unlock_irqrestore(&priv->lock, flags); out: kfree(buffer); return r; @@ -200,9 +221,9 @@ out: kfree(buffer); static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) { + const unsigned int size = 2; char *buffer; int r; - const unsigned size = 8; buffer = kmalloc(size, GFP_KERNEL); if (!buffer) @@ -232,7 +253,7 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - r = ch341_init_set_baudrate(dev, priv, 0); + r = ch341_set_baudrate_lcr(dev, priv, priv->lcr); if (r < 0) goto out; @@ -258,7 +279,6 @@ static int ch341_port_probe(struct usb_serial_port *port) spin_lock_init(&priv->lock); priv->baud_rate = DEFAULT_BAUD_RATE; - priv->line_control = CH341_BIT_RTS | CH341_BIT_DTR; r = ch341_configure(port->serial->dev, priv); if (r < 0) @@ -320,7 +340,7 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) r = ch341_configure(serial->dev, priv); if (r) - goto out; + return r; if (tty) ch341_set_termios(tty, port, NULL); @@ -330,12 +350,19 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) if (r) { dev_err(&port->dev, "%s - failed to submit interrupt urb: %d\n", __func__, r); - goto out; + return r; } r = usb_serial_generic_open(tty, port); + if (r) + goto err_kill_interrupt_urb; + + return 0; + +err_kill_interrupt_urb: + usb_kill_urb(port->interrupt_in_urb); -out: return r; + return r; } /* Old_termios contains the original termios settings and @@ -356,7 +383,6 @@ static void ch341_set_termios(struct tty_struct *tty, baud_rate = tty_get_baud_rate(tty); - priv->baud_rate = baud_rate; ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; switch (C_CSIZE(tty)) { @@ -386,22 +412,25 @@ static void ch341_set_termios(struct tty_struct *tty, ctrl |= CH341_LCR_STOP_BITS_2; if (baud_rate) { - spin_lock_irqsave(&priv->lock, flags); - priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); - spin_unlock_irqrestore(&priv->lock, flags); - r = ch341_init_set_baudrate(port->serial->dev, priv, ctrl); + priv->baud_rate = baud_rate; + + r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl); if (r < 0 && old_termios) { priv->baud_rate = tty_termios_baud_rate(old_termios); tty_termios_copy_hw(&tty->termios, old_termios); + } else if (r == 0) { + priv->lcr = ctrl; } - } else { - spin_lock_irqsave(&priv->lock, flags); - priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); - spin_unlock_irqrestore(&priv->lock, flags); } - ch341_set_handshake(port->serial->dev, priv->line_control); + spin_lock_irqsave(&priv->lock, flags); + if (C_BAUD(tty) == B0) + priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); + else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) + priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); + spin_unlock_irqrestore(&priv->lock, flags); + ch341_set_handshake(port->serial->dev, priv->line_control); } static void ch341_break_ctl(struct tty_struct *tty, int break_state) @@ -576,14 +605,23 @@ static int ch341_tiocmget(struct tty_struct *tty) static int ch341_reset_resume(struct usb_serial *serial) { - struct ch341_private *priv; - - priv = usb_get_serial_port_data(serial->port[0]); + struct usb_serial_port *port = serial->port[0]; + struct ch341_private *priv = usb_get_serial_port_data(port); + int ret; /* reconfigure ch341 serial port after bus-reset */ ch341_configure(serial->dev, priv); - return 0; + if (tty_port_initialized(&port->port)) { + ret = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); + if (ret) { + dev_err(&port->dev, "failed to submit interrupt urb: %d\n", + ret); + return ret; + } + } + + return usb_serial_generic_resume(serial); } static struct usb_serial_driver ch341_device = { diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 5f17a3b9916d..80260b08398b 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -50,6 +50,7 @@ #define CYBERJACK_PRODUCT_ID 0x0100 /* Function prototypes */ +static int cyberjack_attach(struct usb_serial *serial); static int cyberjack_port_probe(struct usb_serial_port *port); static int cyberjack_port_remove(struct usb_serial_port *port); static int cyberjack_open(struct tty_struct *tty, @@ -77,6 +78,7 @@ static struct usb_serial_driver cyberjack_device = { .description = "Reiner SCT Cyberjack USB card reader", .id_table = id_table, .num_ports = 1, + .attach = cyberjack_attach, .port_probe = cyberjack_port_probe, .port_remove = cyberjack_port_remove, .open = cyberjack_open, @@ -100,6 +102,14 @@ struct cyberjack_private { short wrsent; /* Data already sent */ }; +static int cyberjack_attach(struct usb_serial *serial) +{ + if (serial->num_bulk_out < serial->num_ports) + return -ENODEV; + + return 0; +} + static int cyberjack_port_probe(struct usb_serial_port *port) { struct cyberjack_private *priv; diff --git a/drivers/usb/serial/f81534.c b/drivers/usb/serial/f81534.c index 8282a6a18fee..22f23a429a95 100644 --- a/drivers/usb/serial/f81534.c +++ b/drivers/usb/serial/f81534.c @@ -1237,6 +1237,7 @@ static int f81534_attach(struct usb_serial *serial) static int f81534_port_probe(struct usb_serial_port *port) { struct f81534_port_private *port_priv; + int ret; port_priv = devm_kzalloc(&port->dev, sizeof(*port_priv), GFP_KERNEL); if (!port_priv) @@ -1246,10 +1247,11 @@ static int f81534_port_probe(struct usb_serial_port *port) mutex_init(&port_priv->mcr_mutex); /* Assign logic-to-phy mapping */ - port_priv->phy_num = f81534_logic_to_phy_port(port->serial, port); - if (port_priv->phy_num < 0 || port_priv->phy_num >= F81534_NUM_PORT) - return -ENODEV; + ret = f81534_logic_to_phy_port(port->serial, port); + if (ret < 0) + return ret; + port_priv->phy_num = ret; usb_set_serial_port_data(port, port_priv); dev_dbg(&port->dev, "%s: port_number: %d, phy_num: %d\n", __func__, port->port_number, port_priv->phy_num); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 97cabf803c2f..b2f2e87aed94 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1043,6 +1043,7 @@ static int garmin_write_bulk(struct usb_serial_port *port, "%s - usb_submit_urb(write bulk) failed with status = %d\n", __func__, status); count = status; + kfree(buffer); } /* we are done with this urb, so let the host driver diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index dcc0c58aaad5..d50e5773483f 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -2751,6 +2751,11 @@ static int edge_startup(struct usb_serial *serial) EDGE_COMPATIBILITY_MASK1, EDGE_COMPATIBILITY_MASK2 }; + if (serial->num_bulk_in < 1 || serial->num_interrupt_in < 1) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + dev = serial->dev; /* create our private serial structure */ diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index c339163698eb..9a0db2965fbb 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -1499,8 +1499,7 @@ static int do_boot_mode(struct edgeport_serial *serial, dev_dbg(dev, "%s - Download successful -- Device rebooting...\n", __func__); - /* return an error on purpose */ - return -ENODEV; + return 1; } stayinbootmode: @@ -1508,7 +1507,7 @@ stayinbootmode: dev_dbg(dev, "%s - STAYING IN BOOT MODE\n", __func__); serial->product_info.TiMode = TI_MODE_BOOT; - return 0; + return 1; } static int ti_do_config(struct edgeport_port *port, int feature, int on) @@ -2546,6 +2545,13 @@ static int edge_startup(struct usb_serial *serial) int status; u16 product_id; + /* Make sure we have the required endpoints when in download mode. */ + if (serial->interface->cur_altsetting->desc.bNumEndpoints > 1) { + if (serial->num_bulk_in < serial->num_ports || + serial->num_bulk_out < serial->num_ports) + return -ENODEV; + } + /* create our private serial structure */ edge_serial = kzalloc(sizeof(struct edgeport_serial), GFP_KERNEL); if (!edge_serial) @@ -2553,14 +2559,18 @@ static int edge_startup(struct usb_serial *serial) mutex_init(&edge_serial->es_lock); edge_serial->serial = serial; + INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work); usb_set_serial_data(serial, edge_serial); status = download_fw(edge_serial); - if (status) { + if (status < 0) { kfree(edge_serial); return status; } + if (status > 0) + return 1; /* bind but do not register any ports */ + product_id = le16_to_cpu( edge_serial->serial->dev->descriptor.idProduct); @@ -2572,7 +2582,6 @@ static int edge_startup(struct usb_serial *serial) } } - INIT_DELAYED_WORK(&edge_serial->heartbeat_work, edge_heartbeat_work); edge_heartbeat_schedule(edge_serial); return 0; @@ -2580,6 +2589,9 @@ static int edge_startup(struct usb_serial *serial) static void edge_disconnect(struct usb_serial *serial) { + struct edgeport_serial *edge_serial = usb_get_serial_data(serial); + + cancel_delayed_work_sync(&edge_serial->heartbeat_work); } static void edge_release(struct usb_serial *serial) diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 344b4eea4bd5..d57fb5199218 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -68,6 +68,16 @@ struct iuu_private { u32 clk; }; +static int iuu_attach(struct usb_serial *serial) +{ + unsigned char num_ports = serial->num_ports; + + if (serial->num_bulk_in < num_ports || serial->num_bulk_out < num_ports) + return -ENODEV; + + return 0; +} + static int iuu_port_probe(struct usb_serial_port *port) { struct iuu_private *priv; @@ -1196,6 +1206,7 @@ static struct usb_serial_driver iuu_device = { .tiocmset = iuu_tiocmset, .set_termios = iuu_set_termios, .init_termios = iuu_init_termios, + .attach = iuu_attach, .port_probe = iuu_port_probe, .port_remove = iuu_port_remove, }; diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index e49ad0c63ad8..83523fcf6fb9 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -699,6 +699,19 @@ MODULE_FIRMWARE("keyspan_pda/keyspan_pda.fw"); MODULE_FIRMWARE("keyspan_pda/xircom_pgs.fw"); #endif +static int keyspan_pda_attach(struct usb_serial *serial) +{ + unsigned char num_ports = serial->num_ports; + + if (serial->num_bulk_out < num_ports || + serial->num_interrupt_in < num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + return 0; +} + static int keyspan_pda_port_probe(struct usb_serial_port *port) { @@ -776,6 +789,7 @@ static struct usb_serial_driver keyspan_pda_device = { .break_ctl = keyspan_pda_break_ctl, .tiocmget = keyspan_pda_tiocmget, .tiocmset = keyspan_pda_tiocmset, + .attach = keyspan_pda_attach, .port_probe = keyspan_pda_port_probe, .port_remove = keyspan_pda_port_remove, }; diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 0ee190fc1bf8..6cb45757818f 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -192,10 +192,11 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, status_buf, KLSI_STATUSBUF_LEN, 10000 ); - if (rc < 0) - dev_err(&port->dev, "Reading line status failed (error = %d)\n", - rc); - else { + if (rc != KLSI_STATUSBUF_LEN) { + dev_err(&port->dev, "reading line status failed: %d\n", rc); + if (rc >= 0) + rc = -EIO; + } else { status = get_unaligned_le16(status_buf); dev_info(&port->serial->dev->dev, "read status %x %x\n", diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 2363654cafc9..813035f51fe7 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -51,6 +51,7 @@ /* Function prototypes */ +static int kobil_attach(struct usb_serial *serial); static int kobil_port_probe(struct usb_serial_port *probe); static int kobil_port_remove(struct usb_serial_port *probe); static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port); @@ -86,6 +87,7 @@ static struct usb_serial_driver kobil_device = { .description = "KOBIL USB smart card terminal", .id_table = id_table, .num_ports = 1, + .attach = kobil_attach, .port_probe = kobil_port_probe, .port_remove = kobil_port_remove, .ioctl = kobil_ioctl, @@ -113,6 +115,16 @@ struct kobil_private { }; +static int kobil_attach(struct usb_serial *serial) +{ + if (serial->num_interrupt_out < serial->num_ports) { + dev_err(&serial->interface->dev, "missing interrupt-out endpoint\n"); + return -ENODEV; + } + + return 0; +} + static int kobil_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index d52caa03679c..91bc170b408a 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -65,8 +65,6 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; }; -static struct usb_serial_driver moschip7720_2port_driver; - #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 @@ -970,25 +968,6 @@ static void mos7720_bulk_out_data_callback(struct urb *urb) tty_port_tty_wakeup(&mos7720_port->port->port); } -/* - * mos77xx_probe - * this function installs the appropriate read interrupt endpoint callback - * depending on whether the device is a 7720 or 7715, thus avoiding costly - * run-time checks in the high-frequency callback routine itself. - */ -static int mos77xx_probe(struct usb_serial *serial, - const struct usb_device_id *id) -{ - if (id->idProduct == MOSCHIP_DEVICE_ID_7715) - moschip7720_2port_driver.read_int_callback = - mos7715_interrupt_callback; - else - moschip7720_2port_driver.read_int_callback = - mos7720_interrupt_callback; - - return 0; -} - static int mos77xx_calc_num_ports(struct usb_serial *serial) { u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); @@ -1917,6 +1896,11 @@ static int mos7720_startup(struct usb_serial *serial) u16 product; int ret_val; + if (serial->num_bulk_in < 2 || serial->num_bulk_out < 2) { + dev_err(&serial->interface->dev, "missing bulk endpoints\n"); + return -ENODEV; + } + product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; @@ -1941,19 +1925,18 @@ static int mos7720_startup(struct usb_serial *serial) tmp->interrupt_in_endpointAddress; serial->port[1]->interrupt_in_urb = NULL; serial->port[1]->interrupt_in_buffer = NULL; + + if (serial->port[0]->interrupt_in_urb) { + struct urb *urb = serial->port[0]->interrupt_in_urb; + + urb->complete = mos7715_interrupt_callback; + } } /* setting configuration feature to one */ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); - /* start the interrupt urb */ - ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); - if (ret_val) - dev_err(&dev->dev, - "%s - Error %d submitting control urb\n", - __func__, ret_val); - #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT if (product == MOSCHIP_DEVICE_ID_7715) { ret_val = mos7715_parport_init(serial); @@ -1961,6 +1944,13 @@ static int mos7720_startup(struct usb_serial *serial) return ret_val; } #endif + /* start the interrupt urb */ + ret_val = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); + if (ret_val) { + dev_err(&dev->dev, "failed to submit interrupt urb: %d\n", + ret_val); + } + /* LSR For Port 1 */ read_mos_reg(serial, 0, MOS7720_LSR, &data); dev_dbg(&dev->dev, "LSR:%x\n", data); @@ -1970,6 +1960,8 @@ static int mos7720_startup(struct usb_serial *serial) static void mos7720_release(struct usb_serial *serial) { + usb_kill_urb(serial->port[0]->interrupt_in_urb); + #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT /* close the parallel port */ @@ -2019,11 +2011,6 @@ static int mos7720_port_probe(struct usb_serial_port *port) if (!mos7720_port) return -ENOMEM; - /* Initialize all port interrupt end point to port 0 int endpoint. - * Our device has only one interrupt endpoint common to all ports. - */ - port->interrupt_in_endpointAddress = - port->serial->port[0]->interrupt_in_endpointAddress; mos7720_port->port = port; usb_set_serial_port_data(port, mos7720_port); @@ -2053,7 +2040,6 @@ static struct usb_serial_driver moschip7720_2port_driver = { .close = mos7720_close, .throttle = mos7720_throttle, .unthrottle = mos7720_unthrottle, - .probe = mos77xx_probe, .attach = mos7720_startup, .release = mos7720_release, .port_probe = mos7720_port_probe, @@ -2067,7 +2053,7 @@ static struct usb_serial_driver moschip7720_2port_driver = { .chars_in_buffer = mos7720_chars_in_buffer, .break_ctl = mos7720_break, .read_bulk_callback = mos7720_bulk_in_callback, - .read_int_callback = NULL /* dynamically assigned in probe() */ + .read_int_callback = mos7720_interrupt_callback, }; static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 9a220b8e810f..ea27fb23967a 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -214,7 +214,6 @@ MODULE_DEVICE_TABLE(usb, id_table); struct moschip_port { int port_num; /*Actual port number in the device(1,2,etc) */ - struct urb *write_urb; /* write URB for this port */ struct urb *read_urb; /* read URB for this port */ __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ @@ -1037,9 +1036,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) serial, serial->port[0]->interrupt_in_urb->interval); - /* start interrupt read for mos7840 * - * will continue as long as mos7840 is connected */ - + /* start interrupt read for mos7840 */ response = usb_submit_urb(serial->port[0]->interrupt_in_urb, GFP_KERNEL); @@ -1186,7 +1183,6 @@ static void mos7840_close(struct usb_serial_port *port) } } - usb_kill_urb(mos7840_port->write_urb); usb_kill_urb(mos7840_port->read_urb); mos7840_port->read_urb_busy = false; @@ -1199,12 +1195,6 @@ static void mos7840_close(struct usb_serial_port *port) } } - if (mos7840_port->write_urb) { - /* if this urb had a transfer buffer already (old tx) free it */ - kfree(mos7840_port->write_urb->transfer_buffer); - usb_free_urb(mos7840_port->write_urb); - } - Data = 0x0; mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); @@ -2113,6 +2103,17 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) return mos7840_num_ports; } +static int mos7840_attach(struct usb_serial *serial) +{ + if (serial->num_bulk_in < serial->num_ports || + serial->num_bulk_out < serial->num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + return 0; +} + static int mos7840_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; @@ -2388,6 +2389,7 @@ static struct usb_serial_driver moschip7840_4port_device = { .tiocmset = mos7840_tiocmset, .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, + .attach = mos7840_attach, .port_probe = mos7840_port_probe, .port_remove = mos7840_port_remove, .read_bulk_callback = mos7840_bulk_in_callback, diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index f6c6900bccf0..a180b17d2432 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -38,6 +38,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count); static int omninet_write_room(struct tty_struct *tty); static void omninet_disconnect(struct usb_serial *serial); +static int omninet_attach(struct usb_serial *serial); static int omninet_port_probe(struct usb_serial_port *port); static int omninet_port_remove(struct usb_serial_port *port); @@ -56,6 +57,7 @@ static struct usb_serial_driver zyxel_omninet_device = { .description = "ZyXEL - omni.net lcd plus usb", .id_table = id_table, .num_ports = 1, + .attach = omninet_attach, .port_probe = omninet_port_probe, .port_remove = omninet_port_remove, .open = omninet_open, @@ -104,6 +106,17 @@ struct omninet_data { __u8 od_outseq; /* Sequence number for bulk_out URBs */ }; +static int omninet_attach(struct usb_serial *serial) +{ + /* The second bulk-out endpoint is used for writing. */ + if (serial->num_bulk_out < 2) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + return 0; +} + static int omninet_port_probe(struct usb_serial_port *port) { struct omninet_data *od; diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 7ce31a4c7e7f..42cc72e54c05 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2007,6 +2007,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD200, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_6802, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(WETELECOM_VENDOR_ID, WETELECOM_PRODUCT_WMD300, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0x421d, 0xff, 0xff, 0xff) }, /* HP lt2523 (Novatel E371) */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, option_ids); diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index a4b88bc038b6..b8bf52bf7a94 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -134,6 +134,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty); static int oti6858_tiocmget(struct tty_struct *tty); static int oti6858_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); +static int oti6858_attach(struct usb_serial *serial); static int oti6858_port_probe(struct usb_serial_port *port); static int oti6858_port_remove(struct usb_serial_port *port); @@ -158,6 +159,7 @@ static struct usb_serial_driver oti6858_device = { .write_bulk_callback = oti6858_write_bulk_callback, .write_room = oti6858_write_room, .chars_in_buffer = oti6858_chars_in_buffer, + .attach = oti6858_attach, .port_probe = oti6858_port_probe, .port_remove = oti6858_port_remove, }; @@ -324,6 +326,20 @@ static void send_data(struct work_struct *work) usb_serial_port_softint(port); } +static int oti6858_attach(struct usb_serial *serial) +{ + unsigned char num_ports = serial->num_ports; + + if (serial->num_bulk_in < num_ports || + serial->num_bulk_out < num_ports || + serial->num_interrupt_in < num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + return 0; +} + static int oti6858_port_probe(struct usb_serial_port *port) { struct oti6858_private *priv; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index ae682e4eeaef..1db4b61bdf7b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -49,6 +49,7 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID) }, + { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) }, { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) }, { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID_UCSGT) }, @@ -220,9 +221,17 @@ static int pl2303_probe(struct usb_serial *serial, static int pl2303_startup(struct usb_serial *serial) { struct pl2303_serial_private *spriv; + unsigned char num_ports = serial->num_ports; enum pl2303_type type = TYPE_01; unsigned char *buf; + if (serial->num_bulk_in < num_ports || + serial->num_bulk_out < num_ports || + serial->num_interrupt_in < num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) return -ENOMEM; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index e3b7af8adfb7..09d9be88209e 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -27,6 +27,7 @@ #define ATEN_VENDOR_ID 0x0557 #define ATEN_VENDOR_ID2 0x0547 #define ATEN_PRODUCT_ID 0x2008 +#define ATEN_PRODUCT_ID2 0x2118 #define IODATA_VENDOR_ID 0x04bb #define IODATA_PRODUCT_ID 0x0a03 diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 1bc6089b9008..696458db7e3c 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -124,6 +124,7 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ + {USB_DEVICE(0x413c, 0x81a6)}, /* Dell DW5570 QDL (MC8805) */ {USB_DEVICE(0x1199, 0x68a4)}, /* Sierra Wireless QDL */ {USB_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */ {USB_DEVICE(0x1199, 0x68a8)}, /* Sierra Wireless QDL */ diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 659cb8606bd9..5709cc93b083 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -408,16 +408,12 @@ static void qt2_close(struct usb_serial_port *port) { struct usb_serial *serial; struct qt2_port_private *port_priv; - unsigned long flags; int i; serial = port->serial; port_priv = usb_get_serial_port_data(port); - spin_lock_irqsave(&port_priv->urb_lock, flags); usb_kill_urb(port_priv->write_urb); - port_priv->urb_in_use = false; - spin_unlock_irqrestore(&port_priv->urb_lock, flags); /* flush the port transmit buffer */ i = usb_control_msg(serial->dev, diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index ef0dbf0703c5..475e6c31b266 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -154,6 +154,19 @@ static int spcp8x5_probe(struct usb_serial *serial, return 0; } +static int spcp8x5_attach(struct usb_serial *serial) +{ + unsigned char num_ports = serial->num_ports; + + if (serial->num_bulk_in < num_ports || + serial->num_bulk_out < num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + return -ENODEV; + } + + return 0; +} + static int spcp8x5_port_probe(struct usb_serial_port *port) { const struct usb_device_id *id = usb_get_serial_data(port->serial); @@ -477,6 +490,7 @@ static struct usb_serial_driver spcp8x5_device = { .tiocmget = spcp8x5_tiocmget, .tiocmset = spcp8x5_tiocmset, .probe = spcp8x5_probe, + .attach = spcp8x5_attach, .port_probe = spcp8x5_port_probe, .port_remove = spcp8x5_port_remove, }; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 8db9d071d940..64b85b8dedf3 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -579,6 +579,13 @@ static int ti_startup(struct usb_serial *serial) goto free_tdev; } + if (serial->num_bulk_in < serial->num_ports || + serial->num_bulk_out < serial->num_ports) { + dev_err(&serial->interface->dev, "missing endpoints\n"); + status = -ENODEV; + goto free_tdev; + } + return 0; free_tdev: diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index af3c7eecff91..16cc18369111 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -2109,6 +2109,13 @@ UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_BROKEN_FUA ), +/* Reported-by George Cherian <george.cherian@cavium.com> */ +UNUSUAL_DEV(0x152d, 0x9561, 0x0000, 0x9999, + "JMicron", + "JMS56x", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_NO_REPORT_OPCODES), + /* * Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI) * and Mac USB Dock USB-SCSI */ diff --git a/drivers/usb/wusbcore/crypto.c b/drivers/usb/wusbcore/crypto.c index 79451f7ef1b7..062c205f0046 100644 --- a/drivers/usb/wusbcore/crypto.c +++ b/drivers/usb/wusbcore/crypto.c @@ -216,7 +216,6 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, struct scatterlist sg[4], sg_dst; void *dst_buf; size_t dst_size; - const u8 bzero[16] = { 0 }; u8 iv[crypto_skcipher_ivsize(tfm_cbc)]; size_t zero_padding; @@ -261,7 +260,7 @@ static int wusb_ccm_mac(struct crypto_skcipher *tfm_cbc, sg_set_buf(&sg[1], &scratch->b1, sizeof(scratch->b1)); sg_set_buf(&sg[2], b, blen); /* 0 if well behaved :) */ - sg_set_buf(&sg[3], bzero, zero_padding); + sg_set_page(&sg[3], ZERO_PAGE(0), zero_padding, 0); sg_init_one(&sg_dst, dst_buf, dst_size); skcipher_request_set_tfm(req, tfm_cbc); diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index be1ee89ee917..36d75c367d22 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -27,6 +27,45 @@ static LIST_HEAD(parent_list); static DEFINE_MUTEX(parent_list_lock); static struct class_compat *mdev_bus_compat_class; +static LIST_HEAD(mdev_list); +static DEFINE_MUTEX(mdev_list_lock); + +struct device *mdev_parent_dev(struct mdev_device *mdev) +{ + return mdev->parent->dev; +} +EXPORT_SYMBOL(mdev_parent_dev); + +void *mdev_get_drvdata(struct mdev_device *mdev) +{ + return mdev->driver_data; +} +EXPORT_SYMBOL(mdev_get_drvdata); + +void mdev_set_drvdata(struct mdev_device *mdev, void *data) +{ + mdev->driver_data = data; +} +EXPORT_SYMBOL(mdev_set_drvdata); + +struct device *mdev_dev(struct mdev_device *mdev) +{ + return &mdev->dev; +} +EXPORT_SYMBOL(mdev_dev); + +struct mdev_device *mdev_from_dev(struct device *dev) +{ + return dev_is_mdev(dev) ? to_mdev_device(dev) : NULL; +} +EXPORT_SYMBOL(mdev_from_dev); + +uuid_le mdev_uuid(struct mdev_device *mdev) +{ + return mdev->uuid; +} +EXPORT_SYMBOL(mdev_uuid); + static int _find_mdev_device(struct device *dev, void *data) { struct mdev_device *mdev; @@ -42,7 +81,7 @@ static int _find_mdev_device(struct device *dev, void *data) return 0; } -static bool mdev_device_exist(struct parent_device *parent, uuid_le uuid) +static bool mdev_device_exist(struct mdev_parent *parent, uuid_le uuid) { struct device *dev; @@ -56,9 +95,9 @@ static bool mdev_device_exist(struct parent_device *parent, uuid_le uuid) } /* Should be called holding parent_list_lock */ -static struct parent_device *__find_parent_device(struct device *dev) +static struct mdev_parent *__find_parent_device(struct device *dev) { - struct parent_device *parent; + struct mdev_parent *parent; list_for_each_entry(parent, &parent_list, next) { if (parent->dev == dev) @@ -69,8 +108,8 @@ static struct parent_device *__find_parent_device(struct device *dev) static void mdev_release_parent(struct kref *kref) { - struct parent_device *parent = container_of(kref, struct parent_device, - ref); + struct mdev_parent *parent = container_of(kref, struct mdev_parent, + ref); struct device *dev = parent->dev; kfree(parent); @@ -78,7 +117,7 @@ static void mdev_release_parent(struct kref *kref) } static -inline struct parent_device *mdev_get_parent(struct parent_device *parent) +inline struct mdev_parent *mdev_get_parent(struct mdev_parent *parent) { if (parent) kref_get(&parent->ref); @@ -86,7 +125,7 @@ inline struct parent_device *mdev_get_parent(struct parent_device *parent) return parent; } -static inline void mdev_put_parent(struct parent_device *parent) +static inline void mdev_put_parent(struct mdev_parent *parent) { if (parent) kref_put(&parent->ref, mdev_release_parent); @@ -95,7 +134,7 @@ static inline void mdev_put_parent(struct parent_device *parent) static int mdev_device_create_ops(struct kobject *kobj, struct mdev_device *mdev) { - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; int ret; ret = parent->ops->create(kobj, mdev); @@ -122,7 +161,7 @@ static int mdev_device_create_ops(struct kobject *kobj, */ static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) { - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; int ret; /* @@ -153,10 +192,10 @@ static int mdev_device_remove_cb(struct device *dev, void *data) * Add device to list of registered parent devices. * Returns a negative value on error, otherwise 0. */ -int mdev_register_device(struct device *dev, const struct parent_ops *ops) +int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops) { int ret; - struct parent_device *parent; + struct mdev_parent *parent; /* check for mandatory ops */ if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups) @@ -229,7 +268,7 @@ EXPORT_SYMBOL(mdev_register_device); void mdev_unregister_device(struct device *dev) { - struct parent_device *parent; + struct mdev_parent *parent; bool force_remove = true; mutex_lock(&parent_list_lock); @@ -266,7 +305,7 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) { int ret; struct mdev_device *mdev; - struct parent_device *parent; + struct mdev_parent *parent; struct mdev_type *type = to_mdev_type(kobj); parent = mdev_get_parent(type->parent); @@ -316,6 +355,11 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) dev_dbg(&mdev->dev, "MDEV: created\n"); mutex_unlock(&parent->lock); + + mutex_lock(&mdev_list_lock); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + return ret; create_failed: @@ -329,12 +373,30 @@ create_err: int mdev_device_remove(struct device *dev, bool force_remove) { - struct mdev_device *mdev; - struct parent_device *parent; + struct mdev_device *mdev, *tmp; + struct mdev_parent *parent; struct mdev_type *type; int ret; + bool found = false; mdev = to_mdev_device(dev); + + mutex_lock(&mdev_list_lock); + list_for_each_entry(tmp, &mdev_list, next) { + if (tmp == mdev) { + found = true; + break; + } + } + + if (found) + list_del(&mdev->next); + + mutex_unlock(&mdev_list_lock); + + if (!found) + return -ENODEV; + type = to_mdev_type(mdev->type_kobj); parent = mdev->parent; mutex_lock(&parent->lock); @@ -342,6 +404,11 @@ int mdev_device_remove(struct device *dev, bool force_remove) ret = mdev_device_remove_ops(mdev, force_remove); if (ret) { mutex_unlock(&parent->lock); + + mutex_lock(&mdev_list_lock); + list_add(&mdev->next, &mdev_list); + mutex_unlock(&mdev_list_lock); + return ret; } @@ -349,7 +416,8 @@ int mdev_device_remove(struct device *dev, bool force_remove) device_unregister(dev); mutex_unlock(&parent->lock); mdev_put_parent(parent); - return ret; + + return 0; } static int __init mdev_init(void) diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index d35097cbf3d7..a9cefd70a705 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h @@ -16,10 +16,33 @@ int mdev_bus_register(void); void mdev_bus_unregister(void); +struct mdev_parent { + struct device *dev; + const struct mdev_parent_ops *ops; + struct kref ref; + struct mutex lock; + struct list_head next; + struct kset *mdev_types_kset; + struct list_head type_list; +}; + +struct mdev_device { + struct device dev; + struct mdev_parent *parent; + uuid_le uuid; + void *driver_data; + struct kref ref; + struct list_head next; + struct kobject *type_kobj; +}; + +#define to_mdev_device(dev) container_of(dev, struct mdev_device, dev) +#define dev_is_mdev(d) ((d)->bus == &mdev_bus_type) + struct mdev_type { struct kobject kobj; struct kobject *devices_kobj; - struct parent_device *parent; + struct mdev_parent *parent; struct list_head next; struct attribute_group *group; }; @@ -29,8 +52,8 @@ struct mdev_type { #define to_mdev_type(_kobj) \ container_of(_kobj, struct mdev_type, kobj) -int parent_create_sysfs_files(struct parent_device *parent); -void parent_remove_sysfs_files(struct parent_device *parent); +int parent_create_sysfs_files(struct mdev_parent *parent); +void parent_remove_sysfs_files(struct mdev_parent *parent); int mdev_create_sysfs_files(struct device *dev, struct mdev_type *type); void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type); diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index 1a53deb2ee10..802df210929b 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c @@ -92,7 +92,7 @@ static struct kobj_type mdev_type_ktype = { .release = mdev_type_release, }; -struct mdev_type *add_mdev_supported_type(struct parent_device *parent, +struct mdev_type *add_mdev_supported_type(struct mdev_parent *parent, struct attribute_group *group) { struct mdev_type *type; @@ -158,7 +158,7 @@ static void remove_mdev_supported_type(struct mdev_type *type) kobject_put(&type->kobj); } -static int add_mdev_supported_type_groups(struct parent_device *parent) +static int add_mdev_supported_type_groups(struct mdev_parent *parent) { int i; @@ -183,7 +183,7 @@ static int add_mdev_supported_type_groups(struct parent_device *parent) } /* mdev sysfs functions */ -void parent_remove_sysfs_files(struct parent_device *parent) +void parent_remove_sysfs_files(struct mdev_parent *parent) { struct mdev_type *type, *tmp; @@ -196,7 +196,7 @@ void parent_remove_sysfs_files(struct parent_device *parent) kset_unregister(parent->mdev_types_kset); } -int parent_create_sysfs_files(struct parent_device *parent) +int parent_create_sysfs_files(struct mdev_parent *parent) { int ret; diff --git a/drivers/vfio/mdev/vfio_mdev.c b/drivers/vfio/mdev/vfio_mdev.c index ffc36758cb84..fa848a701b8b 100644 --- a/drivers/vfio/mdev/vfio_mdev.c +++ b/drivers/vfio/mdev/vfio_mdev.c @@ -27,7 +27,7 @@ static int vfio_mdev_open(void *device_data) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; int ret; if (unlikely(!parent->ops->open)) @@ -46,7 +46,7 @@ static int vfio_mdev_open(void *device_data) static void vfio_mdev_release(void *device_data) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; if (likely(parent->ops->release)) parent->ops->release(mdev); @@ -58,7 +58,7 @@ static long vfio_mdev_unlocked_ioctl(void *device_data, unsigned int cmd, unsigned long arg) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; if (unlikely(!parent->ops->ioctl)) return -EINVAL; @@ -70,7 +70,7 @@ static ssize_t vfio_mdev_read(void *device_data, char __user *buf, size_t count, loff_t *ppos) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; if (unlikely(!parent->ops->read)) return -EINVAL; @@ -82,7 +82,7 @@ static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, size_t count, loff_t *ppos) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; if (unlikely(!parent->ops->write)) return -EINVAL; @@ -93,7 +93,7 @@ static ssize_t vfio_mdev_write(void *device_data, const char __user *buf, static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma) { struct mdev_device *mdev = device_data; - struct parent_device *parent = mdev->parent; + struct mdev_parent *parent = mdev->parent; if (unlikely(!parent->ops->mmap)) return -EINVAL; diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c index dcd7c2a99618..324c52e3a1a4 100644 --- a/drivers/vfio/pci/vfio_pci.c +++ b/drivers/vfio/pci/vfio_pci.c @@ -1142,6 +1142,10 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma) return ret; vdev->barmap[index] = pci_iomap(pdev, index, 0); + if (!vdev->barmap[index]) { + pci_release_selected_regions(pdev, 1 << index); + return -ENOMEM; + } } vma->vm_private_data = vdev; diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 5ffd1d9ad4bd..357243d76f10 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -193,7 +193,10 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_device *vdev, char __user *buf, if (!vdev->has_vga) return -EINVAL; - switch (pos) { + if (pos > 0xbfffful) + return -EINVAL; + + switch ((u32)pos) { case 0xa0000 ... 0xbffff: count = min(count, (size_t)(0xc0000 - pos)); iomem = ioremap_nocache(0xa0000, 0xbffff - 0xa0000 + 1); diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index c8823578a1b2..59b3f62a2d64 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -1123,12 +1123,11 @@ static long tce_iommu_ioctl(void *iommu_data, mutex_lock(&container->lock); ret = tce_iommu_create_default_window(container); - if (ret) - return ret; - - ret = tce_iommu_create_window(container, create.page_shift, - create.window_size, create.levels, - &create.start_addr); + if (!ret) + ret = tce_iommu_create_window(container, + create.page_shift, + create.window_size, create.levels, + &create.start_addr); mutex_unlock(&container->lock); @@ -1246,6 +1245,8 @@ static void tce_iommu_release_ownership_ddw(struct tce_container *container, static long tce_iommu_take_ownership_ddw(struct tce_container *container, struct iommu_table_group *table_group) { + long i, ret = 0; + if (!table_group->ops->create_table || !table_group->ops->set_window || !table_group->ops->release_ownership) { WARN_ON_ONCE(1); @@ -1254,7 +1255,27 @@ static long tce_iommu_take_ownership_ddw(struct tce_container *container, table_group->ops->take_ownership(table_group); + /* Set all windows to the new group */ + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { + struct iommu_table *tbl = container->tables[i]; + + if (!tbl) + continue; + + ret = table_group->ops->set_window(table_group, i, tbl); + if (ret) + goto release_exit; + } + return 0; + +release_exit: + for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) + table_group->ops->unset_window(table_group, i); + + table_group->ops->release_ownership(table_group); + + return ret; } static int tce_iommu_attach_group(void *iommu_data, @@ -1270,6 +1291,10 @@ static int tce_iommu_attach_group(void *iommu_data, /* pr_debug("tce_vfio: Attaching group #%u to iommu %p\n", iommu_group_id(iommu_group), iommu_group); */ table_group = iommu_group_get_iommudata(iommu_group); + if (!table_group) { + ret = -ENODEV; + goto unlock_exit; + } if (tce_groups_attached(container) && (!table_group->ops || !table_group->ops->take_ownership || diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index f3726ba12aa6..bd6f293c4ebd 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -36,9 +36,10 @@ #include <linux/uaccess.h> #include <linux/vfio.h> #include <linux/workqueue.h> -#include <linux/pid_namespace.h> #include <linux/mdev.h> #include <linux/notifier.h> +#include <linux/dma-iommu.h> +#include <linux/irqdomain.h> #define DRIVER_VERSION "0.2" #define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>" @@ -268,28 +269,38 @@ static void vfio_lock_acct(struct task_struct *task, long npage) { struct vwork *vwork; struct mm_struct *mm; + bool is_current; if (!npage) return; - mm = get_task_mm(task); + is_current = (task->mm == current->mm); + + mm = is_current ? task->mm : get_task_mm(task); if (!mm) - return; /* process exited or nothing to do */ + return; /* process exited */ if (down_write_trylock(&mm->mmap_sem)) { mm->locked_vm += npage; up_write(&mm->mmap_sem); - mmput(mm); + if (!is_current) + mmput(mm); return; } + if (is_current) { + mm = get_task_mm(task); + if (!mm) + return; + } + /* * Couldn't get mmap_sem lock, so must setup to update * mm->locked_vm later. If locked_vm were atomic, we * wouldn't need this silliness */ vwork = kmalloc(sizeof(struct vwork), GFP_KERNEL); - if (!vwork) { + if (WARN_ON(!vwork)) { mmput(mm); return; } @@ -393,77 +404,71 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr, long npage, unsigned long *pfn_base) { - unsigned long limit; - bool lock_cap = ns_capable(task_active_pid_ns(dma->task)->user_ns, - CAP_IPC_LOCK); - struct mm_struct *mm; - long ret, i = 0, lock_acct = 0; + unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + bool lock_cap = capable(CAP_IPC_LOCK); + long ret, pinned = 0, lock_acct = 0; bool rsvd; dma_addr_t iova = vaddr - dma->vaddr + dma->iova; - mm = get_task_mm(dma->task); - if (!mm) + /* This code path is only user initiated */ + if (!current->mm) return -ENODEV; - ret = vaddr_get_pfn(mm, vaddr, dma->prot, pfn_base); + ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, pfn_base); if (ret) - goto pin_pg_remote_exit; + return ret; + pinned++; rsvd = is_invalid_reserved_pfn(*pfn_base); - limit = task_rlimit(dma->task, RLIMIT_MEMLOCK) >> PAGE_SHIFT; /* * Reserved pages aren't counted against the user, externally pinned * pages are already counted against the user. */ if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && mm->locked_vm + 1 > limit) { + if (!lock_cap && current->mm->locked_vm + 1 > limit) { put_pfn(*pfn_base, dma->prot); pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__, limit << PAGE_SHIFT); - ret = -ENOMEM; - goto pin_pg_remote_exit; + return -ENOMEM; } lock_acct++; } - i++; - if (likely(!disable_hugepages)) { - /* Lock all the consecutive pages from pfn_base */ - for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; i < npage; - i++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { - unsigned long pfn = 0; + if (unlikely(disable_hugepages)) + goto out; - ret = vaddr_get_pfn(mm, vaddr, dma->prot, &pfn); - if (ret) - break; + /* Lock all the consecutive pages from pfn_base */ + for (vaddr += PAGE_SIZE, iova += PAGE_SIZE; pinned < npage; + pinned++, vaddr += PAGE_SIZE, iova += PAGE_SIZE) { + unsigned long pfn = 0; + + ret = vaddr_get_pfn(current->mm, vaddr, dma->prot, &pfn); + if (ret) + break; + + if (pfn != *pfn_base + pinned || + rsvd != is_invalid_reserved_pfn(pfn)) { + put_pfn(pfn, dma->prot); + break; + } - if (pfn != *pfn_base + i || - rsvd != is_invalid_reserved_pfn(pfn)) { + if (!rsvd && !vfio_find_vpfn(dma, iova)) { + if (!lock_cap && + current->mm->locked_vm + lock_acct + 1 > limit) { put_pfn(pfn, dma->prot); + pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", + __func__, limit << PAGE_SHIFT); break; } - - if (!rsvd && !vfio_find_vpfn(dma, iova)) { - if (!lock_cap && - mm->locked_vm + lock_acct + 1 > limit) { - put_pfn(pfn, dma->prot); - pr_warn("%s: RLIMIT_MEMLOCK (%ld) " - "exceeded\n", __func__, - limit << PAGE_SHIFT); - break; - } - lock_acct++; - } + lock_acct++; } } - vfio_lock_acct(dma->task, lock_acct); - ret = i; +out: + vfio_lock_acct(current, lock_acct); -pin_pg_remote_exit: - mmput(mm); - return ret; + return pinned; } static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, @@ -473,10 +478,10 @@ static long vfio_unpin_pages_remote(struct vfio_dma *dma, dma_addr_t iova, long unlocked = 0, locked = 0; long i; - for (i = 0; i < npage; i++) { + for (i = 0; i < npage; i++, iova += PAGE_SIZE) { if (put_pfn(pfn++, dma->prot)) { unlocked++; - if (vfio_find_vpfn(dma, iova + (i << PAGE_SHIFT))) + if (vfio_find_vpfn(dma, iova)) locked++; } } @@ -491,8 +496,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr, unsigned long *pfn_base, bool do_accounting) { unsigned long limit; - bool lock_cap = ns_capable(task_active_pid_ns(dma->task)->user_ns, - CAP_IPC_LOCK); + bool lock_cap = has_capability(dma->task, CAP_IPC_LOCK); struct mm_struct *mm; int ret; bool rsvd; @@ -1177,6 +1181,28 @@ static struct vfio_group *find_iommu_group(struct vfio_domain *domain, return NULL; } +static bool vfio_iommu_has_resv_msi(struct iommu_group *group, + phys_addr_t *base) +{ + struct list_head group_resv_regions; + struct iommu_resv_region *region, *next; + bool ret = false; + + INIT_LIST_HEAD(&group_resv_regions); + iommu_get_group_resv_regions(group, &group_resv_regions); + list_for_each_entry(region, &group_resv_regions, list) { + if (region->type & IOMMU_RESV_MSI) { + *base = region->start; + ret = true; + goto out; + } + } +out: + list_for_each_entry_safe(region, next, &group_resv_regions, list) + kfree(region); + return ret; +} + static int vfio_iommu_type1_attach_group(void *iommu_data, struct iommu_group *iommu_group) { @@ -1185,6 +1211,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, struct vfio_domain *domain, *d; struct bus_type *bus = NULL, *mdev_bus; int ret; + bool resv_msi, msi_remap; + phys_addr_t resv_msi_base; mutex_lock(&iommu->lock); @@ -1254,11 +1282,15 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, if (ret) goto out_domain; + resv_msi = vfio_iommu_has_resv_msi(iommu_group, &resv_msi_base); + INIT_LIST_HEAD(&domain->group_list); list_add(&group->next, &domain->group_list); - if (!allow_unsafe_interrupts && - !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) { + msi_remap = resv_msi ? irq_domain_check_msi_remap() : + iommu_capable(bus, IOMMU_CAP_INTR_REMAP); + + if (!allow_unsafe_interrupts && !msi_remap) { pr_warn("%s: No interrupt remapping support. Use the module param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this platform\n", __func__); ret = -EPERM; @@ -1300,6 +1332,12 @@ static int vfio_iommu_type1_attach_group(void *iommu_data, if (ret) goto out_detach; + if (resv_msi) { + ret = iommu_get_msi_cookie(domain->domain, resv_msi_base); + if (ret) + goto out_detach; + } + list_add(&domain->next, &iommu->domain_list); mutex_unlock(&iommu->lock); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 253310cdaaca..fd6c8b66f06f 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -843,7 +843,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) struct iov_iter out_iter, in_iter, prot_iter, data_iter; u64 tag; u32 exp_data_len, data_direction; - unsigned out, in; + unsigned int out = 0, in = 0; int head, ret, prot_bytes; size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp); size_t out_size, in_size; @@ -2087,7 +2087,7 @@ static struct configfs_attribute *vhost_scsi_wwn_attrs[] = { NULL, }; -static struct target_core_fabric_ops vhost_scsi_ops = { +static const struct target_core_fabric_ops vhost_scsi_ops = { .module = THIS_MODULE, .name = "vhost", .get_fabric_name = vhost_scsi_get_fabric_name, diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index d6432603880c..8f99fe08de02 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -130,14 +130,14 @@ static long vhost_get_vring_endian(struct vhost_virtqueue *vq, u32 idx, static void vhost_init_is_le(struct vhost_virtqueue *vq) { - if (vhost_has_feature(vq, VIRTIO_F_VERSION_1)) - vq->is_le = true; + vq->is_le = vhost_has_feature(vq, VIRTIO_F_VERSION_1) + || virtio_legacy_is_little_endian(); } #endif /* CONFIG_VHOST_CROSS_ENDIAN_LEGACY */ static void vhost_reset_is_le(struct vhost_virtqueue *vq) { - vq->is_le = virtio_legacy_is_little_endian(); + vhost_init_is_le(vq); } struct vhost_flush_struct { @@ -1714,10 +1714,8 @@ int vhost_vq_init_access(struct vhost_virtqueue *vq) int r; bool is_le = vq->is_le; - if (!vq->private_data) { - vhost_reset_is_le(vq); + if (!vq->private_data) return 0; - } vhost_init_is_le(vq); diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index bbbf588540ed..ce5e63d2c66a 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -373,6 +373,7 @@ static void vhost_vsock_handle_rx_kick(struct vhost_work *work) static int vhost_vsock_start(struct vhost_vsock *vsock) { + struct vhost_virtqueue *vq; size_t i; int ret; @@ -383,19 +384,20 @@ static int vhost_vsock_start(struct vhost_vsock *vsock) goto err; for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { - struct vhost_virtqueue *vq = &vsock->vqs[i]; + vq = &vsock->vqs[i]; mutex_lock(&vq->mutex); if (!vhost_vq_access_ok(vq)) { ret = -EFAULT; - mutex_unlock(&vq->mutex); goto err_vq; } if (!vq->private_data) { vq->private_data = vsock; - vhost_vq_init_access(vq); + ret = vhost_vq_init_access(vq); + if (ret) + goto err_vq; } mutex_unlock(&vq->mutex); @@ -405,8 +407,11 @@ static int vhost_vsock_start(struct vhost_vsock *vsock) return 0; err_vq: + vq->private_data = NULL; + mutex_unlock(&vq->mutex); + for (i = 0; i < ARRAY_SIZE(vsock->vqs); i++) { - struct vhost_virtqueue *vq = &vsock->vqs[i]; + vq = &vsock->vqs[i]; mutex_lock(&vq->mutex); vq->private_data = NULL; diff --git a/drivers/video/fbdev/cobalt_lcdfb.c b/drivers/video/fbdev/cobalt_lcdfb.c index 2d3b691f3fc4..038ac6934fe9 100644 --- a/drivers/video/fbdev/cobalt_lcdfb.c +++ b/drivers/video/fbdev/cobalt_lcdfb.c @@ -308,6 +308,11 @@ static int cobalt_lcdfb_probe(struct platform_device *dev) info->screen_size = resource_size(res); info->screen_base = devm_ioremap(&dev->dev, res->start, info->screen_size); + if (!info->screen_base) { + framebuffer_release(info); + return -ENOMEM; + } + info->fbops = &cobalt_lcd_fbops; info->fix = cobalt_lcdfb_fix; info->fix.smem_start = res->start; diff --git a/drivers/video/fbdev/core/fbcmap.c b/drivers/video/fbdev/core/fbcmap.c index f89245b8ba8e..68a113594808 100644 --- a/drivers/video/fbdev/core/fbcmap.c +++ b/drivers/video/fbdev/core/fbcmap.c @@ -163,17 +163,18 @@ void fb_dealloc_cmap(struct fb_cmap *cmap) int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) { - int tooff = 0, fromoff = 0; - int size; + unsigned int tooff = 0, fromoff = 0; + size_t size; if (to->start > from->start) fromoff = to->start - from->start; else tooff = from->start - to->start; - size = to->len - tooff; - if (size > (int) (from->len - fromoff)) - size = from->len - fromoff; - if (size <= 0) + if (fromoff >= from->len || tooff >= to->len) + return -EINVAL; + + size = min_t(size_t, to->len - tooff, from->len - fromoff); + if (size == 0) return -EINVAL; size *= sizeof(u16); @@ -187,17 +188,18 @@ int fb_copy_cmap(const struct fb_cmap *from, struct fb_cmap *to) int fb_cmap_to_user(const struct fb_cmap *from, struct fb_cmap_user *to) { - int tooff = 0, fromoff = 0; - int size; + unsigned int tooff = 0, fromoff = 0; + size_t size; if (to->start > from->start) fromoff = to->start - from->start; else tooff = from->start - to->start; - size = to->len - tooff; - if (size > (int) (from->len - fromoff)) - size = from->len - fromoff; - if (size <= 0) + if (fromoff >= from->len || tooff >= to->len) + return -EINVAL; + + size = min_t(size_t, to->len - tooff, from->len - fromoff); + if (size == 0) return -EINVAL; size *= sizeof(u16); diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index d47a2fcef818..c71fde5fe835 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -59,6 +59,7 @@ #define pr_fmt(fmt) "virtio-mmio: " fmt #include <linux/acpi.h> +#include <linux/dma-mapping.h> #include <linux/highmem.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -498,6 +499,7 @@ static int virtio_mmio_probe(struct platform_device *pdev) struct virtio_mmio_device *vm_dev; struct resource *mem; unsigned long magic; + int rc; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) @@ -547,9 +549,25 @@ static int virtio_mmio_probe(struct platform_device *pdev) } vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); - if (vm_dev->version == 1) + if (vm_dev->version == 1) { writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); + rc = dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); + /* + * In the legacy case, ensure our coherently-allocated virtio + * ring will be at an address expressable as a 32-bit PFN. + */ + if (!rc) + dma_set_coherent_mask(&pdev->dev, + DMA_BIT_MASK(32 + PAGE_SHIFT)); + } else { + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + } + if (rc) + rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + if (rc) + dev_warn(&pdev->dev, "Failed to enable 64-bit or 32-bit DMA. Trying to continue, but this might not work.\n"); + platform_set_drvdata(pdev, vm_dev); return register_virtio_device(&vm_dev->vdev); diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c index 6b5ee896af63..7cc51223db1c 100644 --- a/drivers/vme/bridges/vme_ca91cx42.c +++ b/drivers/vme/bridges/vme_ca91cx42.c @@ -464,7 +464,7 @@ static int ca91cx42_slave_get(struct vme_slave_resource *image, int *enabled, vme_bound = ioread32(bridge->base + CA91CX42_VSI_BD[i]); pci_offset = ioread32(bridge->base + CA91CX42_VSI_TO[i]); - *pci_base = (dma_addr_t)vme_base + pci_offset; + *pci_base = (dma_addr_t)*vme_base + pci_offset; *size = (unsigned long long)((vme_bound - *vme_base) + granularity); *enabled = 0; diff --git a/drivers/xen/arm-device.c b/drivers/xen/arm-device.c index 778acf80aacb..85dd20e05726 100644 --- a/drivers/xen/arm-device.c +++ b/drivers/xen/arm-device.c @@ -58,9 +58,13 @@ static int xen_map_device_mmio(const struct resource *resources, xen_pfn_t *gpfns; xen_ulong_t *idxs; int *errs; - struct xen_add_to_physmap_range xatp; for (i = 0; i < count; i++) { + struct xen_add_to_physmap_range xatp = { + .domid = DOMID_SELF, + .space = XENMAPSPACE_dev_mmio + }; + r = &resources[i]; nr = DIV_ROUND_UP(resource_size(r), XEN_PAGE_SIZE); if ((resource_type(r) != IORESOURCE_MEM) || (nr == 0)) @@ -87,9 +91,7 @@ static int xen_map_device_mmio(const struct resource *resources, idxs[j] = XEN_PFN_DOWN(r->start) + j; } - xatp.domid = DOMID_SELF; xatp.size = nr; - xatp.space = XENMAPSPACE_dev_mmio; set_xen_guest_handle(xatp.gpfns, gpfns); set_xen_guest_handle(xatp.idxs, idxs); diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index c03f9c86c7e3..3c41470c7fc4 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -369,8 +369,7 @@ static void evtchn_fifo_resume(void) } ret = init_control_block(cpu, control_block); - if (ret < 0) - BUG(); + BUG_ON(ret < 0); } /* diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index e8c7f09d01be..6890897a6f30 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -125,7 +125,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) while (*new) { struct user_evtchn *this; - this = container_of(*new, struct user_evtchn, node); + this = rb_entry(*new, struct user_evtchn, node); parent = *new; if (this->port < evtchn->port) @@ -157,7 +157,7 @@ static struct user_evtchn *find_evtchn(struct per_user_data *u, unsigned port) while (node) { struct user_evtchn *evtchn; - evtchn = container_of(node, struct user_evtchn, node); + evtchn = rb_entry(node, struct user_evtchn, node); if (evtchn->port < port) node = node->rb_left; diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index 112ce422dc22..2a165cc8a43c 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -42,6 +42,7 @@ static unsigned long platform_mmio; static unsigned long platform_mmio_alloc; static unsigned long platform_mmiolen; +static uint64_t callback_via; static unsigned long alloc_xen_mmio(unsigned long len) { @@ -54,6 +55,51 @@ static unsigned long alloc_xen_mmio(unsigned long len) return addr; } +static uint64_t get_callback_via(struct pci_dev *pdev) +{ + u8 pin; + int irq; + + irq = pdev->irq; + if (irq < 16) + return irq; /* ISA IRQ */ + + pin = pdev->pin; + + /* We don't know the GSI. Specify the PCI INTx line instead. */ + return ((uint64_t)0x01 << HVM_CALLBACK_VIA_TYPE_SHIFT) | /* PCI INTx identifier */ + ((uint64_t)pci_domain_nr(pdev->bus) << 32) | + ((uint64_t)pdev->bus->number << 16) | + ((uint64_t)(pdev->devfn & 0xff) << 8) | + ((uint64_t)(pin - 1) & 3); +} + +static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) +{ + xen_hvm_evtchn_do_upcall(); + return IRQ_HANDLED; +} + +static int xen_allocate_irq(struct pci_dev *pdev) +{ + return request_irq(pdev->irq, do_hvm_evtchn_intr, + IRQF_NOBALANCING | IRQF_TRIGGER_RISING, + "xen-platform-pci", pdev); +} + +static int platform_pci_resume(struct pci_dev *pdev) +{ + int err; + if (!xen_pv_domain()) + return 0; + err = xen_set_callback_via(callback_via); + if (err) { + dev_err(&pdev->dev, "platform_pci_resume failure!\n"); + return err; + } + return 0; +} + static int platform_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -92,6 +138,28 @@ static int platform_pci_probe(struct pci_dev *pdev, platform_mmio = mmio_addr; platform_mmiolen = mmio_len; + /* + * Xen HVM guests always use the vector callback mechanism. + * L1 Dom0 in a nested Xen environment is a PV guest inside in an + * HVM environment. It needs the platform-pci driver to get + * notifications from L0 Xen, but it cannot use the vector callback + * as it is not exported by L1 Xen. + */ + if (xen_pv_domain()) { + ret = xen_allocate_irq(pdev); + if (ret) { + dev_warn(&pdev->dev, "request_irq failed err=%d\n", ret); + goto out; + } + callback_via = get_callback_via(pdev); + ret = xen_set_callback_via(callback_via); + if (ret) { + dev_warn(&pdev->dev, "Unable to set the evtchn callback " + "err=%d\n", ret); + goto out; + } + } + max_nr_gframes = gnttab_max_grant_frames(); grant_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes); ret = gnttab_setup_auto_xlat_frames(grant_frames); @@ -123,6 +191,9 @@ static struct pci_driver platform_driver = { .name = DRV_NAME, .probe = platform_pci_probe, .id_table = platform_pci_tbl, +#ifdef CONFIG_PM + .resume_early = platform_pci_resume, +#endif }; builtin_pci_driver(platform_driver); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 478fb91e3df2..f8afc6dcc29f 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -275,6 +275,10 @@ retry: rc = 0; } else rc = swiotlb_late_init_with_tbl(xen_io_tlb_start, xen_io_tlb_nslabs); + + if (!rc) + swiotlb_set_max_segment(PAGE_SIZE); + return rc; error: if (repeat--) { @@ -392,7 +396,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, if (dma_capable(dev, dev_addr, size) && !range_straddles_page_boundary(phys, size) && !xen_arch_need_swiotlb(dev, phys, dev_addr) && - !swiotlb_force) { + (swiotlb_force != SWIOTLB_FORCE)) { /* we are not interested in the dma_addr returned by * xen_dma_map_page, only in the potential cache flushes executed * by the function. */ @@ -410,9 +414,9 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, if (map == SWIOTLB_MAP_ERROR) return DMA_ERROR_CODE; + dev_addr = xen_phys_to_bus(map); xen_dma_map_page(dev, pfn_to_page(map >> PAGE_SHIFT), dev_addr, map & ~PAGE_MASK, size, dir, attrs); - dev_addr = xen_phys_to_bus(map); /* * Ensure that the address returned is DMA'ble @@ -552,7 +556,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, phys_addr_t paddr = sg_phys(sg); dma_addr_t dev_addr = xen_phys_to_bus(paddr); - if (swiotlb_force || + if (swiotlb_force == SWIOTLB_FORCE || xen_arch_need_swiotlb(hwdev, paddr, dev_addr) || !dma_capable(hwdev, dev_addr, sg->length) || range_straddles_page_boundary(paddr, sg->length)) { @@ -571,13 +575,14 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, sg_dma_len(sgl) = 0; return 0; } + dev_addr = xen_phys_to_bus(map); xen_dma_map_page(hwdev, pfn_to_page(map >> PAGE_SHIFT), dev_addr, map & ~PAGE_MASK, sg->length, dir, attrs); - sg->dma_address = xen_phys_to_bus(map); + sg->dma_address = dev_addr; } else { /* we are not interested in the dma_addr returned by * xen_dma_map_page, only in the potential cache flushes executed diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h index e74f9c1fbd80..867a2e425208 100644 --- a/drivers/xen/xenbus/xenbus_comms.h +++ b/drivers/xen/xenbus/xenbus_comms.h @@ -42,7 +42,6 @@ int xb_write(const void *data, unsigned len); int xb_read(void *data, unsigned len); int xb_data_to_read(void); int xb_wait_for_data_to_read(void); -int xs_input_avail(void); extern struct xenstore_domain_interface *xen_store_interface; extern int xen_store_evtchn; extern enum xenstore_init xen_store_domain_type; diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index 6c0ead4be784..79130b310247 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -302,6 +302,29 @@ static void watch_fired(struct xenbus_watch *watch, mutex_unlock(&adap->dev_data->reply_mutex); } +static int xenbus_command_reply(struct xenbus_file_priv *u, + unsigned int msg_type, const char *reply) +{ + struct { + struct xsd_sockmsg hdr; + const char body[16]; + } msg; + int rc; + + msg.hdr = u->u.msg; + msg.hdr.type = msg_type; + msg.hdr.len = strlen(reply) + 1; + if (msg.hdr.len > sizeof(msg.body)) + return -E2BIG; + + mutex_lock(&u->reply_mutex); + rc = queue_reply(&u->read_buffers, &msg, sizeof(msg.hdr) + msg.hdr.len); + wake_up(&u->read_waitq); + mutex_unlock(&u->reply_mutex); + + return rc; +} + static int xenbus_write_transaction(unsigned msg_type, struct xenbus_file_priv *u) { @@ -316,12 +339,12 @@ static int xenbus_write_transaction(unsigned msg_type, rc = -ENOMEM; goto out; } - } else if (msg_type == XS_TRANSACTION_END) { + } else if (u->u.msg.tx_id != 0) { list_for_each_entry(trans, &u->transactions, list) if (trans->handle.id == u->u.msg.tx_id) break; if (&trans->list == &u->transactions) - return -ESRCH; + return xenbus_command_reply(u, XS_ERROR, "ENOENT"); } reply = xenbus_dev_request_and_reply(&u->u.msg); @@ -372,12 +395,12 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) path = u->u.buffer + sizeof(u->u.msg); token = memchr(path, 0, u->u.msg.len); if (token == NULL) { - rc = -EILSEQ; + rc = xenbus_command_reply(u, XS_ERROR, "EINVAL"); goto out; } token++; if (memchr(token, 0, u->u.msg.len - (token - path)) == NULL) { - rc = -EILSEQ; + rc = xenbus_command_reply(u, XS_ERROR, "EINVAL"); goto out; } @@ -411,23 +434,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) } /* Success. Synthesize a reply to say all is OK. */ - { - struct { - struct xsd_sockmsg hdr; - char body[3]; - } __packed reply = { - { - .type = msg_type, - .len = sizeof(reply.body) - }, - "OK" - }; - - mutex_lock(&u->reply_mutex); - rc = queue_reply(&u->read_buffers, &reply, sizeof(reply)); - wake_up(&u->read_waitq); - mutex_unlock(&u->reply_mutex); - } + rc = xenbus_command_reply(u, msg_type, "OK"); out: return rc; |