From 2e87b7a8bef7901ab56f121f0d7c085aacee86fc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:35 +0000 Subject: extcon: arizona: Add device binding to enable ADC mode micdet Add a simple boolean binding to turn on and off the use of ADC microphone detection mode to determine 3/4 pole jack. Signed-off-by: Charles Keepax Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index e4890dd4fefd..af3afeeb6673 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1236,6 +1236,9 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) pdata->micd_force_micbias = device_property_read_bool(arizona->dev, "wlf,micd-force-micbias"); + pdata->micd_software_compare = device_property_read_bool(arizona->dev, + "wlf,micd-software-compare"); + return 0; } -- cgit v1.2.3 From 99374227cfb9f410965022063baf447ae3c41b9f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:36 +0000 Subject: extcon: arizona: Add device binding for the general purpose switch The switch is generally used in conjunction with the MICDET clamp to suppress pops and clicks associated with jack insertion. This patch adds a binding that allows the user to select the mode of operation for this switch. Signed-off-by: Charles Keepax Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index af3afeeb6673..493da5bc9989 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1239,6 +1239,8 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) pdata->micd_software_compare = device_property_read_bool(arizona->dev, "wlf,micd-software-compare"); + device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw); + return 0; } -- cgit v1.2.3 From 3d7a872fa359e13b6903c7fb45bb15c0078d4a84 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:37 +0000 Subject: extcon: arizona: Add device binding for jack detect polarity inversion By default the driver expects the jackdet pin to be pulled low when a jack is inserted. This patch adds a device binding that allows the user to specify that the jackdet pin will be pulled high when a jack is inserted. Signed-off-by: Charles Keepax Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 493da5bc9989..27ddf9cccca5 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1239,6 +1239,9 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) pdata->micd_software_compare = device_property_read_bool(arizona->dev, "wlf,micd-software-compare"); + pdata->jd_invert = device_property_read_bool(arizona->dev, + "wlf,jd-invert"); + device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw); return 0; -- cgit v1.2.3 From 35247c136a47a05d7747c9c7f0bc0d948d1fdda5 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:38 +0000 Subject: extcon: arizona: Add device binding for second jack detect pin on GPIO5 Some Arizona devices have the option to use the GPIO5 pin as a second jack detection pin. This patch adds device bindings to specify to the driver that it should use this pin. Note that the second jack detection pin is hard wired in the chip so can only be enabled through the binding, rather than a pin being specified. Signed-off-by: Charles Keepax Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 27ddf9cccca5..7c9598db318d 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1244,6 +1244,11 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw); + pdata->jd_gpio5 = device_property_read_bool(arizona->dev, + "wlf,use-jd-gpio"); + pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev, + "wlf,use-jd-gpio-nopull"); + return 0; } -- cgit v1.2.3 From afe330098d255e698088e010be3cb4fa57e9ff86 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:39 +0000 Subject: extcon: arizona: Update DT binding documentation for mic detection Add additional bindings to allow configuration of the system specific microphone detection settings. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- .../devicetree/bindings/extcon/extcon-arizona.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index e1705fae63a8..d6618119a9a8 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -13,3 +13,23 @@ Optional properties: ARIZONA_ACCDET_MODE_HPR or 2 - Headphone detect mode is set to HPDETR If this node is not mentioned or if the value is unknown, then headphone detection mode is set to HPDETL. + + - wlf,micd-software-compare : Use a software comparison to determine mic + presence + - wlf,micd-detect-debounce : Additional software microphone detection + debounce specified in milliseconds. + - wlf,micd-pol-gpio : GPIO specifier for the GPIO controlling the headset + polarity if one exists. + - wlf,micd-bias-start-time : Time allowed for MICBIAS to startup prior to + performing microphone detection, specified as per the ARIZONA_MICD_TIME_XXX + defines. + - wlf,micd-rate : Delay between successive microphone detection measurements, + specified as per the ARIZONA_MICD_TIME_XXX defines. + - wlf,micd-dbtime : Microphone detection hardware debounces specified as the + number of measurements to take, valid values being 2 and 4. + - wlf,micd-timeout : Timeout for microphone detection, specified in + milliseconds. + - wlf,micd-force-micbias : Force MICBIAS continuously on during microphone + detection. + + - wlf,gpsw : Settings for the general purpose switch -- cgit v1.2.3 From 36a86872964609f2596d22f323070b60b17e08ef Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Nov 2015 15:45:40 +0000 Subject: extcon: arizona: Update DT binding documentation for jack detection Add additional bindings for both inverting the polarity of the jack detection pins and allowing the use of a second jack detection pin. Note that the second jack detection pin is hard wired in the chip so can only be enabled through the binding, rather than a pin being specified. Signed-off-by: Charles Keepax Reviewed-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/extcon-arizona.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index d6618119a9a8..7640a3502c67 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -14,6 +14,12 @@ Optional properties: If this node is not mentioned or if the value is unknown, then headphone detection mode is set to HPDETL. + - wlf,use-jd-gpio : Use GPIO input along with JD1 for dual pin jack + detection. + - wlf,use-jd-gpio-nopull : Internal pull on GPIO is disabled when used for + jack detection. + - wlf,jd-invert : Invert the polarity of the jack detection switch + - wlf,micd-software-compare : Use a software comparison to determine mic presence - wlf,micd-detect-debounce : Additional software microphone detection -- cgit v1.2.3 From 832df9e8ecabec271a0c418bdbb94da826dc5b6d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 20 Nov 2015 17:53:59 +0900 Subject: extcon: arizona: Update naming for second jack detection DT binding Update the name for the second jack detection pin binding to be a little less confusing. Signed-off-by: Charles Keepax Acked-by: Rob Herring Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/extcon-arizona.txt | 4 ++-- drivers/extcon/extcon-arizona.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index 7640a3502c67..8aa0bd430f7b 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -14,9 +14,9 @@ Optional properties: If this node is not mentioned or if the value is unknown, then headphone detection mode is set to HPDETL. - - wlf,use-jd-gpio : Use GPIO input along with JD1 for dual pin jack + - wlf,use-jd2 : Use the additional JD input along with JD1 for dual pin jack detection. - - wlf,use-jd-gpio-nopull : Internal pull on GPIO is disabled when used for + - wlf,use-jd2-nopull : Internal pull on JD2 is disabled when used for jack detection. - wlf,jd-invert : Invert the polarity of the jack detection switch diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 7c9598db318d..c377030807c4 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1245,9 +1245,9 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) device_property_read_u32(arizona->dev, "wlf,gpsw", &pdata->gpsw); pdata->jd_gpio5 = device_property_read_bool(arizona->dev, - "wlf,use-jd-gpio"); + "wlf,use-jd2"); pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev, - "wlf,use-jd-gpio-nopull"); + "wlf,use-jd2-nopull"); return 0; } -- cgit v1.2.3 From 7a7ef0f2a4b359d0206772bf291781157d07f7dc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 23 Nov 2015 14:51:30 +0000 Subject: extcon: arizona: Update naming for micd-timeout DT to include units Add time units of -ms (milliseconds) to wlf,micd-timeout. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/extcon-arizona.txt | 2 +- drivers/extcon/extcon-arizona.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index 8aa0bd430f7b..238e10e86a20 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -33,7 +33,7 @@ Optional properties: specified as per the ARIZONA_MICD_TIME_XXX defines. - wlf,micd-dbtime : Microphone detection hardware debounces specified as the number of measurements to take, valid values being 2 and 4. - - wlf,micd-timeout : Timeout for microphone detection, specified in + - wlf,micd-timeout-ms : Timeout for microphone detection, specified in milliseconds. - wlf,micd-force-micbias : Force MICBIAS continuously on during microphone detection. diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index c377030807c4..86475338e51e 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1230,7 +1230,7 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) device_property_read_u32(arizona->dev, "wlf,micd-dbtime", &pdata->micd_dbtime); - device_property_read_u32(arizona->dev, "wlf,micd-timeout", + device_property_read_u32(arizona->dev, "wlf,micd-timeout-ms", &pdata->micd_timeout); pdata->micd_force_micbias = device_property_read_bool(arizona->dev, -- cgit v1.2.3 From 5f01e6bc3336c27b9553494214f05ac439dbeb37 Mon Sep 17 00:00:00 2001 From: Saurabh Sengar Date: Wed, 25 Nov 2015 23:31:11 +0530 Subject: extcon: rt8973: Add IRQF_ONESHOT to interrupt flags This patch adds IRQF_ONESHOT if no primary handler is provided for request threaded irq. Signed-off-by: Saurabh Sengar Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-rt8973a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-rt8973a.c b/drivers/extcon/extcon-rt8973a.c index 36bf1d63791c..e1bb82809bef 100644 --- a/drivers/extcon/extcon-rt8973a.c +++ b/drivers/extcon/extcon-rt8973a.c @@ -603,7 +603,7 @@ static int rt8973a_muic_i2c_probe(struct i2c_client *i2c, ret = devm_request_threaded_irq(info->dev, virq, NULL, rt8973a_muic_irq_handler, - IRQF_NO_SUSPEND, + IRQF_NO_SUSPEND | IRQF_ONESHOT, muic_irq->name, info); if (ret) { dev_err(info->dev, -- cgit v1.2.3 From e2042a8a80ab598bbb8d06cd7f3078923c7c77e3 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 15 Oct 2015 10:37:47 +0200 Subject: checkkconfigsymbols.py: multiprocessing of files Distribute the parsing of source and Kconfig files on all available cores to speed up processing. Signed-off-by: Valentin Rothberg Signed-off-by: Greg Kroah-Hartman --- scripts/checkkconfigsymbols.py | 128 ++++++++++++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 26 deletions(-) diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index 2f4b7ffd5570..cfe397b61c48 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -10,9 +10,11 @@ import os import re +import signal import sys -from subprocess import Popen, PIPE, STDOUT +from multiprocessing import Pool, cpu_count from optparse import OptionParser +from subprocess import Popen, PIPE, STDOUT # regex expressions @@ -26,7 +28,7 @@ SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")" # regex objects REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$") -REGEX_FEATURE = re.compile(r'(?!\B"[^"]*)' + FEATURE + r'(?![^"]*"\B)') +REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)') REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE) REGEX_KCONFIG_DEF = re.compile(DEF) REGEX_KCONFIG_EXPR = re.compile(EXPR) @@ -34,6 +36,7 @@ REGEX_KCONFIG_STMT = re.compile(STMT) REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$") REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$") REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+") +REGEX_QUOTES = re.compile("(\"(.*?)\")") def parse_options(): @@ -209,14 +212,36 @@ def get_head(): return stdout.strip('\n') +def partition(lst, size): + """Partition list @lst into eveni-sized lists of size @size.""" + return [lst[i::size] for i in xrange(size)] + + +def init_worker(): + """Set signal handler to ignore SIGINT.""" + signal.signal(signal.SIGINT, signal.SIG_IGN) + + def check_symbols(ignore): """Find undefined Kconfig symbols and return a dict with the symbol as key and a list of referencing files as value. Files matching %ignore are not checked for undefined symbols.""" + pool = Pool(cpu_count(), init_worker) + try: + return check_symbols_helper(pool, ignore) + except KeyboardInterrupt: + pool.terminate() + pool.join() + sys.exit(1) + + +def check_symbols_helper(pool, ignore): + """Helper method for check_symbols(). Used to catch keyboard interrupts in + check_symbols() in order to properly terminate running worker processes.""" source_files = [] kconfig_files = [] - defined_features = set() - referenced_features = dict() # {feature: [files]} + defined_features = [] + referenced_features = dict() # {file: [features]} # use 'git ls-files' to get the worklist stdout = execute("git ls-files") @@ -231,21 +256,33 @@ def check_symbols(ignore): if REGEX_FILE_KCONFIG.match(gitfile): kconfig_files.append(gitfile) else: - # all non-Kconfig files are checked for consistency + if ignore and not re.match(ignore, gitfile): + continue + # add source files that do not match the ignore pattern source_files.append(gitfile) - for sfile in source_files: - if ignore and re.match(ignore, sfile): - # do not check files matching %ignore - continue - parse_source_file(sfile, referenced_features) + # parse source files + arglist = partition(source_files, cpu_count()) + for res in pool.map(parse_source_files, arglist): + referenced_features.update(res) - for kfile in kconfig_files: - if ignore and re.match(ignore, kfile): - # do not collect references for files matching %ignore - parse_kconfig_file(kfile, defined_features, dict()) - else: - parse_kconfig_file(kfile, defined_features, referenced_features) + + # parse kconfig files + arglist = [] + for part in partition(kconfig_files, cpu_count()): + arglist.append((part, ignore)) + for res in pool.map(parse_kconfig_files, arglist): + defined_features.extend(res[0]) + referenced_features.update(res[1]) + defined_features = set(defined_features) + + # inverse mapping of referenced_features to dict(feature: [files]) + inv_map = dict() + for _file, features in referenced_features.iteritems(): + for feature in features: + inv_map[feature] = inv_map.get(feature, set()) + inv_map[feature].add(_file) + referenced_features = inv_map undefined = {} # {feature: [files]} for feature in sorted(referenced_features): @@ -262,9 +299,23 @@ def check_symbols(ignore): return undefined -def parse_source_file(sfile, referenced_features): - """Parse @sfile for referenced Kconfig features.""" +def parse_source_files(source_files): + """Parse each source file in @source_files and return dictionary with source + files as keys and lists of references Kconfig symbols as values.""" + referenced_features = dict() + for sfile in source_files: + referenced_features[sfile] = parse_source_file(sfile) + return referenced_features + + +def parse_source_file(sfile): + """Parse @sfile and return a list of referenced Kconfig features.""" lines = [] + references = [] + + if not os.path.exists(sfile): + return references + with open(sfile, "r") as stream: lines = stream.readlines() @@ -275,9 +326,9 @@ def parse_source_file(sfile, referenced_features): for feature in features: if not REGEX_FILTER_FEATURES.search(feature): continue - sfiles = referenced_features.get(feature, set()) - sfiles.add(sfile) - referenced_features[feature] = sfiles + references.append(feature) + + return references def get_features_in_line(line): @@ -285,11 +336,35 @@ def get_features_in_line(line): return REGEX_FEATURE.findall(line) -def parse_kconfig_file(kfile, defined_features, referenced_features): +def parse_kconfig_files(args): + """Parse kconfig files and return tuple of defined and references Kconfig + symbols. Note, @args is a tuple of a list of files and the @ignore + pattern.""" + kconfig_files = args[0] + ignore = args[1] + defined_features = [] + referenced_features = dict() + + for kfile in kconfig_files: + defined, references = parse_kconfig_file(kfile) + defined_features.extend(defined) + if ignore and re.match(ignore, kfile): + # do not collect references for files that match the ignore pattern + continue + referenced_features[kfile] = references + return (defined_features, referenced_features) + + +def parse_kconfig_file(kfile): """Parse @kfile and update feature definitions and references.""" lines = [] + defined = [] + references = [] skip = False + if not os.path.exists(kfile): + return defined, references + with open(kfile, "r") as stream: lines = stream.readlines() @@ -300,7 +375,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): if REGEX_KCONFIG_DEF.match(line): feature_def = REGEX_KCONFIG_DEF.findall(line) - defined_features.add(feature_def[0]) + defined.append(feature_def[0]) skip = False elif REGEX_KCONFIG_HELP.match(line): skip = True @@ -308,6 +383,7 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): # ignore content of help messages pass elif REGEX_KCONFIG_STMT.match(line): + line = REGEX_QUOTES.sub("", line) features = get_features_in_line(line) # multi-line statements while line.endswith("\\"): @@ -319,9 +395,9 @@ def parse_kconfig_file(kfile, defined_features, referenced_features): if REGEX_NUMERIC.match(feature): # ignore numeric values continue - paths = referenced_features.get(feature, set()) - paths.add(kfile) - referenced_features[feature] = paths + references.append(feature) + + return defined, references if __name__ == "__main__": -- cgit v1.2.3 From 1b2c841467515425636c15799ac90f6c4821acc0 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 26 Nov 2015 14:17:15 +0100 Subject: checkkconfigsymbols.py: find similar symbols Add support to find string-similar symbols. When option --sim SYM is specified, checkkconfigsymbols.py will print at most 10 symbols defined in Kconfig that are string similar to SYM in the following format: Similar symbols: $COMMA_SEPARATED_LIST_OF_SYMBOLS Note, if no similar symbols are found it is indicated as follows: Similar symbols: no similar symbols found Since the implemented functionality is also useful when searching the entire source or when diffing two commits, a list of similar symbols is printed unconditionally with the other data. In order to make the output more readable, the format now looks as follows: $UNDEFINED_SYMBOL Referencing files: $COMMA_SEPARATED_LIST_OF_FILES Similar symbols: $COMMA_SEPARATED_LIST_OF_SYMBOLS [Optional with '--find'] Commits changing symbol: - $COMMIT_1_HASH ("$COMMIT_1_MESSAGE") - $COMMIT_2_HASH ("$COMMIT_2_MESSAGE") or - no commit found Signed-off-by: Valentin Rothberg Signed-off-by: Greg Kroah-Hartman --- scripts/checkkconfigsymbols.py | 114 +++++++++++++++++++++++++++++++---------- 1 file changed, 88 insertions(+), 26 deletions(-) diff --git a/scripts/checkkconfigsymbols.py b/scripts/checkkconfigsymbols.py index cfe397b61c48..d8f6c094cce5 100755 --- a/scripts/checkkconfigsymbols.py +++ b/scripts/checkkconfigsymbols.py @@ -8,6 +8,7 @@ # Licensed under the terms of the GNU GPL License version 2 +import difflib import os import re import signal @@ -74,6 +75,9 @@ def parse_options(): "the pattern needs to be a Python regex. To " "ignore defconfigs, specify -i '.*defconfig'.") + parser.add_option('-s', '--sim', dest='sim', action='store', default="", + help="Print a list of maximum 10 string-similar symbols.") + parser.add_option('', '--force', dest='force', action='store_true', default=False, help="Reset current Git tree even when it's dirty.") @@ -112,6 +116,18 @@ def main(): """Main function of this module.""" opts = parse_options() + if opts.sim and not opts.commit and not opts.diff: + sims = find_sims(opts.sim, opts.ignore) + if sims: + print "%s: %s" % (yel("Similar symbols"), ', '.join(sims)) + else: + print "%s: no similar symbols found" % yel("Similar symbols") + sys.exit(0) + + # dictionary of (un)defined symbols + defined = {} + undefined = {} + if opts.commit or opts.diff: head = get_head() @@ -130,40 +146,56 @@ def main(): # get undefined items before the commit execute("git reset --hard %s" % commit_a) - undefined_a = check_symbols(opts.ignore) + undefined_a, _ = check_symbols(opts.ignore) # get undefined items for the commit execute("git reset --hard %s" % commit_b) - undefined_b = check_symbols(opts.ignore) + undefined_b, defined = check_symbols(opts.ignore) # report cases that are present for the commit but not before for feature in sorted(undefined_b): # feature has not been undefined before if not feature in undefined_a: files = sorted(undefined_b.get(feature)) - print "%s\t%s" % (yel(feature), ", ".join(files)) - if opts.find: - commits = find_commits(feature, opts.diff) - print red(commits) + undefined[feature] = files # check if there are new files that reference the undefined feature else: files = sorted(undefined_b.get(feature) - undefined_a.get(feature)) if files: - print "%s\t%s" % (yel(feature), ", ".join(files)) - if opts.find: - commits = find_commits(feature, opts.diff) - print red(commits) + undefined[feature] = files # reset to head execute("git reset --hard %s" % head) # default to check the entire tree else: - undefined = check_symbols(opts.ignore) - for feature in sorted(undefined): - files = sorted(undefined.get(feature)) - print "%s\t%s" % (yel(feature), ", ".join(files)) + undefined, defined = check_symbols(opts.ignore) + + # now print the output + for feature in sorted(undefined): + print red(feature) + + files = sorted(undefined.get(feature)) + print "%s: %s" % (yel("Referencing files"), ", ".join(files)) + + sims = find_sims(feature, opts.ignore, defined) + sims_out = yel("Similar symbols") + if sims: + print "%s: %s" % (sims_out, ', '.join(sims)) + else: + print "%s: %s" % (sims_out, "no similar symbols found") + + if opts.find: + print "%s:" % yel("Commits changing symbol") + commits = find_commits(feature, opts.diff) + if commits: + for commit in commits: + commit = commit.split(" ", 1) + print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1]) + else: + print "\t- no commit found" + print # new line def yel(string): @@ -193,7 +225,7 @@ def find_commits(symbol, diff): """Find commits changing %symbol in the given range of %diff.""" commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s" % (symbol, diff)) - return commits + return [x for x in commits.split("\n") if x] def tree_is_dirty(): @@ -222,6 +254,45 @@ def init_worker(): signal.signal(signal.SIGINT, signal.SIG_IGN) +def find_sims(symbol, ignore, defined = []): + """Return a list of max. ten Kconfig symbols that are string-similar to + @symbol.""" + if defined: + return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + + pool = Pool(cpu_count(), init_worker) + kfiles = [] + for gitfile in get_files(): + if REGEX_FILE_KCONFIG.match(gitfile): + kfiles.append(gitfile) + + arglist = [] + for part in partition(kfiles, cpu_count()): + arglist.append((part, ignore)) + + for res in pool.map(parse_kconfig_files, arglist): + defined.extend(res[0]) + + return sorted(difflib.get_close_matches(symbol, set(defined), 10)) + + +def get_files(): + """Return a list of all files in the current git directory.""" + # use 'git ls-files' to get the worklist + stdout = execute("git ls-files") + if len(stdout) > 0 and stdout[-1] == "\n": + stdout = stdout[:-1] + + files = [] + for gitfile in stdout.rsplit("\n"): + if ".git" in gitfile or "ChangeLog" in gitfile or \ + ".log" in gitfile or os.path.isdir(gitfile) or \ + gitfile.startswith("tools/"): + continue + files.append(gitfile) + return files + + def check_symbols(ignore): """Find undefined Kconfig symbols and return a dict with the symbol as key and a list of referencing files as value. Files matching %ignore are not @@ -243,16 +314,7 @@ def check_symbols_helper(pool, ignore): defined_features = [] referenced_features = dict() # {file: [features]} - # use 'git ls-files' to get the worklist - stdout = execute("git ls-files") - if len(stdout) > 0 and stdout[-1] == "\n": - stdout = stdout[:-1] - - for gitfile in stdout.rsplit("\n"): - if ".git" in gitfile or "ChangeLog" in gitfile or \ - ".log" in gitfile or os.path.isdir(gitfile) or \ - gitfile.startswith("tools/"): - continue + for gitfile in get_files(): if REGEX_FILE_KCONFIG.match(gitfile): kconfig_files.append(gitfile) else: @@ -296,7 +358,7 @@ def check_symbols_helper(pool, ignore): if feature[:-len("_MODULE")] in defined_features: continue undefined[feature] = referenced_features.get(feature) - return undefined + return undefined, defined_features def parse_source_files(source_files): -- cgit v1.2.3 From 9220e39b5c900c67ddcb517d52fe52d90fb5e3c8 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 11 Dec 2015 14:23:11 +0530 Subject: Drivers: hv: vmbus: fix build warning We were getting build warning about unused variable "tsc_msr" and "va_tsc" while building for i386 allmodconfig. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index 6341be8739ae..ad7fc6d92c35 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -192,9 +192,7 @@ int hv_init(void) { int max_leaf; union hv_x64_msr_hypercall_contents hypercall_msr; - union hv_x64_msr_hypercall_contents tsc_msr; void *virtaddr = NULL; - void *va_tsc = NULL; memset(hv_context.synic_event_page, 0, sizeof(void *) * NR_CPUS); memset(hv_context.synic_message_page, 0, @@ -240,6 +238,9 @@ int hv_init(void) #ifdef CONFIG_X86_64 if (ms_hyperv.features & HV_X64_MSR_REFERENCE_TSC_AVAILABLE) { + union hv_x64_msr_hypercall_contents tsc_msr; + void *va_tsc; + va_tsc = __vmalloc(PAGE_SIZE, GFP_KERNEL, PAGE_KERNEL); if (!va_tsc) goto cleanup; -- cgit v1.2.3 From bb6da5d954b934305cc536f8cc970c500d1dd54d Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 14 Dec 2015 10:37:11 +0000 Subject: extcon: arizona: Add device bindings for the micd configurations Add device bindings to support configuring the jack detection configurations. Each configuration needs to specify the connection of the mic det pins, which micbias should be used and the value of the micd polarity GPIO required to activate that configuration. Signed-off-by: Charles Keepax Acked-by: Chanwoo Choi Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-arizona.c | 56 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 86475338e51e..c121d01a5cd6 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -1201,10 +1201,58 @@ static void arizona_micd_set_level(struct arizona *arizona, int index, regmap_update_bits(arizona->regmap, reg, mask, level); } -static int arizona_extcon_device_get_pdata(struct arizona *arizona) +static int arizona_extcon_get_micd_configs(struct device *dev, + struct arizona *arizona) +{ + const char * const prop = "wlf,micd-configs"; + const int entries_per_config = 3; + struct arizona_micd_config *micd_configs; + int nconfs, ret; + int i, j; + u32 *vals; + + nconfs = device_property_read_u32_array(arizona->dev, prop, NULL, 0); + if (nconfs <= 0) + return 0; + + vals = kcalloc(nconfs, sizeof(u32), GFP_KERNEL); + if (!vals) + return -ENOMEM; + + ret = device_property_read_u32_array(arizona->dev, prop, vals, nconfs); + if (ret < 0) + goto out; + + nconfs /= entries_per_config; + + micd_configs = devm_kzalloc(dev, + nconfs * sizeof(struct arizona_micd_range), + GFP_KERNEL); + if (!micd_configs) { + ret = -ENOMEM; + goto out; + } + + for (i = 0, j = 0; i < nconfs; ++i) { + micd_configs[i].src = vals[j++] ? ARIZONA_ACCDET_SRC : 0; + micd_configs[i].bias = vals[j++]; + micd_configs[i].gpio = vals[j++]; + } + + arizona->pdata.micd_configs = micd_configs; + arizona->pdata.num_micd_configs = nconfs; + +out: + kfree(vals); + return ret; +} + +static int arizona_extcon_device_get_pdata(struct device *dev, + struct arizona *arizona) { struct arizona_pdata *pdata = &arizona->pdata; unsigned int val = ARIZONA_ACCDET_MODE_HPL; + int ret; device_property_read_u32(arizona->dev, "wlf,hpdet-channel", &val); switch (val) { @@ -1249,6 +1297,10 @@ static int arizona_extcon_device_get_pdata(struct arizona *arizona) pdata->jd_gpio5_nopull = device_property_read_bool(arizona->dev, "wlf,use-jd2-nopull"); + ret = arizona_extcon_get_micd_configs(dev, arizona); + if (ret < 0) + dev_err(arizona->dev, "Failed to read micd configs: %d\n", ret); + return 0; } @@ -1270,7 +1322,7 @@ static int arizona_extcon_probe(struct platform_device *pdev) return -ENOMEM; if (!dev_get_platdata(arizona->dev)) - arizona_extcon_device_get_pdata(arizona); + arizona_extcon_device_get_pdata(&pdev->dev, arizona); info->micvdd = devm_regulator_get(&pdev->dev, "MICVDD"); if (IS_ERR(info->micvdd)) { -- cgit v1.2.3 From cb0eac8fd1a3180ce260a8dca01584bc5495a8e8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 14 Dec 2015 10:37:12 +0000 Subject: extcon: arizona: Update device tree binding for mic detect configurations Update the device tree binding documentation to include documentation for the wlf,micd-configs property that is used to specify the configurations for headset polarity detection (CTIA / OTMP). Signed-off-by: Charles Keepax Acked-by: Rob Herring Signed-off-by: Chanwoo Choi --- Documentation/devicetree/bindings/extcon/extcon-arizona.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index 238e10e86a20..fd9b898d2d7d 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -37,5 +37,13 @@ Optional properties: milliseconds. - wlf,micd-force-micbias : Force MICBIAS continuously on during microphone detection. + - wlf,micd-configs : Headset polarity configurations (generally used for + detection of CTIA / OMTP headsets), the field can be of variable length + but should always be a multiple of 3 cells long, each three cell group + represents one polarity configuration. + The first cell defines the accessory detection pin, zero will use MICDET1 + and all other values will use MICDET2. + The second cell represents the MICBIAS to be used. + The third cell represents the value of the micd-pol-gpio pin. - wlf,gpsw : Settings for the general purpose switch -- cgit v1.2.3 From 36e2693b68562d4b984b841c041ffa76370e9b7f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 14 Dec 2015 10:37:13 +0000 Subject: extcon: arizona: Add DT binding examples Add an example for all elements of the Arizona extcon device tree binding. Signed-off-by: Charles Keepax Signed-off-by: Chanwoo Choi --- .../devicetree/bindings/extcon/extcon-arizona.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt index fd9b898d2d7d..e27341f8a4c7 100644 --- a/Documentation/devicetree/bindings/extcon/extcon-arizona.txt +++ b/Documentation/devicetree/bindings/extcon/extcon-arizona.txt @@ -47,3 +47,29 @@ Optional properties: The third cell represents the value of the micd-pol-gpio pin. - wlf,gpsw : Settings for the general purpose switch + +Example: + +codec: wm8280@0 { + compatible = "wlf,wm8280"; + reg = <0>; + ... + + wlf,use-jd2; + wlf,use-jd2-nopull; + wlf,jd-invert; + + wlf,micd-software-compare; + wlf,micd-detect-debounce = <0>; + wlf,micd-pol-gpio = <&codec 2 0>; + wlf,micd-rate = ; + wlf,micd-dbtime = <4>; + wlf,micd-timeout-ms = <100>; + wlf,micd-force-micbias; + wlf,micd-configs = < + 0 1 0 /* MICDET1 MICBIAS1 GPIO=low */ + 1 2 1 /* MICDET2 MICBIAS2 GPIO=high */ + >; + + wlf,gpsw = <0>; +}; -- cgit v1.2.3 From c2957563ad0965c8bfb393dcd22ddb683dd1ff1c Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 14 Dec 2015 11:06:02 +0100 Subject: extcon: max14577: fix handling return value of regmap_irq_get_virq The function can return negative values, so its result should be assigned to signed variable. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/assign_signed_to_unsigned.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2046107 Signed-off-by: Andrzej Hajda Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max14577.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-max14577.c b/drivers/extcon/extcon-max14577.c index 601dbd996487..b30ab97ce75f 100644 --- a/drivers/extcon/extcon-max14577.c +++ b/drivers/extcon/extcon-max14577.c @@ -692,7 +692,7 @@ static int max14577_muic_probe(struct platform_device *pdev) /* Support irq domain for max14577 MUIC device */ for (i = 0; i < info->muic_irqs_num; i++) { struct max14577_muic_irq *muic_irq = &info->muic_irqs[i]; - unsigned int virq = 0; + int virq = 0; virq = regmap_irq_get_virq(max14577->irq_data, muic_irq->irq); if (virq <= 0) -- cgit v1.2.3 From cbc46603df56b5933aef6765fc50d3aa18f96ced Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 14 Dec 2015 12:12:42 +0100 Subject: extcon: max77693: fix handling return value of regmap_irq_get_virq The function can return negative values, so its result should be assigned to signed variable. Signed-off-by: Andrzej Hajda Suggested-by: Krzysztof Kozlowski Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77693.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index 44c499e1beee..fdf8f5d4d4e9 100644 --- a/drivers/extcon/extcon-max77693.c +++ b/drivers/extcon/extcon-max77693.c @@ -1127,11 +1127,11 @@ static int max77693_muic_probe(struct platform_device *pdev) /* Support irq domain for MAX77693 MUIC device */ for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) { struct max77693_muic_irq *muic_irq = &muic_irqs[i]; - unsigned int virq = 0; + int virq; virq = regmap_irq_get_virq(max77693->irq_data_muic, muic_irq->irq); - if (!virq) + if (virq <= 0) return -EINVAL; muic_irq->virq = virq; -- cgit v1.2.3 From c05c0d544edfb0ffbbd01acd199ea9626bdfd6c3 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 14 Dec 2015 11:06:03 +0100 Subject: extcon: max77843: fix handling return value of regmap_irq_get_virq The function can return negative values, so its result should be assigned to signed variable. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/assign_signed_to_unsigned.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2046107 Signed-off-by: Andrzej Hajda Reviewed-by: Krzysztof Kozlowski Signed-off-by: Chanwoo Choi --- drivers/extcon/extcon-max77843.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/extcon/extcon-max77843.c b/drivers/extcon/extcon-max77843.c index 9f9ea334399c..74dfb7f4f277 100644 --- a/drivers/extcon/extcon-max77843.c +++ b/drivers/extcon/extcon-max77843.c @@ -811,7 +811,7 @@ static int max77843_muic_probe(struct platform_device *pdev) for (i = 0; i < ARRAY_SIZE(max77843_muic_irqs); i++) { struct max77843_muic_irq *muic_irq = &max77843_muic_irqs[i]; - unsigned int virq = 0; + int virq = 0; virq = regmap_irq_get_virq(max77843->irq_data_muic, muic_irq->irq); -- cgit v1.2.3 From c0b200cfb0403740171c7527b3ac71d03f82947a Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:32 -0800 Subject: Drivers: hv: util: Increase the timeout for util services Util services such as KVP and FCOPY need assistance from daemon's running in user space. Increase the timeout so we don't prematurely terminate the transaction in the kernel. Host sets up a 60 second timeout for all util driver transactions. The host will retry the transaction if it times out. Set the guest timeout at 30 seconds. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_fcopy.c | 3 ++- drivers/hv/hv_kvp.c | 3 ++- drivers/hv/hyperv_vmbus.h | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index db4b887b889d..bbdec50c4a1c 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -275,7 +275,8 @@ void hv_fcopy_onchannelcallback(void *context) * Send the information to the user-level daemon. */ schedule_work(&fcopy_send_work); - schedule_delayed_work(&fcopy_timeout_work, 5*HZ); + schedule_delayed_work(&fcopy_timeout_work, + HV_UTIL_TIMEOUT * HZ); return; } icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE; diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 74c38a9f34a6..e6aa33a89b0e 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -668,7 +668,8 @@ void hv_kvp_onchannelcallback(void *context) * user-mode not responding. */ schedule_work(&kvp_sendkey_work); - schedule_delayed_work(&kvp_timeout_work, 5*HZ); + schedule_delayed_work(&kvp_timeout_work, + HV_UTIL_TIMEOUT * HZ); return; diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 3782636562a1..225b96bcf7fe 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -30,6 +30,11 @@ #include #include +/* + * Timeout for services such as KVP and fcopy. + */ +#define HV_UTIL_TIMEOUT 30 + /* * The below CPUID leaves are present if VersionAndFeatures.HypervisorPresent * is set by CPUID(HVCPUID_VERSION_FEATURES). -- cgit v1.2.3 From 3cace4a616108539e2730f8dc21a636474395e0f Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:33 -0800 Subject: Drivers: hv: utils: run polling callback always in interrupt context All channel interrupts are bound to specific VCPUs in the guest at the point channel is created. While currently, we invoke the polling function on the correct CPU (the CPU to which the channel is bound to) in some cases we may run the polling function in a non-interrupt context. This potentially can cause an issue as the polling function can be interrupted by the channel callback function. Fix the issue by running the polling function on the appropriate CPU at interrupt level. Additional details of the issue being addressed by this patch are given below: Currently hv_fcopy_onchannelcallback is called from interrupts and also via the ->write function of hv_utils. Since the used global variables to maintain state are not thread safe the state can get out of sync. This affects the variable state as well as the channel inbound buffer. As suggested by KY adjust hv_poll_channel to always run the given callback on the cpu which the channel is bound to. This avoids the need for locking because all the util services are single threaded and only one transaction is active at any given point in time. Additionally, remove the context variable, they will always be the same as recv_channel. Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_fcopy.c | 34 ++++++++++++---------------------- drivers/hv/hv_kvp.c | 28 ++++++++++------------------ drivers/hv/hv_snapshot.c | 29 +++++++++++------------------ drivers/hv/hyperv_vmbus.h | 6 +----- 4 files changed, 34 insertions(+), 63 deletions(-) diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index bbdec50c4a1c..c37a71e13de0 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -51,7 +51,6 @@ static struct { struct hv_fcopy_hdr *fcopy_msg; /* current message */ struct vmbus_channel *recv_channel; /* chn we got the request */ u64 recv_req_id; /* request ID. */ - void *fcopy_context; /* for the channel callback */ } fcopy_transaction; static void fcopy_respond_to_host(int error); @@ -67,6 +66,13 @@ static struct hvutil_transport *hvt; */ static int dm_reg_value; +static void fcopy_poll_wrapper(void *channel) +{ + /* Transaction is finished, reset the state here to avoid races. */ + fcopy_transaction.state = HVUTIL_READY; + hv_fcopy_onchannelcallback(channel); +} + static void fcopy_timeout_func(struct work_struct *dummy) { /* @@ -74,13 +80,7 @@ static void fcopy_timeout_func(struct work_struct *dummy) * process the pending transaction. */ fcopy_respond_to_host(HV_E_FAIL); - - /* Transaction is finished, reset the state. */ - if (fcopy_transaction.state > HVUTIL_READY) - fcopy_transaction.state = HVUTIL_READY; - - hv_poll_channel(fcopy_transaction.fcopy_context, - hv_fcopy_onchannelcallback); + hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); } static int fcopy_handle_handshake(u32 version) @@ -108,9 +108,7 @@ static int fcopy_handle_handshake(u32 version) return -EINVAL; } pr_debug("FCP: userspace daemon ver. %d registered\n", version); - fcopy_transaction.state = HVUTIL_READY; - hv_poll_channel(fcopy_transaction.fcopy_context, - hv_fcopy_onchannelcallback); + hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); return 0; } @@ -227,15 +225,8 @@ void hv_fcopy_onchannelcallback(void *context) int util_fw_version; int fcopy_srv_version; - if (fcopy_transaction.state > HVUTIL_READY) { - /* - * We will defer processing this callback once - * the current transaction is complete. - */ - fcopy_transaction.fcopy_context = context; + if (fcopy_transaction.state > HVUTIL_READY) return; - } - fcopy_transaction.fcopy_context = NULL; vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, &requestid); @@ -305,9 +296,8 @@ static int fcopy_on_msg(void *msg, int len) if (cancel_delayed_work_sync(&fcopy_timeout_work)) { fcopy_transaction.state = HVUTIL_USERSPACE_RECV; fcopy_respond_to_host(*val); - fcopy_transaction.state = HVUTIL_READY; - hv_poll_channel(fcopy_transaction.fcopy_context, - hv_fcopy_onchannelcallback); + hv_poll_channel(fcopy_transaction.recv_channel, + fcopy_poll_wrapper); } return 0; diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index e6aa33a89b0e..2a3420c4ca59 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -66,7 +66,6 @@ static struct { struct hv_kvp_msg *kvp_msg; /* current message */ struct vmbus_channel *recv_channel; /* chn we got the request */ u64 recv_req_id; /* request ID. */ - void *kvp_context; /* for the channel callback */ } kvp_transaction; /* @@ -94,6 +93,13 @@ static struct hvutil_transport *hvt; */ #define HV_DRV_VERSION "3.1" +static void kvp_poll_wrapper(void *channel) +{ + /* Transaction is finished, reset the state here to avoid races. */ + kvp_transaction.state = HVUTIL_READY; + hv_kvp_onchannelcallback(channel); +} + static void kvp_register(int reg_value) { @@ -121,12 +127,7 @@ static void kvp_timeout_func(struct work_struct *dummy) */ kvp_respond_to_host(NULL, HV_E_FAIL); - /* Transaction is finished, reset the state. */ - if (kvp_transaction.state > HVUTIL_READY) - kvp_transaction.state = HVUTIL_READY; - - hv_poll_channel(kvp_transaction.kvp_context, - hv_kvp_onchannelcallback); + hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); } static int kvp_handle_handshake(struct hv_kvp_msg *msg) @@ -218,9 +219,7 @@ static int kvp_on_msg(void *msg, int len) */ if (cancel_delayed_work_sync(&kvp_timeout_work)) { kvp_respond_to_host(message, error); - kvp_transaction.state = HVUTIL_READY; - hv_poll_channel(kvp_transaction.kvp_context, - hv_kvp_onchannelcallback); + hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); } return 0; @@ -596,15 +595,8 @@ void hv_kvp_onchannelcallback(void *context) int util_fw_version; int kvp_srv_version; - if (kvp_transaction.state > HVUTIL_READY) { - /* - * We will defer processing this callback once - * the current transaction is complete. - */ - kvp_transaction.kvp_context = context; + if (kvp_transaction.state > HVUTIL_READY) return; - } - kvp_transaction.kvp_context = NULL; vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 4, &recvlen, &requestid); diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 815405f2e777..a548ae42c927 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -53,7 +53,6 @@ static struct { struct vmbus_channel *recv_channel; /* chn we got the request */ u64 recv_req_id; /* request ID. */ struct hv_vss_msg *msg; /* current message */ - void *vss_context; /* for the channel callback */ } vss_transaction; @@ -74,6 +73,13 @@ static void vss_timeout_func(struct work_struct *dummy); static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func); static DECLARE_WORK(vss_send_op_work, vss_send_op); +static void vss_poll_wrapper(void *channel) +{ + /* Transaction is finished, reset the state here to avoid races. */ + vss_transaction.state = HVUTIL_READY; + hv_vss_onchannelcallback(channel); +} + /* * Callback when data is received from user mode. */ @@ -86,12 +92,7 @@ static void vss_timeout_func(struct work_struct *dummy) pr_warn("VSS: timeout waiting for daemon to reply\n"); vss_respond_to_host(HV_E_FAIL); - /* Transaction is finished, reset the state. */ - if (vss_transaction.state > HVUTIL_READY) - vss_transaction.state = HVUTIL_READY; - - hv_poll_channel(vss_transaction.vss_context, - hv_vss_onchannelcallback); + hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); } static int vss_handle_handshake(struct hv_vss_msg *vss_msg) @@ -138,9 +139,8 @@ static int vss_on_msg(void *msg, int len) if (cancel_delayed_work_sync(&vss_timeout_work)) { vss_respond_to_host(vss_msg->error); /* Transaction is finished, reset the state. */ - vss_transaction.state = HVUTIL_READY; - hv_poll_channel(vss_transaction.vss_context, - hv_vss_onchannelcallback); + hv_poll_channel(vss_transaction.recv_channel, + vss_poll_wrapper); } } else { /* This is a spurious call! */ @@ -238,15 +238,8 @@ void hv_vss_onchannelcallback(void *context) struct icmsg_hdr *icmsghdrp; struct icmsg_negotiate *negop = NULL; - if (vss_transaction.state > HVUTIL_READY) { - /* - * We will defer processing this callback once - * the current transaction is complete. - */ - vss_transaction.vss_context = context; + if (vss_transaction.state > HVUTIL_READY) return; - } - vss_transaction.vss_context = NULL; vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen, &requestid); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 225b96bcf7fe..12156db2e88e 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -764,11 +764,7 @@ static inline void hv_poll_channel(struct vmbus_channel *channel, if (!channel) return; - if (channel->target_cpu != smp_processor_id()) - smp_call_function_single(channel->target_cpu, - cb, channel, true); - else - cb(channel); + smp_call_function_single(channel->target_cpu, cb, channel, true); } enum hvutil_device_state { -- cgit v1.2.3 From b4ed5d1682c6613988c2eb1de55df5ac9988afcc Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:34 -0800 Subject: tools: hv: report ENOSPC errors in hv_fcopy_daemon Currently some "Unspecified error 0x80004005" is reported on the Windows side if something fails. Handle the ENOSPC case and return ERROR_DISK_FULL, which allows at least Copy-VMFile to report a meaning full error. Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/hyperv.h | 1 + tools/hv/hv_fcopy_daemon.c | 20 +++++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/hyperv.h b/include/uapi/linux/hyperv.h index e4c0a35d6417..e347b24ef9fb 100644 --- a/include/uapi/linux/hyperv.h +++ b/include/uapi/linux/hyperv.h @@ -313,6 +313,7 @@ enum hv_kvp_exchg_pool { #define HV_INVALIDARG 0x80070057 #define HV_GUID_NOTFOUND 0x80041002 #define HV_ERROR_ALREADY_EXISTS 0x80070050 +#define HV_ERROR_DISK_FULL 0x80070070 #define ADDR_FAMILY_NONE 0x00 #define ADDR_FAMILY_IPV4 0x01 diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index 5480e4e424eb..f1d742682317 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -37,12 +37,14 @@ static int target_fd; static char target_fname[W_MAX_PATH]; +static unsigned long long filesize; static int hv_start_fcopy(struct hv_start_fcopy *smsg) { int error = HV_E_FAIL; char *q, *p; + filesize = 0; p = (char *)smsg->path_name; snprintf(target_fname, sizeof(target_fname), "%s/%s", (char *)smsg->path_name, (char *)smsg->file_name); @@ -98,14 +100,26 @@ done: static int hv_copy_data(struct hv_do_fcopy *cpmsg) { ssize_t bytes_written; + int ret = 0; bytes_written = pwrite(target_fd, cpmsg->data, cpmsg->size, cpmsg->offset); - if (bytes_written != cpmsg->size) - return HV_E_FAIL; + filesize += cpmsg->size; + if (bytes_written != cpmsg->size) { + switch (errno) { + case ENOSPC: + ret = HV_ERROR_DISK_FULL; + break; + default: + ret = HV_E_FAIL; + break; + } + syslog(LOG_ERR, "pwrite failed to write %llu bytes: %ld (%s)", + filesize, (long)bytes_written, strerror(errno)); + } - return 0; + return ret; } static int hv_copy_finished(void) -- cgit v1.2.3 From 6dfb867cea9e93ae9220f0b2e702b0440e4c8b4b Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:35 -0800 Subject: tools: hv: remove repeated HV_FCOPY string HV_FCOPY is already used as identifier in syslog. Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_fcopy_daemon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/hv/hv_fcopy_daemon.c b/tools/hv/hv_fcopy_daemon.c index f1d742682317..fdc9ca4c0356 100644 --- a/tools/hv/hv_fcopy_daemon.c +++ b/tools/hv/hv_fcopy_daemon.c @@ -179,7 +179,7 @@ int main(int argc, char *argv[]) } openlog("HV_FCOPY", 0, LOG_USER); - syslog(LOG_INFO, "HV_FCOPY starting; pid is:%d", getpid()); + syslog(LOG_INFO, "starting; pid is:%d", getpid()); fcopy_fd = open("/dev/vmbus/hv_fcopy", O_RDWR); @@ -215,7 +215,7 @@ int main(int argc, char *argv[]) } kernel_modver = *(__u32 *)buffer; in_handshake = 0; - syslog(LOG_INFO, "HV_FCOPY: kernel module version: %d", + syslog(LOG_INFO, "kernel module version: %d", kernel_modver); continue; } -- cgit v1.2.3 From cdc0c0c94e4e6dfa371d497a3130f83349b6ead6 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:36 -0800 Subject: Drivers: hv: util: catch allocation errors Catch allocation errors in hvutil_transport_send. Fixes: 14b50f80c32d ('Drivers: hv: util: introduce hv_utils_transport abstraction') Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 6a9d80a5332d..1505ee6e6605 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -204,9 +204,12 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) goto out_unlock; } hvt->outmsg = kzalloc(len, GFP_KERNEL); - memcpy(hvt->outmsg, msg, len); - hvt->outmsg_len = len; - wake_up_interruptible(&hvt->outmsg_q); + if (hvt->outmsg) { + memcpy(hvt->outmsg, msg, len); + hvt->outmsg_len = len; + wake_up_interruptible(&hvt->outmsg_q); + } else + ret = -ENOMEM; out_unlock: mutex_unlock(&hvt->outmsg_lock); return ret; -- cgit v1.2.3 From b00359642c2427da89dc8f77daa2c9e8a84e6d76 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:37 -0800 Subject: Drivers: hv: utils: use memdup_user in hvt_op_write Use memdup_user to handle OOM. Fixes: 14b50f80c32d ('Drivers: hv: util: introduce hv_utils_transport abstraction') Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 1505ee6e6605..24b2766a6d34 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -80,11 +80,10 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf, hvt = container_of(file->f_op, struct hvutil_transport, fops); - inmsg = kzalloc(count, GFP_KERNEL); - if (copy_from_user(inmsg, buf, count)) { - kfree(inmsg); - return -EFAULT; - } + inmsg = memdup_user(buf, count); + if (IS_ERR(inmsg)) + return PTR_ERR(inmsg); + if (hvt->on_msg(inmsg, count)) return -EFAULT; kfree(inmsg); -- cgit v1.2.3 From 17efbee8ba02ef00d3b270998978f8a1a90f1d92 Mon Sep 17 00:00:00 2001 From: Andrey Smetanin Date: Mon, 14 Dec 2015 16:01:38 -0800 Subject: drivers/hv: cleanup synic msrs if vmbus connect failed Before vmbus_connect() synic is setup per vcpu - this means hypervisor receives writes at synic msr's and probably allocate hypervisor resources per synic setup. If vmbus_connect() failed for some reason it's neccessary to cleanup synic setup by call hv_synic_cleanup() at each vcpu to get a chance to free allocated resources by hypervisor per synic. This patch does appropriate cleanup in case of vmbus_connect() failure. Signed-off-by: Andrey Smetanin Signed-off-by: Denis V. Lunev Reviewed-by: Vitaly Kuznetsov CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index f19b6f7a467a..3297731017e4 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -867,7 +867,7 @@ static int vmbus_bus_init(int irq) on_each_cpu(hv_synic_init, NULL, 1); ret = vmbus_connect(); if (ret) - goto err_alloc; + goto err_connect; if (vmbus_proto_version > VERSION_WIN7) cpu_hotplug_disable(); @@ -885,6 +885,8 @@ static int vmbus_bus_init(int irq) return 0; +err_connect: + on_each_cpu(hv_synic_cleanup, NULL, 1); err_alloc: hv_synic_free(); hv_remove_vmbus_irq(); -- cgit v1.2.3 From 619848bd074343ff2bdeeafca0be39748f6da372 Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Mon, 14 Dec 2015 16:01:39 -0800 Subject: drivers:hv: Export a function that maps Linux CPU num onto Hyper-V proc num This patch exposes the mapping between Linux CPU number and Hyper-V virtual processor number. This is necessary because the hypervisor needs to know which virtual processors to target when making a mapping in the Interrupt Redirection Table in the I/O MMU. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 17 +++++++++++++++++ include/linux/hyperv.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 3297731017e4..c01b689e39b1 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1193,6 +1193,23 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, } EXPORT_SYMBOL_GPL(vmbus_allocate_mmio); +/** + * vmbus_cpu_number_to_vp_number() - Map CPU to VP. + * @cpu_number: CPU number in Linux terms + * + * This function returns the mapping between the Linux processor + * number and the hypervisor's virtual processor number, useful + * in making hypercalls and such that talk about specific + * processors. + * + * Return: Virtual processor number in Hyper-V terms + */ +int vmbus_cpu_number_to_vp_number(int cpu_number) +{ + return hv_context.vp_index[cpu_number]; +} +EXPORT_SYMBOL_GPL(vmbus_cpu_number_to_vp_number); + static int vmbus_acpi_add(struct acpi_device *device) { acpi_status result; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 8fdc17b84739..fddb3e0e8feb 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -983,6 +983,8 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, resource_size_t size, resource_size_t align, bool fb_overlap_ok); +int vmbus_cpu_number_to_vp_number(int cpu_number); + /** * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device * -- cgit v1.2.3 From a108393dbf764efb2405f21ca759806c65b8bc16 Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Mon, 14 Dec 2015 16:01:40 -0800 Subject: drivers:hv: Export the API to invoke a hypercall on Hyper-V This patch exposes the function that hv_vmbus.ko uses to make hypercalls. This is necessary for retargeting an interrupt when it is given a new affinity. Since we are exporting this API, rename the API as it will be visible outside the hv.c file. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 20 ++++++++++---------- drivers/hv/hyperv_vmbus.h | 2 +- include/linux/hyperv.h | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index ad7fc6d92c35..eb4e383dbc58 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -89,9 +89,9 @@ static int query_hypervisor_info(void) } /* - * do_hypercall- Invoke the specified hypercall + * hv_do_hypercall- Invoke the specified hypercall */ -static u64 do_hypercall(u64 control, void *input, void *output) +u64 hv_do_hypercall(u64 control, void *input, void *output) { u64 input_address = (input) ? virt_to_phys(input) : 0; u64 output_address = (output) ? virt_to_phys(output) : 0; @@ -132,6 +132,7 @@ static u64 do_hypercall(u64 control, void *input, void *output) return hv_status_lo | ((u64)hv_status_hi << 32); #endif /* !x86_64 */ } +EXPORT_SYMBOL_GPL(hv_do_hypercall); #ifdef CONFIG_X86_64 static cycle_t read_hv_clock_tsc(struct clocksource *arg) @@ -316,7 +317,7 @@ int hv_post_message(union hv_connection_id connection_id, { struct hv_input_post_message *aligned_msg; - u16 status; + u64 status; if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) return -EMSGSIZE; @@ -330,11 +331,10 @@ int hv_post_message(union hv_connection_id connection_id, aligned_msg->payload_size = payload_size; memcpy((void *)aligned_msg->payload, payload, payload_size); - status = do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL) - & 0xFFFF; + status = hv_do_hypercall(HVCALL_POST_MESSAGE, aligned_msg, NULL); put_cpu(); - return status; + return status & 0xFFFF; } @@ -344,13 +344,13 @@ int hv_post_message(union hv_connection_id connection_id, * * This involves a hypercall. */ -u16 hv_signal_event(void *con_id) +int hv_signal_event(void *con_id) { - u16 status; + u64 status; - status = (do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL) & 0xFFFF); + status = hv_do_hypercall(HVCALL_SIGNAL_EVENT, con_id, NULL); - return status; + return status & 0xFFFF; } static int hv_ce_set_next_event(unsigned long delta, diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 12156db2e88e..9beeb148797f 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -587,7 +587,7 @@ extern int hv_post_message(union hv_connection_id connection_id, enum hv_message_type message_type, void *payload, size_t payload_size); -extern u16 hv_signal_event(void *con_id); +extern int hv_signal_event(void *con_id); extern int hv_synic_alloc(void); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index fddb3e0e8feb..24d0b656e6e7 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -984,6 +984,7 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, bool fb_overlap_ok); int vmbus_cpu_number_to_vp_number(int cpu_number); +u64 hv_do_hypercall(u64 control, void *input, void *output); /** * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device -- cgit v1.2.3 From 3053c762444a83ec6a8777f9476668b23b8ab180 Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Mon, 14 Dec 2015 16:01:41 -0800 Subject: drivers:hv: Define the channel type for Hyper-V PCI Express pass-through This defines the channel type for PCI front-ends in Hyper-V VMs. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 3 +++ include/linux/hyperv.h | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 652afd11a9ef..a77646b4fcc8 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -358,6 +358,7 @@ enum { SCSI, NIC, ND_NIC, + PCIE, MAX_PERF_CHN, }; @@ -375,6 +376,8 @@ static const struct hv_vmbus_device_id hp_devs[] = { { HV_NIC_GUID, }, /* NetworkDirect Guest RDMA */ { HV_ND_GUID, }, + /* PCI Express Pass Through */ + { HV_PCIE_GUID, }, }; diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 24d0b656e6e7..c9a9eed89af2 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1140,6 +1140,17 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); 0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \ } +/* + * PCI Express Pass Through + * {44C4F61D-4444-4400-9D52-802E27EDE19F} + */ + +#define HV_PCIE_GUID \ + .guid = { \ + 0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44, \ + 0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F \ + } + /* * Common header for Hyper-V ICs */ -- cgit v1.2.3 From ed9ba608e4851144af8c7061cbb19f751c73e998 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Mon, 14 Dec 2015 16:01:42 -0800 Subject: Drivers: hv: vss: run only on supported host versions The Backup integration service on WS2012 has appearently trouble to negotiate with a guest which does not support the provided util version. Currently the VSS driver supports only version 5/0. A WS2012 offers only version 1/x and 3/x, and vmbus_prep_negotiate_resp correctly returns an empty icframe_vercnt/icmsg_vercnt. But the host ignores that and continues to send ICMSGTYPE_NEGOTIATE messages. The result are weird errors during boot and general misbehaviour. Check the Windows version to work around the host bug, skip hv_vss_init on WS2012 and older. Signed-off-by: Olaf Hering Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_snapshot.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index a548ae42c927..81882d4848bd 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -331,6 +331,11 @@ static void vss_on_reset(void) int hv_vss_init(struct hv_util_service *srv) { + if (vmbus_proto_version < VERSION_WIN8_1) { + pr_warn("Integration service 'Backup (volume snapshot)'" + " not supported on this host version.\n"); + return -ENOTSUPP; + } recv_buffer = srv->recv_buffer; /* -- cgit v1.2.3 From af3ff643ea91ba64dd8d0b1cbed54d44512f96cd Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:43 -0800 Subject: Drivers: hv: vmbus: Use uuid_le type consistently Consistently use uuid_le type in the Hyper-V driver code. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 2 +- drivers/hv/vmbus_drv.c | 10 ++--- include/linux/hyperv.h | 92 ++++++++++++++--------------------------- include/linux/mod_devicetable.h | 2 +- scripts/mod/file2alias.c | 2 +- 5 files changed, 40 insertions(+), 68 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index a77646b4fcc8..38470aa4387f 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -408,7 +408,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui struct cpumask *alloced_mask; for (i = IDE; i < MAX_PERF_CHN; i++) { - if (!memcmp(type_guid->b, hp_devs[i].guid, + if (!memcmp(type_guid->b, &hp_devs[i].guid, sizeof(uuid_le))) { perf_chn = true; break; diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index c01b689e39b1..7078b5f143a2 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -531,7 +531,7 @@ static int vmbus_uevent(struct device *device, struct kobj_uevent_env *env) static const uuid_le null_guid; -static inline bool is_null_guid(const __u8 *guid) +static inline bool is_null_guid(const uuid_le *guid) { if (memcmp(guid, &null_guid, sizeof(uuid_le))) return false; @@ -544,9 +544,9 @@ static inline bool is_null_guid(const __u8 *guid) */ static const struct hv_vmbus_device_id *hv_vmbus_get_id( const struct hv_vmbus_device_id *id, - const __u8 *guid) + const uuid_le *guid) { - for (; !is_null_guid(id->guid); id++) + for (; !is_null_guid(&id->guid); id++) if (!memcmp(&id->guid, guid, sizeof(uuid_le))) return id; @@ -563,7 +563,7 @@ static int vmbus_match(struct device *device, struct device_driver *driver) struct hv_driver *drv = drv_to_hv_drv(driver); struct hv_device *hv_dev = device_to_hv_device(device); - if (hv_vmbus_get_id(drv->id_table, hv_dev->dev_type.b)) + if (hv_vmbus_get_id(drv->id_table, &hv_dev->dev_type)) return 1; return 0; @@ -580,7 +580,7 @@ static int vmbus_probe(struct device *child_device) struct hv_device *dev = device_to_hv_device(child_device); const struct hv_vmbus_device_id *dev_id; - dev_id = hv_vmbus_get_id(drv->id_table, dev->dev_type.b); + dev_id = hv_vmbus_get_id(drv->id_table, &dev->dev_type); if (drv->probe) { ret = drv->probe(dev, dev_id); if (ret != 0) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index c9a9eed89af2..b9f3bb25d8b4 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -997,6 +997,8 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); .guid = { g0, g1, g2, g3, g4, g5, g6, g7, \ g8, g9, ga, gb, gc, gd, ge, gf }, + + /* * GUID definitions of various offer types - services offered to the guest. */ @@ -1006,118 +1008,94 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); * {f8615163-df3e-46c5-913f-f2d2f965ed0e} */ #define HV_NIC_GUID \ - .guid = { \ - 0x63, 0x51, 0x61, 0xf8, 0x3e, 0xdf, 0xc5, 0x46, \ - 0x91, 0x3f, 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e \ - } + .guid = UUID_LE(0xf8615163, 0xdf3e, 0x46c5, 0x91, 0x3f, \ + 0xf2, 0xd2, 0xf9, 0x65, 0xed, 0x0e) /* * IDE GUID * {32412632-86cb-44a2-9b5c-50d1417354f5} */ #define HV_IDE_GUID \ - .guid = { \ - 0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, \ - 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5 \ - } + .guid = UUID_LE(0x32412632, 0x86cb, 0x44a2, 0x9b, 0x5c, \ + 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5) /* * SCSI GUID * {ba6163d9-04a1-4d29-b605-72e2ffb1dc7f} */ #define HV_SCSI_GUID \ - .guid = { \ - 0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, \ - 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f \ - } + .guid = UUID_LE(0xba6163d9, 0x04a1, 0x4d29, 0xb6, 0x05, \ + 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f) /* * Shutdown GUID * {0e0b6031-5213-4934-818b-38d90ced39db} */ #define HV_SHUTDOWN_GUID \ - .guid = { \ - 0x31, 0x60, 0x0b, 0x0e, 0x13, 0x52, 0x34, 0x49, \ - 0x81, 0x8b, 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb \ - } + .guid = UUID_LE(0x0e0b6031, 0x5213, 0x4934, 0x81, 0x8b, \ + 0x38, 0xd9, 0x0c, 0xed, 0x39, 0xdb) /* * Time Synch GUID * {9527E630-D0AE-497b-ADCE-E80AB0175CAF} */ #define HV_TS_GUID \ - .guid = { \ - 0x30, 0xe6, 0x27, 0x95, 0xae, 0xd0, 0x7b, 0x49, \ - 0xad, 0xce, 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf \ - } + .guid = UUID_LE(0x9527e630, 0xd0ae, 0x497b, 0xad, 0xce, \ + 0xe8, 0x0a, 0xb0, 0x17, 0x5c, 0xaf) /* * Heartbeat GUID * {57164f39-9115-4e78-ab55-382f3bd5422d} */ #define HV_HEART_BEAT_GUID \ - .guid = { \ - 0x39, 0x4f, 0x16, 0x57, 0x15, 0x91, 0x78, 0x4e, \ - 0xab, 0x55, 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d \ - } + .guid = UUID_LE(0x57164f39, 0x9115, 0x4e78, 0xab, 0x55, \ + 0x38, 0x2f, 0x3b, 0xd5, 0x42, 0x2d) /* * KVP GUID * {a9a0f4e7-5a45-4d96-b827-8a841e8c03e6} */ #define HV_KVP_GUID \ - .guid = { \ - 0xe7, 0xf4, 0xa0, 0xa9, 0x45, 0x5a, 0x96, 0x4d, \ - 0xb8, 0x27, 0x8a, 0x84, 0x1e, 0x8c, 0x3, 0xe6 \ - } + .guid = UUID_LE(0xa9a0f4e7, 0x5a45, 0x4d96, 0xb8, 0x27, \ + 0x8a, 0x84, 0x1e, 0x8c, 0x03, 0xe6) /* * Dynamic memory GUID * {525074dc-8985-46e2-8057-a307dc18a502} */ #define HV_DM_GUID \ - .guid = { \ - 0xdc, 0x74, 0x50, 0X52, 0x85, 0x89, 0xe2, 0x46, \ - 0x80, 0x57, 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02 \ - } + .guid = UUID_LE(0x525074dc, 0x8985, 0x46e2, 0x80, 0x57, \ + 0xa3, 0x07, 0xdc, 0x18, 0xa5, 0x02) /* * Mouse GUID * {cfa8b69e-5b4a-4cc0-b98b-8ba1a1f3f95a} */ #define HV_MOUSE_GUID \ - .guid = { \ - 0x9e, 0xb6, 0xa8, 0xcf, 0x4a, 0x5b, 0xc0, 0x4c, \ - 0xb9, 0x8b, 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a \ - } + .guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \ + 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a) /* * VSS (Backup/Restore) GUID */ #define HV_VSS_GUID \ - .guid = { \ - 0x29, 0x2e, 0xfa, 0x35, 0x23, 0xea, 0x36, 0x42, \ - 0x96, 0xae, 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40 \ - } + .guid = UUID_LE(0x35fa2e29, 0xea23, 0x4236, 0x96, 0xae, \ + 0x3a, 0x6e, 0xba, 0xcb, 0xa4, 0x40) /* * Synthetic Video GUID * {DA0A7802-E377-4aac-8E77-0558EB1073F8} */ #define HV_SYNTHVID_GUID \ - .guid = { \ - 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a, \ - 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8 \ - } + .guid = UUID_LE(0xda0a7802, 0xe377, 0x4aac, 0x8e, 0x77, \ + 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8) /* * Synthetic FC GUID * {2f9bcc4a-0069-4af3-b76b-6fd0be528cda} */ #define HV_SYNTHFC_GUID \ - .guid = { \ - 0x4A, 0xCC, 0x9B, 0x2F, 0x69, 0x00, 0xF3, 0x4A, \ - 0xB7, 0x6B, 0x6F, 0xD0, 0xBE, 0x52, 0x8C, 0xDA \ - } + .guid = UUID_LE(0x2f9bcc4a, 0x0069, 0x4af3, 0xb7, 0x6b, \ + 0x6f, 0xd0, 0xbe, 0x52, 0x8c, 0xda) /* * Guest File Copy Service @@ -1125,20 +1103,16 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); */ #define HV_FCOPY_GUID \ - .guid = { \ - 0xE3, 0x4B, 0xD1, 0x34, 0xE4, 0xDE, 0xC8, 0x41, \ - 0x9A, 0xE7, 0x6B, 0x17, 0x49, 0x77, 0xC1, 0x92 \ - } + .guid = UUID_LE(0x34d14be3, 0xdee4, 0x41c8, 0x9a, 0xe7, \ + 0x6b, 0x17, 0x49, 0x77, 0xc1, 0x92) /* * NetworkDirect. This is the guest RDMA service. * {8c2eaf3d-32a7-4b09-ab99-bd1f1c86b501} */ #define HV_ND_GUID \ - .guid = { \ - 0x3d, 0xaf, 0x2e, 0x8c, 0xa7, 0x32, 0x09, 0x4b, \ - 0xab, 0x99, 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01 \ - } + .guid = UUID_LE(0x8c2eaf3d, 0x32a7, 0x4b09, 0xab, 0x99, \ + 0xbd, 0x1f, 0x1c, 0x86, 0xb5, 0x01) /* * PCI Express Pass Through @@ -1146,10 +1120,8 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); */ #define HV_PCIE_GUID \ - .guid = { \ - 0x1D, 0xF6, 0xC4, 0x44, 0x44, 0x44, 0x00, 0x44, \ - 0x9D, 0x52, 0x80, 0x2E, 0x27, 0xED, 0xE1, 0x9F \ - } + .guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \ + 0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f) /* * Common header for Hyper-V ICs diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 64f36e09a790..6e4c645e1c0d 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -404,7 +404,7 @@ struct virtio_device_id { * For Hyper-V devices we use the device guid as the id. */ struct hv_vmbus_device_id { - __u8 guid[16]; + uuid_le guid; kernel_ulong_t driver_data; /* Data private to the driver */ }; diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 5b96206e9aab..8adca4406198 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -917,7 +917,7 @@ static int do_vmbus_entry(const char *filename, void *symval, char guid_name[(sizeof(*guid) + 1) * 2]; for (i = 0; i < (sizeof(*guid) * 2); i += 2) - sprintf(&guid_name[i], "%02x", TO_NATIVE((*guid)[i/2])); + sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); strcpy(alias, "vmbus:"); strcat(alias, guid_name); -- cgit v1.2.3 From 4ae9250893485f380275e7d5cb291df87c4d9710 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:44 -0800 Subject: Drivers: hv: vmbus: Use uuid_le_cmp() for comparing GUIDs Use uuid_le_cmp() for comparing GUIDs. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 3 +-- drivers/hv/vmbus_drv.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 38470aa4387f..dc4fb0bccb8d 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -408,8 +408,7 @@ static void init_vp_index(struct vmbus_channel *channel, const uuid_le *type_gui struct cpumask *alloced_mask; for (i = IDE; i < MAX_PERF_CHN; i++) { - if (!memcmp(type_guid->b, &hp_devs[i].guid, - sizeof(uuid_le))) { + if (!uuid_le_cmp(*type_guid, hp_devs[i].guid)) { perf_chn = true; break; } diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 7078b5f143a2..9e0e25c394f5 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -533,7 +533,7 @@ static const uuid_le null_guid; static inline bool is_null_guid(const uuid_le *guid) { - if (memcmp(guid, &null_guid, sizeof(uuid_le))) + if (uuid_le_cmp(*guid, null_guid)) return false; return true; } @@ -547,7 +547,7 @@ static const struct hv_vmbus_device_id *hv_vmbus_get_id( const uuid_le *guid) { for (; !is_null_guid(&id->guid); id++) - if (!memcmp(&id->guid, guid, sizeof(uuid_le))) + if (!uuid_le_cmp(id->guid, *guid)) return id; return NULL; -- cgit v1.2.3 From 90e031fa06ad6b660a8e9bebbb80bd30e555a2a5 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:45 -0800 Subject: Drivers: hv: vmbus: Get rid of the unused macro The macro VMBUS_DEVICE() is unused; get rid of it. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/linux/hyperv.h | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index b9f3bb25d8b4..f773a6871f4c 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -986,19 +986,6 @@ int vmbus_allocate_mmio(struct resource **new, struct hv_device *device_obj, int vmbus_cpu_number_to_vp_number(int cpu_number); u64 hv_do_hypercall(u64 control, void *input, void *output); -/** - * VMBUS_DEVICE - macro used to describe a specific hyperv vmbus device - * - * This macro is used to create a struct hv_vmbus_device_id that matches a - * specific device. - */ -#define VMBUS_DEVICE(g0, g1, g2, g3, g4, g5, g6, g7, \ - g8, g9, ga, gb, gc, gd, ge, gf) \ - .guid = { g0, g1, g2, g3, g4, g5, g6, g7, \ - g8, g9, ga, gb, gc, gd, ge, gf }, - - - /* * GUID definitions of various offer types - services offered to the guest. */ -- cgit v1.2.3 From efc267226b827f347a329c395e16c08973b0e3d6 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:46 -0800 Subject: Drivers: hv: vmbus: Get rid of the unused irq variable The irq we extract from ACPI is not used - we deliver hypervisor interrupts on a special vector. Make the necessary adjustments. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 9e0e25c394f5..ab888a1abef8 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -47,7 +47,6 @@ static struct acpi_device *hv_acpi_dev; static struct tasklet_struct msg_dpc; static struct completion probe_event; -static int irq; static void hyperv_report_panic(struct pt_regs *regs) @@ -835,10 +834,9 @@ static void vmbus_isr(void) * Here, we * - initialize the vmbus driver context * - invoke the vmbus hv main init routine - * - get the irq resource * - retrieve the channel offers */ -static int vmbus_bus_init(int irq) +static int vmbus_bus_init(void) { int ret; @@ -1033,9 +1031,6 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) struct resource **prev_res = NULL; switch (res->type) { - case ACPI_RESOURCE_TYPE_IRQ: - irq = res->data.irq.interrupts[0]; - return AE_OK; /* * "Address" descriptors are for bus windows. Ignore @@ -1294,7 +1289,7 @@ static int __init hv_acpi_init(void) init_completion(&probe_event); /* - * Get irq resources first. + * Get ACPI resources first. */ ret = acpi_bus_register_driver(&vmbus_acpi_driver); @@ -1307,12 +1302,7 @@ static int __init hv_acpi_init(void) goto cleanup; } - if (irq <= 0) { - ret = -ENODEV; - goto cleanup; - } - - ret = vmbus_bus_init(irq); + ret = vmbus_bus_init(); if (ret) goto cleanup; -- cgit v1.2.3 From 63d55b2aeb5e4faa170316fee73c3c47ea9268c7 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:47 -0800 Subject: Drivers: hv: vmbus: serialize process_chn_event() and vmbus_close_internal() process_chn_event(), running in the tasklet, can race with vmbus_close_internal() in the case of SMP guest, e.g., when the former is accessing channel->inbound.ring_buffer, the latter could be freeing the ring_buffer pages. To resolve the race, we can serialize them by disabling the tasklet when the latter is running here. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index c4dcab048cb8..f7f3d5ccd6bd 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "hyperv_vmbus.h" @@ -496,8 +497,21 @@ static void reset_channel_cb(void *arg) static int vmbus_close_internal(struct vmbus_channel *channel) { struct vmbus_channel_close_channel *msg; + struct tasklet_struct *tasklet; int ret; + /* + * process_chn_event(), running in the tasklet, can race + * with vmbus_close_internal() in the case of SMP guest, e.g., when + * the former is accessing channel->inbound.ring_buffer, the latter + * could be freeing the ring_buffer pages. + * + * To resolve the race, we can serialize them by disabling the + * tasklet when the latter is running here. + */ + tasklet = hv_context.event_dpc[channel->target_cpu]; + tasklet_disable(tasklet); + channel->state = CHANNEL_OPEN_STATE; channel->sc_creation_callback = NULL; /* Stop callback and cancel the timer asap */ @@ -525,7 +539,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to post the close msg, * it is perhaps better to leak memory. */ - return ret; + goto out; } /* Tear down the gpadl for the channel's ring buffer */ @@ -538,7 +552,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel) * If we failed to teardown gpadl, * it is perhaps better to leak memory. */ - return ret; + goto out; } } @@ -555,6 +569,9 @@ static int vmbus_close_internal(struct vmbus_channel *channel) if (channel->rescind) hv_process_channel_removal(channel, channel->offermsg.child_relid); +out: + tasklet_enable(tasklet); + return ret; } -- cgit v1.2.3 From 64b7faf903dae2df94d89edf2c688b16751800e4 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:48 -0800 Subject: Drivers: hv: vmbus: do sanity check of channel state in vmbus_close_internal() This fixes an incorrect assumption of channel state in the function. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index f7f3d5ccd6bd..00e1be775908 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -512,6 +512,18 @@ static int vmbus_close_internal(struct vmbus_channel *channel) tasklet = hv_context.event_dpc[channel->target_cpu]; tasklet_disable(tasklet); + /* + * In case a device driver's probe() fails (e.g., + * util_probe() -> vmbus_open() returns -ENOMEM) and the device is + * rescinded later (e.g., we dynamically disble an Integrated Service + * in Hyper-V Manager), the driver's remove() invokes vmbus_close(): + * here we should skip most of the below cleanup work. + */ + if (channel->state != CHANNEL_OPENED_STATE) { + ret = -EINVAL; + goto out; + } + channel->state = CHANNEL_OPEN_STATE; channel->sc_creation_callback = NULL; /* Stop callback and cancel the timer asap */ -- cgit v1.2.3 From 34c6801e3310ad286c7bb42bc88d42926b8f99bf Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:49 -0800 Subject: Drivers: hv: vmbus: fix rescind-offer handling for device without a driver In the path vmbus_onoffer_rescind() -> vmbus_device_unregister() -> device_unregister() -> ... -> __device_release_driver(), we can see for a device without a driver loaded: dev->driver is NULL, so dev->bus->remove(dev), namely vmbus_remove(), isn't invoked. As a result, vmbus_remove() -> hv_process_channel_removal() isn't invoked and some cleanups(like sending a CHANNELMSG_RELID_RELEASED message to the host) aren't done. We can demo the issue this way: 1. rmmod hv_utils; 2. disable the Heartbeat Integration Service in Hyper-V Manager and lsvmbus shows the device disappears. 3. re-enable the Heartbeat in Hyper-V Manager and modprobe hv_utils, but lsvmbus shows the device can't appear again. This is because, the host thinks the VM hasn't released the relid, so can't re-offer the device to the VM. We can fix the issue by moving hv_process_channel_removal() from vmbus_close_internal() to vmbus_device_release(), since the latter is always invoked on device_unregister(), whether or not the dev has a driver loaded. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 6 ------ drivers/hv/channel_mgmt.c | 6 +++--- drivers/hv/vmbus_drv.c | 15 +++------------ 3 files changed, 6 insertions(+), 21 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 00e1be775908..77d2579d6124 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -575,12 +575,6 @@ static int vmbus_close_internal(struct vmbus_channel *channel) free_pages((unsigned long)channel->ringbuffer_pages, get_order(channel->ringbuffer_pagecount * PAGE_SIZE)); - /* - * If the channel has been rescinded; process device removal. - */ - if (channel->rescind) - hv_process_channel_removal(channel, - channel->offermsg.child_relid); out: tasklet_enable(tasklet); diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index dc4fb0bccb8d..7903acc3403e 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -191,6 +191,8 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) if (channel == NULL) return; + BUG_ON(!channel->rescind); + if (channel->target_cpu != get_cpu()) { put_cpu(); smp_call_function_single(channel->target_cpu, @@ -230,9 +232,7 @@ void vmbus_free_channels(void) list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list, listentry) { - /* if we don't set rescind to true, vmbus_close_internal() - * won't invoke hv_process_channel_removal(). - */ + /* hv_process_channel_removal() needs this */ channel->rescind = true; vmbus_device_unregister(channel->device_obj); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index ab888a1abef8..f123bca77808 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -601,23 +601,11 @@ static int vmbus_remove(struct device *child_device) { struct hv_driver *drv; struct hv_device *dev = device_to_hv_device(child_device); - u32 relid = dev->channel->offermsg.child_relid; if (child_device->driver) { drv = drv_to_hv_drv(child_device->driver); if (drv->remove) drv->remove(dev); - else { - hv_process_channel_removal(dev->channel, relid); - pr_err("remove not set for driver %s\n", - dev_name(child_device)); - } - } else { - /* - * We don't have a driver for this device; deal with the - * rescind message by removing the channel. - */ - hv_process_channel_removal(dev->channel, relid); } return 0; @@ -652,7 +640,10 @@ static void vmbus_shutdown(struct device *child_device) static void vmbus_device_release(struct device *device) { struct hv_device *hv_dev = device_to_hv_device(device); + struct vmbus_channel *channel = hv_dev->channel; + hv_process_channel_removal(channel, + channel->offermsg.child_relid); kfree(hv_dev); } -- cgit v1.2.3 From f52078cf5711ce47c113a58702b35c8ff5f212f5 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:50 -0800 Subject: Drivers: hv: vmbus: release relid on error in vmbus_process_offer() We want to simplify vmbus_onoffer_rescind() by not invoking hv_process_channel_removal(NULL, ...). Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 7903acc3403e..9c9da3a6c03a 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -177,19 +177,22 @@ static void percpu_channel_deq(void *arg) } -void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) +static void vmbus_release_relid(u32 relid) { struct vmbus_channel_relid_released msg; - unsigned long flags; - struct vmbus_channel *primary_channel; memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); msg.child_relid = relid; msg.header.msgtype = CHANNELMSG_RELID_RELEASED; vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released)); +} - if (channel == NULL) - return; +void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) +{ + unsigned long flags; + struct vmbus_channel *primary_channel; + + vmbus_release_relid(relid); BUG_ON(!channel->rescind); @@ -336,6 +339,8 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) return; err_deq_chan: + vmbus_release_relid(newchannel->offermsg.child_relid); + spin_lock_irqsave(&vmbus_connection.channel_lock, flags); list_del(&newchannel->listentry); spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); @@ -587,7 +592,11 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr) channel = relid2channel(rescind->child_relid); if (channel == NULL) { - hv_process_channel_removal(NULL, rescind->child_relid); + /* + * This is very impossible, because in + * vmbus_process_offer(), we have already invoked + * vmbus_release_relid() on error. + */ return; } -- cgit v1.2.3 From d6f591e339d23f434efda11917da511870891472 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:51 -0800 Subject: Drivers: hv: vmbus: channge vmbus_connection.channel_lock to mutex spinlock is unnecessary here. mutex is enough. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 12 ++++++------ drivers/hv/connection.c | 7 +++---- drivers/hv/hyperv_vmbus.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index 9c9da3a6c03a..d0131717c1d5 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -206,9 +206,9 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid) } if (channel->primary_channel == NULL) { - spin_lock_irqsave(&vmbus_connection.channel_lock, flags); + mutex_lock(&vmbus_connection.channel_mutex); list_del(&channel->listentry); - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); + mutex_unlock(&vmbus_connection.channel_mutex); primary_channel = channel; } else { @@ -253,7 +253,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) unsigned long flags; /* Make sure this is a new offer */ - spin_lock_irqsave(&vmbus_connection.channel_lock, flags); + mutex_lock(&vmbus_connection.channel_mutex); list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { if (!uuid_le_cmp(channel->offermsg.offer.if_type, @@ -269,7 +269,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) list_add_tail(&newchannel->listentry, &vmbus_connection.chn_list); - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); + mutex_unlock(&vmbus_connection.channel_mutex); if (!fnew) { /* @@ -341,9 +341,9 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel) err_deq_chan: vmbus_release_relid(newchannel->offermsg.child_relid); - spin_lock_irqsave(&vmbus_connection.channel_lock, flags); + mutex_lock(&vmbus_connection.channel_mutex); list_del(&newchannel->listentry); - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); + mutex_unlock(&vmbus_connection.channel_mutex); if (newchannel->target_cpu != get_cpu()) { put_cpu(); diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 4fc2e8836e60..521f48ed188e 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -146,7 +146,7 @@ int vmbus_connect(void) spin_lock_init(&vmbus_connection.channelmsg_lock); INIT_LIST_HEAD(&vmbus_connection.chn_list); - spin_lock_init(&vmbus_connection.channel_lock); + mutex_init(&vmbus_connection.channel_mutex); /* * Setup the vmbus event connection for channel interrupt @@ -282,11 +282,10 @@ struct vmbus_channel *relid2channel(u32 relid) { struct vmbus_channel *channel; struct vmbus_channel *found_channel = NULL; - unsigned long flags; struct list_head *cur, *tmp; struct vmbus_channel *cur_sc; - spin_lock_irqsave(&vmbus_connection.channel_lock, flags); + mutex_lock(&vmbus_connection.channel_mutex); list_for_each_entry(channel, &vmbus_connection.chn_list, listentry) { if (channel->offermsg.child_relid == relid) { found_channel = channel; @@ -305,7 +304,7 @@ struct vmbus_channel *relid2channel(u32 relid) } } } - spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags); + mutex_unlock(&vmbus_connection.channel_mutex); return found_channel; } diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 9beeb148797f..4d67e984ac4f 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -683,7 +683,7 @@ struct vmbus_connection { /* List of channels */ struct list_head chn_list; - spinlock_t channel_lock; + struct mutex channel_mutex; struct workqueue_struct *work_queue; }; -- cgit v1.2.3 From 40f26f3168bf7a4da490db308dc0bd9f9923f41f Mon Sep 17 00:00:00 2001 From: Jake Oshins Date: Mon, 14 Dec 2015 16:01:52 -0800 Subject: drivers:hv: Allow for MMIO claims that span ACPI _CRS records This patch makes 16GB GPUs work in Hyper-V VMs, since, for compatibility reasons, the Hyper-V BIOS lists MMIO ranges in 2GB chunks in its root bus's _CRS object. Signed-off-by: Jake Oshins Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/vmbus_drv.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index f123bca77808..328e4c3808e0 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1063,12 +1063,28 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx) new_res->start = start; new_res->end = end; + /* + * Stick ranges from higher in address space at the front of the list. + * If two ranges are adjacent, merge them. + */ do { if (!*old_res) { *old_res = new_res; break; } + if (((*old_res)->end + 1) == new_res->start) { + (*old_res)->end = new_res->end; + kfree(new_res); + break; + } + + if ((*old_res)->start == new_res->end + 1) { + (*old_res)->start = new_res->start; + kfree(new_res); + break; + } + if ((*old_res)->end < new_res->start) { new_res->sibling = *old_res; if (prev_res) -- cgit v1.2.3 From 8599846d73997cdbccf63f23394d871cfad1e5e6 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:54 -0800 Subject: Drivers: hv: vmbus: Fix a Host signaling bug Currently we have two policies for deciding when to signal the host: One based on the ring buffer state and the other based on what the VMBUS client driver wants to do. Consider the case when the client wants to explicitly control when to signal the host. In this case, if the client were to defer signaling, we will not be able to signal the host subsequently when the client does want to signal since the ring buffer state will prevent the signaling. Implement logic to have only one signaling policy in force for a given channel. Signed-off-by: K. Y. Srinivasan Reviewed-by: Haiyang Zhang Tested-by: Haiyang Zhang Cc: # v4.2+ Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 18 ++++++++++++++++++ include/linux/hyperv.h | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 77d2579d6124..2889d97c03b1 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -653,10 +653,19 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer, * on the ring. We will not signal if more data is * to be placed. * + * Based on the channel signal state, we will decide + * which signaling policy will be applied. + * * If we cannot write to the ring-buffer; signal the host * even if we may not have written anything. This is a rare * enough condition that it should not matter. */ + + if (channel->signal_policy) + signal = true; + else + kick_q = true; + if (((ret == 0) && kick_q && signal) || (ret)) vmbus_setevent(channel); @@ -756,10 +765,19 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel, * on the ring. We will not signal if more data is * to be placed. * + * Based on the channel signal state, we will decide + * which signaling policy will be applied. + * * If we cannot write to the ring-buffer; signal the host * even if we may not have written anything. This is a rare * enough condition that it should not matter. */ + + if (channel->signal_policy) + signal = true; + else + kick_q = true; + if (((ret == 0) && kick_q && signal) || (ret)) vmbus_setevent(channel); diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index f773a6871f4c..acd995b81c6b 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -630,6 +630,11 @@ struct hv_input_signal_event_buffer { struct hv_input_signal_event event; }; +enum hv_signal_policy { + HV_SIGNAL_POLICY_DEFAULT = 0, + HV_SIGNAL_POLICY_EXPLICIT, +}; + struct vmbus_channel { /* Unique channel id */ int id; @@ -757,8 +762,21 @@ struct vmbus_channel { * link up channels based on their CPU affinity. */ struct list_head percpu_list; + /* + * Host signaling policy: The default policy will be + * based on the ring buffer state. We will also support + * a policy where the client driver can have explicit + * signaling control. + */ + enum hv_signal_policy signal_policy; }; +static inline void set_channel_signal_state(struct vmbus_channel *c, + enum hv_signal_policy policy) +{ + c->signal_policy = policy; +} + static inline void set_channel_read_state(struct vmbus_channel *c, bool state) { c->batched_reading = state; -- cgit v1.2.3 From c35b82ef0294ae5052120615f5cfcef17c5a6bf7 Mon Sep 17 00:00:00 2001 From: Andrey Smetanin Date: Mon, 14 Dec 2015 16:01:55 -0800 Subject: drivers/hv: correct tsc page sequence invalid value Hypervisor Top Level Functional Specification v3/4 says that TSC page sequence value = -1(0xFFFFFFFF) is used to indicate that TSC page no longer reliable source of reference timer. Unfortunately, we found that Windows Hyper-V guest side implementation uses sequence value = 0 to indicate that Tsc page no longer valid. This is clearly visible inside Windows 2012R2 ntoskrnl.exe HvlGetReferenceTime() function dissassembly: HvlGetReferenceTime proc near xchg ax, ax loc_1401C3132: mov rax, cs:HvlpReferenceTscPage mov r9d, [rax] test r9d, r9d jz short loc_1401C3176 rdtsc mov rcx, cs:HvlpReferenceTscPage shl rdx, 20h or rdx, rax mov rax, [rcx+8] mov rcx, cs:HvlpReferenceTscPage mov r8, [rcx+10h] mul rdx mov rax, cs:HvlpReferenceTscPage add rdx, r8 mov ecx, [rax] cmp ecx, r9d jnz short loc_1401C3132 jmp short loc_1401C3184 loc_1401C3176: mov ecx, 40000020h rdmsr shl rdx, 20h or rdx, rax loc_1401C3184: mov rax, rdx retn HvlGetReferenceTime endp This patch aligns Tsc page invalid sequence value with Windows Hyper-V guest implementation which is more compatible with both Hyper-V hypervisor and KVM hypervisor. Signed-off-by: Andrey Smetanin Signed-off-by: Denis V. Lunev CC: "K. Y. Srinivasan" CC: Haiyang Zhang CC: Vitaly Kuznetsov Signed-off-by: Denis V. Lunev Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c index eb4e383dbc58..11bca51ef5ff 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c @@ -140,7 +140,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg) cycle_t current_tick; struct ms_hyperv_tsc_page *tsc_pg = hv_context.tsc_page; - if (tsc_pg->tsc_sequence != -1) { + if (tsc_pg->tsc_sequence != 0) { /* * Use the tsc page to compute the value. */ @@ -162,7 +162,7 @@ static cycle_t read_hv_clock_tsc(struct clocksource *arg) if (tsc_pg->tsc_sequence == sequence) return current_tick; - if (tsc_pg->tsc_sequence != -1) + if (tsc_pg->tsc_sequence != 0) continue; /* * Fallback using MSR method. -- cgit v1.2.3 From b282e4c06fe89fc750fb26791c0bd7b25315973a Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:56 -0800 Subject: Drivers: hv: vmbus: Force all channel messages to be delivered on CPU 0 Force all channel messages to be delivered on CPU0. These messages are not performance critical and are used during the setup and teardown of the channel. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/connection.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 521f48ed188e..3dc5a9c7fad6 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -83,10 +83,13 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); - if (version >= VERSION_WIN8_1) { - msg->target_vcpu = hv_context.vp_index[get_cpu()]; - put_cpu(); - } + /* + * We want all channel messages to be delivered on CPU 0. + * This has been the behavior pre-win8. This is not + * perf issue and having all channel messages delivered on CPU 0 + * would be ok. + */ + msg->target_vcpu = 0; /* * Add to list before we send the request since we may -- cgit v1.2.3 From 2d0c3b5ad739697a68dc8a444f5b9f4817cf8f8f Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Mon, 14 Dec 2015 16:01:57 -0800 Subject: Drivers: hv: utils: Invoke the poll function after handshake When the handshake with daemon is complete, we should poll the channel since during the handshake, we will not be processing any messages. This is a potential bug if the host is waiting for a response from the guest. I would like to thank Dexuan for pointing this out. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_kvp.c | 2 +- drivers/hv/hv_snapshot.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index 2a3420c4ca59..d4ab81bcd515 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -154,7 +154,7 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) pr_debug("KVP: userspace daemon ver. %d registered\n", KVP_OP_REGISTER); kvp_register(dm_reg_value); - kvp_transaction.state = HVUTIL_READY; + hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); return 0; } diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 81882d4848bd..67def4a831c8 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -113,7 +113,7 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg) default: return -EINVAL; } - vss_transaction.state = HVUTIL_READY; + hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value); return 0; } -- cgit v1.2.3 From a689d2510f188e75391dbebacbddfd74d42f2a7e Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 14 Dec 2015 16:01:58 -0800 Subject: tools: hv: vss: fix the write()'s argument: error -> vss_msg Fix the write()'s argument in the daemon code. Cc: Vitaly Kuznetsov Cc: "K. Y. Srinivasan" Signed-off-by: Dexuan Cui Cc: stable@vger.kernel.org Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- tools/hv/hv_vss_daemon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/hv/hv_vss_daemon.c b/tools/hv/hv_vss_daemon.c index 96234b638249..5d51d6ff08e6 100644 --- a/tools/hv/hv_vss_daemon.c +++ b/tools/hv/hv_vss_daemon.c @@ -254,7 +254,7 @@ int main(int argc, char *argv[]) syslog(LOG_ERR, "Illegal op:%d\n", op); } vss_msg->error = error; - len = write(vss_fd, &error, sizeof(struct hv_vss_msg)); + len = write(vss_fd, vss_msg, sizeof(struct hv_vss_msg)); if (len != sizeof(struct hv_vss_msg)) { syslog(LOG_ERR, "write failed; error: %d %s", errno, strerror(errno)); -- cgit v1.2.3 From 1f75338b6fece2bbd42ac3623830c65e2df6e031 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:53 -0800 Subject: Drivers: hv: utils: fix memory leak on on_msg() failure inmsg should be freed in case of on_msg() failure to avoid memory leak. Preserve the error code from on_msg(). Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 24b2766a6d34..40abe44fcd98 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -77,6 +77,7 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf, { struct hvutil_transport *hvt; u8 *inmsg; + int ret; hvt = container_of(file->f_op, struct hvutil_transport, fops); @@ -84,11 +85,11 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf, if (IS_ERR(inmsg)) return PTR_ERR(inmsg); - if (hvt->on_msg(inmsg, count)) - return -EFAULT; + ret = hvt->on_msg(inmsg, count); + kfree(inmsg); - return count; + return ret ? ret : count; } static unsigned int hvt_op_poll(struct file *file, poll_table *wait) -- cgit v1.2.3 From a72f3a4ccff22de879a1f599210ecdd9bd483a43 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:54 -0800 Subject: Drivers: hv: utils: rename outmsg_lock As a preparation to reusing outmsg_lock to protect test-and-set openrations on 'mode' rename it the more general 'lock'. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 14 +++++++------- drivers/hv/hv_utils_transport.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 40abe44fcd98..59c6f3d29f9a 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -27,11 +27,11 @@ static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list); static void hvt_reset(struct hvutil_transport *hvt) { - mutex_lock(&hvt->outmsg_lock); + mutex_lock(&hvt->lock); kfree(hvt->outmsg); hvt->outmsg = NULL; hvt->outmsg_len = 0; - mutex_unlock(&hvt->outmsg_lock); + mutex_unlock(&hvt->lock); if (hvt->on_reset) hvt->on_reset(); } @@ -47,7 +47,7 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0)) return -EINTR; - mutex_lock(&hvt->outmsg_lock); + mutex_lock(&hvt->lock); if (!hvt->outmsg) { ret = -EAGAIN; goto out_unlock; @@ -68,7 +68,7 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, hvt->outmsg_len = 0; out_unlock: - mutex_unlock(&hvt->outmsg_lock); + mutex_unlock(&hvt->lock); return ret; } @@ -197,7 +197,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) return ret; } /* HVUTIL_TRANSPORT_CHARDEV */ - mutex_lock(&hvt->outmsg_lock); + mutex_lock(&hvt->lock); if (hvt->outmsg) { /* Previous message wasn't received */ ret = -EFAULT; @@ -211,7 +211,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) } else ret = -ENOMEM; out_unlock: - mutex_unlock(&hvt->outmsg_lock); + mutex_unlock(&hvt->lock); return ret; } @@ -242,7 +242,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name, hvt->mdev.fops = &hvt->fops; init_waitqueue_head(&hvt->outmsg_q); - mutex_init(&hvt->outmsg_lock); + mutex_init(&hvt->lock); spin_lock(&hvt_list_lock); list_add(&hvt->list, &hvt_list); diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h index 314c76ce1b07..bff4c921e817 100644 --- a/drivers/hv/hv_utils_transport.h +++ b/drivers/hv/hv_utils_transport.h @@ -38,7 +38,7 @@ struct hvutil_transport { u8 *outmsg; /* message to the userspace */ int outmsg_len; /* its length */ wait_queue_head_t outmsg_q; /* poll/read wait queue */ - struct mutex outmsg_lock; /* protects outmsg */ + struct mutex lock; /* protects struct members */ }; struct hvutil_transport *hvutil_transport_init(const char *name, -- cgit v1.2.3 From a15025660d4703a8b37290a14734cb4a84875770 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:55 -0800 Subject: Drivers: hv: utils: introduce HVUTIL_TRANSPORT_DESTROY mode When Hyper-V host asks us to remove some util driver by closing the appropriate channel there is no easy way to force the current file descriptor holder to hang up but we can start to respond -EBADF to all operations asking it to exit gracefully. As we're setting hvt->mode from two separate contexts now we need to use a proper locking. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 71 ++++++++++++++++++++++++++++++++--------- drivers/hv/hv_utils_transport.h | 1 + 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 59c6f3d29f9a..31c2f8649271 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -27,11 +27,9 @@ static struct list_head hvt_list = LIST_HEAD_INIT(hvt_list); static void hvt_reset(struct hvutil_transport *hvt) { - mutex_lock(&hvt->lock); kfree(hvt->outmsg); hvt->outmsg = NULL; hvt->outmsg_len = 0; - mutex_unlock(&hvt->lock); if (hvt->on_reset) hvt->on_reset(); } @@ -44,10 +42,17 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, hvt = container_of(file->f_op, struct hvutil_transport, fops); - if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0)) + if (wait_event_interruptible(hvt->outmsg_q, hvt->outmsg_len > 0 || + hvt->mode != HVUTIL_TRANSPORT_CHARDEV)) return -EINTR; mutex_lock(&hvt->lock); + + if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) { + ret = -EBADF; + goto out_unlock; + } + if (!hvt->outmsg) { ret = -EAGAIN; goto out_unlock; @@ -85,7 +90,10 @@ static ssize_t hvt_op_write(struct file *file, const char __user *buf, if (IS_ERR(inmsg)) return PTR_ERR(inmsg); - ret = hvt->on_msg(inmsg, count); + if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) + ret = -EBADF; + else + ret = hvt->on_msg(inmsg, count); kfree(inmsg); @@ -99,6 +107,10 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait) hvt = container_of(file->f_op, struct hvutil_transport, fops); poll_wait(file, &hvt->outmsg_q, wait); + + if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) + return -EBADF; + if (hvt->outmsg_len > 0) return POLLIN | POLLRDNORM; @@ -108,26 +120,39 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait) static int hvt_op_open(struct inode *inode, struct file *file) { struct hvutil_transport *hvt; + int ret = 0; + bool issue_reset = false; hvt = container_of(file->f_op, struct hvutil_transport, fops); - /* - * Switching to CHARDEV mode. We switch bach to INIT when device - * gets released. - */ - if (hvt->mode == HVUTIL_TRANSPORT_INIT) + mutex_lock(&hvt->lock); + + if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) { + ret = -EBADF; + } else if (hvt->mode == HVUTIL_TRANSPORT_INIT) { + /* + * Switching to CHARDEV mode. We switch bach to INIT when + * device gets released. + */ hvt->mode = HVUTIL_TRANSPORT_CHARDEV; + } else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { /* * We're switching from netlink communication to using char * device. Issue the reset first. */ - hvt_reset(hvt); + issue_reset = true; hvt->mode = HVUTIL_TRANSPORT_CHARDEV; - } else - return -EBUSY; + } else { + ret = -EBUSY; + } - return 0; + if (issue_reset) + hvt_reset(hvt); + + mutex_unlock(&hvt->lock); + + return ret; } static int hvt_op_release(struct inode *inode, struct file *file) @@ -136,12 +161,15 @@ static int hvt_op_release(struct inode *inode, struct file *file) hvt = container_of(file->f_op, struct hvutil_transport, fops); - hvt->mode = HVUTIL_TRANSPORT_INIT; + mutex_lock(&hvt->lock); + if (hvt->mode != HVUTIL_TRANSPORT_DESTROY) + hvt->mode = HVUTIL_TRANSPORT_INIT; /* * Cleanup message buffers to avoid spurious messages when the daemon * connects back. */ hvt_reset(hvt); + mutex_unlock(&hvt->lock); return 0; } @@ -168,6 +196,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) * Switching to NETLINK mode. Switching to CHARDEV happens when someone * opens the device. */ + mutex_lock(&hvt->lock); if (hvt->mode == HVUTIL_TRANSPORT_INIT) hvt->mode = HVUTIL_TRANSPORT_NETLINK; @@ -175,6 +204,7 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) hvt_found->on_msg(msg->data, msg->len); else pr_warn("hvt_cn_callback: unexpected netlink message!\n"); + mutex_unlock(&hvt->lock); } int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) @@ -182,7 +212,8 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) struct cn_msg *cn_msg; int ret = 0; - if (hvt->mode == HVUTIL_TRANSPORT_INIT) { + if (hvt->mode == HVUTIL_TRANSPORT_INIT || + hvt->mode == HVUTIL_TRANSPORT_DESTROY) { return -EINVAL; } else if (hvt->mode == HVUTIL_TRANSPORT_NETLINK) { cn_msg = kzalloc(sizeof(*cn_msg) + len, GFP_ATOMIC); @@ -198,6 +229,11 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) } /* HVUTIL_TRANSPORT_CHARDEV */ mutex_lock(&hvt->lock); + if (hvt->mode != HVUTIL_TRANSPORT_CHARDEV) { + ret = -EINVAL; + goto out_unlock; + } + if (hvt->outmsg) { /* Previous message wasn't received */ ret = -EFAULT; @@ -268,6 +304,11 @@ err_free_hvt: void hvutil_transport_destroy(struct hvutil_transport *hvt) { + mutex_lock(&hvt->lock); + hvt->mode = HVUTIL_TRANSPORT_DESTROY; + wake_up_interruptible(&hvt->outmsg_q); + mutex_unlock(&hvt->lock); + spin_lock(&hvt_list_lock); list_del(&hvt->list); spin_unlock(&hvt_list_lock); diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h index bff4c921e817..06254a165a18 100644 --- a/drivers/hv/hv_utils_transport.h +++ b/drivers/hv/hv_utils_transport.h @@ -25,6 +25,7 @@ enum hvutil_transport_mode { HVUTIL_TRANSPORT_INIT = 0, HVUTIL_TRANSPORT_NETLINK, HVUTIL_TRANSPORT_CHARDEV, + HVUTIL_TRANSPORT_DESTROY, }; struct hvutil_transport { -- cgit v1.2.3 From 9420098adc50a88d4a441e0f92d54bfa7af44448 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:56 -0800 Subject: Drivers: hv: utils: fix crash when device is removed from host side The crash is observed when a service is being disabled host side while userspace daemon is connected to the device: [ 90.244859] general protection fault: 0000 [#1] SMP ... [ 90.800082] Call Trace: [ 90.800082] [] __fput+0xc8/0x1f0 [ 90.800082] [] ____fput+0xe/0x10 ... [ 90.800082] [] do_signal+0x28/0x580 [ 90.800082] [] ? finish_task_switch+0xa6/0x180 [ 90.800082] [] ? __schedule+0x28f/0x870 [ 90.800082] [] ? hvt_op_read+0x12a/0x140 [hv_utils] ... The problem is that hvutil_transport_destroy() which does misc_deregister() freeing the appropriate device is reachable by two paths: module unload and from util_remove(). While module unload path is protected by .owner in struct file_operations util_remove() path is not. Freeing the device while someone holds an open fd for it is a show stopper. In general, it is not possible to revoke an fd from all users so the only way to solve the issue is to defer freeing the hvutil_transport structure. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 31c2f8649271..ee20b5074238 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -155,13 +155,22 @@ static int hvt_op_open(struct inode *inode, struct file *file) return ret; } +static void hvt_transport_free(struct hvutil_transport *hvt) +{ + misc_deregister(&hvt->mdev); + kfree(hvt->outmsg); + kfree(hvt); +} + static int hvt_op_release(struct inode *inode, struct file *file) { struct hvutil_transport *hvt; + int mode_old; hvt = container_of(file->f_op, struct hvutil_transport, fops); mutex_lock(&hvt->lock); + mode_old = hvt->mode; if (hvt->mode != HVUTIL_TRANSPORT_DESTROY) hvt->mode = HVUTIL_TRANSPORT_INIT; /* @@ -171,6 +180,9 @@ static int hvt_op_release(struct inode *inode, struct file *file) hvt_reset(hvt); mutex_unlock(&hvt->lock); + if (mode_old == HVUTIL_TRANSPORT_DESTROY) + hvt_transport_free(hvt); + return 0; } @@ -304,17 +316,25 @@ err_free_hvt: void hvutil_transport_destroy(struct hvutil_transport *hvt) { + int mode_old; + mutex_lock(&hvt->lock); + mode_old = hvt->mode; hvt->mode = HVUTIL_TRANSPORT_DESTROY; wake_up_interruptible(&hvt->outmsg_q); mutex_unlock(&hvt->lock); + /* + * In case we were in 'chardev' mode we still have an open fd so we + * have to defer freeing the device. Netlink interface can be freed + * now. + */ spin_lock(&hvt_list_lock); list_del(&hvt->list); spin_unlock(&hvt_list_lock); if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) cn_del_callback(&hvt->cn_id); - misc_deregister(&hvt->mdev); - kfree(hvt->outmsg); - kfree(hvt); + + if (mode_old != HVUTIL_TRANSPORT_CHARDEV) + hvt_transport_free(hvt); } -- cgit v1.2.3 From 822f18d4d3e9d4efb4996bbe562d0f99ab82d7dd Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:57 -0800 Subject: Drivers: hv: ring_buffer.c: fix comment style Convert 6+-string comments repeating function names to normal kernel-style comments and fix a couple of other comment style issues. No textual or functional changes intended. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/ring_buffer.c | 135 +++++++++-------------------------------------- 1 file changed, 26 insertions(+), 109 deletions(-) diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 70a1a9a22f87..7bca513e32b0 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -112,9 +112,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz, u32 read_loc = rbi->ring_buffer->read_index; u32 pending_sz = rbi->ring_buffer->pending_send_sz; - /* - * If the other end is not blocked on write don't bother. - */ + /* If the other end is not blocked on write don't bother. */ if (pending_sz == 0) return false; @@ -128,12 +126,7 @@ static bool hv_need_to_signal_on_read(u32 prev_write_sz, return false; } -/* - * hv_get_next_write_location() - * - * Get the next write location for the specified ring buffer - * - */ +/* Get the next write location for the specified ring buffer. */ static inline u32 hv_get_next_write_location(struct hv_ring_buffer_info *ring_info) { @@ -142,12 +135,7 @@ hv_get_next_write_location(struct hv_ring_buffer_info *ring_info) return next; } -/* - * hv_set_next_write_location() - * - * Set the next write location for the specified ring buffer - * - */ +/* Set the next write location for the specified ring buffer. */ static inline void hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, u32 next_write_location) @@ -155,11 +143,7 @@ hv_set_next_write_location(struct hv_ring_buffer_info *ring_info, ring_info->ring_buffer->write_index = next_write_location; } -/* - * hv_get_next_read_location() - * - * Get the next read location for the specified ring buffer - */ +/* Get the next read location for the specified ring buffer. */ static inline u32 hv_get_next_read_location(struct hv_ring_buffer_info *ring_info) { @@ -169,10 +153,8 @@ hv_get_next_read_location(struct hv_ring_buffer_info *ring_info) } /* - * hv_get_next_readlocation_withoffset() - * * Get the next read location + offset for the specified ring buffer. - * This allows the caller to skip + * This allows the caller to skip. */ static inline u32 hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, @@ -186,13 +168,7 @@ hv_get_next_readlocation_withoffset(struct hv_ring_buffer_info *ring_info, return next; } -/* - * - * hv_set_next_read_location() - * - * Set the next read location for the specified ring buffer - * - */ +/* Set the next read location for the specified ring buffer. */ static inline void hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, u32 next_read_location) @@ -201,12 +177,7 @@ hv_set_next_read_location(struct hv_ring_buffer_info *ring_info, } -/* - * - * hv_get_ring_buffer() - * - * Get the start of the ring buffer - */ +/* Get the start of the ring buffer. */ static inline void * hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info) { @@ -214,25 +185,14 @@ hv_get_ring_buffer(struct hv_ring_buffer_info *ring_info) } -/* - * - * hv_get_ring_buffersize() - * - * Get the size of the ring buffer - */ +/* Get the size of the ring buffer. */ static inline u32 hv_get_ring_buffersize(struct hv_ring_buffer_info *ring_info) { return ring_info->ring_datasize; } -/* - * - * hv_get_ring_bufferindices() - * - * Get the read and write indices as u64 of the specified ring buffer - * - */ +/* Get the read and write indices as u64 of the specified ring buffer. */ static inline u64 hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) { @@ -240,12 +200,8 @@ hv_get_ring_bufferindices(struct hv_ring_buffer_info *ring_info) } /* - * - * hv_copyfrom_ringbuffer() - * * Helper routine to copy to source from ring buffer. * Assume there is enough room. Handles wrap-around in src case only!! - * */ static u32 hv_copyfrom_ringbuffer( struct hv_ring_buffer_info *ring_info, @@ -277,12 +233,8 @@ static u32 hv_copyfrom_ringbuffer( /* - * - * hv_copyto_ringbuffer() - * * Helper routine to copy from source to ring buffer. * Assume there is enough room. Handles wrap-around in dest case only!! - * */ static u32 hv_copyto_ringbuffer( struct hv_ring_buffer_info *ring_info, @@ -308,13 +260,7 @@ static u32 hv_copyto_ringbuffer( return start_write_offset; } -/* - * - * hv_ringbuffer_get_debuginfo() - * - * Get various debug metrics for the specified ring buffer - * - */ +/* Get various debug metrics for the specified ring buffer. */ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info) { @@ -337,13 +283,7 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, } } -/* - * - * hv_ringbuffer_init() - * - *Initialize the ring buffer - * - */ +/* Initialize the ring buffer. */ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer, u32 buflen) { @@ -356,9 +296,7 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, ring_info->ring_buffer->read_index = ring_info->ring_buffer->write_index = 0; - /* - * Set the feature bit for enabling flow control. - */ + /* Set the feature bit for enabling flow control. */ ring_info->ring_buffer->feature_bits.value = 1; ring_info->ring_size = buflen; @@ -369,24 +307,12 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, return 0; } -/* - * - * hv_ringbuffer_cleanup() - * - * Cleanup the ring buffer - * - */ +/* Cleanup the ring buffer. */ void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info) { } -/* - * - * hv_ringbuffer_write() - * - * Write to the ring buffer - * - */ +/* Write to the ring buffer. */ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, struct kvec *kv_list, u32 kv_count, bool *signal) { @@ -411,10 +337,11 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, &bytes_avail_toread, &bytes_avail_towrite); - - /* If there is only room for the packet, assume it is full. */ - /* Otherwise, the next time around, we think the ring buffer */ - /* is empty since the read index == write index */ + /* + * If there is only room for the packet, assume it is full. + * Otherwise, the next time around, we think the ring buffer + * is empty since the read index == write index. + */ if (bytes_avail_towrite <= totalbytes_towrite) { spin_unlock_irqrestore(&outring_info->ring_lock, flags); return -EAGAIN; @@ -454,13 +381,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, } -/* - * - * hv_ringbuffer_peek() - * - * Read without advancing the read index - * - */ +/* Read without advancing the read index. */ int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info, void *Buffer, u32 buflen) { @@ -497,13 +418,7 @@ int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info, } -/* - * - * hv_ringbuffer_read() - * - * Read and advance the read index - * - */ +/* Read and advance the read index. */ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, u32 buflen, u32 offset, bool *signal) { @@ -542,9 +457,11 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, sizeof(u64), next_read_location); - /* Make sure all reads are done before we update the read index since */ - /* the writer may start writing to the read area once the read index */ - /*is updated */ + /* + * Make sure all reads are done before we update the read index since + * the writer may start writing to the read area once the read index + * is updated. + */ mb(); /* Update the read index */ -- cgit v1.2.3 From 45870a441361d1c05a5f767c4ece2f6e30e0da9c Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:58 -0800 Subject: Drivers: hv: ring_buffer: remove stray smp_read_barrier_depends() smp_read_barrier_depends() does nothing on almost all arcitectures including x86 and having it in the beginning of hv_get_ringbuffer_availbytes() does not provide any guarantees anyway. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- include/linux/hyperv.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index acd995b81c6b..179ff330af59 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -141,8 +141,6 @@ hv_get_ringbuffer_availbytes(struct hv_ring_buffer_info *rbi, { u32 read_loc, write_loc, dsize; - smp_read_barrier_depends(); - /* Capture the read/write indices before they changed */ read_loc = rbi->ring_buffer->read_index; write_loc = rbi->ring_buffer->write_index; -- cgit v1.2.3 From b5f53dde8d8e84a6ee200dbd0bd90a400a8fe1a1 Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:01:59 -0800 Subject: Drivers: hv: ring_buffer: remove code duplication from hv_ringbuffer_peek/read() hv_ringbuffer_peek() does the same as hv_ringbuffer_read() without advancing the read index. The only functional change this patch brings is moving hv_need_to_signal_on_read() call under the ring_lock but this function is just a couple of comparisons. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/ring_buffer.c | 68 ++++++++++++++++++------------------------------ 1 file changed, 25 insertions(+), 43 deletions(-) diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 7bca513e32b0..07f9408fc59e 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -380,47 +380,9 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, return 0; } - -/* Read without advancing the read index. */ -int hv_ringbuffer_peek(struct hv_ring_buffer_info *Inring_info, - void *Buffer, u32 buflen) -{ - u32 bytes_avail_towrite; - u32 bytes_avail_toread; - u32 next_read_location = 0; - unsigned long flags; - - spin_lock_irqsave(&Inring_info->ring_lock, flags); - - hv_get_ringbuffer_availbytes(Inring_info, - &bytes_avail_toread, - &bytes_avail_towrite); - - /* Make sure there is something to read */ - if (bytes_avail_toread < buflen) { - - spin_unlock_irqrestore(&Inring_info->ring_lock, flags); - - return -EAGAIN; - } - - /* Convert to byte offset */ - next_read_location = hv_get_next_read_location(Inring_info); - - next_read_location = hv_copyfrom_ringbuffer(Inring_info, - Buffer, - buflen, - next_read_location); - - spin_unlock_irqrestore(&Inring_info->ring_lock, flags); - - return 0; -} - - -/* Read and advance the read index. */ -int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, - u32 buflen, u32 offset, bool *signal) +static inline int __hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, + void *buffer, u32 buflen, u32 offset, + bool *signal, bool advance) { u32 bytes_avail_towrite; u32 bytes_avail_toread; @@ -452,6 +414,9 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, buflen, next_read_location); + if (!advance) + goto out_unlock; + next_read_location = hv_copyfrom_ringbuffer(inring_info, &prev_indices, sizeof(u64), @@ -467,9 +432,26 @@ int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, void *buffer, /* Update the read index */ hv_set_next_read_location(inring_info, next_read_location); - spin_unlock_irqrestore(&inring_info->ring_lock, flags); - *signal = hv_need_to_signal_on_read(bytes_avail_towrite, inring_info); +out_unlock: + spin_unlock_irqrestore(&inring_info->ring_lock, flags); return 0; } + +/* Read from ring buffer without advancing the read index. */ +int hv_ringbuffer_peek(struct hv_ring_buffer_info *inring_info, + void *buffer, u32 buflen) +{ + return __hv_ringbuffer_read(inring_info, buffer, buflen, + 0, NULL, false); +} + +/* Read from ring buffer and advance the read index. */ +int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, + void *buffer, u32 buflen, u32 offset, + bool *signal) +{ + return __hv_ringbuffer_read(inring_info, buffer, buflen, + offset, signal, true); +} -- cgit v1.2.3 From 667d374064b0cc48b6122101b287908d1b392bdb Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:02:00 -0800 Subject: Drivers: hv: remove code duplication between vmbus_recvpacket()/vmbus_recvpacket_raw() vmbus_recvpacket() and vmbus_recvpacket_raw() are almost identical but there are two discrepancies: 1) vmbus_recvpacket() doesn't propagate errors from hv_ringbuffer_read() which looks like it is not desired. 2) There is an error message printed in packetlen > bufferlen case in vmbus_recvpacket(). I'm removing it as it is usless for users to see such messages and /vmbus_recvpacket_raw() doesn't have it. Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 65 ++++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 43 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index 2889d97c03b1..dd6de7fc442f 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -922,8 +922,10 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer); * * Mainly used by Hyper-V drivers. */ -int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, - u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) +static inline int +__vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, + u32 bufferlen, u32 *buffer_actual_len, u64 *requestid, + bool raw) { struct vmpacket_descriptor desc; u32 packetlen; @@ -941,27 +943,34 @@ int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, return 0; packetlen = desc.len8 << 3; - userlen = packetlen - (desc.offset8 << 3); + if (!raw) + userlen = packetlen - (desc.offset8 << 3); + else + userlen = packetlen; *buffer_actual_len = userlen; - if (userlen > bufferlen) { - - pr_err("Buffer too small - got %d needs %d\n", - bufferlen, userlen); - return -ETOOSMALL; - } + if (userlen > bufferlen) + return -ENOBUFS; *requestid = desc.trans_id; /* Copy over the packet to the user buffer */ ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen, - (desc.offset8 << 3), &signal); + raw ? 0 : desc.offset8 << 3, &signal); if (signal) vmbus_setevent(channel); - return 0; + return ret; +} + +int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, + u32 bufferlen, u32 *buffer_actual_len, + u64 *requestid) +{ + return __vmbus_recvpacket(channel, buffer, bufferlen, + buffer_actual_len, requestid, false); } EXPORT_SYMBOL(vmbus_recvpacket); @@ -972,37 +981,7 @@ int vmbus_recvpacket_raw(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u32 *buffer_actual_len, u64 *requestid) { - struct vmpacket_descriptor desc; - u32 packetlen; - int ret; - bool signal = false; - - *buffer_actual_len = 0; - *requestid = 0; - - - ret = hv_ringbuffer_peek(&channel->inbound, &desc, - sizeof(struct vmpacket_descriptor)); - if (ret != 0) - return 0; - - - packetlen = desc.len8 << 3; - - *buffer_actual_len = packetlen; - - if (packetlen > bufferlen) - return -ENOBUFS; - - *requestid = desc.trans_id; - - /* Copy over the entire packet to the user buffer */ - ret = hv_ringbuffer_read(&channel->inbound, buffer, packetlen, 0, - &signal); - - if (signal) - vmbus_setevent(channel); - - return ret; + return __vmbus_recvpacket(channel, buffer, bufferlen, + buffer_actual_len, requestid, true); } EXPORT_SYMBOL_GPL(vmbus_recvpacket_raw); -- cgit v1.2.3 From 940b68e2c3e4ebf032885203c3970e9649f814af Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Mon, 14 Dec 2015 19:02:01 -0800 Subject: Drivers: hv: ring_buffer: eliminate hv_ringbuffer_peek() Currently, there is only one user for hv_ringbuffer_read()/ hv_ringbuffer_peak() functions and the usage of these functions is: - insecure as we drop ring_lock between them, someone else (in theory only) can acquire it in between; - non-optimal as we do a number of things (acquire/release the above mentioned lock, calculate available space on the ring, ...) twice and this path is performance-critical. Remove hv_ringbuffer_peek() moving the logic from __vmbus_recvpacket() to hv_ringbuffer_read(). Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel.c | 30 ++-------------------- drivers/hv/hyperv_vmbus.h | 11 +++----- drivers/hv/ring_buffer.c | 65 +++++++++++++++++++++++++++-------------------- 3 files changed, 42 insertions(+), 64 deletions(-) diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c index dd6de7fc442f..1161d68a1863 100644 --- a/drivers/hv/channel.c +++ b/drivers/hv/channel.c @@ -927,37 +927,11 @@ __vmbus_recvpacket(struct vmbus_channel *channel, void *buffer, u32 bufferlen, u32 *buffer_actual_len, u64 *requestid, bool raw) { - struct vmpacket_descriptor desc; - u32 packetlen; - u32 userlen; int ret; bool signal = false; - *buffer_actual_len = 0; - *requestid = 0; - - - ret = hv_ringbuffer_peek(&channel->inbound, &desc, - sizeof(struct vmpacket_descriptor)); - if (ret != 0) - return 0; - - packetlen = desc.len8 << 3; - if (!raw) - userlen = packetlen - (desc.offset8 << 3); - else - userlen = packetlen; - - *buffer_actual_len = userlen; - - if (userlen > bufferlen) - return -ENOBUFS; - - *requestid = desc.trans_id; - - /* Copy over the packet to the user buffer */ - ret = hv_ringbuffer_read(&channel->inbound, buffer, userlen, - raw ? 0 : desc.offset8 << 3, &signal); + ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen, + buffer_actual_len, requestid, &signal, raw); if (signal) vmbus_setevent(channel); diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h index 4d67e984ac4f..0411b7bfb3c0 100644 --- a/drivers/hv/hyperv_vmbus.h +++ b/drivers/hv/hyperv_vmbus.h @@ -619,14 +619,9 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info, struct kvec *kv_list, u32 kv_count, bool *signal); -int hv_ringbuffer_peek(struct hv_ring_buffer_info *ring_info, void *buffer, - u32 buflen); - -int hv_ringbuffer_read(struct hv_ring_buffer_info *ring_info, - void *buffer, - u32 buflen, - u32 offset, bool *signal); - +int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, + void *buffer, u32 buflen, u32 *buffer_actual_len, + u64 *requestid, bool *signal, bool raw); void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info, struct hv_ring_buffer_debug_info *debug_info); diff --git a/drivers/hv/ring_buffer.c b/drivers/hv/ring_buffer.c index 07f9408fc59e..b53702ce692f 100644 --- a/drivers/hv/ring_buffer.c +++ b/drivers/hv/ring_buffer.c @@ -380,30 +380,59 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info, return 0; } -static inline int __hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, - void *buffer, u32 buflen, u32 offset, - bool *signal, bool advance) +int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, + void *buffer, u32 buflen, u32 *buffer_actual_len, + u64 *requestid, bool *signal, bool raw) { u32 bytes_avail_towrite; u32 bytes_avail_toread; u32 next_read_location = 0; u64 prev_indices = 0; unsigned long flags; + struct vmpacket_descriptor desc; + u32 offset; + u32 packetlen; + int ret = 0; if (buflen <= 0) return -EINVAL; spin_lock_irqsave(&inring_info->ring_lock, flags); + *buffer_actual_len = 0; + *requestid = 0; + hv_get_ringbuffer_availbytes(inring_info, &bytes_avail_toread, &bytes_avail_towrite); /* Make sure there is something to read */ - if (bytes_avail_toread < buflen) { - spin_unlock_irqrestore(&inring_info->ring_lock, flags); + if (bytes_avail_toread < sizeof(desc)) { + /* + * No error is set when there is even no header, drivers are + * supposed to analyze buffer_actual_len. + */ + goto out_unlock; + } - return -EAGAIN; + next_read_location = hv_get_next_read_location(inring_info); + next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc, + sizeof(desc), + next_read_location); + + offset = raw ? 0 : (desc.offset8 << 3); + packetlen = (desc.len8 << 3) - offset; + *buffer_actual_len = packetlen; + *requestid = desc.trans_id; + + if (bytes_avail_toread < packetlen + offset) { + ret = -EAGAIN; + goto out_unlock; + } + + if (packetlen > buflen) { + ret = -ENOBUFS; + goto out_unlock; } next_read_location = @@ -411,12 +440,9 @@ static inline int __hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, next_read_location = hv_copyfrom_ringbuffer(inring_info, buffer, - buflen, + packetlen, next_read_location); - if (!advance) - goto out_unlock; - next_read_location = hv_copyfrom_ringbuffer(inring_info, &prev_indices, sizeof(u64), @@ -436,22 +462,5 @@ static inline int __hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, out_unlock: spin_unlock_irqrestore(&inring_info->ring_lock, flags); - return 0; -} - -/* Read from ring buffer without advancing the read index. */ -int hv_ringbuffer_peek(struct hv_ring_buffer_info *inring_info, - void *buffer, u32 buflen) -{ - return __hv_ringbuffer_read(inring_info, buffer, buflen, - 0, NULL, false); -} - -/* Read from ring buffer and advance the read index. */ -int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info, - void *buffer, u32 buflen, u32 offset, - bool *signal) -{ - return __hv_ringbuffer_read(inring_info, buffer, buflen, - offset, signal, true); + return ret; } -- cgit v1.2.3 From 08a0a4f987a4b5827e4111eccc97a9271d24633e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 19 Dec 2015 08:17:41 +0900 Subject: extcon: add Maxim MAX3355 driver Maxim Integrated MAX3355E chip integrates a charge pump and comparators to enable a system with an integrated USB OTG dual-role transceiver to function as an USB OTG dual-role device. In addition to sensing/controlling Vbus, the chip also passes thru the ID signal from the USB OTG connector. On some Renesas boards, this signal is just fed into the SoC thru a GPIO pin -- there's no real OTG controller, only host and gadget USB controllers sharing the same USB bus; however, we'd like to allow host or gadget drivers to be loaded depending on the cable type, hence the need for the MAX3355 extcon driver. The Vbus status signals are also wired to GPIOs (however, we aren't currently interested in them), the OFFVBUS# signal is controlled by the host controllers, there's also the SHDN# signal wired to a GPIO, it should be driven high for the normal operation. Signed-off-by: Sergei Shtylyov Acked-by: Chanwoo Choi Acked-by: Rob Herring [cw00.choi: Add the GPIOLIB dependency] Signed-off-by: Chanwoo Choi --- .../devicetree/bindings/extcon/extcon-max3355.txt | 21 +++ drivers/extcon/Kconfig | 9 ++ drivers/extcon/Makefile | 1 + drivers/extcon/extcon-max3355.c | 146 +++++++++++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 Documentation/devicetree/bindings/extcon/extcon-max3355.txt create mode 100644 drivers/extcon/extcon-max3355.c diff --git a/Documentation/devicetree/bindings/extcon/extcon-max3355.txt b/Documentation/devicetree/bindings/extcon/extcon-max3355.txt new file mode 100644 index 000000000000..f2288ea9eb82 --- /dev/null +++ b/Documentation/devicetree/bindings/extcon/extcon-max3355.txt @@ -0,0 +1,21 @@ +Maxim Integrated MAX3355 USB OTG chip +------------------------------------- + +MAX3355 integrates a charge pump and comparators to enable a system with an +integrated USB OTG dual-role transceiver to function as a USB OTG dual-role +device. + +Required properties: +- compatible: should be "maxim,max3355"; +- maxim,shdn-gpios: should contain a phandle and GPIO specifier for the GPIO pin + connected to the MAX3355's SHDN# pin; +- id-gpios: should contain a phandle and GPIO specifier for the GPIO pin + connected to the MAX3355's ID_OUT pin. + +Example: + + usb-otg { + compatible = "maxim,max3355"; + maxim,shdn-gpios = <&gpio2 4 GPIO_ACTIVE_LOW>; + id-gpios = <&gpio5 31 GPIO_ACTIVE_HIGH>; + }; diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 0cebbf668886..3d89e60a3e71 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -52,6 +52,15 @@ config EXTCON_MAX14577 Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory detector and switch. +config EXTCON_MAX3355 + tristate "Maxim MAX3355 USB OTG EXTCON Support" + depends on GPIOLIB || COMPILE_TEST + help + If you say yes here you get support for the USB OTG role detection by + MAX3355. The MAX3355 chip integrates a charge pump and comparators to + enable a system with an integrated USB OTG dual-role transceiver to + function as an USB OTG dual-role device. + config EXTCON_MAX77693 tristate "Maxim MAX77693 EXTCON Support" depends on MFD_MAX77693 && INPUT diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index ba787d04295b..2a0e4f45d5b2 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_EXTCON_ARIZONA) += extcon-arizona.o obj-$(CONFIG_EXTCON_AXP288) += extcon-axp288.o obj-$(CONFIG_EXTCON_GPIO) += extcon-gpio.o obj-$(CONFIG_EXTCON_MAX14577) += extcon-max14577.o +obj-$(CONFIG_EXTCON_MAX3355) += extcon-max3355.o obj-$(CONFIG_EXTCON_MAX77693) += extcon-max77693.o obj-$(CONFIG_EXTCON_MAX77843) += extcon-max77843.o obj-$(CONFIG_EXTCON_MAX8997) += extcon-max8997.o diff --git a/drivers/extcon/extcon-max3355.c b/drivers/extcon/extcon-max3355.c new file mode 100644 index 000000000000..c24abec5d06c --- /dev/null +++ b/drivers/extcon/extcon-max3355.c @@ -0,0 +1,146 @@ +/* + * Maxim Integrated MAX3355 USB OTG chip extcon driver + * + * Copyright (C) 2014-2015 Cogent Embedded, Inc. + * Author: Sergei Shtylyov + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + */ + +#include +#include +#include +#include +#include +#include + +struct max3355_data { + struct extcon_dev *edev; + struct gpio_desc *id_gpiod; + struct gpio_desc *shdn_gpiod; +}; + +static const unsigned int max3355_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +static irqreturn_t max3355_id_irq(int irq, void *dev_id) +{ + struct max3355_data *data = dev_id; + int id = gpiod_get_value_cansleep(data->id_gpiod); + + if (id) { + /* + * ID = 1 means USB HOST cable detached. + * As we don't have event for USB peripheral cable attached, + * we simulate USB peripheral attach here. + */ + extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, false); + extcon_set_cable_state_(data->edev, EXTCON_USB, true); + } else { + /* + * ID = 0 means USB HOST cable attached. + * As we don't have event for USB peripheral cable detached, + * we simulate USB peripheral detach here. + */ + extcon_set_cable_state_(data->edev, EXTCON_USB, false); + extcon_set_cable_state_(data->edev, EXTCON_USB_HOST, true); + } + + return IRQ_HANDLED; +} + +static int max3355_probe(struct platform_device *pdev) +{ + struct max3355_data *data; + struct gpio_desc *gpiod; + int irq, err; + + data = devm_kzalloc(&pdev->dev, sizeof(struct max3355_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN); + if (IS_ERR(gpiod)) { + dev_err(&pdev->dev, "failed to get ID_OUT GPIO\n"); + return PTR_ERR(gpiod); + } + data->id_gpiod = gpiod; + + gpiod = devm_gpiod_get(&pdev->dev, "maxim,shdn", GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) { + dev_err(&pdev->dev, "failed to get SHDN# GPIO\n"); + return PTR_ERR(gpiod); + } + data->shdn_gpiod = gpiod; + + data->edev = devm_extcon_dev_allocate(&pdev->dev, max3355_cable); + if (IS_ERR(data->edev)) { + dev_err(&pdev->dev, "failed to allocate extcon device\n"); + return PTR_ERR(data->edev); + } + + err = devm_extcon_dev_register(&pdev->dev, data->edev); + if (err < 0) { + dev_err(&pdev->dev, "failed to register extcon device\n"); + return err; + } + + irq = gpiod_to_irq(data->id_gpiod); + if (irq < 0) { + dev_err(&pdev->dev, "failed to translate ID_OUT GPIO to IRQ\n"); + return irq; + } + + err = devm_request_threaded_irq(&pdev->dev, irq, NULL, max3355_id_irq, + IRQF_ONESHOT | IRQF_NO_SUSPEND | + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, + pdev->name, data); + if (err < 0) { + dev_err(&pdev->dev, "failed to request ID_OUT IRQ\n"); + return err; + } + + platform_set_drvdata(pdev, data); + + /* Perform initial detection */ + max3355_id_irq(irq, data); + + return 0; +} + +static int max3355_remove(struct platform_device *pdev) +{ + struct max3355_data *data = platform_get_drvdata(pdev); + + gpiod_set_value_cansleep(data->shdn_gpiod, 0); + + return 0; +} + +static const struct of_device_id max3355_match_table[] = { + { .compatible = "maxim,max3355", }, + { } +}; +MODULE_DEVICE_TABLE(of, max3355_match_table); + +static struct platform_driver max3355_driver = { + .probe = max3355_probe, + .remove = max3355_remove, + .driver = { + .name = "extcon-max3355", + .of_match_table = max3355_match_table, + }, +}; + +module_platform_driver(max3355_driver); + +MODULE_AUTHOR("Sergei Shtylyov "); +MODULE_DESCRIPTION("Maxim MAX3355 extcon driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2048157ad02e65f6327118dd4a7b9c9f1fd12f77 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Mon, 21 Dec 2015 12:21:22 -0800 Subject: Drivers: hv: vmbus: fix the building warning with hyperv-keyboard With the recent change af3ff643ea91ba64dd8d0b1cbed54d44512f96cd (Drivers: hv: vmbus: Use uuid_le type consistently), we always get this warning: CC [M] drivers/input/serio/hyperv-keyboard.o drivers/input/serio/hyperv-keyboard.c:427:2: warning: missing braces around initializer [-Wmissing-braces] { HV_KBD_GUID, }, ^ drivers/input/serio/hyperv-keyboard.c:427:2: warning: (near initialization for .id_table[0].guid.b.) [-Wmissing-braces] The patch fixes the warning. Signed-off-by: Dexuan Cui Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/hyperv-keyboard.c | 10 ---------- include/linux/hyperv.h | 8 ++++++++ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c index e74e5d6e5f9f..c948866edf87 100644 --- a/drivers/input/serio/hyperv-keyboard.c +++ b/drivers/input/serio/hyperv-keyboard.c @@ -412,16 +412,6 @@ static int hv_kbd_remove(struct hv_device *hv_dev) return 0; } -/* - * Keyboard GUID - * {f912ad6d-2b17-48ea-bd65-f927a61c7684} - */ -#define HV_KBD_GUID \ - .guid = { \ - 0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48, \ - 0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84 \ - } - static const struct hv_vmbus_device_id id_table[] = { /* Keyboard guid */ { HV_KBD_GUID, }, diff --git a/include/linux/hyperv.h b/include/linux/hyperv.h index 179ff330af59..753dbad0bf94 100644 --- a/include/linux/hyperv.h +++ b/include/linux/hyperv.h @@ -1078,6 +1078,14 @@ u64 hv_do_hypercall(u64 control, void *input, void *output); .guid = UUID_LE(0xcfa8b69e, 0x5b4a, 0x4cc0, 0xb9, 0x8b, \ 0x8b, 0xa1, 0xa1, 0xf3, 0xf9, 0x5a) +/* + * Keyboard GUID + * {f912ad6d-2b17-48ea-bd65-f927a61c7684} + */ +#define HV_KBD_GUID \ + .guid = UUID_LE(0xf912ad6d, 0x2b17, 0x48ea, 0xbd, 0x65, \ + 0xf9, 0x27, 0xa6, 0x1c, 0x76, 0x84) + /* * VSS (Backup/Restore) GUID */ -- cgit v1.2.3 From 77b744a598d604de49df79cf161bbd1809a6948a Mon Sep 17 00:00:00 2001 From: Vitaly Kuznetsov Date: Tue, 15 Dec 2015 16:27:26 -0800 Subject: Drivers: hv: utils: fix hvt_op_poll() return value on transport destroy The return type of hvt_op_poll() is unsigned int and -EBADF is inappropriate, poll functions return POLL* statuses. Reported-by: Dexuan Cui Signed-off-by: Vitaly Kuznetsov Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/hv_utils_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index ee20b5074238..4f42c0e20c20 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -109,7 +109,7 @@ static unsigned int hvt_op_poll(struct file *file, poll_table *wait) poll_wait(file, &hvt->outmsg_q, wait); if (hvt->mode == HVUTIL_TRANSPORT_DESTROY) - return -EBADF; + return POLLERR | POLLHUP; if (hvt->outmsg_len > 0) return POLLIN | POLLRDNORM; -- cgit v1.2.3 From 879a650a273bc3efb9d472886b8ced12630ea8ed Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Tue, 15 Dec 2015 16:27:27 -0800 Subject: Drivers: hv: vmbus: Treat Fibre Channel devices as performance critical For performance critical devices, we distribute the incoming channel interrupt load across available CPUs in the guest. Include Fibre channel devices in the set of devices for which we would distribute the interrupt load. Signed-off-by: K. Y. Srinivasan Signed-off-by: Greg Kroah-Hartman --- drivers/hv/channel_mgmt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c index d0131717c1d5..1c1ad47042c5 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c @@ -361,6 +361,7 @@ err_free_chan: enum { IDE = 0, SCSI, + FC, NIC, ND_NIC, PCIE, @@ -377,6 +378,8 @@ static const struct hv_vmbus_device_id hp_devs[] = { { HV_IDE_GUID, }, /* Storage - SCSI */ { HV_SCSI_GUID, }, + /* Storage - FC */ + { HV_SYNTHFC_GUID, }, /* Network */ { HV_NIC_GUID, }, /* NetworkDirect Guest RDMA */ -- cgit v1.2.3 From fadf3a44e974b030e7145218ad1ab25e3ef91738 Mon Sep 17 00:00:00 2001 From: Mathieu Poirier Date: Thu, 17 Dec 2015 08:47:02 -0700 Subject: coresight: checking for NULL string in coresight_name_match() Connection child names associated to ports can sometimes be NULL, which is the case when booting a system on QEMU or when the Coresight power domain isn't switched on. This patch is adding a check to make sure a NULL string isn't fed to strcmp(), something that avoid crashing the system. Cc: # v3.18+ Reported-by: Tyler Baker Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/coresight.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/coresight.c b/drivers/hwtracing/coresight/coresight.c index e25492137d8b..93738dfbf631 100644 --- a/drivers/hwtracing/coresight/coresight.c +++ b/drivers/hwtracing/coresight/coresight.c @@ -548,7 +548,7 @@ static int coresight_name_match(struct device *dev, void *data) to_match = data; i_csdev = to_coresight_device(dev); - if (!strcmp(to_match, dev_name(&i_csdev->dev))) + if (to_match && !strcmp(to_match, dev_name(&i_csdev->dev))) return 1; return 0; -- cgit v1.2.3 From b9884d3b79f60846cdf04be262d13bca8996f99a Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Thu, 17 Dec 2015 08:47:02 -0700 Subject: coresight: Fix a typo in Kconfig Signed-off-by: Andrew F. Davis Signed-off-by: Mathieu Poirier Signed-off-by: Greg Kroah-Hartman --- drivers/hwtracing/coresight/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hwtracing/coresight/Kconfig b/drivers/hwtracing/coresight/Kconfig index 6c8921140f02..c85935f3525a 100644 --- a/drivers/hwtracing/coresight/Kconfig +++ b/drivers/hwtracing/coresight/Kconfig @@ -8,7 +8,7 @@ menuconfig CORESIGHT This framework provides a kernel interface for the CoreSight debug and trace drivers to register themselves with. It's intended to build a topological view of the CoreSight components based on a DT - specification and configure the right serie of components when a + specification and configure the right series of components when a trace source gets enabled. if CORESIGHT -- cgit v1.2.3 From e952736586098063fcb734550429b8a81a2c5d25 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 28 Oct 2015 14:41:30 +0530 Subject: parport: fix a trivial typo s/regsiter/register/ Signed-off-by: Geliang Tang Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 5ce5ef211bdb..89316965904f 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -148,7 +148,7 @@ void parport_bus_exit(void) /* * iterates through all the drivers registered with the bus and sends the port * details to the match_port callback of the driver, so that the driver can - * know about the new port that just regsitered with the bus and decide if it + * know about the new port that just registered with the bus and decide if it * wants to use this new port. */ static int driver_check(struct device_driver *dev_drv, void *_port) -- cgit v1.2.3 From 657e24d35479b3edd84706db082f5e18a2270631 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:31 +0530 Subject: parport: remove trailing white space Trailing white space is not accepted in kernel coding style. Remove them. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 89316965904f..b7fcb7fdb44a 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -1,6 +1,6 @@ /* * Parallel-port resource manager code. - * + * * Authors: David Campbell * Tim Waugh * Jose Renau @@ -93,7 +93,7 @@ static struct parport_operations dead_ops = { .ecp_write_data = dead_write, /* ecp */ .ecp_read_data = dead_read, .ecp_write_addr = dead_write, - + .compat_write_data = dead_write, /* compat */ .nibble_read_data = dead_read, /* nibble */ .byte_read_data = dead_read, /* byte */ @@ -689,7 +689,7 @@ void parport_remove_port(struct parport *port) struct pardevice * parport_register_device(struct parport *port, const char *name, int (*pf)(void *), void (*kf)(void *), - void (*irq_func)(void *), + void (*irq_func)(void *), int flags, void *handle) { struct pardevice *tmp; @@ -730,7 +730,7 @@ parport_register_device(struct parport *port, const char *name, if (!try_module_get(port->ops->owner)) { return NULL; } - + parport_get_port (port); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); -- cgit v1.2.3 From 27c6db2655502978c670bd15a1639066ff13c78c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:32 +0530 Subject: parport: EXPORT_SYMBOL should follow function All symbols were exported at the end of the file but they are supposed to be exported just after the function. And checkpatch was complaining about it. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index b7fcb7fdb44a..d85e566548b1 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -343,6 +343,7 @@ void parport_unregister_driver (struct parport_driver *drv) } mutex_unlock(®istration_lock); } +EXPORT_SYMBOL(parport_unregister_driver); static void free_port(struct device *dev) { @@ -378,6 +379,7 @@ struct parport *parport_get_port (struct parport *port) return to_parport_dev(dev); } +EXPORT_SYMBOL(parport_get_port); void parport_del_port(struct parport *port) { @@ -398,6 +400,7 @@ void parport_put_port (struct parport *port) { put_device(&port->bus_dev); } +EXPORT_SYMBOL(parport_put_port); /** * parport_register_port - register a parallel port @@ -508,6 +511,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, return tmp; } +EXPORT_SYMBOL(parport_register_port); /** * parport_announce_port - tell device drivers about a parallel port @@ -555,6 +559,7 @@ void parport_announce_port (struct parport *port) } mutex_unlock(®istration_lock); } +EXPORT_SYMBOL(parport_announce_port); /** * parport_remove_port - deregister a parallel port @@ -616,6 +621,7 @@ void parport_remove_port(struct parport *port) parport_put_port(slave); } } +EXPORT_SYMBOL(parport_remove_port); /** * parport_register_device - register a device on a parallel port @@ -810,6 +816,7 @@ parport_register_device(struct parport *port, const char *name, return NULL; } +EXPORT_SYMBOL(parport_register_device); static void free_pardevice(struct device *dev) { @@ -1025,6 +1032,7 @@ void parport_unregister_device(struct pardevice *dev) module_put(port->ops->owner); parport_put_port (port); } +EXPORT_SYMBOL(parport_unregister_device); /** * parport_find_number - find a parallel port by number @@ -1055,6 +1063,7 @@ struct parport *parport_find_number (int number) spin_unlock (&parportlist_lock); return result; } +EXPORT_SYMBOL(parport_find_number); /** * parport_find_base - find a parallel port by base address @@ -1085,6 +1094,7 @@ struct parport *parport_find_base (unsigned long base) spin_unlock (&parportlist_lock); return result; } +EXPORT_SYMBOL(parport_find_base); /** * parport_claim - claim access to a parallel port device @@ -1197,6 +1207,7 @@ blocked: write_unlock_irqrestore (&port->cad_lock, flags); return -EAGAIN; } +EXPORT_SYMBOL(parport_claim); /** * parport_claim_or_block - claim access to a parallel port device @@ -1259,6 +1270,7 @@ int parport_claim_or_block(struct pardevice *dev) dev->waiting = 0; return r; } +EXPORT_SYMBOL(parport_claim_or_block); /** * parport_release - give up access to a parallel port device @@ -1330,6 +1342,7 @@ void parport_release(struct pardevice *dev) pd->wakeup(pd->private); } } +EXPORT_SYMBOL(parport_release); irqreturn_t parport_irq_handler(int irq, void *dev_id) { @@ -1339,22 +1352,6 @@ irqreturn_t parport_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } - -/* Exported symbols for modules. */ - -EXPORT_SYMBOL(parport_claim); -EXPORT_SYMBOL(parport_claim_or_block); -EXPORT_SYMBOL(parport_release); -EXPORT_SYMBOL(parport_register_port); -EXPORT_SYMBOL(parport_announce_port); -EXPORT_SYMBOL(parport_remove_port); -EXPORT_SYMBOL(parport_unregister_driver); -EXPORT_SYMBOL(parport_register_device); -EXPORT_SYMBOL(parport_unregister_device); -EXPORT_SYMBOL(parport_get_port); -EXPORT_SYMBOL(parport_put_port); -EXPORT_SYMBOL(parport_find_number); -EXPORT_SYMBOL(parport_find_base); EXPORT_SYMBOL(parport_irq_handler); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 7b7a0a30c985145bf4474639d832c94cd63059fa Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:33 +0530 Subject: parport: fix coding style The multi-line comments were not according to the kernel coding style. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 69 +++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index d85e566548b1..840c73063a6a 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -207,8 +207,10 @@ static void detach_driver_chain(struct parport *port) /* Ask kmod for some lowlevel drivers. */ static void get_lowlevel_driver (void) { - /* There is no actual module called this: you should set - * up an alias for modutils. */ + /* + * There is no actual module called this: you should set + * up an alias for modutils. + */ request_module ("parport_lowlevel"); } @@ -728,11 +730,12 @@ parport_register_device(struct parport *port, const char *name, } } - /* We up our own module reference count, and that of the port - on which a device is to be registered, to ensure that - neither of us gets unloaded while we sleep in (e.g.) - kmalloc. - */ + /* + * We up our own module reference count, and that of the port + * on which a device is to be registered, to ensure that + * neither of us gets unloaded while we sleep in (e.g.) + * kmalloc. + */ if (!try_module_get(port->ops->owner)) { return NULL; } @@ -783,9 +786,11 @@ parport_register_device(struct parport *port, const char *name, } tmp->next = port->physport->devices; - wmb(); /* Make sure that tmp->next is written before it's - added to the list; see comments marked 'no locking - required' */ + wmb(); /* + * Make sure that tmp->next is written before it's + * added to the list; see comments marked 'no locking + * required' + */ if (port->physport->devices) port->physport->devices->prev = tmp; port->physport->devices = tmp; @@ -1008,8 +1013,10 @@ void parport_unregister_device(struct pardevice *dev) spin_unlock(&port->pardevice_lock); - /* Make sure we haven't left any pointers around in the wait - * list. */ + /* + * Make sure we haven't left any pointers around in the wait + * list. + */ spin_lock_irq(&port->waitlist_lock); if (dev->waitprev || dev->waitnext || port->waithead == dev) { if (dev->waitprev) @@ -1131,8 +1138,10 @@ int parport_claim(struct pardevice *dev) goto blocked; if (port->cad != oldcad) { - /* I think we'll actually deadlock rather than - get here, but just in case.. */ + /* + * I think we'll actually deadlock rather than + * get here, but just in case.. + */ printk(KERN_WARNING "%s: %s released port when preempted!\n", port->name, oldcad->name); @@ -1185,9 +1194,11 @@ int parport_claim(struct pardevice *dev) return 0; blocked: - /* If this is the first time we tried to claim the port, register an - interest. This is only allowed for devices sleeping in - parport_claim_or_block(), or those with a wakeup function. */ + /* + * If this is the first time we tried to claim the port, register an + * interest. This is only allowed for devices sleeping in + * parport_claim_or_block(), or those with a wakeup function. + */ /* The cad_lock is still held for writing here */ if (dev->waiting & 2 || dev->wakeup) { @@ -1223,8 +1234,10 @@ int parport_claim_or_block(struct pardevice *dev) { int r; - /* Signal to parport_claim() that we can wait even without a - wakeup function. */ + /* + * Signal to parport_claim() that we can wait even without a + * wakeup function. + */ dev->waiting = 2; /* Try to claim the port. If this fails, we need to sleep. */ @@ -1242,8 +1255,10 @@ int parport_claim_or_block(struct pardevice *dev) * See also parport_release() */ - /* If dev->waiting is clear now, an interrupt - gave us the port and we would deadlock if we slept. */ + /* + * If dev->waiting is clear now, an interrupt + * gave us the port and we would deadlock if we slept. + */ if (dev->waiting) { wait_event_interruptible(dev->wait_q, !dev->waiting); @@ -1316,8 +1331,10 @@ void parport_release(struct pardevice *dev) /* Save control registers */ port->ops->save_state(port, dev->state); - /* If anybody is waiting, find out who's been there longest and - then wake them up. (Note: no locking required) */ + /* + * If anybody is waiting, find out who's been there longest and + * then wake them up. (Note: no locking required) + */ /* !!! LOCKING IS NEEDED HERE */ for (pd = port->waithead; pd; pd = pd->waitnext) { if (pd->waiting & 2) { /* sleeping in claim_or_block */ @@ -1334,8 +1351,10 @@ void parport_release(struct pardevice *dev) } } - /* Nobody was waiting, so walk the list to see if anyone is - interested in being woken up. (Note: no locking required) */ + /* + * Nobody was waiting, so walk the list to see if anyone is + * interested in being woken up. (Note: no locking required) + */ /* !!! LOCKING IS NEEDED HERE */ for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { if (pd->wakeup && pd != dev) -- cgit v1.2.3 From b075e6f0510e12b38dbbb66141c5188e8c11ab8b Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:34 +0530 Subject: parport: code indent should use tabs Code should be indented using tabs and not by space. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 840c73063a6a..388c138304c1 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -455,7 +455,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->dma = dma; tmp->muxport = tmp->daisy = tmp->muxsel = -1; tmp->modes = 0; - INIT_LIST_HEAD(&tmp->list); + INIT_LIST_HEAD(&tmp->list); tmp->devices = tmp->cad = NULL; tmp->flags = 0; tmp->ops = ops; -- cgit v1.2.3 From a162188f9ca940b84a9ea61d88b50a8f408e0c0c Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:35 +0530 Subject: parport: quoted strings should not be split user visible strings should not be split as that affects the ability to grep. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 388c138304c1..dcad902f04a4 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -537,9 +537,8 @@ void parport_announce_port (struct parport *port) #endif if (!port->dev) - printk(KERN_WARNING "%s: fix this legacy " - "no-device port driver!\n", - port->name); + printk(KERN_WARNING "%s: fix this legacy no-device port driver!\n", + port->name); parport_proc_register(port); mutex_lock(®istration_lock); @@ -778,8 +777,8 @@ parport_register_device(struct parport *port, const char *name, if (port->physport->devices) { spin_unlock (&port->physport->pardevice_lock); printk (KERN_DEBUG - "%s: cannot grant exclusive access for " - "device %s\n", port->name, name); + "%s: cannot grant exclusive access for device %s\n", + port->name, name); goto out_free_all; } port->flags |= PARPORT_FLAG_EXCL; @@ -1276,9 +1275,8 @@ int parport_claim_or_block(struct pardevice *dev) #ifdef PARPORT_DEBUG_SHARING if (dev->port->physport->cad != dev) - printk(KERN_DEBUG "%s: exiting parport_claim_or_block " - "but %s owns port!\n", dev->name, - dev->port->physport->cad ? + printk(KERN_DEBUG "%s: exiting parport_claim_or_block but %s owns port!\n", + dev->name, dev->port->physport->cad ? dev->port->physport->cad->name:"nobody"); #endif } @@ -1306,8 +1304,8 @@ void parport_release(struct pardevice *dev) write_lock_irqsave(&port->cad_lock, flags); if (port->cad != dev) { write_unlock_irqrestore (&port->cad_lock, flags); - printk(KERN_WARNING "%s: %s tried to release parport " - "when not owner\n", port->name, dev->name); + printk(KERN_WARNING "%s: %s tried to release parport when not owner\n", + port->name, dev->name); return; } -- cgit v1.2.3 From 13efa75d4e5d467f685bd54df310919ae4dc8eac Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:36 +0530 Subject: parport: remove braces checkpatch was complaining about braces for single statement block. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index dcad902f04a4..5dbd6f434a91 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -735,9 +735,8 @@ parport_register_device(struct parport *port, const char *name, * neither of us gets unloaded while we sleep in (e.g.) * kmalloc. */ - if (!try_module_get(port->ops->owner)) { + if (!try_module_get(port->ops->owner)) return NULL; - } parport_get_port (port); @@ -1261,9 +1260,8 @@ int parport_claim_or_block(struct pardevice *dev) if (dev->waiting) { wait_event_interruptible(dev->wait_q, !dev->waiting); - if (signal_pending (current)) { + if (signal_pending (current)) return -EINTR; - } r = 1; } else { r = 0; -- cgit v1.2.3 From 47ec57ec0e52839b92066567e6eb02fb1e60e603 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:37 +0530 Subject: parport: remove unnecessary out of memory message If kmalloc() or kzalloc() fails we will get sufficient messages in the logs, no need to print these extra messages. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 5dbd6f434a91..441333bd4839 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -444,10 +444,8 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, int ret; tmp = kzalloc(sizeof(struct parport), GFP_KERNEL); - if (!tmp) { - printk(KERN_WARNING "parport: memory squeeze\n"); + if (!tmp) return NULL; - } /* Init our structure */ tmp->base = base; @@ -473,7 +471,6 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, name = kmalloc(15, GFP_KERNEL); if (!name) { - printk(KERN_ERR "parport: memory squeeze\n"); kfree(tmp); return NULL; } @@ -741,16 +738,12 @@ parport_register_device(struct parport *port, const char *name, parport_get_port (port); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); - if (tmp == NULL) { - printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); + if (tmp == NULL) goto out; - } tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); - if (tmp->state == NULL) { - printk(KERN_WARNING "%s: memory squeeze, couldn't register %s.\n", port->name, name); + if (tmp->state == NULL) goto out_free_pardevice; - } tmp->name = name; tmp->port = port; -- cgit v1.2.3 From b95b9d6cdecabfd99e074d6fda51dc962fd2a1cf Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:38 +0530 Subject: parport: change style of NULL comparison checkpatch was complaining about NULL comparisons. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index 441333bd4839..ccd7df458ebc 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -738,11 +738,11 @@ parport_register_device(struct parport *port, const char *name, parport_get_port (port); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); - if (tmp == NULL) + if (!tmp) goto out; tmp->state = kmalloc(sizeof(struct parport_state), GFP_KERNEL); - if (tmp->state == NULL) + if (!tmp->state) goto out_free_pardevice; tmp->name = name; @@ -971,7 +971,7 @@ void parport_unregister_device(struct pardevice *dev) struct parport *port; #ifdef PARPORT_PARANOID - if (dev == NULL) { + if (!dev) { printk(KERN_ERR "parport_unregister_device: passed NULL\n"); return; } @@ -1345,7 +1345,7 @@ void parport_release(struct pardevice *dev) * interested in being woken up. (Note: no locking required) */ /* !!! LOCKING IS NEEDED HERE */ - for (pd = port->devices; (port->cad == NULL) && pd; pd = pd->next) { + for (pd = port->devices; !port->cad && pd; pd = pd->next) { if (pd->wakeup && pd != dev) pd->wakeup(pd->private); } -- cgit v1.2.3 From e732b93c3276548bfa903d79c2083b2c8dc552af Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:39 +0530 Subject: parport: remove unneeded space checkpatch complains that space is prohibited between function name and open parenthesis '('. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 94 ++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index ccd7df458ebc..b68f19480dcf 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -54,16 +54,16 @@ static LIST_HEAD(drivers); static DEFINE_MUTEX(registration_lock); /* What you can do to a port that's gone away.. */ -static void dead_write_lines (struct parport *p, unsigned char b){} -static unsigned char dead_read_lines (struct parport *p) { return 0; } -static unsigned char dead_frob_lines (struct parport *p, unsigned char b, +static void dead_write_lines(struct parport *p, unsigned char b){} +static unsigned char dead_read_lines(struct parport *p) { return 0; } +static unsigned char dead_frob_lines(struct parport *p, unsigned char b, unsigned char c) { return 0; } -static void dead_onearg (struct parport *p){} -static void dead_initstate (struct pardevice *d, struct parport_state *s) { } -static void dead_state (struct parport *p, struct parport_state *s) { } -static size_t dead_write (struct parport *p, const void *b, size_t l, int f) +static void dead_onearg(struct parport *p){} +static void dead_initstate(struct pardevice *d, struct parport_state *s) { } +static void dead_state(struct parport *p, struct parport_state *s) { } +static size_t dead_write(struct parport *p, const void *b, size_t l, int f) { return 0; } -static size_t dead_read (struct parport *p, void *b, size_t l, int f) +static size_t dead_read(struct parport *p, void *b, size_t l, int f) { return 0; } static struct parport_operations dead_ops = { .write_data = dead_write_lines, /* data */ @@ -194,7 +194,7 @@ static void detach_driver_chain(struct parport *port) struct parport_driver *drv; /* caller has exclusive registration_lock */ list_for_each_entry(drv, &drivers, list) - drv->detach (port); + drv->detach(port); /* * call the detach function of the drivers registered in @@ -205,13 +205,13 @@ static void detach_driver_chain(struct parport *port) } /* Ask kmod for some lowlevel drivers. */ -static void get_lowlevel_driver (void) +static void get_lowlevel_driver(void) { /* * There is no actual module called this: you should set * up an alias for modutils. */ - request_module ("parport_lowlevel"); + request_module("parport_lowlevel"); } /* @@ -267,7 +267,7 @@ int __parport_register_driver(struct parport_driver *drv, struct module *owner, const char *mod_name) { if (list_empty(&portlist)) - get_lowlevel_driver (); + get_lowlevel_driver(); if (drv->devmodel) { /* using device model */ @@ -330,7 +330,7 @@ static int port_detach(struct device *dev, void *_drv) * finished by the time this function returns. **/ -void parport_unregister_driver (struct parport_driver *drv) +void parport_unregister_driver(struct parport_driver *drv) { struct parport *port; @@ -375,7 +375,7 @@ static void free_port(struct device *dev) * until the matching parport_put_port() call. **/ -struct parport *parport_get_port (struct parport *port) +struct parport *parport_get_port(struct parport *port) { struct device *dev = get_device(&port->bus_dev); @@ -398,7 +398,7 @@ EXPORT_SYMBOL(parport_del_port); * zero (port is no longer used), free_port is called. **/ -void parport_put_port (struct parport *port) +void parport_put_port(struct parport *port) { put_device(&port->bus_dev); } @@ -458,7 +458,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->flags = 0; tmp->ops = ops; tmp->physport = tmp; - memset (tmp->probe_info, 0, 5 * sizeof (struct parport_device_info)); + memset(tmp->probe_info, 0, 5 * sizeof(struct parport_device_info)); rwlock_init(&tmp->cad_lock); spin_lock_init(&tmp->waitlist_lock); spin_lock_init(&tmp->pardevice_lock); @@ -466,7 +466,7 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma, tmp->ieee1284.phase = IEEE1284_PH_FWD_IDLE; sema_init(&tmp->ieee1284.irq, 0); tmp->spintime = parport_default_spintime; - atomic_set (&tmp->ref_count, 1); + atomic_set(&tmp->ref_count, 1); INIT_LIST_HEAD(&tmp->full_list); name = kmalloc(15, GFP_KERNEL); @@ -524,7 +524,7 @@ EXPORT_SYMBOL(parport_register_port); * functions will be called, with @port as the parameter. **/ -void parport_announce_port (struct parport *port) +void parport_announce_port(struct parport *port) { int i; @@ -549,7 +549,7 @@ void parport_announce_port (struct parport *port) spin_unlock_irq(&parportlist_lock); /* Let drivers know that new port(s) has arrived. */ - attach_driver_chain (port); + attach_driver_chain(port); for (i = 1; i < 3; i++) { struct parport *slave = port->slaves[i-1]; if (slave) @@ -585,7 +585,7 @@ void parport_remove_port(struct parport *port) mutex_lock(®istration_lock); /* Spread the word. */ - detach_driver_chain (port); + detach_driver_chain(port); #ifdef CONFIG_PARPORT_1284 /* Forget the IEEE1284.3 topology of the port. */ @@ -700,7 +700,7 @@ parport_register_device(struct parport *port, const char *name, if (port->physport->flags & PARPORT_FLAG_EXCL) { /* An exclusive device is registered. */ - printk (KERN_DEBUG "%s: no more devices allowed\n", + printk(KERN_DEBUG "%s: no more devices allowed\n", port->name); return NULL; } @@ -735,7 +735,7 @@ parport_register_device(struct parport *port, const char *name, if (!try_module_get(port->ops->owner)) return NULL; - parport_get_port (port); + parport_get_port(port); tmp = kmalloc(sizeof(struct pardevice), GFP_KERNEL); if (!tmp) @@ -767,8 +767,8 @@ parport_register_device(struct parport *port, const char *name, if (flags & PARPORT_DEV_EXCL) { if (port->physport->devices) { - spin_unlock (&port->physport->pardevice_lock); - printk (KERN_DEBUG + spin_unlock(&port->physport->pardevice_lock); + printk(KERN_DEBUG "%s: cannot grant exclusive access for device %s\n", port->name, name); goto out_free_all; @@ -807,7 +807,7 @@ parport_register_device(struct parport *port, const char *name, out_free_pardevice: kfree(tmp); out: - parport_put_port (port); + parport_put_port(port); module_put(port->ops->owner); return NULL; @@ -988,7 +988,7 @@ void parport_unregister_device(struct pardevice *dev) if (port->cad == dev) { printk(KERN_DEBUG "%s: %s forgot to release port\n", port->name, dev->name); - parport_release (dev); + parport_release(dev); } spin_lock(&port->pardevice_lock); @@ -1028,7 +1028,7 @@ void parport_unregister_device(struct pardevice *dev) kfree(dev); module_put(port->ops->owner); - parport_put_port (port); + parport_put_port(port); } EXPORT_SYMBOL(parport_unregister_device); @@ -1044,21 +1044,21 @@ EXPORT_SYMBOL(parport_unregister_device); * gives you, use parport_put_port(). */ -struct parport *parport_find_number (int number) +struct parport *parport_find_number(int number) { struct parport *port, *result = NULL; if (list_empty(&portlist)) - get_lowlevel_driver (); + get_lowlevel_driver(); - spin_lock (&parportlist_lock); + spin_lock(&parportlist_lock); list_for_each_entry(port, &portlist, list) { if (port->number == number) { - result = parport_get_port (port); + result = parport_get_port(port); break; } } - spin_unlock (&parportlist_lock); + spin_unlock(&parportlist_lock); return result; } EXPORT_SYMBOL(parport_find_number); @@ -1075,21 +1075,21 @@ EXPORT_SYMBOL(parport_find_number); * gives you, use parport_put_port(). */ -struct parport *parport_find_base (unsigned long base) +struct parport *parport_find_base(unsigned long base) { struct parport *port, *result = NULL; if (list_empty(&portlist)) - get_lowlevel_driver (); + get_lowlevel_driver(); - spin_lock (&parportlist_lock); + spin_lock(&parportlist_lock); list_for_each_entry(port, &portlist, list) { if (port->base == base) { - result = parport_get_port (port); + result = parport_get_port(port); break; } } - spin_unlock (&parportlist_lock); + spin_unlock(&parportlist_lock); return result; } EXPORT_SYMBOL(parport_find_base); @@ -1119,7 +1119,7 @@ int parport_claim(struct pardevice *dev) } /* Preempt any current device */ - write_lock_irqsave (&port->cad_lock, flags); + write_lock_irqsave(&port->cad_lock, flags); if ((oldcad = port->cad) != NULL) { if (oldcad->preempt) { if (oldcad->preempt(oldcad->private)) @@ -1146,7 +1146,7 @@ int parport_claim(struct pardevice *dev) dev->waiting = 0; /* Take ourselves out of the wait list again. */ - spin_lock_irq (&port->waitlist_lock); + spin_lock_irq(&port->waitlist_lock); if (dev->waitprev) dev->waitprev->waitnext = dev->waitnext; else @@ -1155,7 +1155,7 @@ int parport_claim(struct pardevice *dev) dev->waitnext->waitprev = dev->waitprev; else port->waittail = dev->waitprev; - spin_unlock_irq (&port->waitlist_lock); + spin_unlock_irq(&port->waitlist_lock); dev->waitprev = dev->waitnext = NULL; } @@ -1172,7 +1172,7 @@ int parport_claim(struct pardevice *dev) /* If it's a daisy chain device, select it. */ if (dev->daisy >= 0) { /* This could be lazier. */ - if (!parport_daisy_select (port, dev->daisy, + if (!parport_daisy_select(port, dev->daisy, IEEE1284_MODE_COMPAT)) port->daisy = dev->daisy; } @@ -1193,7 +1193,7 @@ blocked: /* The cad_lock is still held for writing here */ if (dev->waiting & 2 || dev->wakeup) { - spin_lock (&port->waitlist_lock); + spin_lock(&port->waitlist_lock); if (test_and_set_bit(0, &dev->waiting) == 0) { /* First add ourselves to the end of the wait list. */ dev->waitnext = NULL; @@ -1204,9 +1204,9 @@ blocked: } else port->waithead = port->waittail = dev; } - spin_unlock (&port->waitlist_lock); + spin_unlock(&port->waitlist_lock); } - write_unlock_irqrestore (&port->cad_lock, flags); + write_unlock_irqrestore(&port->cad_lock, flags); return -EAGAIN; } EXPORT_SYMBOL(parport_claim); @@ -1253,7 +1253,7 @@ int parport_claim_or_block(struct pardevice *dev) if (dev->waiting) { wait_event_interruptible(dev->wait_q, !dev->waiting); - if (signal_pending (current)) + if (signal_pending(current)) return -EINTR; r = 1; } else { @@ -1294,7 +1294,7 @@ void parport_release(struct pardevice *dev) /* Make sure that dev is the current device */ write_lock_irqsave(&port->cad_lock, flags); if (port->cad != dev) { - write_unlock_irqrestore (&port->cad_lock, flags); + write_unlock_irqrestore(&port->cad_lock, flags); printk(KERN_WARNING "%s: %s tried to release parport when not owner\n", port->name, dev->name); return; @@ -1309,7 +1309,7 @@ void parport_release(struct pardevice *dev) /* If this is a daisy device, deselect it. */ if (dev->daisy >= 0) { - parport_daisy_deselect_all (port); + parport_daisy_deselect_all(port); port->daisy = -1; } #endif -- cgit v1.2.3 From e0a7f1f04cd9bb13df7503ba7156ff0a37c9f460 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 28 Oct 2015 14:41:40 +0530 Subject: parport: avoid assignment in if It is not an usual practise to assign some value to a variable in the if test condition. Signed-off-by: Sudip Mukherjee Signed-off-by: Greg Kroah-Hartman --- drivers/parport/share.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/parport/share.c b/drivers/parport/share.c index b68f19480dcf..3308427ed9f7 100644 --- a/drivers/parport/share.c +++ b/drivers/parport/share.c @@ -1120,7 +1120,8 @@ int parport_claim(struct pardevice *dev) /* Preempt any current device */ write_lock_irqsave(&port->cad_lock, flags); - if ((oldcad = port->cad) != NULL) { + oldcad = port->cad; + if (oldcad) { if (oldcad->preempt) { if (oldcad->preempt(oldcad->private)) goto blocked; -- cgit v1.2.3 From ed6dc538e5a36a331b6256d54f435c80f6715460 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 7 Jan 2016 14:46:38 +0200 Subject: mei: fix fasync return value on error fasync should return a negative value on error and not poll mask POLLERR. Cc: # 4.3+ Cc: Al Viro Reported-by: Al Viro Signed-off-by: Tomas Winkler Signed-off-by: Greg Kroah-Hartman --- drivers/misc/mei/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c index b2f2486b3d75..677d0362f334 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c @@ -657,7 +657,9 @@ out: * @file: pointer to file structure * @band: band bitmap * - * Return: poll mask + * Return: negative on error, + * 0 if it did no changes, + * and positive a process was added or deleted */ static int mei_fasync(int fd, struct file *file, int band) { @@ -665,7 +667,7 @@ static int mei_fasync(int fd, struct file *file, int band) struct mei_cl *cl = file->private_data; if (!mei_cl_is_connected(cl)) - return POLLERR; + return -ENODEV; return fasync_helper(fd, file, band, &cl->ev_async); } -- cgit v1.2.3